From 133ad0946b8d8e89aa132227a9074ce47420f7e9 Mon Sep 17 00:00:00 2001 From: Godfrain Jacques Date: Tue, 21 May 2024 14:01:14 -0700 Subject: [PATCH] fix_: persist left communities even for restored account (#5174) This PR fixes #7858 by making sure left persisted communities are restored during the backup restore flow --- protocol/communities/manager.go | 4 +++ protocol/communities/persistence.go | 11 ++++++ protocol/messenger_backup.go | 31 ++++++++++++++-- protocol/messenger_backup_test.go | 55 +++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 3 deletions(-) diff --git a/protocol/communities/manager.go b/protocol/communities/manager.go index feb5343fa..0df03ac39 100644 --- a/protocol/communities/manager.go +++ b/protocol/communities/manager.go @@ -887,6 +887,10 @@ func (m *Manager) JoinedAndPendingCommunitiesWithRequests() ([]*Community, error return m.persistence.JoinedAndPendingCommunitiesWithRequests(&m.identity.PublicKey) } +func (m *Manager) LeftCommunities() ([]*Community, error) { + return m.persistence.LeftCommunities(&m.identity.PublicKey) +} + func (m *Manager) DeletedCommunities() ([]*Community, error) { return m.persistence.DeletedCommunities(&m.identity.PublicKey) } diff --git a/protocol/communities/persistence.go b/protocol/communities/persistence.go index fb3f841af..81d5c493b 100644 --- a/protocol/communities/persistence.go +++ b/protocol/communities/persistence.go @@ -327,6 +327,17 @@ func (p *Persistence) rowsToCommunities(rows *sql.Rows) (comms []*Community, err return comms, nil } +func (p *Persistence) LeftCommunities(memberIdentity *ecdsa.PublicKey) (comms []*Community, err error) { + query := communitiesBaseQuery + ` WHERE NOT c.Joined AND NOT c.spectated AND r.state != ?` + + rows, err := p.db.Query(query, common.PubkeyToHex(memberIdentity), RequestToJoinStatePending) + if err != nil { + return nil, err + } + + return p.rowsToCommunities(rows) +} + func (p *Persistence) JoinedAndPendingCommunitiesWithRequests(memberIdentity *ecdsa.PublicKey) (comms []*Community, err error) { query := communitiesBaseQuery + ` WHERE c.Joined OR r.state = ?` diff --git a/protocol/messenger_backup.go b/protocol/messenger_backup.go index ec5558e14..912a85e5f 100644 --- a/protocol/messenger_backup.go +++ b/protocol/messenger_backup.go @@ -26,6 +26,12 @@ var backupTickerInterval = 120 * time.Second // backups var backupIntervalSeconds uint64 = 28800 +type CommunitySet struct { + Joined []*communities.Community + Left []*communities.Community + Deleted []*communities.Community +} + func (m *Messenger) backupEnabled() (bool, error) { return m.settings.BackupEnabled() } @@ -286,20 +292,39 @@ func (m *Messenger) backupContacts(ctx context.Context) []*protobuf.Backup { return backupMessages } -func (m *Messenger) backupCommunities(ctx context.Context, clock uint64) ([]*protobuf.Backup, error) { +func (m *Messenger) retrieveAllCommunities() (*CommunitySet, error) { joinedCs, err := m.communitiesManager.JoinedAndPendingCommunitiesWithRequests() if err != nil { return nil, err } + leftCs, err := m.communitiesManager.LeftCommunities() + if err != nil { + return nil, err + } + deletedCs, err := m.communitiesManager.DeletedCommunities() if err != nil { return nil, err } + return &CommunitySet{ + Joined: joinedCs, + Left: leftCs, + Deleted: deletedCs, + }, nil +} + +func (m *Messenger) backupCommunities(ctx context.Context, clock uint64) ([]*protobuf.Backup, error) { + communitySet, err := m.retrieveAllCommunities() + if err != nil { + return nil, err + } + var backupMessages []*protobuf.Backup - cs := append(joinedCs, deletedCs...) - for _, c := range cs { + combinedCs := append(append(communitySet.Joined, communitySet.Left...), communitySet.Deleted...) + + for _, c := range combinedCs { _, beingImported := m.importingCommunities[c.IDString()] if !beingImported { backupMessage, err := m.backupCommunity(c, clock) diff --git a/protocol/messenger_backup_test.go b/protocol/messenger_backup_test.go index 3874b0050..f968ecbd5 100644 --- a/protocol/messenger_backup_test.go +++ b/protocol/messenger_backup_test.go @@ -917,3 +917,58 @@ func (s *MessengerBackupSuite) TestBackupChats() { s.Require().True(ok) s.Require().Equal("", chat.Name) } + +func (s *MessengerBackupSuite) TestLeftCommunitiesAreBackedUp() { + bob1 := s.m + // Create bob2 + bob2, err := newMessengerWithKey(s.shh, bob1.identity, s.logger, nil) + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob2) + + description := &requests.CreateCommunity{ + Membership: protobuf.CommunityPermissions_MANUAL_ACCEPT, + Name: "other-status", + Color: "#fffff4", + Description: "other status community description", + } + + // Create another community chat + response, err := bob1.CreateCommunity(description, true) + s.Require().NoError(err) + s.Require().NotNil(response) + s.Require().Len(response.Communities(), 1) + + newCommunity := response.Communities()[0] + + response, err = bob1.LeaveCommunity(newCommunity.ID()) + s.Require().NoError(err) + s.Require().NotNil(response) + + // trigger artificial Backup + _, err = bob1.BackupData(context.Background()) + s.Require().NoError(err) + + communities, err := bob1.Communities() + s.Require().NoError(err) + s.Require().Len(communities, 1) + + // Safety check + communities, err = bob2.Communities() + s.Require().NoError(err) + s.Require().Len(communities, 0) + + // Wait for the message to reach its destination + _, err = WaitOnMessengerResponse( + bob2, + func(r *MessengerResponse) bool { + return r.BackupHandled + }, + "no messages", + ) + + s.Require().NoError(err) + + communities, err = bob2.JoinedCommunities() + s.Require().NoError(err) + s.Require().Len(communities, 0) +}