From ad342c8887b0cc6fd91cac73919f45ac951efca9 Mon Sep 17 00:00:00 2001 From: Mykhailo Prakhov Date: Tue, 19 Mar 2024 20:44:49 +0100 Subject: [PATCH] feat: get and delete community member messages API (#4932) --- protocol/communities_events_utils_test.go | 2 +- protocol/message_persistence.go | 25 +- protocol/messenger_communities.go | 106 +++++- protocol/messenger_delete_messages_test.go | 360 ++++++++++++++++++ protocol/messenger_handlers.go | 21 + protocol/messenger_messages.go | 16 +- ...st.go => messenger_remove_message_test.go} | 26 +- protocol/messenger_response.go | 9 +- protocol/persistence_test.go | 98 +++-- .../application_metadata_message.pb.go | 31 +- .../application_metadata_message.proto | 1 + protocol/protobuf/communities.pb.go | 259 ++++++++++--- protocol/protobuf/communities.proto | 12 + .../requests/community_member_messages.go | 25 ++ .../delete_community_member_messages.go | 54 +++ services/ext/api.go | 9 + 16 files changed, 937 insertions(+), 117 deletions(-) create mode 100644 protocol/messenger_delete_messages_test.go rename protocol/{messenger_delete_message_test.go => messenger_remove_message_test.go} (96%) create mode 100644 protocol/requests/community_member_messages.go create mode 100644 protocol/requests/delete_community_member_messages.go diff --git a/protocol/communities_events_utils_test.go b/protocol/communities_events_utils_test.go index 73b590d69..acf45cd5d 100644 --- a/protocol/communities_events_utils_test.go +++ b/protocol/communities_events_utils_test.go @@ -771,7 +771,7 @@ func banMember(base CommunityEventsTestsInterface, banRequest *requests.BanUserF waitOnMessengerResponse(s, verifyPendingState, base.GetMember()) checkMsgDeletion := func(messenger *Messenger, expectedMsgsCount int) { - msgs, err := messenger.persistence.GetCommunityMemberAllMessagesID(bannedPK, communityStr) + msgs, err := messenger.persistence.GetCommunityMemberMessagesToDelete(bannedPK, communityStr) s.Require().NoError(err) s.Require().Len(msgs, expectedMsgsCount) } diff --git a/protocol/message_persistence.go b/protocol/message_persistence.go index 8c3d5d466..92108b1b7 100644 --- a/protocol/message_persistence.go +++ b/protocol/message_persistence.go @@ -2922,7 +2922,7 @@ func (db sqlitePersistence) saveBridgeMessage(tx *sql.Tx, message *protobuf.Brid return } -func (db sqlitePersistence) GetCommunityMemberAllMessagesID(member string, communityID string) ([]*DeletedMessage, error) { +func (db sqlitePersistence) GetCommunityMemberMessagesToDelete(member string, communityID string) ([]*protobuf.DeleteCommunityMemberMessage, error) { rows, err := db.db.Query(`SELECT m.id, m.chat_id FROM user_messages as m INNER JOIN chats AS ch ON ch.id = m.chat_id AND ch.community_id = ? WHERE m.source = ?`, communityID, member) @@ -2933,11 +2933,11 @@ func (db sqlitePersistence) GetCommunityMemberAllMessagesID(member string, commu defer rows.Close() - result := []*DeletedMessage{} + result := []*protobuf.DeleteCommunityMemberMessage{} for rows.Next() { - removeMsgsInfo := &DeletedMessage{} - err = rows.Scan(&removeMsgsInfo.ID, &removeMsgsInfo.ChatID) + removeMsgsInfo := &protobuf.DeleteCommunityMemberMessage{} + err = rows.Scan(&removeMsgsInfo.Id, &removeMsgsInfo.ChatId) if err != nil { return nil, err } @@ -3025,3 +3025,20 @@ func (db sqlitePersistence) findAndUpdateRepliedTo(tx *sql.Tx, discordParentMess } return db.updateStatusMessagesWithResponse(tx, []string{statusMessageID}, repliedMessageID) } + +func (db sqlitePersistence) GetCommunityMemberAllMessages(member string, communityID string) ([]*common.Message, error) { + additionalRequestData := "INNER JOIN chats AS ch ON ch.id = m1.chat_id AND ch.community_id = ? WHERE m1.source = ?" + query := db.buildMessagesQueryWithAdditionalFields("", additionalRequestData) + + rows, err := db.db.Query(query, communityID, member) + + if err != nil { + if err == sql.ErrNoRows { + return []*common.Message{}, nil + } + + return nil, err + } + + return getMessagesFromScanRows(db, rows, false) +} diff --git a/protocol/messenger_communities.go b/protocol/messenger_communities.go index fbd75188d..bc8573e69 100644 --- a/protocol/messenger_communities.go +++ b/protocol/messenger_communities.go @@ -2740,7 +2740,7 @@ func (m *Messenger) BanUserFromCommunity(ctx context.Context, request *requests. response.AddCommunity(community) if request.DeleteAllMessages && community.IsControlNode() { - deleteMessagesResponse, err := m.DeleteAllCommunityMemberMessages(request.User.String(), request.CommunityID.String()) + deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.User.String(), request.CommunityID.String(), []*protobuf.DeleteCommunityMemberMessage{}) if err != nil { return nil, err } @@ -2894,7 +2894,7 @@ func (m *Messenger) handleCommunityResponse(state *ReceivedMessageState, communi if len(communityResponse.Changes.MembersBanned) > 0 { for memberID, deleteAllMessages := range communityResponse.Changes.MembersBanned { if deleteAllMessages { - response, err := m.DeleteAllCommunityMemberMessages(memberID, community.IDString()) + response, err := m.deleteCommunityMemberMessages(memberID, community.IDString(), []*protobuf.DeleteCommunityMemberMessage{}) if err != nil { return err } @@ -4435,3 +4435,105 @@ func (m *Messenger) leaveCommunityDueToKickOrBan(changes *communities.CommunityC m.logger.Error("cannot merge leave and notification response", zap.Error(err)) } } + +func (m *Messenger) GetCommunityMemberAllMessages(request *requests.CommunityMemberMessages) ([]*common.Message, error) { + if err := request.Validate(); err != nil { + return nil, err + } + + messages, err := m.persistence.GetCommunityMemberAllMessages(request.MemberPublicKey, request.CommunityID) + if err != nil { + return nil, err + } + + for _, message := range messages { + updatedMessages, err := m.persistence.MessagesByResponseTo(message.ID) + if err != nil { + return nil, err + } + + messages = append(messages, updatedMessages...) + } + + return messages, nil + +} + +func (m *Messenger) DeleteCommunityMemberMessages(request *requests.DeleteCommunityMemberMessages) (*MessengerResponse, error) { + if err := request.Validate(); err != nil { + return nil, err + } + + community, err := m.GetCommunityByID(request.CommunityID) + if err != nil { + return nil, err + } + + if community == nil { + return nil, communities.ErrOrgNotFound + } + + if !community.IsControlNode() && !community.IsPrivilegedMember(m.IdentityPublicKey()) { + return nil, communities.ErrNotEnoughPermissions + } + + memberPubKey, err := common.HexToPubkey(request.MemberPubKey) + if err != nil { + return nil, err + } + + if community.IsMemberOwner(memberPubKey) && !m.IdentityPublicKey().Equal(memberPubKey) { + return nil, communities.ErrNotOwner + } + + deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.MemberPubKey, request.CommunityID.String(), request.Messages) + if err != nil { + return nil, err + } + + deletedMessages := &protobuf.DeleteCommunityMemberMessages{ + Clock: uint64(time.Now().Unix()), + CommunityId: community.ID(), + MemberId: request.MemberPubKey, + Messages: request.Messages, + } + + payload, err := proto.Marshal(deletedMessages) + if err != nil { + return nil, err + } + + rawMessage := common.RawMessage{ + Payload: payload, + Sender: community.PrivateKey(), + SkipEncryptionLayer: true, + MessageType: protobuf.ApplicationMetadataMessage_DELETE_COMMUNITY_MEMBER_MESSAGES, + PubsubTopic: community.PubsubTopic(), + } + + _, err = m.sender.SendPublic(context.Background(), community.IDString(), rawMessage) + + return deleteMessagesResponse, err +} + +func (m *Messenger) HandleDeleteCommunityMemberMessages(state *ReceivedMessageState, request *protobuf.DeleteCommunityMemberMessages, statusMessage *v1protocol.StatusMessage) error { + community, err := m.communitiesManager.GetByID(request.CommunityId) + if err != nil { + return err + } + + if community == nil { + return communities.ErrOrgNotFound + } + + if !community.ControlNode().Equal(state.CurrentMessageState.PublicKey) && !community.IsPrivilegedMember(state.CurrentMessageState.PublicKey) { + return communities.ErrNotAuthorized + } + + deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.MemberId, community.IDString(), request.Messages) + if err != nil { + return err + } + + return state.Response.Merge(deleteMessagesResponse) +} diff --git a/protocol/messenger_delete_messages_test.go b/protocol/messenger_delete_messages_test.go new file mode 100644 index 000000000..b3890b4f2 --- /dev/null +++ b/protocol/messenger_delete_messages_test.go @@ -0,0 +1,360 @@ +package protocol + +import ( + "context" + "testing" + + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + + "github.com/ethereum/go-ethereum/crypto" + gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/communities" + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/protocol/requests" + "github.com/status-im/status-go/protocol/tt" + "github.com/status-im/status-go/waku" +) + +func TestMessengerDeleteMessagesSuite(t *testing.T) { + suite.Run(t, new(MessengerDeleteMessagesSuite)) +} + +type MessengerDeleteMessagesSuite struct { + suite.Suite + owner *Messenger + admin *Messenger + bob *Messenger + shh types.Waku + logger *zap.Logger +} + +func (s *MessengerDeleteMessagesSuite) SetupTest() { + s.logger = tt.MustCreateTestLogger() + + config := waku.DefaultConfig + config.MinimumAcceptedPoW = 0 + shh := waku.New(&config, s.logger) + s.shh = gethbridge.NewGethWakuWrapper(shh) + s.Require().NoError(shh.Start()) + + s.owner = s.newMessenger() + s.bob = s.newMessenger() + s.admin = s.newMessenger() +} + +func (s *MessengerDeleteMessagesSuite) TearDownTest() { + TearDownMessenger(&s.Suite, s.owner) + TearDownMessenger(&s.Suite, s.bob) + TearDownMessenger(&s.Suite, s.admin) + _ = s.logger.Sync() +} + +func (s *MessengerDeleteMessagesSuite) newMessenger() *Messenger { + privateKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + messenger, err := newMessengerWithKey(s.shh, privateKey, s.logger, nil) + s.Require().NoError(err) + return messenger +} + +func (s *MessengerDeleteMessagesSuite) sendMessageAndCheckDelivery(sender *Messenger, text string, chatID string) *common.Message { + ctx := context.Background() + messageToSend := common.NewMessage() + messageToSend.ChatId = chatID + messageToSend.ContentType = protobuf.ChatMessage_TEXT_PLAIN + messageToSend.Text = text + response, err := sender.SendChatMessage(ctx, messageToSend) + s.Require().NoError(err) + s.Require().Len(response.Messages(), 1) + + var message *common.Message + if sender.identity != s.admin.identity { + response, err := WaitOnMessengerResponse(s.admin, func(response *MessengerResponse) bool { + return len(response.Messages()) == 1 + }, "admin did not receive message") + s.Require().NoError(err) + message = response.Messages()[0] + s.Require().Equal(messageToSend.Text, message.Text) + } + + if sender.identity != s.owner.identity { + response, err = WaitOnMessengerResponse(s.owner, func(response *MessengerResponse) bool { + return len(response.Messages()) == 1 + }, "owner did not receive message") + s.Require().NoError(err) + message = response.Messages()[0] + s.Require().Equal(messageToSend.Text, message.Text) + } + + if sender.identity != s.bob.identity { + response, err = WaitOnMessengerResponse(s.bob, func(response *MessengerResponse) bool { + return len(response.Messages()) == 1 + }, "bob did not receive message") + s.Require().NoError(err) + message = response.Messages()[0] + s.Require().Equal(messageToSend.Text, message.Text) + } + + return message +} + +func (s *MessengerDeleteMessagesSuite) checkStoredMemberMessagesAmount(messenger *Messenger, memberPubKey string, expectedAmount int, communityID string) { + storedMessages, err := messenger.GetCommunityMemberAllMessages( + &requests.CommunityMemberMessages{ + CommunityID: communityID, + MemberPublicKey: memberPubKey}) + s.Require().NoError(err) + s.Require().Len(storedMessages, expectedAmount) +} + +func (s *MessengerDeleteMessagesSuite) checkAllMembersHasMemberMessages(memberPubKey string, expectedAmount int, communityID string) { + s.checkStoredMemberMessagesAmount(s.bob, memberPubKey, expectedAmount, communityID) + s.checkStoredMemberMessagesAmount(s.owner, memberPubKey, expectedAmount, communityID) + s.checkStoredMemberMessagesAmount(s.admin, memberPubKey, expectedAmount, communityID) +} + +func (s *MessengerDeleteMessagesSuite) TestDeleteMessageErrors() { + community, communityChat := createCommunity(&s.Suite, s.owner) + + request := &requests.RequestToJoinCommunity{CommunityID: community.ID()} + + advertiseCommunityTo(&s.Suite, community, s.owner, s.admin) + joinCommunity(&s.Suite, community, s.owner, s.admin, request, "") + + advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) + joinCommunity(&s.Suite, community, s.owner, s.bob, request, "") + + grantPermission(&s.Suite, community, s.owner, s.admin, protobuf.CommunityMember_ROLE_ADMIN) + + bobMessage := s.sendMessageAndCheckDelivery(s.bob, "bob message", communityChat.ID) + + expectedMsgsToRemove := 1 + communityID := community.IDString() + s.checkAllMembersHasMemberMessages(s.bob.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + + // empty request + deleteMessagesRequest := &requests.DeleteCommunityMemberMessages{} + _, err := s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidCommunityID) + + // only community ID provided + deleteMessagesRequest.CommunityID = community.ID() + _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidMemberID) + + // only community ID and member ID provided, but delete flag false and no messages IDs + deleteMessagesRequest.MemberPubKey = s.bob.IdentityPublicKeyString() + _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidDeleteMessagesByID) + + // message provided without id + deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{ + ChatId: bobMessage.ChatId, + }} + + _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidMsgID) + + // message provided without chatId + deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{ + Id: bobMessage.ID, + }} + _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidMsgChatID) + + // messages id provided but with flag deleteAll + deleteMessagesRequest.CommunityID = community.ID() + deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{ + Id: bobMessage.ID, + ChatId: bobMessage.ChatId, + }} + deleteMessagesRequest.DeleteAll = true + _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidDeleteAll) + + // bob tries to delete his own message + deleteMessagesRequest.DeleteAll = false + _, err = s.bob.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().ErrorIs(err, communities.ErrNotEnoughPermissions) + + // admin tries to delete owner message + deleteMessagesRequest.MemberPubKey = s.owner.IdentityPublicKeyString() + _, err = s.admin.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().ErrorIs(err, communities.ErrNotOwner) +} + +func (s *MessengerDeleteMessagesSuite) TestDeleteMessage() { + community, communityChat := createCommunity(&s.Suite, s.owner) + + request := &requests.RequestToJoinCommunity{CommunityID: community.ID()} + + advertiseCommunityTo(&s.Suite, community, s.owner, s.admin) + joinCommunity(&s.Suite, community, s.owner, s.admin, request, "") + + advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) + joinCommunity(&s.Suite, community, s.owner, s.bob, request, "") + + grantPermission(&s.Suite, community, s.owner, s.admin, protobuf.CommunityMember_ROLE_ADMIN) + + bobMessage := s.sendMessageAndCheckDelivery(s.bob, "bob message", communityChat.ID) + bobMessage2 := s.sendMessageAndCheckDelivery(s.bob, "bob message2", communityChat.ID) + ownerMessage := s.sendMessageAndCheckDelivery(s.owner, "owner message", communityChat.ID) + adminMessage := s.sendMessageAndCheckDelivery(s.admin, "admin message", communityChat.ID) + + identityString := s.bob.IdentityPublicKeyString() + expectedMsgsToRemove := 2 + communityID := community.IDString() + s.checkAllMembersHasMemberMessages(identityString, expectedMsgsToRemove, communityID) + s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), 1, communityID) + s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), 1, communityID) + + // delete bob message + deleteMessagesRequest := &requests.DeleteCommunityMemberMessages{ + CommunityID: community.ID(), + MemberPubKey: identityString, + Messages: []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{ + Id: bobMessage.ID, + ChatId: bobMessage.ChatId, + }}, + } + response, err := s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().NoError(err) + + checkMessageDeleted := func(response *MessengerResponse) bool { + if len(response.DeletedMessages()) == 0 { + return false + } + + if _, exists := response.DeletedMessages()[deleteMessagesRequest.Messages[0].Id]; !exists { + return false + } + return true + } + + s.Require().True(checkMessageDeleted(response)) + + _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "message was not deleted for bob") + s.Require().NoError(err) + _, err = WaitOnMessengerResponse(s.admin, checkMessageDeleted, "message was not deleted for admin") + s.Require().NoError(err) + + expectedMsgsToRemove = 1 + s.checkAllMembersHasMemberMessages(s.bob.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + + // check that other users messages were not removed + s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + + // check that admin can delete member message + deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{ + Id: bobMessage2.ID, + ChatId: bobMessage2.ChatId, + }} + response, err = s.admin.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().NoError(err) + s.Require().True(checkMessageDeleted(response)) + + _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "message2 was not deleted for bob") + s.Require().NoError(err) + _, err = WaitOnMessengerResponse(s.owner, checkMessageDeleted, "message2 was not deleted for owner") + s.Require().NoError(err) + + expectedMsgsToRemove = 0 + s.checkAllMembersHasMemberMessages(s.bob.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + + // check that other users messages were not removed + expectedMsgsToRemove = 1 + s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + + // check that owner can delete member message + deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{ + Id: adminMessage.ID, + ChatId: adminMessage.ChatId, + }} + response, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().NoError(err) + s.Require().True(checkMessageDeleted(response)) + + _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "adminMessage was not deleted for bob") + s.Require().NoError(err) + _, err = WaitOnMessengerResponse(s.admin, checkMessageDeleted, "adminMessage was not deleted for admin") + s.Require().NoError(err) + + s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), 0, communityID) + s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), 1, communityID) + + // check that owner can delete his own message + deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{ + Id: ownerMessage.ID, + ChatId: ownerMessage.ChatId, + }} + response, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().NoError(err) + s.Require().True(checkMessageDeleted(response)) + + _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "ownerMessage was not deleted for bob") + s.Require().NoError(err) + _, err = WaitOnMessengerResponse(s.admin, checkMessageDeleted, "ownerMessage was not deleted for admin") + s.Require().NoError(err) + + s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), 0, communityID) +} + +func (s *MessengerDeleteMessagesSuite) TestDeleteAllMemberMessage() { + community, communityChat := createCommunity(&s.Suite, s.owner) + + request := &requests.RequestToJoinCommunity{CommunityID: community.ID()} + + advertiseCommunityTo(&s.Suite, community, s.owner, s.admin) + joinCommunity(&s.Suite, community, s.owner, s.admin, request, "") + + advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) + joinCommunity(&s.Suite, community, s.owner, s.bob, request, "") + + grantPermission(&s.Suite, community, s.owner, s.admin, protobuf.CommunityMember_ROLE_ADMIN) + + _ = s.sendMessageAndCheckDelivery(s.bob, "bob message", communityChat.ID) + _ = s.sendMessageAndCheckDelivery(s.bob, "bob message2", communityChat.ID) + _ = s.sendMessageAndCheckDelivery(s.owner, "owner message", communityChat.ID) + _ = s.sendMessageAndCheckDelivery(s.admin, "admin message", communityChat.ID) + + identityString := s.bob.IdentityPublicKeyString() + expectedMsgsToRemove := 2 + communityID := community.IDString() + s.checkAllMembersHasMemberMessages(identityString, expectedMsgsToRemove, communityID) + s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), 1, communityID) + s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), 1, communityID) + + // delete all bob message + deleteMessagesRequest := &requests.DeleteCommunityMemberMessages{ + CommunityID: community.ID(), + MemberPubKey: identityString, + DeleteAll: true, + } + response, err := s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest) + s.Require().NoError(err) + + checkMessageDeleted := func(response *MessengerResponse) bool { + return len(response.DeletedMessages()) == 2 + } + + s.Require().True(checkMessageDeleted(response)) + + _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "messages were not deleted for bob") + s.Require().NoError(err) + _, err = WaitOnMessengerResponse(s.admin, checkMessageDeleted, "messages were not deleted for admin") + s.Require().NoError(err) + + expectedMsgsToRemove = 0 + s.checkAllMembersHasMemberMessages(s.bob.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + + // check that other users messages were not removed + expectedMsgsToRemove = 1 + s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) + s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), expectedMsgsToRemove, communityID) +} diff --git a/protocol/messenger_handlers.go b/protocol/messenger_handlers.go index 75fd3c47d..de0761f7a 100644 --- a/protocol/messenger_handlers.go +++ b/protocol/messenger_handlers.go @@ -253,6 +253,9 @@ func (m *Messenger) dispatchToHandler(messageState *ReceivedMessageState, protoB case protobuf.ApplicationMetadataMessage_COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST: return m.handleCommunityReevaluatePermissionsRequestProtobuf(messageState, protoBytes, msg, filter) + case protobuf.ApplicationMetadataMessage_DELETE_COMMUNITY_MEMBER_MESSAGES: + return m.handleDeleteCommunityMemberMessagesProtobuf(messageState, protoBytes, msg, filter) + default: m.logger.Info("protobuf type not found", zap.String("type", string(msg.ApplicationLayer.Type))) return errors.New("protobuf type not found") @@ -1817,3 +1820,21 @@ func (m *Messenger) handleCommunityReevaluatePermissionsRequestProtobuf(messageS } +func (m *Messenger) handleDeleteCommunityMemberMessagesProtobuf(messageState *ReceivedMessageState, protoBytes []byte, msg *v1protocol.StatusMessage, filter transport.Filter) error { + m.logger.Info("handling DeleteCommunityMemberMessages") + + + + p := &protobuf.DeleteCommunityMemberMessages{} + err := proto.Unmarshal(protoBytes, p) + if err != nil { + return err + } + + m.outputToCSV(msg.TransportLayer.Message.Timestamp, msg.ApplicationLayer.ID, messageState.CurrentMessageState.Contact.ID, filter.ContentTopic, filter.ChatID, msg.ApplicationLayer.Type, p) + + return m.HandleDeleteCommunityMemberMessages(messageState, p, msg) + +} + + diff --git a/protocol/messenger_messages.go b/protocol/messenger_messages.go index cd7e202d8..afc6c6043 100644 --- a/protocol/messenger_messages.go +++ b/protocol/messenger_messages.go @@ -519,10 +519,14 @@ func (m *Messenger) SendGroupChatMessage(request *requests.SendGroupChatMessage) return m.sendChatMessage(context.Background(), message) } -func (m *Messenger) DeleteAllCommunityMemberMessages(member string, communityID string) (*MessengerResponse, error) { - messagesToDelete, err := m.persistence.GetCommunityMemberAllMessagesID(member, communityID) - if err != nil { - return nil, err +func (m *Messenger) deleteCommunityMemberMessages(member string, communityID string, deleteMessages []*protobuf.DeleteCommunityMemberMessage) (*MessengerResponse, error) { + messagesToDelete := deleteMessages + var err error + if len(deleteMessages) == 0 { + messagesToDelete, err = m.persistence.GetCommunityMemberMessagesToDelete(member, communityID) + if err != nil { + return nil, err + } } response := &MessengerResponse{} @@ -532,7 +536,7 @@ func (m *Messenger) DeleteAllCommunityMemberMessages(member string, communityID } for _, messageToDelete := range messagesToDelete { - updatedMessages, err := m.persistence.MessagesByResponseTo(messageToDelete.ID) + updatedMessages, err := m.persistence.MessagesByResponseTo(messageToDelete.Id) if err != nil { return nil, err } @@ -544,7 +548,7 @@ func (m *Messenger) DeleteAllCommunityMemberMessages(member string, communityID messageIDs := make([]string, 0, len(messagesToDelete)) for _, rm := range messagesToDelete { - messageIDs = append(messageIDs, rm.ID) + messageIDs = append(messageIDs, rm.Id) } if err = m.persistence.DeleteMessages(messageIDs); err != nil { diff --git a/protocol/messenger_delete_message_test.go b/protocol/messenger_remove_message_test.go similarity index 96% rename from protocol/messenger_delete_message_test.go rename to protocol/messenger_remove_message_test.go index a2cd6270a..6f2ca4246 100644 --- a/protocol/messenger_delete_message_test.go +++ b/protocol/messenger_remove_message_test.go @@ -11,15 +11,15 @@ import ( "github.com/status-im/status-go/server" ) -func TestMessengerDeleteMessageSuite(t *testing.T) { - suite.Run(t, new(MessengerDeleteMessageSuite)) +func TestMessengerRemoveMessageSuite(t *testing.T) { + suite.Run(t, new(MessengerRemoveMessageSuite)) } -type MessengerDeleteMessageSuite struct { +type MessengerRemoveMessageSuite struct { MessengerBaseTestSuite } -func (s *MessengerDeleteMessageSuite) TestDeleteMessage() { +func (s *MessengerRemoveMessageSuite) TestDeleteMessage() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -68,7 +68,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteMessage() { s.Require().ErrorContains(err, "can't find chat") } -func (s *MessengerDeleteMessageSuite) TestDeleteMessagePreviousLastMessage() { +func (s *MessengerRemoveMessageSuite) TestDeleteMessagePreviousLastMessage() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -117,7 +117,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteMessagePreviousLastMessage() { } -func (s *MessengerDeleteMessageSuite) TestDeleteWrongMessageType() { +func (s *MessengerRemoveMessageSuite) TestDeleteWrongMessageType() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -144,7 +144,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteWrongMessageType() { // TODO fix activity center notifications not being deleted when a message is deleted -func (s *MessengerDeleteMessageSuite) TestDeleteMessageFirstThenMessage() { +func (s *MessengerRemoveMessageSuite) TestDeleteMessageFirstThenMessage() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -197,7 +197,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteMessageFirstThenMessage() { s.Require().Nil(state.Response.Chats()[0].LastMessage) } -func (s *MessengerDeleteMessageSuite) TestDeleteImageMessage() { +func (s *MessengerRemoveMessageSuite) TestDeleteImageMessage() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -271,7 +271,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteImageMessage() { s.Require().ErrorContains(err, "can't find chat") } -func (s *MessengerDeleteMessageSuite) TestDeleteImageMessageFirstThenMessage() { +func (s *MessengerRemoveMessageSuite) TestDeleteImageMessageFirstThenMessage() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -349,7 +349,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteImageMessageFirstThenMessage() { s.Require().Nil(state.Response.Chats()[0].LastMessage) } -func (s *MessengerDeleteMessageSuite) TestDeleteMessageWithAMention() { +func (s *MessengerRemoveMessageSuite) TestDeleteMessageWithAMention() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -409,7 +409,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteMessageWithAMention() { // This test makes sure the UnviewMessageCount doesn't go below 0 in a very rare case where the Chat could be marked // as read but the message still unseen (Seen == false) -func (s *MessengerDeleteMessageSuite) TestDeleteMessageAndChatIsAlreadyRead() { +func (s *MessengerRemoveMessageSuite) TestDeleteMessageAndChatIsAlreadyRead() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -468,7 +468,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteMessageAndChatIsAlreadyRead() { s.Require().Equal(0, int(state.Response.Chats()[0].UnviewedMessagesCount)) } -func (s *MessengerDeleteMessageSuite) TestDeleteMessageReplyToImage() { +func (s *MessengerRemoveMessageSuite) TestDeleteMessageReplyToImage() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) @@ -521,7 +521,7 @@ func (s *MessengerDeleteMessageSuite) TestDeleteMessageReplyToImage() { s.Require().NotEmpty(sendResponse.Messages()[0].ImageLocalURL) } -func (s *MessengerDeleteMessageSuite) TestDeleteMessageForMeReplyToImage() { +func (s *MessengerRemoveMessageSuite) TestDeleteMessageForMeReplyToImage() { theirMessenger := s.newMessenger() defer TearDownMessenger(&s.Suite, theirMessenger) diff --git a/protocol/messenger_response.go b/protocol/messenger_response.go index 033307051..c63d19767 100644 --- a/protocol/messenger_response.go +++ b/protocol/messenger_response.go @@ -33,11 +33,6 @@ type RemovedMessage struct { DeletedBy string `json:"deletedBy,omitempty"` } -type DeletedMessage struct { - ID string `json:"id"` - ChatID string `json:"chatID"` -} - type ClearedHistory struct { ChatID string `json:"chatId"` ClearedAt uint64 `json:"clearedAt"` @@ -605,13 +600,13 @@ func (r *MessengerResponse) AddRemovedMessage(rm *RemovedMessage) { } } -func (r *MessengerResponse) AddDeletedMessages(messagesToAdd []*DeletedMessage) { +func (r *MessengerResponse) AddDeletedMessages(messagesToAdd []*protobuf.DeleteCommunityMemberMessage) { if r.deletedMessages == nil { r.deletedMessages = make(map[string]string) } for _, message := range messagesToAdd { - r.deletedMessages[message.ID] = message.ChatID + r.deletedMessages[message.Id] = message.ChatId } } diff --git a/protocol/persistence_test.go b/protocol/persistence_test.go index dfd6c61c4..82fe74a82 100644 --- a/protocol/persistence_test.go +++ b/protocol/persistence_test.go @@ -2029,25 +2029,25 @@ func TestBridgeMessageReplies(t *testing.T) { require.Equal(t, "333", responseTo) } -func TestGetCommunityMemberAllNonDeletedMessages(t *testing.T) { +func createAndSaveMessage(p *sqlitePersistence, id string, from string, deleted bool, communityID string) error { + return p.SaveMessages([]*common.Message{{ + ID: id, + From: from, + CommunityID: communityID, + ChatMessage: &protobuf.ChatMessage{ + Timestamp: uint64(time.Now().Unix()), + Text: "some-text", + ChatId: testPublicChatID, + }, + Deleted: deleted, + }}) +} + +func TestGetCommunityMemberMessagesID(t *testing.T) { db, err := openTestDB() require.NoError(t, err) p := newSQLitePersistence(db) testCommunity := "test-community" - clock := uint64(time.Now().Unix()) - saveMessage := func(id string, from string, deleted bool) { - err = p.SaveMessages([]*common.Message{{ - ID: id, - From: from, - CommunityID: testCommunity, - ChatMessage: &protobuf.ChatMessage{ - Timestamp: clock, - Text: "some-text", - ChatId: testPublicChatID, - }, - Deleted: deleted, - }}) - } chat := &Chat{ ID: testPublicChatID, @@ -2057,35 +2057,81 @@ func TestGetCommunityMemberAllNonDeletedMessages(t *testing.T) { err = p.SaveChats([]*Chat{chat}) require.NoError(t, err) - messages, err := p.GetCommunityMemberAllMessagesID(testPK, testCommunity) + messages, err := p.GetCommunityMemberMessagesToDelete(testPK, testCommunity) require.NoError(t, err) require.Len(t, messages, 0) - saveMessage("1", testPK, false) + require.NoError(t, createAndSaveMessage(p, "1", testPK, false, testCommunity)) - messages, err = p.GetCommunityMemberAllMessagesID(testPK, "wrong community") + messages, err = p.GetCommunityMemberMessagesToDelete(testPK, "wrong community") require.NoError(t, err) require.Len(t, messages, 0) - messages, err = p.GetCommunityMemberAllMessagesID("wrong user name", testCommunity) + messages, err = p.GetCommunityMemberMessagesToDelete("wrong user name", testCommunity) require.NoError(t, err) require.Len(t, messages, 0) - messages, err = p.GetCommunityMemberAllMessagesID(testPK, testCommunity) + messages, err = p.GetCommunityMemberMessagesToDelete(testPK, testCommunity) require.NoError(t, err) require.Len(t, messages, 1) - require.Exactly(t, "1", messages[0].ID) - require.Exactly(t, testPublicChatID, messages[0].ChatID) + require.Exactly(t, "1", messages[0].Id) + require.Exactly(t, testPublicChatID, messages[0].ChatId) - saveMessage("2", "another user", false) + require.NoError(t, createAndSaveMessage(p, "2", "another user", false, testCommunity)) - messages, err = p.GetCommunityMemberAllMessagesID(testPK, testCommunity) + messages, err = p.GetCommunityMemberMessagesToDelete(testPK, testCommunity) require.NoError(t, err) require.Len(t, messages, 1) - saveMessage("3", testPK, true) + require.NoError(t, createAndSaveMessage(p, "3", testPK, true, testCommunity)) - messages, err = p.GetCommunityMemberAllMessagesID(testPK, testCommunity) + messages, err = p.GetCommunityMemberMessagesToDelete(testPK, testCommunity) + require.NoError(t, err) + require.Len(t, messages, 2) +} + +func TestGetCommunityMemberMessages(t *testing.T) { + db, err := openTestDB() + require.NoError(t, err) + p := newSQLitePersistence(db) + testCommunity := "test-community" + + chat := &Chat{ + ID: testPublicChatID, + CommunityID: testCommunity, + } + + err = p.SaveChats([]*Chat{chat}) + require.NoError(t, err) + + messages, err := p.GetCommunityMemberAllMessages(testPK, testCommunity) + require.NoError(t, err) + require.Len(t, messages, 0) + + require.NoError(t, createAndSaveMessage(p, "1", testPK, false, testCommunity)) + + messages, err = p.GetCommunityMemberAllMessages(testPK, "wrong community") + require.NoError(t, err) + require.Len(t, messages, 0) + + messages, err = p.GetCommunityMemberAllMessages("wrong user name", testCommunity) + require.NoError(t, err) + require.Len(t, messages, 0) + + messages, err = p.GetCommunityMemberAllMessages(testPK, testCommunity) + require.NoError(t, err) + require.Len(t, messages, 1) + require.Exactly(t, "1", messages[0].ID) + + require.NoError(t, createAndSaveMessage(p, "2", "another user", false, testCommunity)) + + messages, err = p.GetCommunityMemberAllMessages(testPK, testCommunity) + require.NoError(t, err) + require.Len(t, messages, 1) + + require.NoError(t, createAndSaveMessage(p, "3", testPK, true, testCommunity)) + + messages, err = p.GetCommunityMemberAllMessages(testPK, testCommunity) require.NoError(t, err) require.Len(t, messages, 2) } diff --git a/protocol/protobuf/application_metadata_message.pb.go b/protocol/protobuf/application_metadata_message.pb.go index d36759ab0..3681d73cc 100644 --- a/protocol/protobuf/application_metadata_message.pb.go +++ b/protocol/protobuf/application_metadata_message.pb.go @@ -106,6 +106,7 @@ const ( ApplicationMetadataMessage_SYNC_PROFILE_SHOWCASE_PREFERENCES ApplicationMetadataMessage_Type = 82 ApplicationMetadataMessage_COMMUNITY_PUBLIC_STORENODES_INFO ApplicationMetadataMessage_Type = 83 ApplicationMetadataMessage_COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST ApplicationMetadataMessage_Type = 84 + ApplicationMetadataMessage_DELETE_COMMUNITY_MEMBER_MESSAGES ApplicationMetadataMessage_Type = 85 ) // Enum value maps for ApplicationMetadataMessage_Type. @@ -192,6 +193,7 @@ var ( 82: "SYNC_PROFILE_SHOWCASE_PREFERENCES", 83: "COMMUNITY_PUBLIC_STORENODES_INFO", 84: "COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST", + 85: "DELETE_COMMUNITY_MEMBER_MESSAGES", } ApplicationMetadataMessage_Type_value = map[string]int32{ "UNKNOWN": 0, @@ -275,6 +277,7 @@ var ( "SYNC_PROFILE_SHOWCASE_PREFERENCES": 82, "COMMUNITY_PUBLIC_STORENODES_INFO": 83, "COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST": 84, + "DELETE_COMMUNITY_MEMBER_MESSAGES": 85, } ) @@ -376,7 +379,7 @@ var File_application_metadata_message_proto protoreflect.FileDescriptor var file_application_metadata_message_proto_rawDesc = []byte{ 0x0a, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x9b, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0xc1, 0x15, 0x0a, 0x1a, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, @@ -386,7 +389,7 @@ var file_application_metadata_message_proto_rawDesc = []byte{ 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x85, 0x14, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, + 0x74, 0x79, 0x70, 0x65, 0x22, 0xab, 0x14, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x48, 0x41, 0x54, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, @@ -538,17 +541,19 @@ var file_application_metadata_message_proto_rawDesc = []byte{ 0x54, 0x4f, 0x52, 0x45, 0x4e, 0x4f, 0x44, 0x45, 0x53, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x53, 0x12, 0x2c, 0x0a, 0x28, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x52, 0x45, 0x45, 0x56, 0x41, 0x4c, 0x55, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, - 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x54, 0x22, 0x04, - 0x08, 0x0e, 0x10, 0x0e, 0x22, 0x04, 0x08, 0x41, 0x10, 0x41, 0x22, 0x04, 0x08, 0x42, 0x10, 0x42, - 0x2a, 0x1d, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x41, 0x54, - 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x43, 0x48, 0x41, 0x54, 0x2a, - 0x22, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, - 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, - 0x4f, 0x4e, 0x53, 0x2a, 0x27, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x49, - 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, - 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x42, 0x0d, 0x5a, 0x0b, - 0x2e, 0x2f, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x54, 0x12, 0x24, + 0x0a, 0x20, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, + 0x54, 0x59, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, + 0x45, 0x53, 0x10, 0x55, 0x22, 0x04, 0x08, 0x0e, 0x10, 0x0e, 0x22, 0x04, 0x08, 0x41, 0x10, 0x41, + 0x22, 0x04, 0x08, 0x42, 0x10, 0x42, 0x2a, 0x1d, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x49, 0x4e, 0x53, + 0x54, 0x41, 0x4c, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, + 0x5f, 0x43, 0x48, 0x41, 0x54, 0x2a, 0x22, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x2a, 0x27, 0x53, 0x59, 0x4e, 0x43, 0x5f, + 0x41, 0x43, 0x54, 0x49, 0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, + 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/protocol/protobuf/application_metadata_message.proto b/protocol/protobuf/application_metadata_message.proto index 4eeef1b98..71fa0dd83 100644 --- a/protocol/protobuf/application_metadata_message.proto +++ b/protocol/protobuf/application_metadata_message.proto @@ -102,5 +102,6 @@ message ApplicationMetadataMessage { SYNC_PROFILE_SHOWCASE_PREFERENCES = 82; COMMUNITY_PUBLIC_STORENODES_INFO = 83; COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST = 84; + DELETE_COMMUNITY_MEMBER_MESSAGES = 85; } } diff --git a/protocol/protobuf/communities.pb.go b/protocol/protobuf/communities.pb.go index 4944379da..c32c21c53 100644 --- a/protocol/protobuf/communities.pb.go +++ b/protocol/protobuf/communities.pb.go @@ -2378,6 +2378,132 @@ func (x *CommunityReevaluatePermissionsRequest) GetCommunityId() []byte { return nil } +type DeleteCommunityMemberMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ChatId string `protobuf:"bytes,2,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"` +} + +func (x *DeleteCommunityMemberMessage) Reset() { + *x = DeleteCommunityMemberMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_communities_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteCommunityMemberMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteCommunityMemberMessage) ProtoMessage() {} + +func (x *DeleteCommunityMemberMessage) ProtoReflect() protoreflect.Message { + mi := &file_communities_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteCommunityMemberMessage.ProtoReflect.Descriptor instead. +func (*DeleteCommunityMemberMessage) Descriptor() ([]byte, []int) { + return file_communities_proto_rawDescGZIP(), []int{28} +} + +func (x *DeleteCommunityMemberMessage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *DeleteCommunityMemberMessage) GetChatId() string { + if x != nil { + return x.ChatId + } + return "" +} + +type DeleteCommunityMemberMessages struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"` + CommunityId []byte `protobuf:"bytes,2,opt,name=community_id,json=communityId,proto3" json:"community_id,omitempty"` + MemberId string `protobuf:"bytes,3,opt,name=member_id,json=memberId,proto3" json:"member_id,omitempty"` + Messages []*DeleteCommunityMemberMessage `protobuf:"bytes,4,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (x *DeleteCommunityMemberMessages) Reset() { + *x = DeleteCommunityMemberMessages{} + if protoimpl.UnsafeEnabled { + mi := &file_communities_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteCommunityMemberMessages) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteCommunityMemberMessages) ProtoMessage() {} + +func (x *DeleteCommunityMemberMessages) ProtoReflect() protoreflect.Message { + mi := &file_communities_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteCommunityMemberMessages.ProtoReflect.Descriptor instead. +func (*DeleteCommunityMemberMessages) Descriptor() ([]byte, []int) { + return file_communities_proto_rawDescGZIP(), []int{29} +} + +func (x *DeleteCommunityMemberMessages) GetClock() uint64 { + if x != nil { + return x.Clock + } + return 0 +} + +func (x *DeleteCommunityMemberMessages) GetCommunityId() []byte { + if x != nil { + return x.CommunityId + } + return nil +} + +func (x *DeleteCommunityMemberMessages) GetMemberId() string { + if x != nil { + return x.MemberId + } + return "" +} + +func (x *DeleteCommunityMemberMessages) GetMessages() []*DeleteCommunityMemberMessage { + if x != nil { + return x.Messages + } + return nil +} + var File_communities_proto protoreflect.FileDescriptor var file_communities_proto_rawDesc = []byte{ @@ -2834,9 +2960,25 @@ var file_communities_proto_rawDesc = []byte{ 0x52, 0x65, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x49, 0x64, 0x42, - 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x49, 0x64, 0x22, + 0x47, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, + 0x74, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x17, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x63, 0x68, 0x61, 0x74, 0x49, 0x64, 0x22, 0xb9, 0x01, 0x0a, 0x1d, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, + 0x79, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x42, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2852,7 +2994,7 @@ func file_communities_proto_rawDescGZIP() []byte { } var file_communities_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_communities_proto_msgTypes = make([]protoimpl.MessageInfo, 38) +var file_communities_proto_msgTypes = make([]protoimpl.MessageInfo, 40) var file_communities_proto_goTypes = []interface{}{ (CommunityMember_Roles)(0), // 0: protobuf.CommunityMember.Roles (CommunityMember_ChannelRole)(0), // 1: protobuf.CommunityMember.ChannelRole @@ -2886,65 +3028,68 @@ var file_communities_proto_goTypes = []interface{}{ (*CommunityStorenodes)(nil), // 29: protobuf.CommunityStorenodes (*Storenode)(nil), // 30: protobuf.Storenode (*CommunityReevaluatePermissionsRequest)(nil), // 31: protobuf.CommunityReevaluatePermissionsRequest - nil, // 32: protobuf.CommunityTokenMetadata.ContractAddressesEntry - nil, // 33: protobuf.TokenCriteria.ContractAddressesEntry - nil, // 34: protobuf.CommunityDescription.MembersEntry - nil, // 35: protobuf.CommunityDescription.ChatsEntry - nil, // 36: protobuf.CommunityDescription.CategoriesEntry - nil, // 37: protobuf.CommunityDescription.TokenPermissionsEntry - nil, // 38: protobuf.CommunityDescription.BannedMembersEntry - nil, // 39: protobuf.CommunityDescription.PrivateDataEntry - nil, // 40: protobuf.CommunityChat.MembersEntry - nil, // 41: protobuf.WakuMessageArchiveIndex.ArchivesEntry - (CommunityTokenType)(0), // 42: protobuf.CommunityTokenType - (*ChatIdentity)(nil), // 43: protobuf.ChatIdentity - (*Shard)(nil), // 44: protobuf.Shard + (*DeleteCommunityMemberMessage)(nil), // 32: protobuf.DeleteCommunityMemberMessage + (*DeleteCommunityMemberMessages)(nil), // 33: protobuf.DeleteCommunityMemberMessages + nil, // 34: protobuf.CommunityTokenMetadata.ContractAddressesEntry + nil, // 35: protobuf.TokenCriteria.ContractAddressesEntry + nil, // 36: protobuf.CommunityDescription.MembersEntry + nil, // 37: protobuf.CommunityDescription.ChatsEntry + nil, // 38: protobuf.CommunityDescription.CategoriesEntry + nil, // 39: protobuf.CommunityDescription.TokenPermissionsEntry + nil, // 40: protobuf.CommunityDescription.BannedMembersEntry + nil, // 41: protobuf.CommunityDescription.PrivateDataEntry + nil, // 42: protobuf.CommunityChat.MembersEntry + nil, // 43: protobuf.WakuMessageArchiveIndex.ArchivesEntry + (CommunityTokenType)(0), // 44: protobuf.CommunityTokenType + (*ChatIdentity)(nil), // 45: protobuf.ChatIdentity + (*Shard)(nil), // 46: protobuf.Shard } var file_communities_proto_depIdxs = []int32{ 0, // 0: protobuf.CommunityMember.roles:type_name -> protobuf.CommunityMember.Roles 15, // 1: protobuf.CommunityMember.revealed_accounts:type_name -> protobuf.RevealedAccount 1, // 2: protobuf.CommunityMember.channel_role:type_name -> protobuf.CommunityMember.ChannelRole - 32, // 3: protobuf.CommunityTokenMetadata.contract_addresses:type_name -> protobuf.CommunityTokenMetadata.ContractAddressesEntry - 42, // 4: protobuf.CommunityTokenMetadata.tokenType:type_name -> protobuf.CommunityTokenType + 34, // 3: protobuf.CommunityTokenMetadata.contract_addresses:type_name -> protobuf.CommunityTokenMetadata.ContractAddressesEntry + 44, // 4: protobuf.CommunityTokenMetadata.tokenType:type_name -> protobuf.CommunityTokenType 2, // 5: protobuf.CommunityPermissions.access:type_name -> protobuf.CommunityPermissions.Access - 33, // 6: protobuf.TokenCriteria.contract_addresses:type_name -> protobuf.TokenCriteria.ContractAddressesEntry - 42, // 7: protobuf.TokenCriteria.type:type_name -> protobuf.CommunityTokenType + 35, // 6: protobuf.TokenCriteria.contract_addresses:type_name -> protobuf.TokenCriteria.ContractAddressesEntry + 44, // 7: protobuf.TokenCriteria.type:type_name -> protobuf.CommunityTokenType 3, // 8: protobuf.CommunityTokenPermission.type:type_name -> protobuf.CommunityTokenPermission.Type 8, // 9: protobuf.CommunityTokenPermission.token_criteria:type_name -> protobuf.TokenCriteria - 34, // 10: protobuf.CommunityDescription.members:type_name -> protobuf.CommunityDescription.MembersEntry + 36, // 10: protobuf.CommunityDescription.members:type_name -> protobuf.CommunityDescription.MembersEntry 7, // 11: protobuf.CommunityDescription.permissions:type_name -> protobuf.CommunityPermissions - 43, // 12: protobuf.CommunityDescription.identity:type_name -> protobuf.ChatIdentity - 35, // 13: protobuf.CommunityDescription.chats:type_name -> protobuf.CommunityDescription.ChatsEntry - 36, // 14: protobuf.CommunityDescription.categories:type_name -> protobuf.CommunityDescription.CategoriesEntry + 45, // 12: protobuf.CommunityDescription.identity:type_name -> protobuf.ChatIdentity + 37, // 13: protobuf.CommunityDescription.chats:type_name -> protobuf.CommunityDescription.ChatsEntry + 38, // 14: protobuf.CommunityDescription.categories:type_name -> protobuf.CommunityDescription.CategoriesEntry 12, // 15: protobuf.CommunityDescription.admin_settings:type_name -> protobuf.CommunityAdminSettings - 37, // 16: protobuf.CommunityDescription.token_permissions:type_name -> protobuf.CommunityDescription.TokenPermissionsEntry + 39, // 16: protobuf.CommunityDescription.token_permissions:type_name -> protobuf.CommunityDescription.TokenPermissionsEntry 6, // 17: protobuf.CommunityDescription.community_tokens_metadata:type_name -> protobuf.CommunityTokenMetadata - 38, // 18: protobuf.CommunityDescription.banned_members:type_name -> protobuf.CommunityDescription.BannedMembersEntry - 39, // 19: protobuf.CommunityDescription.privateData:type_name -> protobuf.CommunityDescription.PrivateDataEntry - 40, // 20: protobuf.CommunityChat.members:type_name -> protobuf.CommunityChat.MembersEntry + 40, // 18: protobuf.CommunityDescription.banned_members:type_name -> protobuf.CommunityDescription.BannedMembersEntry + 41, // 19: protobuf.CommunityDescription.privateData:type_name -> protobuf.CommunityDescription.PrivateDataEntry + 42, // 20: protobuf.CommunityChat.members:type_name -> protobuf.CommunityChat.MembersEntry 7, // 21: protobuf.CommunityChat.permissions:type_name -> protobuf.CommunityPermissions - 43, // 22: protobuf.CommunityChat.identity:type_name -> protobuf.ChatIdentity + 45, // 22: protobuf.CommunityChat.identity:type_name -> protobuf.ChatIdentity 15, // 23: protobuf.CommunityRequestToJoin.revealed_accounts:type_name -> protobuf.RevealedAccount 15, // 24: protobuf.CommunityEditSharedAddresses.revealed_accounts:type_name -> protobuf.RevealedAccount 10, // 25: protobuf.CommunityRequestToJoinResponse.community:type_name -> protobuf.CommunityDescription - 44, // 26: protobuf.CommunityRequestToJoinResponse.shard:type_name -> protobuf.Shard + 46, // 26: protobuf.CommunityRequestToJoinResponse.shard:type_name -> protobuf.Shard 24, // 27: protobuf.WakuMessageArchive.metadata:type_name -> protobuf.WakuMessageArchiveMetadata 23, // 28: protobuf.WakuMessageArchive.messages:type_name -> protobuf.WakuMessage 24, // 29: protobuf.WakuMessageArchiveIndexMetadata.metadata:type_name -> protobuf.WakuMessageArchiveMetadata - 41, // 30: protobuf.WakuMessageArchiveIndex.archives:type_name -> protobuf.WakuMessageArchiveIndex.ArchivesEntry + 43, // 30: protobuf.WakuMessageArchiveIndex.archives:type_name -> protobuf.WakuMessageArchiveIndex.ArchivesEntry 30, // 31: protobuf.CommunityStorenodes.storenodes:type_name -> protobuf.Storenode - 5, // 32: protobuf.CommunityDescription.MembersEntry.value:type_name -> protobuf.CommunityMember - 13, // 33: protobuf.CommunityDescription.ChatsEntry.value:type_name -> protobuf.CommunityChat - 14, // 34: protobuf.CommunityDescription.CategoriesEntry.value:type_name -> protobuf.CommunityCategory - 9, // 35: protobuf.CommunityDescription.TokenPermissionsEntry.value:type_name -> protobuf.CommunityTokenPermission - 11, // 36: protobuf.CommunityDescription.BannedMembersEntry.value:type_name -> protobuf.CommunityBanInfo - 5, // 37: protobuf.CommunityChat.MembersEntry.value:type_name -> protobuf.CommunityMember - 26, // 38: protobuf.WakuMessageArchiveIndex.ArchivesEntry.value:type_name -> protobuf.WakuMessageArchiveIndexMetadata - 39, // [39:39] is the sub-list for method output_type - 39, // [39:39] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 32, // 32: protobuf.DeleteCommunityMemberMessages.messages:type_name -> protobuf.DeleteCommunityMemberMessage + 5, // 33: protobuf.CommunityDescription.MembersEntry.value:type_name -> protobuf.CommunityMember + 13, // 34: protobuf.CommunityDescription.ChatsEntry.value:type_name -> protobuf.CommunityChat + 14, // 35: protobuf.CommunityDescription.CategoriesEntry.value:type_name -> protobuf.CommunityCategory + 9, // 36: protobuf.CommunityDescription.TokenPermissionsEntry.value:type_name -> protobuf.CommunityTokenPermission + 11, // 37: protobuf.CommunityDescription.BannedMembersEntry.value:type_name -> protobuf.CommunityBanInfo + 5, // 38: protobuf.CommunityChat.MembersEntry.value:type_name -> protobuf.CommunityMember + 26, // 39: protobuf.WakuMessageArchiveIndex.ArchivesEntry.value:type_name -> protobuf.WakuMessageArchiveIndexMetadata + 40, // [40:40] is the sub-list for method output_type + 40, // [40:40] is the sub-list for method input_type + 40, // [40:40] is the sub-list for extension type_name + 40, // [40:40] is the sub-list for extension extendee + 0, // [0:40] is the sub-list for field type_name } func init() { file_communities_proto_init() } @@ -3292,6 +3437,30 @@ func file_communities_proto_init() { return nil } } + file_communities_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteCommunityMemberMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_communities_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteCommunityMemberMessages); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -3299,7 +3468,7 @@ func file_communities_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_communities_proto_rawDesc, NumEnums: 4, - NumMessages: 38, + NumMessages: 40, NumExtensions: 0, NumServices: 0, }, diff --git a/protocol/protobuf/communities.proto b/protocol/protobuf/communities.proto index fb7dd550c..48d5565cb 100644 --- a/protocol/protobuf/communities.proto +++ b/protocol/protobuf/communities.proto @@ -257,3 +257,15 @@ message Storenode { message CommunityReevaluatePermissionsRequest { bytes community_id = 1; } + +message DeleteCommunityMemberMessage { + string id = 1; + string chat_id = 2; +} + +message DeleteCommunityMemberMessages { + uint64 clock = 1; + bytes community_id = 2; + string member_id = 3; + repeated DeleteCommunityMemberMessage messages = 4; +} \ No newline at end of file diff --git a/protocol/requests/community_member_messages.go b/protocol/requests/community_member_messages.go new file mode 100644 index 000000000..2ff8941e0 --- /dev/null +++ b/protocol/requests/community_member_messages.go @@ -0,0 +1,25 @@ +package requests + +import ( + "errors" +) + +var ErrCommunityMemberMessagesCommunityID = errors.New("community member messages: invalid id") +var ErrCommunityMemberMessagesMemberPK = errors.New("community member messages: invalid member PK") + +type CommunityMemberMessages struct { + CommunityID string `json:"communityId"` + MemberPublicKey string `json:"memberPublicKey"` +} + +func (c *CommunityMemberMessages) Validate() error { + if len(c.CommunityID) == 0 { + return ErrCommunityMemberMessagesCommunityID + } + + if len(c.MemberPublicKey) == 0 { + return ErrCommunityMemberMessagesMemberPK + } + + return nil +} diff --git a/protocol/requests/delete_community_member_messages.go b/protocol/requests/delete_community_member_messages.go new file mode 100644 index 000000000..813bbcd8b --- /dev/null +++ b/protocol/requests/delete_community_member_messages.go @@ -0,0 +1,54 @@ +package requests + +import ( + "errors" + + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/protocol/protobuf" +) + +var ErrDeleteCommunityMemberMessagesInvalidCommunityID = errors.New("delete-community-member-messages: invalid community id") +var ErrDeleteCommunityMemberMessagesInvalidMemberID = errors.New("delete-community-member-messages: invalid member id") +var ErrDeleteCommunityMemberMessagesInvalidData = errors.New("delete-community-member-messages: invalid data") +var ErrDeleteCommunityMemberMessagesInvalidDeleteAll = errors.New("delete-community-member-messages: invalid delete all setup") +var ErrDeleteCommunityMemberMessagesInvalidDeleteMessagesByID = errors.New("delete-community-member-messages: invalid delete messages by ID setups") +var ErrDeleteCommunityMemberMessagesInvalidMsgID = errors.New("delete-community-member-messages: invalid messages Id") +var ErrDeleteCommunityMemberMessagesInvalidMsgChatID = errors.New("delete-community-member-messages: invalid messages chatId") + +type DeleteCommunityMemberMessages struct { + CommunityID types.HexBytes `json:"communityId"` + MemberPubKey string `json:"memberPubKey"` + Messages []*protobuf.DeleteCommunityMemberMessage `json:"messages"` + DeleteAll bool `json:"deleteAll"` +} + +func (d *DeleteCommunityMemberMessages) Validate() error { + if len(d.CommunityID) == 0 { + return ErrDeleteCommunityMemberMessagesInvalidCommunityID + } + + if len(d.MemberPubKey) == 0 { + return ErrDeleteCommunityMemberMessagesInvalidMemberID + } + + if d.Messages != nil && len(d.Messages) > 0 && d.DeleteAll { + return ErrDeleteCommunityMemberMessagesInvalidDeleteAll + } + + if (d.Messages == nil || (d.Messages != nil && len(d.Messages) == 0)) && !d.DeleteAll { + return ErrDeleteCommunityMemberMessagesInvalidDeleteMessagesByID + } + + if d.Messages != nil { + for _, message := range d.Messages { + if len(message.Id) == 0 { + return ErrDeleteCommunityMemberMessagesInvalidMsgID + } + if len(message.ChatId) == 0 { + return ErrDeleteCommunityMemberMessagesInvalidMsgChatID + } + } + } + + return nil +} diff --git a/services/ext/api.go b/services/ext/api.go index 13fa5f854..36d2057f4 100644 --- a/services/ext/api.go +++ b/services/ext/api.go @@ -1775,6 +1775,15 @@ func (api *PublicAPI) SetCustomizationColor(ctx context.Context, request *reques return api.service.messenger.SetCustomizationColor(ctx, request) } +func (api *PublicAPI) GetCommunityMemberAllMessages(request *requests.CommunityMemberMessages) ([]*common.Message, error) { + return api.service.messenger.GetCommunityMemberAllMessages(request) +} + +// Delete a specific community member messages or all community member messages (based on provided parameters) +func (api *PublicAPI) DeleteCommunityMemberMessages(request *requests.DeleteCommunityMemberMessages) (*protocol.MessengerResponse, error) { + return api.service.messenger.DeleteCommunityMemberMessages(request) +} + // ----- // HELPER // -----