From 21edd8e33c244545d4944bafd9e67d7ea00ff6a0 Mon Sep 17 00:00:00 2001 From: 0xzer <0xzer@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:46:02 +0200 Subject: [PATCH] events for name update, delete conv, new members --- pkg/connector/client.go | 17 +++++++- pkg/connector/handletwit.go | 56 ++++++++++++++++++++++++- pkg/connector/mapping.go | 35 ++++++++++++++-- pkg/twittermeow/data/response/events.go | 20 +++++++++ pkg/twittermeow/data/types/messaging.go | 10 +++++ pkg/twittermeow/event/event.go | 10 +++++ 6 files changed, 143 insertions(+), 5 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 9495a24..6895cbf 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -19,6 +19,8 @@ package connector import ( "context" "fmt" + "strings" + "github.com/rs/zerolog" "go.mau.fi/mautrix-twitter/pkg/twittermeow" "go.mau.fi/mautrix-twitter/pkg/twittermeow/cookies" @@ -173,7 +175,9 @@ func (tc *TwitterClient) convertToMatrix(ctx context.Context, portal *bridgev2.P RemoveEntityLinkFromText(textPart, indices) } - parts = append(parts, textPart) + if len(textPart.Content.Body) > 0 { + parts = append(parts, textPart) + } cm := &bridgev2.ConvertedMessage{ ReplyTo: MessageOptionalPartID, @@ -192,4 +196,15 @@ func (tc *TwitterClient) MakePortalKey(conv types.Conversation) networkid.Portal ID: networkid.PortalID(conv.ConversationID), Receiver: receiver, } +} + +func (tc *TwitterClient) MakePortalKeyFromID(conversationId string) networkid.PortalKey { + var receiver networkid.UserLoginID + if strings.Contains(conversationId, "-") { + receiver = tc.userLogin.ID + } + return networkid.PortalKey{ + ID: networkid.PortalID(conversationId), + Receiver: receiver, + } } \ No newline at end of file diff --git a/pkg/connector/handletwit.go b/pkg/connector/handletwit.go index 94efaca..f45996e 100644 --- a/pkg/connector/handletwit.go +++ b/pkg/connector/handletwit.go @@ -6,6 +6,7 @@ import ( "go.mau.fi/mautrix-twitter/pkg/twittermeow/event" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/bridgev2/simplevent" ) func (tc *TwitterClient) HandleTwitterEvent(rawEvt any) { @@ -66,8 +67,61 @@ func (tc *TwitterClient) HandleTwitterEvent(rawEvt any) { tc.connector.br.QueueRemoteEvent(tc.userLogin, messageDeleteRemoteEvent) } case event.XEventConversationNameUpdate: - tc.client.Logger.Info().Str("new_name", evtData.Name).Any("conversation_id", evtData.Conversation.ConversationID).Any("executor", evtData.Executor).Msg("XEventConversationNameUpdate") + portalUpdateRemoteEvent := &simplevent.ChatInfoChange{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatInfoChange, + Sender: bridgev2.EventSender{ + IsFromMe: evtData.Executor.IDStr == string(tc.userLogin.ID), + SenderLogin: networkid.UserLoginID(evtData.Executor.IDStr), + Sender: networkid.UserID(evtData.Executor.IDStr), + }, + LogContext: func(c zerolog.Context) zerolog.Context { + return c. + Str("conversation_id", evtData.Conversation.ConversationID). + Str("new_name", evtData.Name). + Str("changed_by_user_id", evtData.Executor.IDStr) + }, + PortalKey: tc.MakePortalKey(evtData.Conversation), + Timestamp: evtData.UpdatedAt, + }, + ChatInfoChange: &bridgev2.ChatInfoChange{ + ChatInfo: &bridgev2.ChatInfo{ + Name: &evtData.Name, + }, + }, + } + tc.connector.br.QueueRemoteEvent(tc.userLogin, portalUpdateRemoteEvent) + case event.XEventParticipantsJoined: + portalMembersAddedRemoteEvent := &simplevent.ChatInfoChange{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatInfoChange, + LogContext: func(c zerolog.Context) zerolog.Context { + return c. + Str("conversation_id", evtData.Conversation.ConversationID). + Int("total_new_members", len(evtData.NewParticipants)) + }, + PortalKey: tc.MakePortalKey(evtData.Conversation), + Timestamp: evtData.EventTime, + }, + ChatInfoChange: &bridgev2.ChatInfoChange{ + MemberChanges: tc.UsersToMemberList(evtData.NewParticipants), + }, + } + tc.connector.br.QueueRemoteEvent(tc.userLogin, portalMembersAddedRemoteEvent) case event.XEventConversationDelete: + portalDeleteRemoteEvent := &simplevent.ChatDelete{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatDelete, + PortalKey: tc.MakePortalKeyFromID(evtData.ConversationID), + LogContext: func(c zerolog.Context) zerolog.Context { + return c. + Str("conversation_id", evtData.ConversationID) + }, + Timestamp: evtData.DeletedAt, + }, + OnlyForMe: true, + } + tc.connector.br.QueueRemoteEvent(tc.userLogin, portalDeleteRemoteEvent) tc.client.Logger.Info().Any("data", evtData).Msg("Deleted conversation") default: tc.client.Logger.Warn().Any("event_data", evtData).Msg("Received unhandled event case from twitter library") diff --git a/pkg/connector/mapping.go b/pkg/connector/mapping.go index 9cb9847..3171ca3 100644 --- a/pkg/connector/mapping.go +++ b/pkg/connector/mapping.go @@ -74,7 +74,10 @@ func (tc *TwitterClient) MessageToBackfillMessage(ctx context.Context, message t parts = append(parts, convertedAttachmentPart) } - parts = append(parts, textPart) + if len(textPart.Content.Body) > 0 { + parts = append(parts, textPart) + } + return &bridgev2.BackfillMessage{ ConvertedMessage: &bridgev2.ConvertedMessage{ ReplyTo: replyTo, @@ -90,10 +93,9 @@ func (tc *TwitterClient) MessageToBackfillMessage(ctx context.Context, message t }, nil } -// bugged, displays an empty message func RemoveEntityLinkFromText(msgPart *bridgev2.ConvertedMessagePart, indices []int) { start, end := indices[0], indices[1] - msgPart.Content.Body = msgPart.Content.Body[:start] + msgPart.Content.Body[end:] + msgPart.Content.Body = msgPart.Content.Body[:start-1] + msgPart.Content.Body[end:] } func (tc *TwitterClient) MessageReactionsToBackfillReactions(reactions []types.MessageReaction, selfUserId string) ([]*bridgev2.BackfillReaction, error) { @@ -141,6 +143,20 @@ func (tc *TwitterClient) ConversationTypeToRoomType(convType types.ConversationT return &roomType } +func (tc *TwitterClient) UsersToMemberList(users []types.User) *bridgev2.ChatMemberList { + selfUserId := tc.client.GetCurrentUserID() + chatMembers := make([]bridgev2.ChatMember, len(users)-1) + for _, user := range users { + chatMembers = append(chatMembers, tc.UserToChatMember(user, user.IDStr == selfUserId)) + } + + return &bridgev2.ChatMemberList{ + IsFull: true, + TotalMemberCount: len(users), + Members: chatMembers, + } +} + func (tc *TwitterClient) ParticipantsToMemberList(participants []types.Participant) *bridgev2.ChatMemberList { selfUserId := tc.client.GetCurrentUserID() chatMembers := make([]bridgev2.ChatMember, len(participants)-1) @@ -155,6 +171,19 @@ func (tc *TwitterClient) ParticipantsToMemberList(participants []types.Participa } } +func (tc *TwitterClient) UserToChatMember(user types.User, isFromMe bool) bridgev2.ChatMember { + return bridgev2.ChatMember{ + EventSender: bridgev2.EventSender{ + IsFromMe: isFromMe, + Sender: networkid.UserID(user.IDStr), + }, + UserInfo: &bridgev2.UserInfo{ + Name: &user.Name, + Avatar: MakeAvatar(user.ProfileImageURL), + }, + } +} + func (tc *TwitterClient) ParticipantToChatMember(participant types.Participant, isFromMe bool) bridgev2.ChatMember { return bridgev2.ChatMember{ EventSender: bridgev2.EventSender{ diff --git a/pkg/twittermeow/data/response/events.go b/pkg/twittermeow/data/response/events.go index 9ded776..5d4c694 100644 --- a/pkg/twittermeow/data/response/events.go +++ b/pkg/twittermeow/data/response/events.go @@ -129,6 +129,26 @@ func (data *XInboxData) ToEventEntries() ([]interface{}, error) { AffectsSort: convNameUpdateEventData.AffectsSort, UpdatedAt: updatedAt, } + case event.XParticipantsJoinedEvent: + var participantsJoinedEventData types.ParticipantsJoinedData + err = json.Unmarshal(jsonEvData, &participantsJoinedEventData) + if err != nil { + return nil, err + } + + eventTime, err := methods.UnixStringMilliToTime(participantsJoinedEventData.Time) + if err != nil { + return nil, err + } + + updatedEntry = event.XEventParticipantsJoined{ + EventID: participantsJoinedEventData.ID, + EventTime: eventTime, + AffectsSort: participantsJoinedEventData.AffectsSort, + Conversation: data.GetConversationByID(participantsJoinedEventData.ConversationID), + Sender: data.GetUserByID(participantsJoinedEventData.SenderID), + NewParticipants: data.GetParticipantUsers(participantsJoinedEventData.Participants), + } case event.XMessageDeleteEvent: var messageDeletedEventData types.MessageDeleted err = json.Unmarshal(jsonEvData, &messageDeletedEventData) diff --git a/pkg/twittermeow/data/types/messaging.go b/pkg/twittermeow/data/types/messaging.go index 12a625f..db5d3e2 100644 --- a/pkg/twittermeow/data/types/messaging.go +++ b/pkg/twittermeow/data/types/messaging.go @@ -86,6 +86,16 @@ type ConversationNameUpdateData struct { AffectsSort bool `json:"affects_sort,omitempty"` } + +type ParticipantsJoinedData struct { + ID string `json:"id,omitempty"` + Time string `json:"time,omitempty"` + AffectsSort bool `json:"affects_sort,omitempty"` + ConversationID string `json:"conversation_id,omitempty"` + SenderID string `json:"sender_id,omitempty"` + Participants []Participant `json:"participants,omitempty"` +} + type ConversationType string const ( diff --git a/pkg/twittermeow/event/event.go b/pkg/twittermeow/event/event.go index 930965d..23421da 100644 --- a/pkg/twittermeow/event/event.go +++ b/pkg/twittermeow/event/event.go @@ -17,6 +17,7 @@ const ( XConversationNameUpdate XEventType = "conversation_name_update" XConversationCreateEvent XEventType = "conversation_create" XConversationDeleteEvent XEventType = "remove_conversation" + XParticipantsJoinedEvent XEventType = "participants_join" XDisableNotificationsEvent XEventType = "disable_notifications" ) @@ -58,6 +59,15 @@ type XEventConversationDelete struct { LastEventID string } +type XEventParticipantsJoined struct { + EventID string + EventTime time.Time + AffectsSort bool + Conversation types.Conversation + Sender types.User + NewParticipants []types.User +} + type XEventConversationMetadataUpdate struct { Conversation types.Conversation EventID string