feat_: delete or update permission when deleting a channel (#5297)

* feat_: delete or update channel permissions when deleting a channel

* chore_: review fixes

* chore_: review fixes (second iteration, squash it!)
This commit is contained in:
Mikhail Rogachev 2024-06-07 18:30:01 +02:00 committed by GitHub
parent 24da58d7fa
commit b0213e6a41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 168 additions and 1 deletions

View File

@ -74,6 +74,54 @@ func EmptyCommunityChanges() *CommunityChanges {
}
}
func (c *CommunityChanges) Merge(other *CommunityChanges) {
for memberID, member := range other.MembersAdded {
c.MembersAdded[memberID] = member
}
for memberID := range other.MembersRemoved {
c.MembersRemoved[memberID] = other.MembersRemoved[memberID]
}
for memberID, banned := range other.MembersBanned {
c.MembersBanned[memberID] = banned
}
for memberID, unbanned := range other.MembersUnbanned {
c.MembersUnbanned[memberID] = unbanned
}
for permissionID, permission := range other.TokenPermissionsAdded {
c.TokenPermissionsAdded[permissionID] = permission
}
for permissionID, permission := range other.TokenPermissionsModified {
c.TokenPermissionsModified[permissionID] = permission
}
for permissionID, permission := range other.TokenPermissionsRemoved {
c.TokenPermissionsRemoved[permissionID] = permission
}
for chatID, chat := range other.ChatsRemoved {
c.ChatsRemoved[chatID] = chat
}
for chatID, chat := range other.ChatsAdded {
c.ChatsAdded[chatID] = chat
}
for chatID, changes := range other.ChatsModified {
c.ChatsModified[chatID] = changes
}
c.CategoriesRemoved = append(c.CategoriesRemoved, other.CategoriesRemoved...)
for categoryID, category := range other.CategoriesAdded {
c.CategoriesAdded[categoryID] = category
}
for categoryID, category := range other.CategoriesModified {
c.CategoriesModified[categoryID] = category
}
c.MemberWalletsRemoved = append(c.MemberWalletsRemoved, other.MemberWalletsRemoved...)
for walletID, wallets := range other.MemberWalletsAdded {
c.MemberWalletsAdded[walletID] = wallets
}
}
func (c *CommunityChanges) HasNewMember(identity string) bool {
if len(c.MembersAdded) == 0 {
return false

View File

@ -2,6 +2,7 @@ package communities
import (
"reflect"
"slices"
"github.com/status-im/status-go/protocol/protobuf"
)
@ -46,6 +47,18 @@ func (p *CommunityTokenPermission) Equals(other *CommunityTokenPermission) bool
return reflect.DeepEqual(p.ChatIds, other.ChatIds)
}
func (p *CommunityTokenPermission) HasChat(chatId string) bool {
return slices.Contains(p.ChatIds, chatId)
}
func (p *CommunityTokenPermission) ChatIdsAsMap() map[string]struct{} {
chats := map[string]struct{}{}
for _, id := range p.GetChatIds() {
chats[id] = struct{}{}
}
return chats
}
func compareTokenCriteria(a, b *protobuf.TokenCriteria) bool {
if a == nil && b == nil {
return true

View File

@ -1768,14 +1768,50 @@ func (m *Manager) DeleteChat(communityID types.HexBytes, chatID string) (*Commun
return nil, nil, err
}
// Check for channel permissions
changes := community.emptyCommunityChanges()
for tokenPermissionID, tokenPermission := range community.tokenPermissions() {
chats := tokenPermission.ChatIdsAsMap()
_, hasChat := chats[chatID]
if !hasChat {
continue
}
if len(chats) == 1 {
// Delete channel permission, if there is only one channel
deletePermissionChanges, err := community.DeleteTokenPermission(tokenPermissionID)
if err != nil {
return nil, nil, err
}
changes.Merge(deletePermissionChanges)
} else {
// Remove the channel from the permission, if there are other channels
delete(chats, chatID)
var chatIDs []string
for chatID := range chats {
chatIDs = append(chatIDs, chatID)
}
tokenPermission.ChatIds = chatIDs
updatePermissionChanges, err := community.UpsertTokenPermission(tokenPermission.CommunityTokenPermission)
if err != nil {
return nil, nil, err
}
changes.Merge(updatePermissionChanges)
}
}
// Remove communityID prefix from chatID if exists
if strings.HasPrefix(chatID, communityID.String()) {
chatID = strings.TrimPrefix(chatID, communityID.String())
}
changes, err := community.DeleteChat(chatID)
deleteChanges, err := community.DeleteChat(chatID)
if err != nil {
return nil, nil, err
}
changes.Merge(deleteChanges)
err = m.saveAndPublish(community)
if err != nil {

View File

@ -2368,3 +2368,73 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TestImportDecryptedArchiveMe
s.Require().True(ok)
s.Require().Equal(messageText1, receivedMessage1.Text)
}
func (s *MessengerCommunitiesTokenPermissionsSuite) TestDeleteChannelWithTokenPermission() {
// Setup community with two permitted channels
community, firstChat := s.createCommunity()
response, err := s.owner.CreateCommunityChat(community.ID(), &protobuf.CommunityChat{
Permissions: &protobuf.CommunityPermissions{
Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
},
Identity: &protobuf.ChatIdentity{
DisplayName: "new channel",
Emoji: "",
Description: "chat created after joining the community",
},
})
s.Require().NoError(err)
s.Require().Len(response.Chats(), 1)
secondChat := response.Chats()[0]
channelPermission := &requests.CreateCommunityTokenPermission{
CommunityID: community.ID(),
Type: protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL,
ChatIds: []string{firstChat.ID, secondChat.ID},
TokenCriteria: []*protobuf.TokenCriteria{
{
Type: protobuf.CommunityTokenType_ERC20,
ContractAddresses: map[uint64]string{testChainID1: "0x124"},
Symbol: "TEST2",
AmountInWei: "200000000000000000000",
Decimals: uint64(18),
},
},
}
response, err = s.owner.CreateCommunityTokenPermission(channelPermission)
s.Require().NoError(err)
s.Require().NotNil(response)
s.Require().Len(response.Communities(), 1)
// Make sure both channels are covered with permission
community, err = s.owner.GetCommunityByID(community.ID())
s.Require().NoError(err)
s.Require().Len(community.Chats(), 2)
s.Require().Len(community.TokenPermissions(), 1)
for _, permission := range community.TokenPermissions() {
s.Require().Len(permission.ChatIds, 2)
s.Require().True(permission.HasChat(firstChat.ID))
s.Require().True(permission.HasChat(secondChat.ID))
}
// Delete first community channel
response, err = s.owner.DeleteCommunityChat(community.ID(), firstChat.ID)
s.Require().NoError(err)
s.Require().Len(response.Communities(), 1)
community = response.Communities()[0]
s.Require().Len(community.Chats(), 1)
for _, permission := range community.TokenPermissions() {
s.Require().Len(permission.ChatIds, 1)
s.Require().False(permission.HasChat(firstChat.ID))
s.Require().True(permission.HasChat(secondChat.ID))
}
// Delete second community channel
response, err = s.owner.DeleteCommunityChat(community.ID(), secondChat.ID)
s.Require().NoError(err)
s.Require().Len(response.Communities(), 1)
community = response.Communities()[0]
s.Require().Len(community.Chats(), 0)
s.Require().Len(community.TokenPermissions(), 0)
}