Handle edit first & then message
This commit is contained in:
parent
075ee9c29f
commit
ee06809ff8
|
@ -48,7 +48,7 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed, err := m.isMessageAllowedFrom(messageState.AllContacts, messageState.CurrentMessageState.Contact.ID, chat)
|
allowed, err := m.isMessageAllowedFrom(messageState.CurrentMessageState.Contact.ID, chat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -189,12 +189,12 @@ func (m *Messenger) handleCommandMessage(state *ReceivedMessageState, message *c
|
||||||
if err := message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)); err != nil {
|
if err := message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)); err != nil {
|
||||||
return fmt.Errorf("failed to prepare content: %v", err)
|
return fmt.Errorf("failed to prepare content: %v", err)
|
||||||
}
|
}
|
||||||
chat, err := m.matchChatEntity(message, state.AllChats, state.AllContacts, state.Timesource)
|
chat, err := m.matchChatEntity(message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed, err := m.isMessageAllowedFrom(state.AllContacts, state.CurrentMessageState.Contact.ID, chat)
|
allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, chat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,7 @@ func (m *Messenger) HandlePinMessage(state *ReceivedMessageState, message protob
|
||||||
Alias: state.CurrentMessageState.Contact.Alias,
|
Alias: state.CurrentMessageState.Contact.Alias,
|
||||||
}
|
}
|
||||||
|
|
||||||
chat, err := m.matchChatEntity(pinMessage, state.AllChats, state.AllContacts, state.Timesource)
|
chat, err := m.matchChatEntity(pinMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // matchChatEntity returns a descriptive error message
|
return err // matchChatEntity returns a descriptive error message
|
||||||
}
|
}
|
||||||
|
@ -363,7 +363,7 @@ func (m *Messenger) HandleContactUpdate(state *ReceivedMessageState, message pro
|
||||||
contact := state.CurrentMessageState.Contact
|
contact := state.CurrentMessageState.Contact
|
||||||
chat, ok := state.AllChats.Load(contact.ID)
|
chat, ok := state.AllChats.Load(contact.ID)
|
||||||
|
|
||||||
allowed, err := m.isMessageAllowedFrom(state.AllContacts, state.CurrentMessageState.Contact.ID, chat)
|
allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, chat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -497,7 +497,7 @@ func (m *Messenger) HandleEditMessage(response *MessengerResponse, editMessage E
|
||||||
var err error
|
var err error
|
||||||
originalMessage, err = m.persistence.MessageByID(messageID)
|
originalMessage, err = m.persistence.MessageByID(messageID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil && err != common.ErrRecordNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -554,12 +554,12 @@ func (m *Messenger) HandleChatMessage(state *ReceivedMessageState) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to prepare message content: %v", err)
|
return fmt.Errorf("failed to prepare message content: %v", err)
|
||||||
}
|
}
|
||||||
chat, err := m.matchChatEntity(receivedMessage, state.AllChats, state.AllContacts, state.Timesource)
|
chat, err := m.matchChatEntity(receivedMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // matchChatEntity returns a descriptive error message
|
return err // matchChatEntity returns a descriptive error message
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed, err := m.isMessageAllowedFrom(state.AllContacts, state.CurrentMessageState.Contact.ID, chat)
|
allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, chat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -587,7 +587,7 @@ func (m *Messenger) HandleChatMessage(state *ReceivedMessageState) error {
|
||||||
// Set the LocalChatID for the message
|
// Set the LocalChatID for the message
|
||||||
receivedMessage.LocalChatID = chat.ID
|
receivedMessage.LocalChatID = chat.ID
|
||||||
|
|
||||||
if c, ok := state.AllChats.Load(chat.ID); ok {
|
if c, ok := m.allChats.Load(chat.ID); ok {
|
||||||
chat = c
|
chat = c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +602,12 @@ func (m *Messenger) HandleChatMessage(state *ReceivedMessageState) error {
|
||||||
receivedMessage.OutgoingStatus = common.OutgoingStatusSent
|
receivedMessage.OutgoingStatus = common.OutgoingStatusSent
|
||||||
}
|
}
|
||||||
|
|
||||||
err = chat.UpdateFromMessage(receivedMessage, state.Timesource)
|
err = m.checkForEdits(receivedMessage)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = chat.UpdateFromMessage(receivedMessage, m.getTimesource())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -615,7 +620,7 @@ func (m *Messenger) HandleChatMessage(state *ReceivedMessageState) error {
|
||||||
// Set in the modified maps chat
|
// Set in the modified maps chat
|
||||||
state.Response.AddChat(chat)
|
state.Response.AddChat(chat)
|
||||||
// TODO(samyoul) remove storing of an updated reference pointer?
|
// TODO(samyoul) remove storing of an updated reference pointer?
|
||||||
state.AllChats.Store(chat.ID, chat)
|
m.allChats.Store(chat.ID, chat)
|
||||||
|
|
||||||
contact := state.CurrentMessageState.Contact
|
contact := state.CurrentMessageState.Contact
|
||||||
if receivedMessage.EnsName != "" {
|
if receivedMessage.EnsName != "" {
|
||||||
|
@ -861,7 +866,7 @@ func (m *Messenger) HandleDeclineRequestTransaction(messageState *ReceivedMessag
|
||||||
return m.handleCommandMessage(messageState, oldMessage)
|
return m.handleCommandMessage(messageState, oldMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity, chats *chatMap, contacts *contactMap, timesource common.TimeSource) (*Chat, error) {
|
func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity) (*Chat, error) {
|
||||||
if chatEntity.GetSigPubKey() == nil {
|
if chatEntity.GetSigPubKey() == nil {
|
||||||
m.logger.Error("public key can't be empty")
|
m.logger.Error("public key can't be empty")
|
||||||
return nil, errors.New("received a chatEntity with empty public key")
|
return nil, errors.New("received a chatEntity with empty public key")
|
||||||
|
@ -872,7 +877,7 @@ func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity, chats *chatMap
|
||||||
// For public messages, all outgoing and incoming messages have the same chatID
|
// For public messages, all outgoing and incoming messages have the same chatID
|
||||||
// equal to a public chat name.
|
// equal to a public chat name.
|
||||||
chatID := chatEntity.GetChatId()
|
chatID := chatEntity.GetChatId()
|
||||||
chat, ok := chats.Load(chatID)
|
chat, ok := m.allChats.Load(chatID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("received a public chatEntity from non-existing chat")
|
return nil, errors.New("received a public chatEntity from non-existing chat")
|
||||||
}
|
}
|
||||||
|
@ -881,7 +886,7 @@ func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity, chats *chatMap
|
||||||
// It's a private message coming from us so we rely on Message.ChatID
|
// It's a private message coming from us so we rely on Message.ChatID
|
||||||
// If chat does not exist, it should be created to support multidevice synchronization.
|
// If chat does not exist, it should be created to support multidevice synchronization.
|
||||||
chatID := chatEntity.GetChatId()
|
chatID := chatEntity.GetChatId()
|
||||||
chat, ok := chats.Load(chatID)
|
chat, ok := m.allChats.Load(chatID)
|
||||||
if !ok {
|
if !ok {
|
||||||
if len(chatID) != PubKeyStringLength {
|
if len(chatID) != PubKeyStringLength {
|
||||||
return nil, errors.New("invalid pubkey length")
|
return nil, errors.New("invalid pubkey length")
|
||||||
|
@ -896,27 +901,27 @@ func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity, chats *chatMap
|
||||||
return nil, errors.Wrap(err, "failed to decode pubkey")
|
return nil, errors.Wrap(err, "failed to decode pubkey")
|
||||||
}
|
}
|
||||||
|
|
||||||
chat = CreateOneToOneChat(chatID[:8], pubKey, timesource)
|
chat = CreateOneToOneChat(chatID[:8], pubKey, m.getTimesource())
|
||||||
}
|
}
|
||||||
return chat, nil
|
return chat, nil
|
||||||
case chatEntity.GetMessageType() == protobuf.MessageType_ONE_TO_ONE:
|
case chatEntity.GetMessageType() == protobuf.MessageType_ONE_TO_ONE:
|
||||||
// It's an incoming private chatEntity. ChatID is calculated from the signature.
|
// It's an incoming private chatEntity. ChatID is calculated from the signature.
|
||||||
// If a chat does not exist, a new one is created and saved.
|
// If a chat does not exist, a new one is created and saved.
|
||||||
chatID := contactIDFromPublicKey(chatEntity.GetSigPubKey())
|
chatID := contactIDFromPublicKey(chatEntity.GetSigPubKey())
|
||||||
chat, ok := chats.Load(chatID)
|
chat, ok := m.allChats.Load(chatID)
|
||||||
if !ok {
|
if !ok {
|
||||||
// TODO: this should be a three-word name used in the mobile client
|
// TODO: this should be a three-word name used in the mobile client
|
||||||
chat = CreateOneToOneChat(chatID[:8], chatEntity.GetSigPubKey(), timesource)
|
chat = CreateOneToOneChat(chatID[:8], chatEntity.GetSigPubKey(), m.getTimesource())
|
||||||
chat.Active = false
|
chat.Active = false
|
||||||
}
|
}
|
||||||
// We set the chat as inactive and will create a notification
|
// We set the chat as inactive and will create a notification
|
||||||
// if it's not coming from a contact
|
// if it's not coming from a contact
|
||||||
contact, ok := contacts.Load(chatID)
|
contact, ok := m.allContacts.Load(chatID)
|
||||||
chat.Active = chat.Active || (ok && contact.IsAdded())
|
chat.Active = chat.Active || (ok && contact.IsAdded())
|
||||||
return chat, nil
|
return chat, nil
|
||||||
case chatEntity.GetMessageType() == protobuf.MessageType_COMMUNITY_CHAT:
|
case chatEntity.GetMessageType() == protobuf.MessageType_COMMUNITY_CHAT:
|
||||||
chatID := chatEntity.GetChatId()
|
chatID := chatEntity.GetChatId()
|
||||||
chat, ok := chats.Load(chatID)
|
chat, ok := m.allChats.Load(chatID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("received community chat chatEntity for non-existing chat")
|
return nil, errors.New("received community chat chatEntity for non-existing chat")
|
||||||
}
|
}
|
||||||
|
@ -945,7 +950,7 @@ func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity, chats *chatMap
|
||||||
// In the case of a group chatEntity, ChatID is the same for all messages belonging to a group.
|
// In the case of a group chatEntity, ChatID is the same for all messages belonging to a group.
|
||||||
// It needs to be verified if the signature public key belongs to the chat.
|
// It needs to be verified if the signature public key belongs to the chat.
|
||||||
chatID := chatEntity.GetChatId()
|
chatID := chatEntity.GetChatId()
|
||||||
chat, ok := chats.Load(chatID)
|
chat, ok := m.allChats.Load(chatID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("received group chat chatEntity for non-existing chat")
|
return nil, errors.New("received group chat chatEntity for non-existing chat")
|
||||||
}
|
}
|
||||||
|
@ -1019,7 +1024,7 @@ func (m *Messenger) HandleEmojiReaction(state *ReceivedMessageState, pbEmojiR pr
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
chat, err := m.matchChatEntity(emojiReaction, state.AllChats, state.AllContacts, state.Timesource)
|
chat, err := m.matchChatEntity(emojiReaction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // matchChatEntity returns a descriptive error message
|
return err // matchChatEntity returns a descriptive error message
|
||||||
}
|
}
|
||||||
|
@ -1049,7 +1054,7 @@ func (m *Messenger) HandleEmojiReaction(state *ReceivedMessageState, pbEmojiR pr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) HandleGroupChatInvitation(state *ReceivedMessageState, pbGHInvitations protobuf.GroupChatInvitation) error {
|
func (m *Messenger) HandleGroupChatInvitation(state *ReceivedMessageState, pbGHInvitations protobuf.GroupChatInvitation) error {
|
||||||
allowed, err := m.isMessageAllowedFrom(state.AllContacts, state.CurrentMessageState.Contact.ID, nil)
|
allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1102,7 +1107,7 @@ func (m *Messenger) HandleGroupChatInvitation(state *ReceivedMessageState, pbGHI
|
||||||
// extracts contact information stored in the protobuf and adds it to the user's contact for update.
|
// extracts contact information stored in the protobuf and adds it to the user's contact for update.
|
||||||
func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci protobuf.ChatIdentity) error {
|
func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci protobuf.ChatIdentity) error {
|
||||||
logger := m.logger.With(zap.String("site", "HandleChatIdentity"))
|
logger := m.logger.With(zap.String("site", "HandleChatIdentity"))
|
||||||
allowed, err := m.isMessageAllowedFrom(state.AllContacts, state.CurrentMessageState.Contact.ID, nil)
|
allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1135,10 +1140,31 @@ func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci protobuf.
|
||||||
func (m *Messenger) checkForEdits(message *common.Message) error {
|
func (m *Messenger) checkForEdits(message *common.Message) error {
|
||||||
// Check for any pending edit
|
// Check for any pending edit
|
||||||
// If any pending edits are available and valid, apply them
|
// If any pending edits are available and valid, apply them
|
||||||
|
edits, err := m.persistence.GetEdits(message.ID, message.From)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(edits) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) isMessageAllowedFrom(allContacts *contactMap, publicKey string, chat *Chat) (bool, error) {
|
// Apply the first edit that is valid
|
||||||
|
for _, e := range edits {
|
||||||
|
if e.Clock >= message.Clock {
|
||||||
|
// Update message and return it
|
||||||
|
err := m.applyEditMessage(&e.EditMessage, message)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) isMessageAllowedFrom(publicKey string, chat *Chat) (bool, error) {
|
||||||
onlyFromContacts, err := m.settings.GetMessagesFromContactsOnly()
|
onlyFromContacts, err := m.settings.GetMessagesFromContactsOnly()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -1163,7 +1189,7 @@ func (m *Messenger) isMessageAllowedFrom(allContacts *contactMap, publicKey stri
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
contact, ok := allContacts.Load(publicKey)
|
contact, ok := m.allContacts.Load(publicKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
// If it's not in contacts, we don't allow it
|
// If it's not in contacts, we don't allow it
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
|
@ -1428,10 +1428,30 @@ func (db sqlitePersistence) deactivateChat(chat *Chat, currentClockValue uint64,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db sqlitePersistence) SaveEdit(editMessage EditMessage) error {
|
func (db sqlitePersistence) SaveEdit(editMessage EditMessage) error {
|
||||||
_, err := db.db.Exec(`INSERT INTO user_messages_edits (clock, chat_id, message_id, source, text, id) VALUES(?,?,?,?,?,?)`, editMessage.Clock, editMessage.ChatId, editMessage.MessageId, editMessage.Text, editMessage.From, editMessage.ID)
|
_, err := db.db.Exec(`INSERT INTO user_messages_edits (clock, chat_id, message_id, text, source, id) VALUES(?,?,?,?,?,?)`, editMessage.Clock, editMessage.ChatId, editMessage.MessageId, editMessage.Text, editMessage.From, editMessage.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db sqlitePersistence) GetEdits(messageID string, from string) ([]*EditMessage, error) {
|
||||||
|
rows, err := db.db.Query(`SELECT clock, chat_id, message_id, source, text, id FROM user_messages_edits WHERE message_id = ? AND source = ? ORDER BY CLOCK DESC`, messageID, from)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages []*EditMessage
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
e := &EditMessage{}
|
||||||
|
err := rows.Scan(&e.Clock, &e.ChatId, &e.MessageId, &e.From, &e.Text, &e.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
messages = append(messages, e)
|
||||||
|
|
||||||
|
}
|
||||||
|
return messages, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (db sqlitePersistence) clearHistory(chat *Chat, currentClockValue uint64, tx *sql.Tx, deactivate bool) error {
|
func (db sqlitePersistence) clearHistory(chat *Chat, currentClockValue uint64, tx *sql.Tx, deactivate bool) error {
|
||||||
// Set deleted at clock value if it's not a public chat so that
|
// Set deleted at clock value if it's not a public chat so that
|
||||||
// old messages will be discarded, or if it's a straight clear history
|
// old messages will be discarded, or if it's a straight clear history
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
"github.com/status-im/status-go/protocol/requests"
|
"github.com/status-im/status-go/protocol/requests"
|
||||||
"github.com/status-im/status-go/protocol/tt"
|
"github.com/status-im/status-go/protocol/tt"
|
||||||
|
@ -220,3 +221,59 @@ func (s *MessengerEditMessageSuite) TestEditMessageEdgeCases() {
|
||||||
// It discards the edit
|
// It discards the edit
|
||||||
s.Require().Len(response.Messages(), 0)
|
s.Require().Len(response.Messages(), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *MessengerEditMessageSuite) TestEditMessageFirstEditsThenMessage() {
|
||||||
|
theirMessenger := s.newMessenger()
|
||||||
|
_, err := theirMessenger.Start()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
||||||
|
err = theirMessenger.SaveChat(theirChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
contact, err := BuildContactFromPublicKey(&theirMessenger.identity.PublicKey)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
||||||
|
err = s.m.SaveChat(ourChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
messageID := "message-id"
|
||||||
|
|
||||||
|
inputMessage := buildTestMessage(*theirChat)
|
||||||
|
inputMessage.Clock = 1
|
||||||
|
editMessage := EditMessage{
|
||||||
|
EditMessage: protobuf.EditMessage{
|
||||||
|
Clock: 2,
|
||||||
|
Text: "some text",
|
||||||
|
MessageId: messageID,
|
||||||
|
ChatId: theirChat.ID,
|
||||||
|
},
|
||||||
|
From: common.PubkeyToHex(&theirMessenger.identity.PublicKey),
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &MessengerResponse{}
|
||||||
|
|
||||||
|
// Handle edit first
|
||||||
|
err = s.m.HandleEditMessage(response, editMessage)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
// Handle chat message
|
||||||
|
response = &MessengerResponse{}
|
||||||
|
state := &ReceivedMessageState{
|
||||||
|
Response: response,
|
||||||
|
CurrentMessageState: &CurrentMessageState{
|
||||||
|
Message: inputMessage.ChatMessage,
|
||||||
|
MessageID: messageID,
|
||||||
|
WhisperTimestamp: s.m.getTimesource().GetCurrentTime(),
|
||||||
|
Contact: contact,
|
||||||
|
PublicKey: &theirMessenger.identity.PublicKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = s.m.HandleChatMessage(state)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(response.Messages(), 1)
|
||||||
|
|
||||||
|
editedMessage := response.Messages()[0]
|
||||||
|
|
||||||
|
s.Require().Equal(uint64(2), editedMessage.EditedAt)
|
||||||
|
}
|
||||||
|
|
|
@ -24,12 +24,7 @@ func (m *Messenger) EditMessage(ctx context.Context, request *requests.EditMessa
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sender, err := message.GetSenderPubKey()
|
if message.From != common.PubkeyToHex(&m.identity.PublicKey) {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sender.Equal(&m.identity.PublicKey) {
|
|
||||||
return nil, ErrInvalidEditAuthor
|
return nil, ErrInvalidEditAuthor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +75,7 @@ func (m *Messenger) EditMessage(ctx context.Context, request *requests.EditMessa
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) applyEditMessage(editMessage *protobuf.EditMessage, message *common.Message) error {
|
func (m *Messenger) applyEditMessage(editMessage *protobuf.EditMessage, message *common.Message) error {
|
||||||
|
// TODO: should save an edit if it's the first time it's being edited
|
||||||
message.Text = editMessage.Text
|
message.Text = editMessage.Text
|
||||||
message.EditedAt = editMessage.Clock
|
message.EditedAt = editMessage.Clock
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@
|
||||||
// 1622464518_set_synced_to_from.up.sql (105B)
|
// 1622464518_set_synced_to_from.up.sql (105B)
|
||||||
// 1622464519_add_chat_description.up.sql (93B)
|
// 1622464519_add_chat_description.up.sql (93B)
|
||||||
// 1622622253_add_pinned_by_to_pin_messages.up.sql (52B)
|
// 1622622253_add_pinned_by_to_pin_messages.up.sql (52B)
|
||||||
// 1622722745_add_original_message_id.up.sql (273B)
|
|
||||||
// 1623938329_add_author_activity_center_notification_field.up.sql (66B)
|
// 1623938329_add_author_activity_center_notification_field.up.sql (66B)
|
||||||
|
// 1623938330_add_edit_messages.up.sql (369B)
|
||||||
// README.md (554B)
|
// README.md (554B)
|
||||||
// doc.go (850B)
|
// doc.go (850B)
|
||||||
|
|
||||||
|
@ -828,26 +828,6 @@ func _1622622253_add_pinned_by_to_pin_messagesUpSql() (*asset, error) {
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var __1622722745_add_original_message_idUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\xcc\xc1\x8a\x83\x30\x14\x85\xe1\x7d\x9e\xe2\x2c\x15\xe6\x0d\x5c\xdd\xd1\xcb\x8c\x4c\x8c\x43\x88\x05\x57\x41\xcc\xa5\x95\xb6\x08\x26\x42\x1f\xbf\x08\xed\xa2\xa0\xeb\xef\x9c\x9f\xb4\x63\x0b\x47\xdf\x9a\xb1\x46\x59\xfc\x5d\x62\x1c\xce\x12\x41\x55\x85\xb2\xd5\x5d\x63\x20\x61\x4a\x12\xfc\x90\x50\x1b\xc7\x3f\x6c\x0b\xa5\x4a\xcb\xe4\x78\xef\xe9\xb7\x79\x44\xa6\x80\xf1\x36\x8f\xd7\xf7\x09\xa6\x75\x30\x9d\xd6\x5f\x9b\x5c\x86\xe4\xa7\x80\x13\xd9\xf2\x97\x3e\xed\x15\x3a\xe2\x38\xaf\xcb\x28\xbb\x94\xe4\x91\x76\xe1\x20\xf5\x6f\xeb\x86\x6c\x8f\x3f\xee\xb3\x29\xe4\x2a\x2f\xd4\x33\x00\x00\xff\xff\x94\x32\x5e\xe6\x11\x01\x00\x00")
|
|
||||||
|
|
||||||
func _1622722745_add_original_message_idUpSqlBytes() ([]byte, error) {
|
|
||||||
return bindataRead(
|
|
||||||
__1622722745_add_original_message_idUpSql,
|
|
||||||
"1622722745_add_original_message_id.up.sql",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _1622722745_add_original_message_idUpSql() (*asset, error) {
|
|
||||||
bytes, err := _1622722745_add_original_message_idUpSqlBytes()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1622722745_add_original_message_id.up.sql", size: 273, mode: os.FileMode(0644), modTime: time.Unix(1624368044, 0)}
|
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0x47, 0x48, 0x84, 0x7a, 0x2f, 0x30, 0x5c, 0x33, 0xa4, 0x42, 0xfb, 0x7d, 0xe1, 0xa6, 0x46, 0x9d, 0x20, 0x19, 0x99, 0x56, 0xbb, 0x9f, 0xd, 0xe4, 0x6b, 0x99, 0x29, 0xe5, 0xef, 0xef, 0x58}}
|
|
||||||
return a, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var __1623938329_add_author_activity_center_notification_fieldUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4c\x2e\xc9\x2c\xcb\x2c\xa9\x8c\x4f\x4e\xcd\x2b\x49\x2d\x8a\xcf\xcb\x2f\xc9\x4c\xcb\x4c\x4e\x2c\xc9\xcc\xcf\x2b\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x2c\x2d\xc9\xc8\x2f\x52\x08\x71\x8d\x08\xb1\xe6\x02\x04\x00\x00\xff\xff\xc4\xaa\x64\x1f\x42\x00\x00\x00")
|
var __1623938329_add_author_activity_center_notification_fieldUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4c\x2e\xc9\x2c\xcb\x2c\xa9\x8c\x4f\x4e\xcd\x2b\x49\x2d\x8a\xcf\xcb\x2f\xc9\x4c\xcb\x4c\x4e\x2c\xc9\xcc\xcf\x2b\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x2c\x2d\xc9\xc8\x2f\x52\x08\x71\x8d\x08\xb1\xe6\x02\x04\x00\x00\xff\xff\xc4\xaa\x64\x1f\x42\x00\x00\x00")
|
||||||
|
|
||||||
func _1623938329_add_author_activity_center_notification_fieldUpSqlBytes() ([]byte, error) {
|
func _1623938329_add_author_activity_center_notification_fieldUpSqlBytes() ([]byte, error) {
|
||||||
|
@ -868,6 +848,26 @@ func _1623938329_add_author_activity_center_notification_fieldUpSql() (*asset, e
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var __1623938330_add_edit_messagesUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x8f\xc1\x8a\x83\x30\x14\x45\xf7\xf9\x8a\xb7\x54\xf0\x0f\x5c\xbd\xd1\xc7\x8c\x4c\x8c\x25\xc4\x52\x57\x41\xcc\xa3\x95\xb6\x08\x26\x42\x3f\xbf\x08\x16\x29\xc4\xf5\xb9\xf7\x72\x2e\x4a\x43\x1a\x0c\xfe\x48\x82\xc5\xf3\x6c\x9f\xec\x7d\x7f\x65\x0f\x58\x96\x50\x34\xb2\xad\x15\xb0\x1b\x03\x3b\xdb\x07\xa8\x94\xa1\x5f\xd2\xb9\x10\x85\x26\x34\x14\x6b\xda\x35\xee\x21\x11\x00\xc3\x63\x1a\xee\x9f\x12\xa8\xc6\x80\x6a\xa5\xcc\x56\x72\xeb\x83\x1d\x1d\x9c\x51\x17\x7f\xf8\xcd\xb6\xa1\x23\xec\xa7\x65\x1e\x38\x8a\x02\xbf\x42\x14\x1c\x4c\x9d\x74\x55\xa3\xee\xe0\x9f\xba\x64\x74\xa9\x48\xf7\x63\x95\x2a\xe9\x12\x3b\x66\x77\x3d\xbb\xa9\x34\x2a\x16\x4c\xf6\x60\xb6\x49\xa7\xb9\x78\x07\x00\x00\xff\xff\x6a\x1b\xa7\x21\x71\x01\x00\x00")
|
||||||
|
|
||||||
|
func _1623938330_add_edit_messagesUpSqlBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
__1623938330_add_edit_messagesUpSql,
|
||||||
|
"1623938330_add_edit_messages.up.sql",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _1623938330_add_edit_messagesUpSql() (*asset, error) {
|
||||||
|
bytes, err := _1623938330_add_edit_messagesUpSqlBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{name: "1623938330_add_edit_messages.up.sql", size: 369, mode: os.FileMode(0644), modTime: time.Unix(1624368052, 0)}
|
||||||
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7e, 0xd2, 0xce, 0xe, 0x5c, 0x19, 0xbe, 0x5e, 0x29, 0xbe, 0x9b, 0x31, 0x53, 0x76, 0xb2, 0xc8, 0x56, 0xf0, 0x82, 0xfe, 0x7d, 0x6c, 0xe8, 0x5c, 0xe9, 0x7a, 0x5d, 0x5, 0xc4, 0x92, 0x38, 0xe3}}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
var _readmeMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x91\xc1\xce\xd3\x30\x10\x84\xef\x7e\x8a\x91\x7a\x01\xa9\x2a\x8f\xc0\x0d\x71\x82\x03\x48\x1c\xc9\x36\x9e\x36\x96\x1c\x6f\xf0\xae\x93\xe6\xed\x91\xa3\xc2\xdf\xff\x66\xed\xd8\x33\xdf\x78\x4f\xa7\x13\xbe\xea\x06\x57\x6c\x35\x39\x31\xa7\x7b\x15\x4f\x5a\xec\x73\x08\xbf\x08\x2d\x79\x7f\x4a\x43\x5b\x86\x17\xfd\x8c\x21\xea\x56\x5e\x47\x90\x4a\x14\x75\x48\xde\x64\x37\x2c\x6a\x96\xae\x99\x48\x05\xf6\x27\x77\x13\xad\x08\xae\x8a\x51\xe7\x25\xf3\xf1\xa9\x9f\xf9\x58\x58\x2c\xad\xbc\xe0\x8b\x56\xf0\x21\x5d\xeb\x4c\x95\xb3\xae\x84\x60\xd4\xdc\xe6\x82\x5d\x1b\x36\x6d\x39\x62\x92\xf5\xb8\x11\xdb\x92\xd3\x28\xce\xe0\x13\xe1\x72\xcd\x3c\x63\xd4\x65\x87\xae\xac\xe8\xc3\x28\x2e\x67\x44\x66\x3a\x21\x25\xa2\x72\xac\x14\x67\xbc\x84\x9f\x53\x32\x8c\x52\x70\x25\x56\xd6\xfd\x8d\x05\x37\xad\x30\x9d\x9f\xa6\x86\x0f\xcd\x58\x7f\xcf\x34\x93\x3b\xed\x90\x9f\xa4\x1f\xcf\x30\x85\x4d\x07\x58\xaf\x7f\x25\xc4\x9d\xf3\x72\x64\x84\xd0\x7f\xf9\x9b\x3a\x2d\x84\xef\x85\x48\x66\x8d\xd8\x88\x9b\x8c\x8c\x98\x5b\xf6\x74\x14\x4e\x33\x0d\xc9\xe0\x93\x38\xda\x12\xc5\x69\xbd\xe4\xf0\x2e\x7a\x78\x07\x1c\xfe\x13\x9f\x91\x29\x31\x95\x7b\x7f\x62\x59\x37\xb4\xe5\x5e\x25\xfe\x33\xee\xd5\x53\x71\xd6\xda\x3a\xd8\xcb\xde\x2e\xf8\xa1\x90\x55\x53\x0c\xc7\xaa\x0d\xe9\x76\x14\x29\x1c\x7b\x68\xdd\x2f\xe1\x6f\x00\x00\x00\xff\xff\x3c\x0a\xc2\xfe\x2a\x02\x00\x00")
|
var _readmeMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x91\xc1\xce\xd3\x30\x10\x84\xef\x7e\x8a\x91\x7a\x01\xa9\x2a\x8f\xc0\x0d\x71\x82\x03\x48\x1c\xc9\x36\x9e\x36\x96\x1c\x6f\xf0\xae\x93\xe6\xed\x91\xa3\xc2\xdf\xff\x66\xed\xd8\x33\xdf\x78\x4f\xa7\x13\xbe\xea\x06\x57\x6c\x35\x39\x31\xa7\x7b\x15\x4f\x5a\xec\x73\x08\xbf\x08\x2d\x79\x7f\x4a\x43\x5b\x86\x17\xfd\x8c\x21\xea\x56\x5e\x47\x90\x4a\x14\x75\x48\xde\x64\x37\x2c\x6a\x96\xae\x99\x48\x05\xf6\x27\x77\x13\xad\x08\xae\x8a\x51\xe7\x25\xf3\xf1\xa9\x9f\xf9\x58\x58\x2c\xad\xbc\xe0\x8b\x56\xf0\x21\x5d\xeb\x4c\x95\xb3\xae\x84\x60\xd4\xdc\xe6\x82\x5d\x1b\x36\x6d\x39\x62\x92\xf5\xb8\x11\xdb\x92\xd3\x28\xce\xe0\x13\xe1\x72\xcd\x3c\x63\xd4\x65\x87\xae\xac\xe8\xc3\x28\x2e\x67\x44\x66\x3a\x21\x25\xa2\x72\xac\x14\x67\xbc\x84\x9f\x53\x32\x8c\x52\x70\x25\x56\xd6\xfd\x8d\x05\x37\xad\x30\x9d\x9f\xa6\x86\x0f\xcd\x58\x7f\xcf\x34\x93\x3b\xed\x90\x9f\xa4\x1f\xcf\x30\x85\x4d\x07\x58\xaf\x7f\x25\xc4\x9d\xf3\x72\x64\x84\xd0\x7f\xf9\x9b\x3a\x2d\x84\xef\x85\x48\x66\x8d\xd8\x88\x9b\x8c\x8c\x98\x5b\xf6\x74\x14\x4e\x33\x0d\xc9\xe0\x93\x38\xda\x12\xc5\x69\xbd\xe4\xf0\x2e\x7a\x78\x07\x1c\xfe\x13\x9f\x91\x29\x31\x95\x7b\x7f\x62\x59\x37\xb4\xe5\x5e\x25\xfe\x33\xee\xd5\x53\x71\xd6\xda\x3a\xd8\xcb\xde\x2e\xf8\xa1\x90\x55\x53\x0c\xc7\xaa\x0d\xe9\x76\x14\x29\x1c\x7b\x68\xdd\x2f\xe1\x6f\x00\x00\x00\xff\xff\x3c\x0a\xc2\xfe\x2a\x02\x00\x00")
|
||||||
|
|
||||||
func readmeMdBytes() ([]byte, error) {
|
func readmeMdBytes() ([]byte, error) {
|
||||||
|
@ -1071,10 +1071,10 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
|
|
||||||
"1622622253_add_pinned_by_to_pin_messages.up.sql": _1622622253_add_pinned_by_to_pin_messagesUpSql,
|
"1622622253_add_pinned_by_to_pin_messages.up.sql": _1622622253_add_pinned_by_to_pin_messagesUpSql,
|
||||||
|
|
||||||
"1622722745_add_original_message_id.up.sql": _1622722745_add_original_message_idUpSql,
|
|
||||||
|
|
||||||
"1623938329_add_author_activity_center_notification_field.up.sql": _1623938329_add_author_activity_center_notification_fieldUpSql,
|
"1623938329_add_author_activity_center_notification_field.up.sql": _1623938329_add_author_activity_center_notification_fieldUpSql,
|
||||||
|
|
||||||
|
"1623938330_add_edit_messages.up.sql": _1623938330_add_edit_messagesUpSql,
|
||||||
|
|
||||||
"README.md": readmeMd,
|
"README.md": readmeMd,
|
||||||
|
|
||||||
"doc.go": docGo,
|
"doc.go": docGo,
|
||||||
|
@ -1157,8 +1157,8 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
||||||
"1622464518_set_synced_to_from.up.sql": &bintree{_1622464518_set_synced_to_fromUpSql, map[string]*bintree{}},
|
"1622464518_set_synced_to_from.up.sql": &bintree{_1622464518_set_synced_to_fromUpSql, map[string]*bintree{}},
|
||||||
"1622464519_add_chat_description.up.sql": &bintree{_1622464519_add_chat_descriptionUpSql, map[string]*bintree{}},
|
"1622464519_add_chat_description.up.sql": &bintree{_1622464519_add_chat_descriptionUpSql, map[string]*bintree{}},
|
||||||
"1622622253_add_pinned_by_to_pin_messages.up.sql": &bintree{_1622622253_add_pinned_by_to_pin_messagesUpSql, map[string]*bintree{}},
|
"1622622253_add_pinned_by_to_pin_messages.up.sql": &bintree{_1622622253_add_pinned_by_to_pin_messagesUpSql, map[string]*bintree{}},
|
||||||
"1622722745_add_original_message_id.up.sql": &bintree{_1622722745_add_original_message_idUpSql, map[string]*bintree{}},
|
|
||||||
"1623938329_add_author_activity_center_notification_field.up.sql": &bintree{_1623938329_add_author_activity_center_notification_fieldUpSql, map[string]*bintree{}},
|
"1623938329_add_author_activity_center_notification_field.up.sql": &bintree{_1623938329_add_author_activity_center_notification_fieldUpSql, map[string]*bintree{}},
|
||||||
|
"1623938330_add_edit_messages.up.sql": &bintree{_1623938330_add_edit_messagesUpSql, map[string]*bintree{}},
|
||||||
"README.md": &bintree{readmeMd, map[string]*bintree{}},
|
"README.md": &bintree{readmeMd, map[string]*bintree{}},
|
||||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -9,3 +9,5 @@ CREATE TABLE user_messages_edits (
|
||||||
id VARCHAR NOT NULL,
|
id VARCHAR NOT NULL,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE INDEX user_messages_edits_message_id_source ON user_messages_edits(message_id, source);
|
|
@ -591,6 +591,10 @@ func (api *PublicAPI) SendChatMessages(ctx context.Context, messages []*common.M
|
||||||
return api.service.messenger.SendChatMessages(ctx, messages)
|
return api.service.messenger.SendChatMessages(ctx, messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *PublicAPI) EditMessage(ctx context.Context, request *requests.EditMessage) (*protocol.MessengerResponse, error) {
|
||||||
|
return api.service.messenger.EditMessage(ctx, request)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *PublicAPI) SendPinMessage(ctx context.Context, message *common.PinMessage) (*protocol.MessengerResponse, error) {
|
func (api *PublicAPI) SendPinMessage(ctx context.Context, message *common.PinMessage) (*protocol.MessengerResponse, error) {
|
||||||
return api.service.messenger.SendPinMessage(ctx, message)
|
return api.service.messenger.SendPinMessage(ctx, message)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue