From 98176d9d1011541a7c24ba9f0bceeeea5501aae0 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Wed, 18 Dec 2024 11:36:27 -0500 Subject: [PATCH] feat(message)_: add PinnedBy to common.Message Needed for https://github.com/status-im/status-desktop/issues/16896 Having `PinnedBy` directly in the Message object makes it way simpler in the client to know if a message is pinned. This saves us from having to keep a cache of the pinned messages and comparing all new messages. --- protocol/common/message.go | 5 +++++ protocol/message_persistence.go | 15 +++++++++++---- protocol/persistence_test.go | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/protocol/common/message.go b/protocol/common/message.go index e77ecd31dc1..7ce37ddd753 100644 --- a/protocol/common/message.go +++ b/protocol/common/message.go @@ -221,6 +221,9 @@ type Message struct { ContactVerificationState ContactVerificationState `json:"contactVerificationState,omitempty"` DiscordMessage *protobuf.DiscordMessage `json:"discordMessage,omitempty"` + + // When a message is pinned, the pubkey of the user that pinned it is stored here + PinnedBy string `json:"pinnedBy,omitempty"` } func (m *Message) MarshalJSON() ([]byte, error) { @@ -284,6 +287,7 @@ func (m *Message) MarshalJSON() ([]byte, error) { DiscordMessage *protobuf.DiscordMessage `json:"discordMessage,omitempty"` BridgeMessage *protobuf.BridgeMessage `json:"bridgeMessage,omitempty"` PaymentRequests []*protobuf.PaymentRequest `json:"paymentRequests,omitempty"` + PinnedBy string `json:"pinnedBy,omitempty"` } item := MessageStructType{ ID: m.ID, @@ -327,6 +331,7 @@ func (m *Message) MarshalJSON() ([]byte, error) { ContactRequestState: m.ContactRequestState, ContactVerificationState: m.ContactVerificationState, PaymentRequests: m.PaymentRequests, + PinnedBy: m.PinnedBy, } if sticker := m.GetSticker(); sticker != nil { diff --git a/protocol/message_persistence.go b/protocol/message_persistence.go index 3b914487782..10fc15a5b54 100644 --- a/protocol/message_persistence.go +++ b/protocol/message_persistence.go @@ -36,6 +36,8 @@ LEFT JOIN bridge_messages bm ON m1.id = bm.user_messages_id LEFT JOIN bridge_messages bm_response ON m2.id = bm_response.user_messages_id +LEFT JOIN pin_messages pm +ON m1.id = pm.message_id AND pm.pinned = 1 ` var basicInsertDiscordMessageAuthorQuery = `INSERT OR REPLACE INTO discord_message_authors(id,name,discriminator,nickname,avatar_url, avatar_image_payload) VALUES (?,?,?,?,?,?)` @@ -135,6 +137,7 @@ func (db sqlitePersistence) tableUserMessagesAllFieldsJoin() string { m1.seen, m1.outgoing_status, m1.parsed_text, + pm.pinned_by, m1.sticker_pack, m1.sticker_hash, m1.image_payload, @@ -257,6 +260,7 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message var deletedForMe sql.NullBool var contactRequestState sql.NullInt64 var contactVerificationState sql.NullInt64 + var pinnedBy sql.NullString sticker := &protobuf.StickerMessage{} command := &common.CommandParameters{} @@ -292,6 +296,7 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message &message.Seen, &message.OutgoingStatus, &message.ParsedText, + &pinnedBy, &sticker.Pack, &sticker.Hash, &image.Payload, @@ -405,6 +410,10 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message message.ContactVerificationState = common.ContactVerificationState(contactVerificationState.Int64) } + if pinnedBy.Valid { + message.PinnedBy = pinnedBy.String + } + if quotedText.Valid { if quotedDeleted.Bool || quotedDeletedForMe.Bool { message.QuotedMessage = &common.QuotedMessage{ @@ -1199,7 +1208,6 @@ func (db sqlitePersistence) PinnedMessageByChatIDs(chatIDs []string, currCursor SELECT %s, pm.clock_value as pinnedAt, - pm.pinned_by as pinnedBy, %s FROM pin_messages pm @@ -2940,18 +2948,17 @@ func getPinnedMessagesAndCursorsFromScanRows(db sqlitePersistence, rows *sql.Row for rows.Next() { var ( pinnedAt uint64 - pinnedBy string cursor string ) message := common.NewMessage() - if err := db.tableUserMessagesScanAllFields(rows, message, &pinnedAt, &pinnedBy, &cursor); err != nil { + if err := db.tableUserMessagesScanAllFields(rows, message, &pinnedAt, &cursor); err != nil { return nil, nil, err } if msg, ok := messageIdx[message.ID]; !ok { pinnedMessage := &common.PinnedMessage{ Message: message, PinnedAt: pinnedAt, - PinnedBy: pinnedBy, + PinnedBy: message.PinnedBy, } messageIdx[message.ID] = pinnedMessage messages = append(messages, pinnedMessage) diff --git a/protocol/persistence_test.go b/protocol/persistence_test.go index adfa26ce639..7211c0031d2 100644 --- a/protocol/persistence_test.go +++ b/protocol/persistence_test.go @@ -476,6 +476,25 @@ func TestPinMessageByChatID(t *testing.T) { for i := 0; i < len(result)-1; i++ { require.Equal(t, testPK, result[i].PinnedBy) } + + // The Message itself should have the pinnedBy field + p.PinnedMessageByChatID(chatID, cursor, pageSize) + + pinnedMessageID := result[len(result)-1].Message.ID + + m, err := p.MessagesByIDs([]string{pinnedMessageID}) + require.NoError(t, err) + require.Len(t, m, 1) + require.Equal(t, "them", m[0].PinnedBy) + + msgs, _, err := p.MessageByChatID(chatID, cursor, 10) + require.NoError(t, err) + require.Len(t, msgs, 10) + for _, msg := range msgs { + if msg.ID == pinnedMessageID { + require.Equal(t, "them", msg.PinnedBy) + } + } } func TestMessageReplies(t *testing.T) {