Skip to content
Snippets Groups Projects
Unverified Commit b34be76e authored by Sumner Evans's avatar Sumner Evans
Browse files

linkedingo/types: remove

parent 7f58d31c
No related branches found
No related tags found
No related merge requests found
Showing
with 445 additions and 146 deletions
......@@ -2,42 +2,35 @@ package connector
import (
"context"
"fmt"
"strconv"
"time"
"go.mau.fi/util/jsontime"
"maunium.net/go/mautrix/bridgev2"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/mautrix-linkedin/pkg/linkedingoold/routingold/queryold"
)
func (l *LinkedInClient) FetchMessages(ctx context.Context, fetchParams bridgev2.FetchMessagesParams) (*bridgev2.FetchMessagesResponse, error) {
variables := queryold.FetchMessagesVariables{
ConversationURN: types.NewURN(fetchParams.Portal.ID),
CountBefore: 20,
}
if fetchParams.Cursor == "" {
if fetchParams.AnchorMessage != nil {
variables.DeliveredAt = jsontime.UM(fetchParams.AnchorMessage.Timestamp)
}
} else {
deliveredAt, err := strconv.ParseInt(string(fetchParams.Cursor), 10, 64)
if err != nil {
return nil, err
}
variables.DeliveredAt = jsontime.UnixMilli{Time: time.UnixMilli(deliveredAt)}
}
fetchMessages, err := l.client.FetchMessages(ctx, variables)
if err != nil {
return nil, err
}
fmt.Printf("%+v\n", fetchMessages)
// variables := queryold.FetchMessagesVariables{
// ConversationURN: linkedingo.NewURN(fetchParams.Portal.ID),
// CountBefore: 20,
// }
//
// if fetchParams.Cursor == "" {
// if fetchParams.AnchorMessage != nil {
// variables.DeliveredAt = jsontime.UM(fetchParams.AnchorMessage.Timestamp)
// }
// } else {
// deliveredAt, err := strconv.ParseInt(string(fetchParams.Cursor), 10, 64)
// if err != nil {
// return nil, err
// }
// variables.DeliveredAt = jsontime.UnixMilli{Time: time.UnixMilli(deliveredAt)}
// }
//
// fetchMessages, err := l.client.FetchMessages(ctx, variables)
// if err != nil {
// return nil, err
// }
//
// fmt.Printf("%+v\n", fetchMessages)
//
panic("here")
//
// messages := fetchMessages.Messages
......
......@@ -34,7 +34,6 @@ import (
"go.mau.fi/mautrix-linkedin/pkg/connector/linkedinfmt"
"go.mau.fi/mautrix-linkedin/pkg/connector/matrixfmt"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
)
type LinkedInClient struct {
......@@ -72,7 +71,7 @@ func NewLinkedInClient(ctx context.Context, lc *LinkedInConnector, login *bridge
}
client.client = linkedingo.NewClient(
ctx,
types.NewURN(login.ID),
linkedingo.NewURN(login.ID),
login.Metadata.(*UserLoginMetadata).Cookies,
linkedingo.Handlers{
Heartbeat: func(ctx context.Context) {
......@@ -80,6 +79,8 @@ func NewLinkedInClient(ctx context.Context, lc *LinkedInConnector, login *bridge
},
ClientConnection: func(context.Context, *linkedingo.ClientConnection) {
login.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected})
go client.syncConversations(ctx)
},
TransientDisconnect: client.onTransientDisconnect,
BadCredentials: client.onBadCredentials,
......@@ -89,7 +90,7 @@ func NewLinkedInClient(ctx context.Context, lc *LinkedInConnector, login *bridge
)
client.linkedinFmtParams = linkedinfmt.FormatParams{
GetMXIDByURN: func(ctx context.Context, entityURN types.URN) (id.UserID, error) {
GetMXIDByURN: func(ctx context.Context, entityURN linkedingo.URN) (id.UserID, error) {
ghost, err := lc.Bridge.GetGhostByID(ctx, networkid.UserID(entityURN.ID()))
if err != nil {
return "", err
......@@ -131,8 +132,8 @@ func (l *LinkedInClient) Connect(ctx context.Context) {
if err := l.client.RealtimeConnect(ctx); err != nil {
l.userLogin.BridgeState.Send(status.BridgeState{
StateEvent: status.StateUnknownError,
Error: "linkedin-realtime-connect-failed",
StateEvent: status.StateBadCredentials,
Error: "linkedin-logged-out",
Message: fmt.Sprintf("Failed to connect to the realtime stream: %v", err),
})
}
......@@ -184,7 +185,7 @@ func (l *LinkedInClient) onDecoratedEvent(ctx context.Context, decoratedEvent *l
}
}
func (l *LinkedInClient) onRealtimeMessage(ctx context.Context, msg types.Message) {
func (l *LinkedInClient) onRealtimeMessage(ctx context.Context, msg linkedingo.Message) {
log := zerolog.Ctx(ctx)
meta := simplevent.EventMeta{
LogContext: func(c zerolog.Context) zerolog.Context {
......@@ -204,7 +205,7 @@ func (l *LinkedInClient) onRealtimeMessage(ctx context.Context, msg types.Messag
LatestMessageTS: msg.DeliveredAt.Time,
})
evt := simplevent.Message[types.Message]{
evt := simplevent.Message[linkedingo.Message]{
ID: msg.MessageID(),
TargetMessage: msg.MessageID(),
Data: msg,
......@@ -212,17 +213,17 @@ func (l *LinkedInClient) onRealtimeMessage(ctx context.Context, msg types.Messag
ConvertEditFunc: l.convertEditToMatrix,
}
switch msg.MessageBodyRenderFormat {
case types.MessageBodyRenderFormatDefault:
case linkedingo.MessageBodyRenderFormatDefault:
evt.EventMeta = meta.WithType(bridgev2.RemoteEventMessage)
case types.MessageBodyRenderFormatEdited:
case linkedingo.MessageBodyRenderFormatEdited:
evt.EventMeta = meta.WithType(bridgev2.RemoteEventEdit)
case types.MessageBodyRenderFormatRecalled:
case linkedingo.MessageBodyRenderFormatRecalled:
l.main.Bridge.QueueRemoteEvent(l.userLogin, &simplevent.MessageRemove{
EventMeta: meta.WithType(bridgev2.RemoteEventMessageRemove),
TargetMessage: msg.MessageID(),
})
return
case types.MessageBodyRenderFormatSystem:
case linkedingo.MessageBodyRenderFormatSystem:
log.Info().Msg("Ignoring system message")
return
default:
......@@ -252,7 +253,7 @@ func (l *LinkedInClient) onRealtimeTypingIndicator(decoratedEvent *linkedingo.De
})
}
func (l *LinkedInClient) onRealtimeMessageSeenReceipts(ctx context.Context, receipt types.SeenReceipt) {
func (l *LinkedInClient) onRealtimeMessageSeenReceipts(ctx context.Context, receipt linkedingo.SeenReceipt) {
log := zerolog.Ctx(ctx)
part, err := l.main.Bridge.DB.Message.GetLastPartByID(ctx, l.userLogin.ID, receipt.Message.MessageID())
if err != nil {
......@@ -278,7 +279,7 @@ func (l *LinkedInClient) onRealtimeMessageSeenReceipts(ctx context.Context, rece
})
}
func (l *LinkedInClient) onRealtimeReactionSummaries(ctx context.Context, summary types.RealtimeReactionSummary) {
func (l *LinkedInClient) onRealtimeReactionSummaries(ctx context.Context, summary linkedingo.RealtimeReactionSummary) {
messageData, err := l.main.Bridge.DB.Message.GetFirstPartByID(context.TODO(), l.userLogin.ID, summary.Message.MessageID())
if err != nil {
zerolog.Ctx(ctx).Err(err).Msg("failed to get reacted to message")
......@@ -308,7 +309,7 @@ func (l *LinkedInClient) onRealtimeReactionSummaries(ctx context.Context, summar
})
}
func (l *LinkedInClient) getAvatar(img *types.VectorImage) (avatar bridgev2.Avatar) {
func (l *LinkedInClient) getAvatar(img *linkedingo.VectorImage) (avatar bridgev2.Avatar) {
avatar.ID = networkid.AvatarID(img.RootURL)
avatar.Remove = img.RootURL == ""
avatar.Get = func(ctx context.Context) ([]byte, error) {
......@@ -317,7 +318,7 @@ func (l *LinkedInClient) getAvatar(img *types.VectorImage) (avatar bridgev2.Avat
return
}
func (l *LinkedInClient) getMessagingParticipantUserInfo(participant types.MessagingParticipant) (ui bridgev2.UserInfo) {
func (l *LinkedInClient) getMessagingParticipantUserInfo(participant linkedingo.MessagingParticipant) (ui bridgev2.UserInfo) {
ui.Name = ptr.Ptr(l.main.Config.FormatDisplayname(DisplaynameParams{
FirstName: participant.ParticipantType.Member.FirstName.Text,
LastName: participant.ParticipantType.Member.LastName.Text,
......@@ -327,7 +328,7 @@ func (l *LinkedInClient) getMessagingParticipantUserInfo(participant types.Messa
return
}
func (l *LinkedInClient) conversationToChatInfo(conv types.Conversation) (ci bridgev2.ChatInfo) {
func (l *LinkedInClient) conversationToChatInfo(conv linkedingo.Conversation) (ci bridgev2.ChatInfo) {
if conv.Title != "" {
ci.Name = &conv.Title
}
......
......@@ -4,10 +4,10 @@ import (
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
)
func (l *LinkedInClient) makePortalKey(entityURN types.URN) (key networkid.PortalKey) {
func (l *LinkedInClient) makePortalKey(entityURN linkedingo.URN) (key networkid.PortalKey) {
key.ID = networkid.PortalID(entityURN.String())
if l.main.Bridge.Config.SplitPortals {
key.Receiver = l.userLogin.ID
......@@ -15,7 +15,7 @@ func (l *LinkedInClient) makePortalKey(entityURN types.URN) (key networkid.Porta
return key
}
func (l *LinkedInClient) makeSender(participant types.MessagingParticipant) (sender bridgev2.EventSender) {
func (l *LinkedInClient) makeSender(participant linkedingo.MessagingParticipant) (sender bridgev2.EventSender) {
id := participant.EntityURN.ID()
sender.IsFromMe = id == string(l.userID)
sender.Sender = networkid.UserID(id)
......
......@@ -26,7 +26,7 @@ import (
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
)
type UserInfo struct {
......@@ -35,7 +35,7 @@ type UserInfo struct {
}
type FormatParams struct {
GetMXIDByURN func(ctx context.Context, entityURN types.URN) (id.UserID, error)
GetMXIDByURN func(ctx context.Context, entityURN linkedingo.URN) (id.UserID, error)
}
type formatContext struct {
......@@ -49,7 +49,7 @@ func (ctx formatContext) TextToHTML(text string) string {
return event.TextToHTML(text)
}
func Parse(ctx context.Context, message string, attributes []types.Attribute, params FormatParams) (content *event.MessageEventContent, err error) {
func Parse(ctx context.Context, message string, attributes []linkedingo.Attribute, params FormatParams) (content *event.MessageEventContent, err error) {
log := zerolog.Ctx(ctx).With().Str("func", "Parse").Logger()
content = &event.MessageEventContent{
MsgType: event.MsgText,
......
......@@ -26,7 +26,6 @@ import (
"maunium.net/go/mautrix/bridgev2/networkid"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/mautrix-linkedin/pkg/stringcookiejar"
)
......@@ -96,7 +95,7 @@ func (c *CookieLogin) SubmitCookies(ctx context.Context, cookies map[string]stri
return nil, err
}
loginClient := linkedingo.NewClient(ctx, types.NewURN(""), jar, linkedingo.Handlers{})
loginClient := linkedingo.NewClient(ctx, linkedingo.NewURN(""), jar, linkedingo.Handlers{})
profile, err := loginClient.GetCurrentUserProfile(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get current user profile: %w", err)
......
......@@ -16,7 +16,6 @@ import (
"go.mau.fi/mautrix-linkedin/pkg/connector/matrixfmt"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
)
func getMediaFilename(content *event.MessageEventContent) (filename string) {
......@@ -29,7 +28,7 @@ func getMediaFilename(content *event.MessageEventContent) (filename string) {
}
func (l *LinkedInClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (*bridgev2.MatrixMessageResponse, error) {
conversationURN := types.NewURN(msg.Portal.ID)
conversationURN := linkedingo.NewURN(msg.Portal.ID)
// Handle emotes by adding a "*" and the user's name to the message
if msg.Content.MsgType == event.MsgEmote {
......@@ -86,11 +85,11 @@ func (l *LinkedInClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
}
func (l *LinkedInClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error {
return l.client.EditMessage(ctx, types.NewURN(msg.EditTarget.ID), matrixfmt.Parse(ctx, l.matrixParser, msg.Content))
return l.client.EditMessage(ctx, linkedingo.NewURN(msg.EditTarget.ID), matrixfmt.Parse(ctx, l.matrixParser, msg.Content))
}
func (l *LinkedInClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error {
return l.client.RecallMessage(ctx, types.NewURN(msg.TargetMessage.ID))
return l.client.RecallMessage(ctx, linkedingo.NewURN(msg.TargetMessage.ID))
}
func (l *LinkedInClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) {
......@@ -110,21 +109,21 @@ func (l *LinkedInClient) PreHandleMatrixReaction(ctx context.Context, msg *bridg
}
func (l *LinkedInClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) {
return &database.Reaction{}, l.client.SendReaction(ctx, types.NewURN(msg.TargetMessage.ID), msg.PreHandleResp.Emoji)
return &database.Reaction{}, l.client.SendReaction(ctx, linkedingo.NewURN(msg.TargetMessage.ID), msg.PreHandleResp.Emoji)
}
func (l *LinkedInClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error {
return l.client.RemoveReaction(ctx, types.NewURN(msg.TargetReaction.MessageID), msg.TargetReaction.Emoji)
return l.client.RemoveReaction(ctx, linkedingo.NewURN(msg.TargetReaction.MessageID), msg.TargetReaction.Emoji)
}
func (l *LinkedInClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridgev2.MatrixReadReceipt) error {
_, err := l.client.MarkConversationRead(ctx, types.NewURN(msg.Portal.ID))
_, err := l.client.MarkConversationRead(ctx, linkedingo.NewURN(msg.Portal.ID))
return err
}
func (l *LinkedInClient) HandleMatrixTyping(ctx context.Context, msg *bridgev2.MatrixTyping) error {
if msg.IsTyping && msg.Type == bridgev2.TypingTypeText {
return l.client.StartTyping(ctx, types.NewURN(msg.Portal.ID))
return l.client.StartTyping(ctx, linkedingo.NewURN(msg.Portal.ID))
}
return nil
}
......@@ -23,7 +23,6 @@ import (
"go.mau.fi/mautrix-linkedin/pkg/connector/linkedinfmt"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
)
func toLinkedInAttribute(br linkedinfmt.BodyRange) linkedingo.SendMessageAttribute {
......@@ -32,9 +31,9 @@ func toLinkedInAttribute(br linkedinfmt.BodyRange) linkedingo.SendMessageAttribu
return linkedingo.SendMessageAttribute{
Start: br.Start,
Length: br.Length,
AttributeKindUnion: types.AttributeKind{
Entity: &types.Entity{
URN: types.NewURN(val.UserID).WithPrefix("urn", "li", "fsd_profile"),
AttributeKindUnion: linkedingo.AttributeKind{
Entity: &linkedingo.Entity{
URN: linkedingo.NewURN(val.UserID).WithPrefix("urn", "li", "fsd_profile"),
},
},
}
......
package connector
import (
"context"
"fmt"
"github.com/rs/zerolog"
)
func (l *LinkedInClient) syncConversations(ctx context.Context) {
log := zerolog.Ctx(ctx).With().Str("action", "sync_conversations").Logger()
conversations, err := l.client.GetConversations(ctx)
if err != nil {
log.Error().Err(err).Msg("failed to fetch initial inbox state")
return
}
fmt.Printf("%+v\n", conversations)
}
......@@ -11,10 +11,10 @@ import (
"maunium.net/go/mautrix/event"
"go.mau.fi/mautrix-linkedin/pkg/connector/linkedinfmt"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
)
func (l *LinkedInClient) convertToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, msg types.Message) (*bridgev2.ConvertedMessage, error) {
func (l *LinkedInClient) convertToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, msg linkedingo.Message) (*bridgev2.ConvertedMessage, error) {
var cm bridgev2.ConvertedMessage
if len(msg.Body.Text) > 0 {
......@@ -60,7 +60,7 @@ func (l *LinkedInClient) convertToMatrix(ctx context.Context, portal *bridgev2.P
return &cm, nil
}
func (l *LinkedInClient) convertEditToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, existing []*database.Message, msg types.Message) (*bridgev2.ConvertedEdit, error) {
func (l *LinkedInClient) convertEditToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, existing []*database.Message, msg linkedingo.Message) (*bridgev2.ConvertedEdit, error) {
if len(existing) != 1 {
return nil, fmt.Errorf("editing a message that was bridged as multiple parts is not supported")
}
......@@ -79,7 +79,7 @@ func (l *LinkedInClient) convertEditToMatrix(ctx context.Context, portal *bridge
return &convertedEdit, nil
}
func (l *LinkedInClient) convertAudioToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, audio *types.AudioMetadata) (cmp *bridgev2.ConvertedMessagePart, err error) {
func (l *LinkedInClient) convertAudioToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, audio *linkedingo.AudioMetadata) (cmp *bridgev2.ConvertedMessagePart, err error) {
info, filename, err := l.client.GetAudioFileInfo(ctx, audio)
if err != nil {
return nil, err
......@@ -106,7 +106,7 @@ func (l *LinkedInClient) convertAudioToMatrix(ctx context.Context, portal *bridg
}, err
}
func (l *LinkedInClient) convertExternalMediaToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, media *types.ExternalMedia) (cmp *bridgev2.ConvertedMessagePart, err error) {
func (l *LinkedInClient) convertExternalMediaToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, media *linkedingo.ExternalMedia) (cmp *bridgev2.ConvertedMessagePart, err error) {
content := event.MessageEventContent{
Info: &event.FileInfo{MimeType: "image/gif"},
MsgType: event.MsgImage,
......@@ -124,7 +124,7 @@ func (l *LinkedInClient) convertExternalMediaToMatrix(ctx context.Context, porta
}, err
}
func (l *LinkedInClient) convertFileToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, attachment *types.FileAttachment) (cmp *bridgev2.ConvertedMessagePart, err error) {
func (l *LinkedInClient) convertFileToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, attachment *linkedingo.FileAttachment) (cmp *bridgev2.ConvertedMessagePart, err error) {
content := event.MessageEventContent{
Info: &event.FileInfo{
MimeType: attachment.MediaType,
......@@ -148,7 +148,7 @@ func (l *LinkedInClient) convertFileToMatrix(ctx context.Context, portal *bridge
}, err
}
func (l *LinkedInClient) convertVectorImageToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, img *types.VectorImage) (cmp *bridgev2.ConvertedMessagePart, err error) {
func (l *LinkedInClient) convertVectorImageToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, img *linkedingo.VectorImage) (cmp *bridgev2.ConvertedMessagePart, err error) {
info, filename, err := l.client.GetVectorImageFileInfo(ctx, img)
if err != nil {
return nil, err
......@@ -172,7 +172,7 @@ func (l *LinkedInClient) convertVectorImageToMatrix(ctx context.Context, portal
}, err
}
func (l *LinkedInClient) convertVideoToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, video *types.VideoPlayMetadata) (cmp *bridgev2.ConvertedMessagePart, err error) {
func (l *LinkedInClient) convertVideoToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, video *linkedingo.VideoPlayMetadata) (cmp *bridgev2.ConvertedMessagePart, err error) {
if len(video.ProgressiveStreams) == 0 {
return nil, fmt.Errorf("VideoPlayMetadata had no ProgressiveStreams")
}
......
package types
package linkedingo
// AttributedText represents a com.linkedin.pemberly.text.AttributedText
// object.
......
......@@ -22,14 +22,13 @@ import (
"github.com/google/uuid"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/mautrix-linkedin/pkg/stringcookiejar"
)
type Client struct {
http *http.Client
jar *stringcookiejar.Jar
userEntityURN types.URN
userEntityURN URN
realtimeSessionID uuid.UUID
realtimeCtx context.Context
......@@ -44,7 +43,7 @@ type Client struct {
i18nLocale string
}
func NewClient(ctx context.Context, userEntityURN types.URN, jar *stringcookiejar.Jar, handlers Handlers) *Client {
func NewClient(ctx context.Context, userEntityURN URN, jar *stringcookiejar.Jar, handlers Handlers) *Client {
return &Client{
userEntityURN: userEntityURN,
jar: jar,
......
......@@ -58,9 +58,9 @@ const (
)
const (
graphQLQueryIDMessengerConversations = "messengerConversations.95e0a4b80fbc6bc53550e670d34d05d9"
graphQLQueryIDMessengerConversationsWithCursor = "messengerConversations.18240d6a3ac199067a703996eeb4b163"
graphQLQueryIDMessengerConversationsWithSyncToken = "messengerConversations.be2479ed77df3dd407dd90efc8ac41de"
graphQLQueryIDMessengerConversations = "messengerConversations.7b27164c5517548167d9adb4ba603e55"
graphQLQueryIDMessengerConversationsWithCursor = "messengerConversations.8656fb361a8ad0c178e8d3ff1a84ce26"
graphQLQueryIDMessengerConversationsWithSyncToken = "messengerConversations.277103fa0741e804ec5f21e6f64cb598"
graphQLQueryIDMessengerMessagesBySyncToken = "messengerMessages.d1b494ac18c24c8be71ea07b5bd1f831"
graphQLQueryIDMessengerMessagesByAnchorTimestamp = "messengerMessages.b52340f92136e74c2aab21dac7cf7ff2"
graphQLQueryIDMessengerMessagesByConversation = "messengerMessages.86ca573adc64110d94d8bce89c5b2f3b"
......
package linkedingo
import (
"context"
"encoding/json"
"net/http"
)
// https://www.linkedin.com/voyager/api/voyagerMessagingGraphQL/graphql?queryId=messengerConversations.7b27164c5517548167d9adb4ba603e55&variables=(mailboxUrn:urn%3Ali%3Afsd_profile%3AACoAADZsHU0BD7Cr7MwzvkzsAcCoeOii7kl0mPU)
// https://www.linkedin.com/voyager/api/voyagerMessagingGraphQL/graphql?queryId=messengerConversations.8656fb361a8ad0c178e8d3ff1a84ce26&variables=(query:(predicateUnions:List((conversationCategoryPredicate:(category:PRIMARY_INBOX)))),count:20,mailboxUrn:urn%3Ali%3Afsd_profile%3AACoAADZsHU0BD7Cr7MwzvkzsAcCoeOii7kl0mPU,lastUpdatedBefore:1739209141023)
// curl 'https://www.linkedin.com/voyager/api/voyagerMessagingGraphQL/graphql?queryId=messengerConversations.277103fa0741e804ec5f21e6f64cb598&variables=(mailboxUrn:urn%3Ali%3Afsd_profile%3AACoAADZsHU0BD7Cr7MwzvkzsAcCoeOii7kl0mPU,syncToken:-trA4KJljszB4KJlLnVybjpsaTpmYWJyaWM6cHJvZC1sb3IxAA%3D%3D)' \
// type GetThreadsVariables struct {
// InboxCategory InboxCategory `graphql:"category"`
// Count int64 `graphql:"count"`
// MailboxUrn string `graphql:"mailboxUrn"`
// LastUpdatedBefore int64 `graphql:"lastUpdatedBefore"`
// NextCursor string `graphql:"nextCursor"`
// SyncToken string `graphql:"syncToken"`
// }
type GraphQlResponse[T any] struct {
Data GraphQLData[T] `json:"data,omitempty"`
}
type GraphQLData[T any] struct {
MessengerConversationsBySyncToken *CollectionResponse[T] `json:"messengerConversationsBySyncToken,omitempty"`
}
// CollectionResponse represents a
// com.linkedin.restli.common.CollectionResponse object.
type CollectionResponse[T any] struct {
Metadata SyncMetadata `json:"metadata,omitempty"`
Elements []T `json:"elements,omitempty"`
}
// SyncMetadata represents a com.linkedin.messenger.SyncMetadata object.
type SyncMetadata struct {
NewSyncToken string `json:"newSyncToken,omitempty"`
}
// Conversation represents a com.linkedin.messenger.Conversation object
type Conversation struct {
Title string `json:"title,omitempty"`
EntityURN URN `json:"entityUrn,omitempty"`
GroupChat bool `json:"groupChat,omitempty"`
ConversationParticipants []MessagingParticipant `json:"conversationParticipants,omitempty"`
Read bool `json:"read,omitempty"`
// Messages []CollectionResponse[Message] `json:"messages,omitempty"`
}
// MessagingParticipant represents a
// com.linkedin.messenger.MessagingParticipant object.
type MessagingParticipant struct {
ParticipantType ParticipantType `json:"participantType,omitempty"`
EntityURN URN `json:"entityUrn,omitempty"`
}
type ParticipantType struct {
Member MemberParticipantInfo `json:"member,omitempty"`
}
// MemberParticipantInfo represents a
// com.linkedin.messenger.MemberParticipantInfo object.
type MemberParticipantInfo struct {
ProfileURL string `json:"profileUrl,omitempty"`
FirstName AttributedText `json:"firstName,omitempty"`
LastName AttributedText `json:"lastName,omitempty"`
ProfilePicture *VectorImage `json:"profilePicture,omitempty"`
Pronoun any `json:"pronoun,omitempty"`
Headline AttributedText `json:"headline,omitempty"`
}
func (c *Client) GetConversations(ctx context.Context) (*CollectionResponse[Conversation], error) {
variables := map[string]string{
"mailboxUrn": c.userEntityURN.WithPrefix("urn", "li", "fsd_profile").String(),
}
// withCursor := variables.LastUpdatedBefore != 0 && variables.NextCursor != ""
queryId := graphQLQueryIDMessengerConversations
// if withCursor {
// queryId = graphQLQueryIDMessengerConversationsWithCursor
// } else if variables.SyncToken != "" {
// queryId = graphQLQueryIDMessengerConversationsWithSyncToken
// }
resp, err := c.newAuthedRequest(http.MethodGet, linkedInVoyagerMessagingGraphQLURL).
WithGraphQLQuery(queryId, variables).
WithCSRF().
WithXLIHeaders().
WithHeader("accept", contentTypeGraphQL).
Do(ctx)
if err != nil {
return nil, err
}
var response GraphQlResponse[Conversation]
if err = json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, err
}
return response.Data.MessengerConversationsBySyncToken, nil
}
// func (c *Client) GetThreads(variables queryold.GetThreadsVariables) (*responseold.MessengerConversationsResponse, error) {
// if variables.MailboxUrn == "" {
// variables.MailboxUrn = c.PageLoader.CurrentUser.FsdProfileID
// }
//
// withCursor := variables.LastUpdatedBefore != 0 && variables.NextCursor != ""
// var queryId typesold.GraphQLQueryIDs
// if withCursor {
// queryId = typesold.GraphQLQueryIDMessengerConversationsWithCursor
// } else if variables.SyncToken != "" {
// queryId = typesold.GraphQLQueryIDMessengerConversationsWithSyncToken
// } else {
// queryId = typesold.GraphQLQueryIDMessengerConversations
// }
//
// variablesQuery, err := variables.Encode()
// if err != nil {
// return nil, err
// }
//
// threadQuery := queryold.GraphQLQuery{
// QueryID: queryId,
// Variables: string(variablesQuery),
// }
//
// _, respData, err := c.MakeRoutingRequest(routingold.LinkedInVoyagerMessagingGraphQLURL, nil, &threadQuery)
// if err != nil {
// return nil, err
// }
// fmt.Printf("%s\n", respData)
//
// graphQLResponse, ok := respData.(*responseold.GraphQlResponse)
// if !ok || graphQLResponse == nil {
// return nil, newErrorResponseTypeAssertFailed("*responseold.GraphQlResponse")
// }
//
// graphQLResponseData := graphQLResponse.Data
// fmt.Printf("%+v\n", graphQLResponseData)
// if withCursor {
// return graphQLResponseData.MessengerConversationsByCategory, nil
// }
//
// return graphQLResponseData.MessengerConversationsBySyncToken, nil
// }
......@@ -12,9 +12,92 @@ import (
"maunium.net/go/mautrix/event"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/util/jsontime"
)
// VectorArtifact represents a com.linkedin.common.VectorArtifact object.
type VectorArtifact struct {
ExpiresAt jsontime.UnixMilli `json:"expiresAt,omitempty"`
FileIdentifyingURLPathSegment string `json:"fileIdentifyingUrlPathSegment,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
}
// VectorImage represents a com.linkedin.common.VectorImage object.
type VectorImage struct {
RootURL string `json:"rootUrl,omitempty"`
Artifacts []VectorArtifact `json:"artifacts,omitempty"`
}
func (vi VectorImage) GetLargestArtifactURL() string {
var largestVersion VectorArtifact
for _, a := range vi.Artifacts {
if a.Height > largestVersion.Height {
largestVersion = a
}
}
return vi.RootURL + largestVersion.FileIdentifyingURLPathSegment
}
// FileAttachment represents a com.linkedin.messenger.FileAttachment object.
type FileAttachment struct {
AssetURN URN `json:"assetUrn,omitempty"`
ByteSize int `json:"byteSize,omitempty"`
MediaType string `json:"mediaType,omitempty"`
Name string `json:"name,omitempty"`
URL string `json:"url,omitempty"`
}
// ExternalProxyImage represents a com.linkedin.messenger.ExternalProxyImage
// object.
type ExternalProxyImage struct {
OriginalHeight int `json:"originalHeight,omitempty"`
OriginalWidth int `json:"originalWidth,omitempty"`
URL string `json:"url,omitempty"`
}
// ExternalMedia represents a com.linkedin.messenger.ExternalMedia object.
type ExternalMedia struct {
Media ExternalProxyImage `json:"media,omitempty"`
Title string `json:"title,omitempty"`
EntityURN URN `json:"entityUrn,omitempty"`
PreviewMedia ExternalProxyImage `json:"previewMedia,omitempty"`
}
// VideoPlayMetadata represents a com.linkedin.videocontent.VideoPlayMetadata
// object.
type VideoPlayMetadata struct {
Thumbnail *VectorImage `json:"thumbnail,omitempty"`
ProgressiveStreams []ProgressiveDownloadMetadata `json:"progressiveStreams,omitempty"`
AspectRatio float64 `json:"aspectRatio,omitempty"`
Media URN `json:"media,omitempty"`
Duration jsontime.Milliseconds `json:"duration,omitempty"`
EntityURN URN `json:"entityUrn,omitempty"`
}
// ProgressiveDownloadMetadata represents a
// com.linkedin.videocontent.ProgressiveDownloadMetadata object.
type ProgressiveDownloadMetadata struct {
StreamingLocations []StreamingLocation `json:"streamingLocations,omitempty"`
Size int `json:"size,omitempty"`
BitRate int `json:"bitRate,omitempty"`
Width int `json:"width,omitempty"`
MediaType string `json:"mediaType,omitempty"`
Height int `json:"height,omitempty"`
}
// StreamingLocation represents a com.linkedin.videocontent.StreamingLocation
// object.
type StreamingLocation struct {
URL string `json:"url,omitempty"`
}
// AudioMetadata represents a com.linkedin.messenger.AudioMetadata object.
type AudioMetadata struct {
Duration jsontime.Milliseconds `json:"duration,omitempty"`
URL string `json:"url,omitempty"`
}
func (c *Client) Download(ctx context.Context, w io.Writer, url string) error {
resp, err := c.newAuthedRequest(http.MethodGet, url).Do(ctx)
if err != nil {
......@@ -42,7 +125,7 @@ func (c *Client) getFileInfoFromHeadRequest(ctx context.Context, url string) (in
return
}
func (c *Client) GetVectorImageFileInfo(ctx context.Context, vi *types.VectorImage) (info event.FileInfo, filename string, err error) {
func (c *Client) GetVectorImageFileInfo(ctx context.Context, vi *VectorImage) (info event.FileInfo, filename string, err error) {
info, filename, err = c.getFileInfoFromHeadRequest(ctx, vi.GetLargestArtifactURL())
if filename == "" {
filename = "image"
......@@ -50,7 +133,7 @@ func (c *Client) GetVectorImageFileInfo(ctx context.Context, vi *types.VectorIma
return
}
func (c *Client) GetAudioFileInfo(ctx context.Context, audio *types.AudioMetadata) (info event.FileInfo, filename string, err error) {
func (c *Client) GetAudioFileInfo(ctx context.Context, audio *AudioMetadata) (info event.FileInfo, filename string, err error) {
info, filename, err = c.getFileInfoFromHeadRequest(ctx, audio.URL)
if filename == "" {
filename = "voice_message"
......@@ -84,11 +167,11 @@ type ActionResponse struct {
// MediaUploadMetadata represents a
// com.linkedin.mediauploader.MediaUploadMetadata object.
type MediaUploadMetadata struct {
URN types.URN `json:"urn,omitempty"`
SingleUploadURL string `json:"singleUploadUrl,omitempty"`
URN URN `json:"urn,omitempty"`
SingleUploadURL string `json:"singleUploadUrl,omitempty"`
}
func (c *Client) UploadMedia(ctx context.Context, mediaUploadType MediaUploadType, filename, contentType string, size int, r io.Reader) (types.URN, error) {
func (c *Client) UploadMedia(ctx context.Context, mediaUploadType MediaUploadType, filename, contentType string, size int, r io.Reader) (URN, error) {
resp, err := c.newAuthedRequest(http.MethodPost, linkedInVoyagerMediaUploadMetadataURL).
WithQueryParam("action", "upload").
WithCSRF().
......@@ -102,14 +185,14 @@ func (c *Client) UploadMedia(ctx context.Context, mediaUploadType MediaUploadTyp
}).
Do(ctx)
if err != nil {
return types.URN{}, err
return URN{}, err
} else if resp.StatusCode != http.StatusOK {
return types.URN{}, fmt.Errorf("failed to get upload media metadata (statusCode=%d)", resp.StatusCode)
return URN{}, fmt.Errorf("failed to get upload media metadata (statusCode=%d)", resp.StatusCode)
}
var uploadMetadata UploadMediaMetadataResponse
if err = json.NewDecoder(resp.Body).Decode(&uploadMetadata); err != nil {
return types.URN{}, err
return URN{}, err
}
resp, err = c.newAuthedRequest(http.MethodPut, uploadMetadata.Data.Value.SingleUploadURL).
......@@ -119,9 +202,9 @@ func (c *Client) UploadMedia(ctx context.Context, mediaUploadType MediaUploadTyp
WithBody(r).
Do(ctx)
if err != nil {
return types.URN{}, err
return URN{}, err
} else if resp.StatusCode != http.StatusCreated {
return types.URN{}, fmt.Errorf("failed to upload media: status=%d", resp.StatusCode)
return URN{}, fmt.Errorf("failed to upload media: status=%d", resp.StatusCode)
}
return uploadMetadata.Data.Value.URN, nil
}
......@@ -10,25 +10,25 @@ import (
"github.com/google/uuid"
"go.mau.fi/util/jsontime"
"go.mau.fi/util/random"
"maunium.net/go/mautrix/bridgev2/networkid"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/mautrix-linkedin/pkg/linkedingoold/routingold/queryold"
"go.mau.fi/mautrix-linkedin/pkg/linkedingoold/routingold/responseold"
)
type sendMessagePayload struct {
Message SendMessage `json:"message,omitempty"`
MailboxURN types.URN `json:"mailboxUrn,omitempty"`
MailboxURN URN `json:"mailboxUrn,omitempty"`
TrackingID string `json:"trackingId,omitempty"`
DedupeByClientGeneratedToken bool `json:"dedupeByClientGeneratedToken"`
HostRecipientURNs []types.URN `json:"hostRecipientUrns,omitempty"`
HostRecipientURNs []URN `json:"hostRecipientUrns,omitempty"`
ConversationTitle string `json:"conversationTitle,omitempty"`
}
type SendMessage struct {
Body SendMessageBody `json:"body,omitempty"`
RenderContentUnions []SendRenderContent `json:"renderContentUnions,omitempty"`
ConversationURN types.URN `json:"conversationUrn,omitempty"`
ConversationURN URN `json:"conversationUrn,omitempty"`
OriginToken uuid.UUID `json:"originToken,omitempty"`
}
......@@ -38,13 +38,13 @@ type SendMessageBody struct {
}
type SendMessageAttribute struct {
Start int `json:"start"`
Length int `json:"length"`
AttributeKindUnion types.AttributeKind `json:"attributeKindUnion"`
Start int `json:"start"`
Length int `json:"length"`
AttributeKindUnion AttributeKind `json:"attributeKindUnion"`
}
type AttributeType struct {
Entity *types.Entity `json:"com.linkedin.pemberly.text.Entity,omitempty"`
Entity *Entity `json:"com.linkedin.pemberly.text.Entity,omitempty"`
}
type SendRenderContent struct {
......@@ -53,23 +53,66 @@ type SendRenderContent struct {
}
type SendAudio struct {
AssetURN types.URN `json:"assetUrn,omitempty"`
AssetURN URN `json:"assetUrn,omitempty"`
ByteSize int `json:"byteSize,omitempty"`
Duration jsontime.Milliseconds `json:"duration,omitempty"`
}
type SendFile struct {
AssetURN types.URN `json:"assetUrn,omitempty"`
ByteSize int `json:"byteSize,omitempty"`
MediaType string `json:"mediaType,omitempty"`
Name string `json:"name,omitempty"`
AssetURN URN `json:"assetUrn,omitempty"`
ByteSize int `json:"byteSize,omitempty"`
MediaType string `json:"mediaType,omitempty"`
Name string `json:"name,omitempty"`
}
type MessageSentResponse struct {
Data types.Message `json:"value,omitempty"`
Data Message `json:"value,omitempty"`
}
func (c *Client) SendMessage(ctx context.Context, conversationURN types.URN, body SendMessageBody, renderContent []SendRenderContent) (*MessageSentResponse, error) {
type DecoratedMessage struct {
Result Message `json:"result,omitempty"`
}
// Message represents a com.linkedin.messenger.Message object.
type Message struct {
Body AttributedText `json:"body,omitempty"`
DeliveredAt jsontime.UnixMilli `json:"deliveredAt,omitempty"`
EntityURN URN `json:"entityUrn,omitempty"`
Sender MessagingParticipant `json:"sender,omitempty"`
MessageBodyRenderFormat MessageBodyRenderFormat `json:"messageBodyRenderFormat,omitempty"`
BackendConversationURN URN `json:"backendConversationUrn,omitempty"`
Conversation Conversation `json:"conversation,omitempty"`
RenderContent []RenderContent `json:"renderContent,omitempty"`
}
func (m Message) MessageID() networkid.MessageID {
return networkid.MessageID(m.EntityURN.String())
}
type MessageBodyRenderFormat string
const (
MessageBodyRenderFormatDefault MessageBodyRenderFormat = "DEFAULT"
MessageBodyRenderFormatEdited MessageBodyRenderFormat = "EDITED"
MessageBodyRenderFormatRecalled MessageBodyRenderFormat = "RECALLED"
MessageBodyRenderFormatSystem MessageBodyRenderFormat = "SYSTEM"
)
type RenderContent struct {
Audio *AudioMetadata `json:"audio,omitempty"`
ExternalMedia *ExternalMedia `json:"externalMedia,omitempty"`
File *FileAttachment `json:"file,omitempty"`
RepliedMessageContent *RepliedMessage `json:"repliedMessageContent,omitempty"`
VectorImage *VectorImage `json:"vectorImage,omitempty"`
Video *VideoPlayMetadata `json:"video,omitempty"`
}
// RepliedMessage represents a com.linkedin.messenger.RepliedMessage object.
type RepliedMessage struct {
OriginalMessage Message `json:"originalMessage,omitempty"`
}
func (c *Client) SendMessage(ctx context.Context, conversationURN URN, body SendMessageBody, renderContent []SendRenderContent) (*MessageSentResponse, error) {
payload := sendMessagePayload{
Message: SendMessage{
Body: body,
......@@ -113,7 +156,7 @@ type EditMessagePayload struct {
Body SendMessageBody `json:"body,omitempty"`
}
func (c *Client) EditMessage(ctx context.Context, messageURN types.URN, p SendMessageBody) error {
func (c *Client) EditMessage(ctx context.Context, messageURN URN, p SendMessageBody) error {
url, err := url.JoinPath(linkedInVoyagerMessagingDashMessengerMessagesURL, messageURN.URLEscaped())
if err != nil {
return err
......@@ -132,7 +175,7 @@ func (c *Client) EditMessage(ctx context.Context, messageURN types.URN, p SendMe
return nil
}
func (c *Client) RecallMessage(ctx context.Context, messageURN types.URN) error {
func (c *Client) RecallMessage(ctx context.Context, messageURN URN) error {
resp, err := c.newAuthedRequest(http.MethodPost, linkedInVoyagerMessagingDashMessengerMessagesURL).
WithQueryParam("action", "recall").
WithCSRF().
......
......@@ -4,19 +4,38 @@ import (
"context"
"fmt"
"net/http"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
)
func (c *Client) SendReaction(ctx context.Context, messageURN types.URN, emoji string) error {
type DecoratedReactionSummary struct {
Result RealtimeReactionSummary `json:"result,omitempty"`
}
// RealtimeReactionSummary represents a
// com.linkedin.messenger.RealtimeReactionSummary object.
type RealtimeReactionSummary struct {
ReactionAdded bool `json:"reactionAdded"`
Actor MessagingParticipant `json:"actor"`
Message Message `json:"message"`
ReactionSummary ReactionSummary `json:"reactionSummary"`
}
// ReactionSummary represents a com.linkedin.messenger.ReactionSummary object.
type ReactionSummary struct {
Count int `json:"count,omitempty"`
FirstReactedAt int64 `json:"firstReactedAt,omitempty"`
Emoji string `json:"emoji,omitempty"`
ViewerReacted bool `json:"viewerReacted"`
}
func (c *Client) SendReaction(ctx context.Context, messageURN URN, emoji string) error {
return c.doReactAction(ctx, messageURN, emoji, "reactWithEmoji")
}
func (c *Client) RemoveReaction(ctx context.Context, messageURN types.URN, emoji string) error {
func (c *Client) RemoveReaction(ctx context.Context, messageURN URN, emoji string) error {
return c.doReactAction(ctx, messageURN, emoji, "unreactWithEmoji")
}
func (c *Client) doReactAction(ctx context.Context, messageURN types.URN, emoji, action string) error {
func (c *Client) doReactAction(ctx context.Context, messageURN URN, emoji, action string) error {
resp, err := c.newAuthedRequest(http.MethodPost, linkedInVoyagerMessagingDashMessengerMessagesURL).
WithQueryParam("action", action).
WithContentType(contentTypePlaintextUTF8).
......
......@@ -17,8 +17,6 @@ import (
"go.mau.fi/util/exerrors"
"go.mau.fi/util/jsontime"
"golang.org/x/net/html"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
)
//go:embed x-li-recipe-map.json
......@@ -50,7 +48,7 @@ type ClientConnection struct {
}
type DecoratedEvent struct {
Topic types.URN `json:"topic,omitempty"`
Topic URN `json:"topic,omitempty"`
LeftServerAt jsontime.UnixMilli `json:"leftServerAt,omitempty"`
ID string `json:"id,omitempty"`
Payload DecoratedEventPayload `json:"payload,omitempty"`
......@@ -70,22 +68,6 @@ type DecoratedEventData struct {
DecoratedReactionSummary *DecoratedReactionSummary `json:"doDecorateRealtimeReactionSummaryMessengerRealtimeDecoration,omitempty"`
}
type DecoratedMessage struct {
Result types.Message `json:"result,omitempty"`
}
type DecoratedTypingIndicator struct {
Result types.RealtimeTypingIndicator `json:"result,omitempty"`
}
type DecoratedSeenReceipt struct {
Result types.SeenReceipt `json:"result,omitempty"`
}
type DecoratedReactionSummary struct {
Result types.RealtimeReactionSummary `json:"result,omitempty"`
}
func (c *Client) cacheMetaValues(ctx context.Context) error {
if c.clientPageInstanceID != "" && c.xLITrack != "" && c.i18nLocale != "" {
return nil
......@@ -279,8 +261,10 @@ func (c *Client) realtimeConnectLoop(ctx context.Context) {
switch {
case realtimeEvent.Heartbeat != nil:
log.Trace().Msg("Received heartbeat")
c.handlers.onHeartbeat(ctx)
case realtimeEvent.ClientConnection != nil:
log.Info().Msg("Client connected")
c.handlers.onClientConnection(ctx, realtimeEvent.ClientConnection)
case realtimeEvent.DecoratedEvent != nil:
log.Debug().
......
......@@ -11,29 +11,41 @@ import (
"slices"
"strings"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
"go.mau.fi/util/jsontime"
"go.mau.fi/mautrix-linkedin/pkg/linkedingoold/routingold/responseold"
)
type DecoratedSeenReceipt struct {
Result SeenReceipt `json:"result,omitempty"`
}
// SeenReceipt represents a com.linkedin.messenger.SeenReceipt object.
type SeenReceipt struct {
SeenAt jsontime.UnixMilli `json:"seenAt,omitempty"`
Message Message `json:"message,omitempty"`
SeenByParticipant MessagingParticipant `json:"seenByParticipant,omitempty"`
}
type MarkMessageReadBody struct {
Read bool `json:"read"`
}
type PatchEntitiesPayload struct {
Entities map[types.URNString]GraphQLPatchBody `json:"entities,omitempty"`
Entities map[URNString]GraphQLPatchBody `json:"entities,omitempty"`
}
func (c *Client) MarkConversationRead(ctx context.Context, convURNs ...types.URN) (*responseold.MarkThreadReadResponse, error) {
func (c *Client) MarkConversationRead(ctx context.Context, convURNs ...URN) (*responseold.MarkThreadReadResponse, error) {
return c.doMarkConversationRead(ctx, true, convURNs...)
}
func (c *Client) MarkConversationUnread(ctx context.Context, convURNs ...types.URN) (*responseold.MarkThreadReadResponse, error) {
func (c *Client) MarkConversationUnread(ctx context.Context, convURNs ...URN) (*responseold.MarkThreadReadResponse, error) {
return c.doMarkConversationRead(ctx, false, convURNs...)
}
func (c *Client) doMarkConversationRead(ctx context.Context, read bool, convURNs ...types.URN) (*responseold.MarkThreadReadResponse, error) {
func (c *Client) doMarkConversationRead(ctx context.Context, read bool, convURNs ...URN) (*responseold.MarkThreadReadResponse, error) {
conversationList := make([]string, len(convURNs))
entities := map[types.URNString]GraphQLPatchBody{}
entities := map[URNString]GraphQLPatchBody{}
for i, convURN := range convURNs {
conversationList[i] = url.QueryEscape(convURN.String())
entities[convURN.URNString()] = GraphQLPatchBody{Patch: Patch{Set: MarkMessageReadBody{Read: read}}}
......
......@@ -71,7 +71,7 @@ func (a *authedRequest) WithRawQuery(raw string) *authedRequest {
func (a *authedRequest) WithGraphQLQuery(queryID string, variables map[string]string) *authedRequest {
var queryStr strings.Builder
queryStr.WriteString("query=")
queryStr.WriteString("queryId=")
queryStr.WriteString(queryID)
queryStr.WriteString("&variables=(")
first := true
......
......@@ -20,12 +20,10 @@ import (
"context"
"encoding/json"
"net/http"
"go.mau.fi/mautrix-linkedin/pkg/linkedingo/types"
)
type Picture struct {
VectorImage *types.VectorImage `json:"com.linkedin.common.VectorImage,omitempty"`
VectorImage *VectorImage `json:"com.linkedin.common.VectorImage,omitempty"`
}
type MiniProfile struct {
......@@ -35,8 +33,8 @@ type MiniProfile struct {
PublicIdentifier string `json:"publicIdentifier"`
Memorialized bool `json:"memorialized"`
EntityURN types.URN `json:"entityUrn"`
DashEntityURN types.URN `json:"dashEntityUrn"`
EntityURN URN `json:"entityUrn"`
DashEntityURN URN `json:"dashEntityUrn"`
TrackingID string `json:"trackingId"`
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment