feat(edit-message): Edit image messages (#3393)

* feat(edit-message): Edit image messages

* feat(edit-message): Adds tests for edit image messages text

* chore(messenger_messages): Replace ErrChatNotFound duplications
This commit is contained in:
Boris Melnik 2023-04-26 14:10:17 +03:00 committed by GitHub
parent 213dc463bc
commit 2950d37e43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 149 additions and 58 deletions

View File

@ -6293,20 +6293,21 @@ func (m *Messenger) GetMentionsManager() *MentionManager {
return m.mentionsManager
}
func (m *Messenger) getMessagesToDelete(message *common.Message, chatID string) ([]*common.Message, error) {
var messagesToDelete []*common.Message
func (m *Messenger) getConnectedMessages(message *common.Message, chatID string) ([]*common.Message, error) {
var connectedMessages []*common.Message
// In case of Image messages, we need to delete all the images in the album
if message.ContentType == protobuf.ChatMessage_IMAGE {
image := message.GetImage()
messagesInTheAlbum, err := m.persistence.albumMessages(chatID, image.GetAlbumId())
if err != nil {
return nil, err
if image != nil && image.AlbumId != "" {
messagesInTheAlbum, err := m.persistence.albumMessages(chatID, image.GetAlbumId())
if err != nil {
return nil, err
}
connectedMessages = append(connectedMessages, messagesInTheAlbum...)
return connectedMessages, nil
}
messagesToDelete = append(messagesToDelete, messagesInTheAlbum...)
} else {
messagesToDelete = append(messagesToDelete, message)
}
return messagesToDelete, nil
return append(connectedMessages, message), nil
}
func (m *Messenger) withChatClock(callback func(string, uint64) error) error {

View File

@ -104,7 +104,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteMessage() {
// Main instance user attempts to delete the message it received from theirMessenger
_, err = s.m.DeleteMessageAndSend(context.Background(), ogMessage.ID)
s.Require().ErrorContains(err, "Chat not found")
s.Require().ErrorContains(err, "can't find chat")
}
func (s *MessengerDeleteMessageSuite) TestDeleteMessagePreviousLastMessage() {
@ -309,7 +309,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteImageMessage() {
// Main instance user attempts to delete the message it received from theirMessenger
_, err = theirMessenger.DeleteMessageAndSend(context.Background(), firstMessageID)
s.Require().ErrorContains(err, "Chat not found")
s.Require().ErrorContains(err, "can't find chat")
}
func (s *MessengerDeleteMessageSuite) TestDeleteImageMessageFirstThenMessage() {

View File

@ -1592,7 +1592,7 @@ func (m *Messenger) HandleDeleteMessage(state *ReceivedMessageState, deleteMessa
}
}
messagesToDelete, err := m.getMessagesToDelete(originalMessage, deleteMessage.ChatId)
messagesToDelete, err := m.getConnectedMessages(originalMessage, deleteMessage.ChatId)
if err != nil {
return err
}
@ -1674,7 +1674,7 @@ func (m *Messenger) HandleDeleteForMeMessage(state *ReceivedMessageState, delete
return errors.New("chat not found")
}
messagesToDelete, err := m.getMessagesToDelete(originalMessage, deleteForMeMessage.LocalChatID)
messagesToDelete, err := m.getConnectedMessages(originalMessage, deleteForMeMessage.LocalChatID)
if err != nil {
return err
}

View File

@ -33,66 +33,74 @@ func (m *Messenger) EditMessage(ctx context.Context, request *requests.EditMessa
return nil, ErrInvalidEditOrDeleteAuthor
}
if message.ContentType != protobuf.ChatMessage_TEXT_PLAIN && message.ContentType != protobuf.ChatMessage_EMOJI {
if message.ContentType != protobuf.ChatMessage_TEXT_PLAIN && message.ContentType != protobuf.ChatMessage_EMOJI && message.ContentType != protobuf.ChatMessage_IMAGE {
return nil, ErrInvalidEditContentType
}
// A valid added chat is required.
chat, ok := m.allChats.Load(message.ChatId)
if !ok {
return nil, errors.New("Chat not found")
return nil, ErrChatNotFound
}
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
editMessage := &EditMessage{}
editMessage.Text = request.Text
editMessage.ContentType = request.ContentType
editMessage.ChatId = message.ChatId
editMessage.MessageId = request.ID.String()
editMessage.Clock = clock
err = m.applyEditMessage(&editMessage.EditMessage, message)
messages, err := m.getConnectedMessages(message, message.LocalChatID)
if err != nil {
return nil, err
}
encodedMessage, err := m.encodeChatEntity(chat, editMessage)
if err != nil {
return nil, err
}
rawMessage := common.RawMessage{
LocalChatID: chat.ID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_EDIT_MESSAGE,
SkipGroupMessageWrap: true,
ResendAutomatically: true,
}
_, err = m.dispatchMessage(ctx, rawMessage)
if err != nil {
return nil, err
}
if chat.LastMessage != nil && chat.LastMessage.ID == message.ID {
chat.LastMessage = message
err := m.saveChat(chat)
if err != nil {
return nil, err
}
}
response := &MessengerResponse{}
for _, message := range messages {
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
editMessage := &EditMessage{}
editMessage.Text = request.Text
editMessage.ContentType = request.ContentType
editMessage.ChatId = message.ChatId
editMessage.MessageId = message.ID
editMessage.Clock = clock
err = m.applyEditMessage(&editMessage.EditMessage, message)
if err != nil {
return nil, err
}
encodedMessage, err := m.encodeChatEntity(chat, editMessage)
if err != nil {
return nil, err
}
rawMessage := common.RawMessage{
LocalChatID: chat.ID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_EDIT_MESSAGE,
SkipGroupMessageWrap: true,
ResendAutomatically: true,
}
_, err = m.dispatchMessage(ctx, rawMessage)
if err != nil {
return nil, err
}
if chat.LastMessage != nil && chat.LastMessage.ID == message.ID {
chat.LastMessage = message
err := m.saveChat(chat)
if err != nil {
return nil, err
}
}
response.AddMessage(message)
}
// pull updated messages
updatedMessages, err := m.persistence.MessagesByResponseTo(request.ID.String())
if err != nil {
return nil, err
}
response.AddMessages(updatedMessages)
response.AddMessage(message)
response.AddChat(chat)
return response, nil
@ -129,7 +137,7 @@ func (m *Messenger) DeleteMessageAndSend(ctx context.Context, messageID string)
// A valid added chat is required.
chat, ok := m.allChats.Load(message.ChatId)
if !ok {
return nil, errors.New("Chat not found")
return nil, ErrChatNotFound
}
var canDeleteMessageForEveryone = false
@ -165,7 +173,7 @@ func (m *Messenger) DeleteMessageAndSend(ctx context.Context, messageID string)
return nil, ErrInvalidDeleteTypeAuthor
}
messagesToDelete, err := m.getMessagesToDelete(message, message.ChatId)
messagesToDelete, err := m.getConnectedMessages(message, message.ChatId)
if err != nil {
return nil, err
}
@ -235,7 +243,7 @@ func (m *Messenger) DeleteMessageForMeAndSync(ctx context.Context, chatID string
// A valid added chat is required.
chat, ok := m.allChats.Load(chatID)
if !ok {
return nil, errors.New("Chat not found")
return nil, ErrChatNotFound
}
// Only certain types of messages can be deleted
@ -247,7 +255,7 @@ func (m *Messenger) DeleteMessageForMeAndSync(ctx context.Context, chatID string
return nil, ErrInvalidDeleteTypeAuthor
}
messagesToDelete, err := m.getMessagesToDelete(message, message.ChatId)
messagesToDelete, err := m.getConnectedMessages(message, message.ChatId)
if err != nil {
return nil, err
}

View File

@ -13,8 +13,8 @@ import (
"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/requests"
// "github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/waku"
)
@ -172,3 +172,85 @@ func (s *MessengerSendImagesAlbumSuite) TestAlbumImageMessagesWithMentionSend()
s.Require().Equal(uint(1), response.Chats()[0].UnviewedMessagesCount, "Just one unread message")
}
func (s *MessengerSendImagesAlbumSuite) TestAlbumImageEditText() {
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)
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
err = s.m.SaveChat(ourChat)
s.Require().NoError(err)
const messageCount = 3
var album []*common.Message
for i := 0; i < messageCount; i++ {
outgoingMessage, err := buildImageWithoutAlbumIDMessage(*ourChat)
s.NoError(err)
outgoingMessage.Text = "You can edit me now"
album = append(album, outgoingMessage)
}
err = s.m.SaveChat(ourChat)
s.NoError(err)
response, err := s.m.SendChatMessages(context.Background(), album)
s.NoError(err)
s.Require().Equal(messageCount, len(response.Messages()), "it returns the messages")
s.Require().NoError(err)
s.Require().Len(response.Messages(), messageCount)
response, err = WaitOnMessengerResponse(
theirMessenger,
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
"no messages",
)
s.Require().NoError(err)
s.Require().Len(response.Chats(), 1)
s.Require().Len(response.Messages(), messageCount)
for _, message := range response.Messages() {
image := message.GetImage()
s.Require().NotNil(image, "Message.ID=%s", message.ID)
s.Require().NotEmpty(image.AlbumId, "Message.ID=%s", message.ID)
}
firstMessageID, err := types.DecodeHex(album[0].ID)
s.Require().NoError(err)
editedText := "edited"
editedMessage := &requests.EditMessage{
ID: firstMessageID,
Text: editedText,
}
sendResponse, err := s.m.EditMessage(context.Background(), editedMessage)
s.Require().NoError(err)
s.Require().Len(sendResponse.Messages(), messageCount)
for _, message := range sendResponse.Messages() {
s.Require().NotEmpty(message.EditedAt)
s.Require().Equal(message.Text, editedText)
}
response, err = WaitOnMessengerResponse(
theirMessenger,
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
"no messages",
)
s.Require().NoError(err)
s.Require().Len(response.Chats(), 1)
s.Require().Len(response.Messages(), messageCount)
for _, message := range response.Messages() {
s.Require().NotEmpty(message.EditedAt)
s.Require().Equal(message.Text, editedText)
}
}