From cd4d92aef079f665d2ce788f1640cc3f6da5c941 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Thu, 5 Oct 2023 00:41:51 +0300 Subject: [PATCH] Feat/issue 11795 introduce KickedPending and BannedPending states (#12068) * feat(Communities): Introduce pending states for kick, ban and unban actions Close #11795 * feat(Communities): Show bannedMembers pending states on the UI * feat(Communities:) make kick, ban and unban methods async * feat(Communities): add signal about community membership status change * fix(Communities): move membership managment to to the appropriate model * chore: review fixes --- .../chat_content/users/controller.nim | 5 -- .../modules/main/chat_section/controller.nim | 6 +- src/app/modules/main/communities/module.nim | 17 +++- src/app/modules/main/controller.nim | 4 + src/app/modules/main/io_interface.nim | 5 +- src/app/modules/main/module.nim | 5 ++ src/app/modules/shared_models/member_item.nim | 2 +- .../modules/shared_models/member_model.nim | 11 +++ .../modules/shared_models/section_item.nim | 6 ++ src/app_service/common/types.nim | 5 +- .../service/community/async_tasks.nim | 48 ++++++++++ .../service/community/dto/community.nim | 39 +++++++-- src/app_service/service/community/service.nim | 87 +++++++++++++++---- storybook/pages/MembersTabPanelPage.qml | 2 +- .../Communities/panels/MembersTabPanel.qml | 8 +- ui/imports/utils/Constants.qml | 1 + vendor/status-go | 2 +- 17 files changed, 211 insertions(+), 42 deletions(-) diff --git a/src/app/modules/main/chat_section/chat_content/users/controller.nim b/src/app/modules/main/chat_section/chat_content/users/controller.nim index 84a8195514..ecebc93bc9 100644 --- a/src/app/modules/main/chat_section/chat_content/users/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/users/controller.nim @@ -59,11 +59,6 @@ proc handleCommunityOnlyConnections(self: Controller) = self.delegate.onMembersChanged(args.members) - self.events.on(SIGNAL_COMMUNITY_MEMBER_REMOVED) do(e: Args): - let args = CommunityMemberArgs(e) - if (args.communityId == self.sectionId): - self.delegate.onChatMemberRemoved(args.pubKey) - proc init*(self: Controller) = # Events that are needed for all chats because of mentions self.events.on(SIGNAL_CONTACT_NICKNAME_CHANGED) do(e: Args): diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim index d4f2227ddc..fa6215b728 100644 --- a/src/app/modules/main/chat_section/controller.nim +++ b/src/app/modules/main/chat_section/controller.nim @@ -576,13 +576,13 @@ proc leaveCommunity*(self: Controller) = self.communityService.leaveCommunity(self.sectionId) proc removeUserFromCommunity*(self: Controller, pubKey: string) = - self.communityService.removeUserFromCommunity(self.sectionId, pubKey) + self.communityService.asyncRemoveUserFromCommunity(self.sectionId, pubKey) proc banUserFromCommunity*(self: Controller, pubKey: string) = - self.communityService.banUserFromCommunity(self.sectionId, pubKey) + self.communityService.asyncBanUserFromCommunity(self.sectionId, pubKey) proc unbanUserFromCommunity*(self: Controller, pubKey: string) = - self.communityService.unbanUserFromCommunity(self.sectionId, pubKey) + self.communityService.asyncUnbanUserFromCommunity(self.sectionId, pubKey) proc editCommunity*( self: Controller, diff --git a/src/app/modules/main/communities/module.nim b/src/app/modules/main/communities/module.nim index 83f8e7c4e1..1335b47293 100644 --- a/src/app/modules/main/communities/module.nim +++ b/src/app/modules/main/communities/module.nim @@ -145,6 +145,17 @@ proc createMemberItem(self: Module, memberId, requestId: string, status: Members ) method getCommunityItem(self: Module, c: CommunityDto): SectionItem = + # TODO: unite bannedMembers, pendingMemberRequests and declinedMemberRequests + var members: seq[MemberItem] = @[] + for member in c.members: + if c.pendingAndBannedMembers.hasKey(member.id): + let communityMemberState = c.pendingAndBannedMembers[member.id] + members.add(self.createMemberItem(member.id, "", toMembershipRequestState(communityMemberState))) + + var bannedMembers: seq[MemberItem] = @[] + for memberId, communityMemberState in c.pendingAndBannedMembers: + bannedMembers.add(self.createMemberItem(memberId, "", toMembershipRequestState(communityMemberState))) + return initItem( c.id, SectionType.Community, @@ -172,11 +183,9 @@ method getCommunityItem(self: Module, c: CommunityDto): SectionItem = c.permissions.access, c.permissions.ensOnly, c.muted, - c.members.map(proc(member: ChatMember): MemberItem = - result = self.createMemberItem(member.id, "", MembershipRequestState.Accepted)), + members = members, historyArchiveSupportEnabled = c.settings.historyArchiveSupportEnabled, - bannedMembers = c.bannedMembersIds.map(proc(bannedMemberId: string): MemberItem = - result = self.createMemberItem(bannedMemberId, "", MembershipRequestState.Banned)), + bannedMembers = bannedMembers, pendingMemberRequests = c.pendingRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem = result = self.createMemberItem(requestDto.publicKey, requestDto.id, MembershipRequestState(requestDto.state))), declinedMemberRequests = c.declinedRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem = diff --git a/src/app/modules/main/controller.nim b/src/app/modules/main/controller.nim index 483d89198f..d5f430dd0b 100644 --- a/src/app/modules/main/controller.nim +++ b/src/app/modules/main/controller.nim @@ -381,6 +381,10 @@ proc init*(self: Controller) = var args = CommunityMemberArgs(e) self.delegate.onAcceptRequestToJoinSuccess(args.communityId, args.pubKey, args.requestId) + self.events.on(SIGNAL_COMMUNITY_MEMBER_STATUS_CHANGED) do(e: Args): + let args = CommunityMemberStatusUpdatedArgs(e) + self.delegate.onMembershipStatusUpdated(args.communityId, args.memberPubkey, args.status) + self.events.on(SIGNAL_COMMUNITY_MEMBERS_CHANGED) do(e: Args): let args = CommunityMembersArgs(e) self.communityTokensService.fetchCommunityTokenOwners(args.communityId) diff --git a/src/app/modules/main/io_interface.nim b/src/app/modules/main/io_interface.nim index 8722266a51..40cae3ebcd 100644 --- a/src/app/modules/main/io_interface.nim +++ b/src/app/modules/main/io_interface.nim @@ -13,7 +13,7 @@ import app_service/service/wallet_account/service as wallet_account_service import app_service/service/token/service as token_service import app_service/service/community_tokens/service as community_tokens_service import app_service/service/community_tokens/community_collectible_owner -from app_service/common/types import StatusType, ContractTransactionStatus +from app_service/common/types import StatusType, ContractTransactionStatus, MembershipRequestState import app/global/app_signals import app/core/eventemitter @@ -341,6 +341,9 @@ method onAcceptRequestToJoinLoading*(self: AccessInterface, communityId: string, method onAcceptRequestToJoinSuccess*(self: AccessInterface, communityId: string, memberKey: string, requestId: string) {.base.} = raise newException(ValueError, "No implementation available") +method onMembershipStatusUpdated*(self: AccessInterface, communityId: string, memberPubkey: string, status: MembershipRequestState) {.base.} = + raise newException(ValueError, "No implementation available") + method onDeactivateChatLoader*(self: AccessInterface, sectionId: string, chatId: string) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 54d3f0c9ae..1d9aac47e6 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -1181,6 +1181,11 @@ method onAcceptRequestToJoinSuccess*[T](self: Module[T], communityId: string, me if item.id != "": item.updatePendingRequestLoadingState(memberKey, false) +method onMembershipStatusUpdated*[T](self: Module[T], communityId: string, memberPubkey: string, status: MembershipRequestState) = + let item = self.view.model().getItemById(communityId) + if item.id != "": + item.updateMembershipStatus(memberPubkey, status) + method calculateProfileSectionHasNotification*[T](self: Module[T]): bool = return not self.controller.isMnemonicBackedUp() diff --git a/src/app/modules/shared_models/member_item.nim b/src/app/modules/shared_models/member_item.nim index 84822983ed..f33754b0a2 100644 --- a/src/app/modules/shared_models/member_item.nim +++ b/src/app/modules/shared_models/member_item.nim @@ -12,7 +12,7 @@ type requestToJoinId: string requestToJoinLoading*: bool airdropAddress*: string - membershipRequestState: MembershipRequestState + membershipRequestState*: MembershipRequestState # FIXME: remove defaults proc initMemberItem*( diff --git a/src/app/modules/shared_models/member_model.nim b/src/app/modules/shared_models/member_model.nim index 5cea6af780..72b92ffcd3 100644 --- a/src/app/modules/shared_models/member_model.nim +++ b/src/app/modules/shared_models/member_model.nim @@ -358,3 +358,14 @@ QtObject: ModelRole.RequestToJoinLoading.int ]) + proc updateMembershipStatus*(self: Model, memberKey: string, status: MembershipRequestState) {.inline.} = + let idx = self.findIndexForMember(memberKey) + if(idx == -1): + return + + self.items[idx].membershipRequestState = status + let index = self.createIndex(idx, 0, nil) + defer: index.delete + self.dataChanged(index, index, @[ + ModelRole.MembershipRequestState.int + ]) diff --git a/src/app/modules/shared_models/section_item.nim b/src/app/modules/shared_models/section_item.nim index 8b0546bda5..03304a3e7a 100644 --- a/src/app/modules/shared_models/section_item.nim +++ b/src/app/modules/shared_models/section_item.nim @@ -360,3 +360,9 @@ proc communityTokens*(self: SectionItem): community_tokens_model.TokenModel {.in proc updatePendingRequestLoadingState*(self: SectionItem, memberKey: string, loading: bool) {.inline.} = self.pendingMemberRequestsModel.updateLoadingState(memberKey, loading) + +proc updateMembershipStatus*(self: SectionItem, memberKey: string, status: MembershipRequestState) {.inline.} = + if status == MembershipRequestState.UnbannedPending or status == MembershipRequestState.Banned: + self.bannedMembersModel.updateMembershipStatus(memberKey, status) + else: + self.membersModel.updateMembershipStatus(memberKey, status) diff --git a/src/app_service/common/types.nim b/src/app_service/common/types.nim index 59ffc4139d..4f50a51211 100644 --- a/src/app_service/common/types.nim +++ b/src/app_service/common/types.nim @@ -55,6 +55,8 @@ type MemberRole* {.pure} = enum Admin TokenMaster +# TODO: consider refactor MembershipRequestState to MembershipState and use both for request to join and kick/ban actions +# Issue: https://github.com/status-im/status-desktop/issues/11842 type MembershipRequestState* {.pure} = enum None = 0, Pending = 1, @@ -65,7 +67,8 @@ type MembershipRequestState* {.pure} = enum Banned = 6, Kicked = 7, BannedPending = 8, - KickedPending = 9 + UnbannedPending = 9, + KickedPending = 10, type ContractTransactionStatus* {.pure.} = enum diff --git a/src/app_service/service/community/async_tasks.nim b/src/app_service/service/community/async_tasks.nim index 151509912c..11d09e79a4 100644 --- a/src/app_service/service/community/async_tasks.nim +++ b/src/app_service/service/community/async_tasks.nim @@ -103,6 +103,54 @@ const asyncAcceptRequestToJoinCommunityTask: Task = proc(argEncoded: string) {.g "requestId": arg.requestId }) +type + AsyncCommunityMemberActionTaskArg = ref object of QObjectTaskArg + communityId: string + pubKey: string + +const asyncRemoveUserFromCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncCommunityMemberActionTaskArg](argEncoded) + try: + let response = status_go.removeUserFromCommunity(arg.communityId, arg.pubKey) + arg.finish(%* { + "communityId": arg.communityId, + "pubKey": arg.pubKey, + "response": response, + "error": "", + }) + except Exception as e: + arg.finish(%* { + "communityId": arg.communityId, + "pubKey": arg.pubKey, + "error": e.msg, + }) + +const asyncBanUserFromCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncCommunityMemberActionTaskArg](argEncoded) + try: + let response = status_go.banUserFromCommunity(arg.communityId, arg.pubKey) + let tpl: tuple[communityId: string, pubKey: string, response: RpcResponse[JsonNode], error: string] = (arg.communityId, arg.pubKey, response, "") + arg.finish(tpl) + except Exception as e: + arg.finish(%* { + "error": e.msg, + "communityId": arg.communityId, + "pubKey": arg.pubKey + }) + +const asyncUnbanUserFromCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncCommunityMemberActionTaskArg](argEncoded) + try: + let response = status_go.unbanUserFromCommunity(arg.communityId, arg.pubKey) + let tpl: tuple[communityId: string, pubKey: string, response: RpcResponse[JsonNode], error: string] = (arg.communityId, arg.pubKey, response, "") + arg.finish(tpl) + except Exception as e: + arg.finish(%* { + "error": e.msg, + "communityId": arg.communityId, + "pubKey": arg.pubKey + }) + type AsyncRequestToJoinCommunityTaskArg = ref object of QObjectTaskArg communityId: string diff --git a/src/app_service/service/community/dto/community.nim b/src/app_service/service/community/dto/community.nim index ca03573331..3e405b0f37 100644 --- a/src/app_service/service/community/dto/community.nim +++ b/src/app_service/service/community/dto/community.nim @@ -34,6 +34,13 @@ type Members, ControlNodeUptime +type + CommunityMemberPendingBanOrKick* {.pure.} = enum + Banned = 0, + BanPending, + UnbanPending, + KickPending + type CommunityMembershipRequestDto* = object id*: string publicKey*: string @@ -154,7 +161,7 @@ type CommunityDto* = object pendingRequestsToJoin*: seq[CommunityMembershipRequestDto] settings*: CommunitySettingsDto adminSettings*: CommunityAdminSettingsDto - bannedMembersIds*: seq[string] + pendingAndBannedMembers*: Table[string, CommunityMemberPendingBanOrKick] declinedRequestsToJoin*: seq[CommunityMembershipRequestDto] encrypted*: bool canceledRequestsToJoin*: seq[CommunityMembershipRequestDto] @@ -427,10 +434,11 @@ proc toCommunityDto*(jsonObj: JsonNode): CommunityDto = else: result.tags = "[]" - var bannedMembersIdsObj: JsonNode - if(jsonObj.getProp("banList", bannedMembersIdsObj) and bannedMembersIdsObj.kind == JArray): - for bannedMemberId in bannedMembersIdsObj: - result.bannedMembersIds.add(bannedMemberId.getStr) + var pendingAndBannedMembersObj: JsonNode + if (jsonObj.getProp("pendingAndBannedMembers", pendingAndBannedMembersObj) and pendingAndBannedMembersObj.kind == JObject): + result.pendingAndBannedMembers = initTable[string, CommunityMemberPendingBanOrKick]() + for memberId, pendingKickOrBanMember in pendingAndBannedMembersObj: + result.pendingAndBannedMembers[memberId] = CommunityMemberPendingBanOrKick(pendingKickOrBanMember.getInt()) discard jsonObj.getProp("canRequestAccess", result.canRequestAccess) discard jsonObj.getProp("canManageUsers", result.canManageUsers) @@ -446,6 +454,18 @@ proc toCommunityDto*(jsonObj: JsonNode): CommunityDto = for tokenObj in communityTokensMetadataObj: result.communityTokensMetadata.add(tokenObj.toCommunityTokensMetadataDto()) +proc toMembershipRequestState*(state: CommunityMemberPendingBanOrKick): MembershipRequestState = + case state: + of CommunityMemberPendingBanOrKick.Banned: + return MembershipRequestState.Banned + of CommunityMemberPendingBanOrKick.BanPending: + return MembershipRequestState.BannedPending + of CommunityMemberPendingBanOrKick.UnbanPending: + return MembershipRequestState.UnbannedPending + of CommunityMemberPendingBanOrKick.KickPending: + return MembershipRequestState.KickedPending + return MembershipRequestState.None + proc toCommunityMembershipRequestDto*(jsonObj: JsonNode): CommunityMembershipRequestDto = result = CommunityMembershipRequestDto() discard jsonObj.getProp("id", result.id) @@ -494,6 +514,13 @@ proc contains(arrayToSearch: seq[int], searched: int): bool = return true return false +proc getBannedMembersIds*(self: CommunityDto): seq[string] = + var bannedIds: seq[string] = @[] + for memberId, state in self.pendingAndBannedMembers: + if state == CommunityMemberPendingBanOrKick.Banned: + bannedIds.add(memberId) + return bannedIds + proc toChannelGroupDto*(communityDto: CommunityDto): ChannelGroupDto = ChannelGroupDto( id: communityDto.id, @@ -520,7 +547,7 @@ proc toChannelGroupDto*(communityDto: CommunityDto): ChannelGroupDto = canManageUsers: communityDto.canManageUsers, muted: communityDto.muted, historyArchiveSupportEnabled: communityDto.settings.historyArchiveSupportEnabled, - bannedMembersIds: communityDto.bannedMembersIds, + bannedMembersIds: communityDto.getBannedMembersIds(), encrypted: communityDto.encrypted, ) diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index 34f95b601c..c756d65e87 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -139,6 +139,11 @@ type communityId*: string membersRevealedAccounts*: MembersRevealedAccounts + CommunityMemberStatusUpdatedArgs* = ref object of Args + communityId*: string + memberPubkey*: string + status*: MembershipRequestState + # Signals which may be emitted by this service: const SIGNAL_COMMUNITY_DATA_LOADED* = "communityDataLoaded" const SIGNAL_COMMUNITY_JOINED* = "communityJoined" @@ -169,7 +174,7 @@ const SIGNAL_COMMUNITY_CATEGORY_DELETED* = "communityCategoryDeleted" const SIGNAL_COMMUNITY_CATEGORY_REORDERED* = "communityCategoryReordered" const SIGNAL_COMMUNITY_CHANNEL_CATEGORY_CHANGED* = "communityChannelCategoryChanged" const SIGNAL_COMMUNITY_MEMBER_APPROVED* = "communityMemberApproved" -const SIGNAL_COMMUNITY_MEMBER_REMOVED* = "communityMemberRemoved" +const SIGNAL_COMMUNITY_MEMBER_STATUS_CHANGED* = "communityMemberStatusChanged" const SIGNAL_COMMUNITY_MEMBERS_CHANGED* = "communityMembersChanged" const SIGNAL_COMMUNITY_KICKED* = "communityKicked" const SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY* = "newRequestToJoinCommunity" @@ -466,6 +471,8 @@ QtObject: self.events.emit(SIGNAL_COMMUNITY_CATEGORY_NAME_EDITED, CommunityCategoryArgs(communityId: community.id, category: category)) + self.events.emit(SIGNAL_COMMUNITY_MEMBERS_CHANGED, + CommunityMembersArgs(communityId: community.id, members: community.members)) proc handleCommunityUpdates(self: Service, communities: seq[CommunityDto], updatedChats: seq[ChatDto], removedChats: seq[string]) = try: @@ -1884,26 +1891,74 @@ QtObject: except Exception as e: error "Error unmuting category", msg = e.msg - proc removeUserFromCommunity*(self: Service, communityId: string, pubKey: string) = - try: - discard status_go.removeUserFromCommunity(communityId, pubKey) + proc asyncRemoveUserFromCommunity*(self: Service, communityId, pubKey: string) = + let arg = AsyncCommunityMemberActionTaskArg( + tptr: cast[ByteAddress](asyncRemoveUserFromCommunityTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncCommunityMemberActionCompleted", + communityId: communityId, + pubKey: pubKey, + ) + self.threadpool.start(arg) - self.events.emit(SIGNAL_COMMUNITY_MEMBER_REMOVED, - CommunityMemberArgs(communityId: communityId, pubKey: pubKey)) - except Exception as e: - error "Error removing user from community", msg = e.msg + proc asyncBanUserFromCommunity*(self: Service, communityId, pubKey: string) = + let arg = AsyncCommunityMemberActionTaskArg( + tptr: cast[ByteAddress](asyncBanUserFromCommunityTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncCommunityMemberActionCompleted", + communityId: communityId, + pubKey: pubKey, + ) + self.threadpool.start(arg) - proc banUserFromCommunity*(self: Service, communityId: string, pubKey: string) = - try: - discard status_go.banUserFromCommunity(communityId, pubKey) - except Exception as e: - error "Error banning user from community", msg = e.msg + proc asyncUnbanUserFromCommunity*(self: Service, communityId, pubKey: string) = + let arg = AsyncCommunityMemberActionTaskArg( + tptr: cast[ByteAddress](asyncUnbanUserFromCommunityTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncCommunityMemberActionCompleted", + communityId: communityId, + pubKey: pubKey, + ) + self.threadpool.start(arg) - proc unbanUserFromCommunity*(self: Service, communityId: string, pubKey: string) = + proc onAsyncCommunityMemberActionCompleted*(self: Service, response: string) {.slot.} = try: - discard status_go.unbanUserFromCommunity(communityId, pubKey) + let rpcResponseObj = response.parseJson + + if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "": + raise newException(RpcException, rpcResponseObj["error"].getStr) + + if rpcResponseObj["response"]{"error"}.kind != JNull: + let error = Json.decode(rpcResponseObj["response"]["error"].getStr, RpcError) + raise newException(RpcException, error.message) + + let memberPubkey = rpcResponseObj{"pubKey"}.getStr() + + var communityJArr: JsonNode + if not rpcResponseObj["response"]{"result"}.getProp("communities", communityJArr): + raise newException(RpcException, "there is no `communities` key in the response") + + if communityJArr.len == 0: + raise newException(RpcException, "`communities` array is empty in the response") + + var community = communityJArr[0].toCommunityDto() + + var status: MembershipRequestState = MembershipRequestState.None + if community.pendingAndBannedMembers.hasKey(memberPubkey): + status = community.pendingAndBannedMembers[memberPubkey].toMembershipRequestState() + else: + for member in community.members: + if member.id == memberPubkey: + status = MembershipRequestState.Accepted + + self.events.emit(SIGNAL_COMMUNITY_MEMBER_STATUS_CHANGED, CommunityMemberStatusUpdatedArgs( + communityId: community.id, + memberPubkey: memberPubkey, + status: status + )) + except Exception as e: - error "Error banning user from community", msg = e.msg + error "error while getting the community members' revealed addressesses", msg = e.msg proc setCommunityMuted*(self: Service, communityId: string, mutedType: int) = try: diff --git a/storybook/pages/MembersTabPanelPage.qml b/storybook/pages/MembersTabPanelPage.qml index 14aa961c48..b7923172b3 100644 --- a/storybook/pages/MembersTabPanelPage.qml +++ b/storybook/pages/MembersTabPanelPage.qml @@ -94,7 +94,7 @@ SplitView { SortFilterProxyModel { id: usersModelWithMembershipState readonly property var membershipStatePerView: [ - [Constants.CommunityMembershipRequestState.Accepted , Constants.CommunityMembershipRequestState.BannedPending, Constants.CommunityMembershipRequestState.KickedPending], + [Constants.CommunityMembershipRequestState.Accepted , Constants.CommunityMembershipRequestState.BannedPending, Constants.CommunityMembershipRequestState.UnbannedPending, Constants.CommunityMembershipRequestState.KickedPending], [Constants.CommunityMembershipRequestState.Banned], [Constants.CommunityMembershipRequestState.Pending, Constants.CommunityMembershipRequestState.AcceptedPending, Constants.CommunityMembershipRequestState.RejectedPending], [Constants.CommunityMembershipRequestState.Rejected] diff --git a/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml b/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml index b615b2338e..1d0882c09c 100644 --- a/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml @@ -101,13 +101,14 @@ Item { readonly property bool isRejectedPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.RejectedPending readonly property bool isAcceptedPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.AcceptedPending readonly property bool isBanPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.BannedPending + readonly property bool isUnbanPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.UnbannedPending readonly property bool isKickPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.KickedPending readonly property bool isBanned: model.membershipRequestState === Constants.CommunityMembershipRequestState.Banned readonly property bool isKicked: model.membershipRequestState === Constants.CommunityMembershipRequestState.Kicked // TODO: Connect to backend when available // The admin that initited the pending state can change the state. Actions are not visible for other admins - readonly property bool ctaAllowed: !isRejectedPending && !isAcceptedPending && !isBanPending && !isKickPending + readonly property bool ctaAllowed: !isRejectedPending && !isAcceptedPending && !isBanPending && !isUnbanPending && !isKickPending readonly property bool itsMe: model.pubKey.toLowerCase() === Global.userProfile.pubKey.toLowerCase() readonly property bool isHovered: memberItem.sensor.containsMouse @@ -140,10 +141,11 @@ Item { readonly property bool unbanButtonVisible: tabIsShowingUnbanButton && isBanned && showOnHover /// Pending states /// - readonly property bool isPendingState: isAcceptedPending || isRejectedPending || isBanPending || isKickPending + readonly property bool isPendingState: isAcceptedPending || isRejectedPending || isBanPending || isUnbanPending || isKickPending readonly property string pendingStateText: isAcceptedPending ? qsTr("Accept pending...") : isRejectedPending ? qsTr("Reject pending...") : isBanPending ? qsTr("Ban pending...") : + isUnbanPending ? qsTr("Unban pending...") : isKickPending ? qsTr("Kick pending...") : "" statusListItemComponentsSlot.spacing: 16 @@ -160,7 +162,7 @@ Item { d.pendingTextMaxWidth = Math.max(implicitWidth, d.pendingTextMaxWidth) } visible: !!text && isPendingState - rightPadding: isKickPending || isBanPending ? 0 : Style.current.bigPadding + rightPadding: isKickPending || isBanPending || isUnbanPending ? 0 : Style.current.bigPadding anchors.verticalCenter: parent.verticalCenter text: pendingStateText color: Theme.palette.baseColor1 diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index f357356e84..1cc0db4b85 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -1184,6 +1184,7 @@ QtObject { Banned, Kicked, BannedPending, + UnbannedPending, KickedPending } diff --git a/vendor/status-go b/vendor/status-go index c85a110a31..a17ee052fb 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit c85a110a3185e89e4565ef67fe4527c5708eb8c4 +Subproject commit a17ee052fb28e4108be1b02b45aca9c764c845f2