From 42234c7d49f0478e3c80ab0a8f1e8607075cc9f6 Mon Sep 17 00:00:00 2001 From: Boris Melnik Date: Fri, 21 Oct 2022 13:09:17 +0300 Subject: [PATCH] feat(communities): User is able to cancel membership request Part of: #7072 --- .../modules/main/communities/controller.nim | 3 + .../modules/main/communities/io_interface.nim | 3 + src/app/modules/main/communities/module.nim | 3 + src/app/modules/main/communities/view.nim | 3 + .../service/community/dto/community.nim | 8 ++- src/app_service/service/community/service.nim | 70 +++++++++++++++++-- src/backend/communities.nim | 11 +++ ui/app/AppLayouts/Chat/stores/RootStore.qml | 4 ++ .../Chat/views/CommunityColumnView.qml | 12 +++- .../shared/popups/CommunityIntroDialog.qml | 22 ++++-- 10 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/app/modules/main/communities/controller.nim b/src/app/modules/main/communities/controller.nim index d12c85a3c7..ec69ef3169 100644 --- a/src/app/modules/main/communities/controller.nim +++ b/src/app/modules/main/communities/controller.nim @@ -86,6 +86,9 @@ proc getCuratedCommunities*(self: Controller): seq[CuratedCommunity] = proc spectateCommunity*(self: Controller, communityId: string): string = self.communityService.spectateCommunity(communityId) +proc cancelRequestToJoinCommunity*(self: Controller, communityId: string) = + self.communityService.cancelRequestToJoinCommunity(communityId) + proc requestToJoinCommunity*(self: Controller, communityId: string, ensName: string) = self.communityService.requestToJoinCommunity(communityId, ensName) diff --git a/src/app/modules/main/communities/io_interface.nim b/src/app/modules/main/communities/io_interface.nim index 415fe51b09..37d79e3616 100644 --- a/src/app/modules/main/communities/io_interface.nim +++ b/src/app/modules/main/communities/io_interface.nim @@ -62,6 +62,9 @@ method userCanJoin*(self: AccessInterface, communityId: string): bool {.base.} = method isCommunityRequestPending*(self: AccessInterface, communityId: string): bool {.base.} = raise newException(ValueError, "No implementation available") +method cancelRequestToJoinCommunity*(self: AccessInterface, communityId: string) {.base.} = + raise newException(ValueError, "No implementation available") + method requestToJoinCommunity*(self: AccessInterface, communityId: string, ensName: string) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/communities/module.nim b/src/app/modules/main/communities/module.nim index bf10ffb11b..210ad4a76b 100644 --- a/src/app/modules/main/communities/module.nim +++ b/src/app/modules/main/communities/module.nim @@ -272,6 +272,9 @@ method discordCategoriesAndChannelsExtracted*(self: Module, categories: seq[Disc self.view.setDiscordImportErrorsCount(errorsCount) self.view.discordChannelsModel().hasSelectedItemsChanged() +method cancelRequestToJoinCommunity*(self: Module, communityId: string) = + self.controller.cancelRequestToJoinCommunity(communityId) + method requestToJoinCommunity*(self: Module, communityId: string, ensName: string) = self.controller.requestToJoinCommunity(communityId, ensName) diff --git a/src/app/modules/main/communities/view.nim b/src/app/modules/main/communities/view.nim index a1b5d8fe68..da949e9107 100644 --- a/src/app/modules/main/communities/view.nim +++ b/src/app/modules/main/communities/view.nim @@ -418,6 +418,9 @@ QtObject: proc reorderCommunityChannel*(self: View, communityId: string, categoryId: string, chatId: string, position: int): string {.slot} = self.delegate.reorderCommunityChannel(communityId, categoryId, chatId, position) + proc cancelRequestToJoinCommunity*(self: View, communityId: string) {.slot.} = + self.delegate.cancelRequestToJoinCommunity(communityId) + proc requestToJoinCommunity*(self: View, communityId: string, ensName: string) {.slot.} = self.delegate.requestToJoinCommunity(communityId, ensName) diff --git a/src/app_service/service/community/dto/community.nim b/src/app_service/service/community/dto/community.nim index ae38fa2c8e..44e997970e 100644 --- a/src/app_service/service/community/dto/community.nim +++ b/src/app_service/service/community/dto/community.nim @@ -8,9 +8,10 @@ include ../../../common/json_utils import ../../chat/dto/chat type RequestToJoinType* {.pure.}= enum - Pending = 0, - Declined = 1, - Accepted = 2 + Pending = 1, + Declined = 2, + Accepted = 3, + Canceled = 4 type Member* = object id*: string @@ -72,6 +73,7 @@ type CommunityDto* = object bannedMembersIds*: seq[string] declinedRequestsToJoin*: seq[CommunityMembershipRequestDto] encrypted*: bool + canceledRequestsToJoin*: seq[CommunityMembershipRequestDto] type CuratedCommunity* = object available*: bool diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index d38b95c137..22af670e3f 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -114,6 +114,7 @@ const SIGNAL_COMMUNITY_CATEGORY_REORDERED* = "communityCategoryReordered" const SIGNAL_COMMUNITY_MEMBER_APPROVED* = "communityMemberApproved" const SIGNAL_COMMUNITY_MEMBER_REMOVED* = "communityMemberRemoved" const SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY* = "newRequestToJoinCommunity" +const SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED* = "requestToJoinCommunityCanceled" const SIGNAL_CURATED_COMMUNITY_FOUND* = "curatedCommunityFound" const SIGNAL_COMMUNITY_MUTED* = "communityMuted" const SIGNAL_CATEGORY_MUTED* = "categoryMuted" @@ -142,10 +143,13 @@ QtObject: proc loadCuratedCommunities(self: Service): seq[CuratedCommunity] proc loadCommunitiesSettings(self: Service): seq[CommunitySettingsDto] proc loadMyPendingRequestsToJoin*(self: Service) + proc loadMyCanceledRequestsToJoin*(self: Service) proc handleCommunityUpdates(self: Service, communities: seq[CommunityDto], updatedChats: seq[ChatDto]) proc handleCommunitiesSettingsUpdates(self: Service, communitiesSettings: seq[CommunitySettingsDto]) proc pendingRequestsToJoinForCommunity*(self: Service, communityId: string): seq[CommunityMembershipRequestDto] proc declinedRequestsToJoinForCommunity*(self: Service, communityId: string): seq[CommunityMembershipRequestDto] + proc canceledRequestsToJoinForCommunity*(self: Service, communityId: string): seq[CommunityMembershipRequestDto] + proc getPendingRequestIndex(self: Service, communityId: string, requestId: string): int proc delete*(self: Service) = discard @@ -199,11 +203,25 @@ QtObject: error "Received a membership request for an unknown community", communityId=membershipRequest.communityId continue var community = self.joinedCommunities[membershipRequest.communityId] - community.pendingRequestsToJoin.add(membershipRequest) - self.joinedCommunities[membershipRequest.communityId] = community - self.events.emit(SIGNAL_COMMUNITY_EDITED, CommunityArgs(community: community)) - self.events.emit(SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY, CommunityRequestArgs(communityRequest: membershipRequest)) + case RequestToJoinType(membershipRequest.state): + of RequestToJoinType.Pending: + community.pendingRequestsToJoin.add(membershipRequest) + self.joinedCommunities[membershipRequest.communityId] = community + self.events.emit(SIGNAL_COMMUNITY_EDITED, CommunityArgs(community: community)) + self.events.emit(SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY, CommunityRequestArgs(communityRequest: membershipRequest)) + + of RequestToJoinType.Canceled: + let indexPending = self.getPendingRequestIndex(membershipRequest.communityId, membershipRequest.id) + if (indexPending != -1): + community.pendingRequestsToJoin.delete(indexPending) + self.joinedCommunities[membershipRequest.communityId] = community + self.events.emit(SIGNAL_COMMUNITY_EDITED, CommunityArgs(community: community)) + + of RequestToJoinType.Declined: + break + of RequestToJoinType.Accepted: + break self.events.on(SignalType.DiscordCategoriesAndChannelsExtracted.event) do(e: Args): var receivedData = DiscordCategoriesAndChannelsExtractedSignal(e) @@ -264,6 +282,7 @@ QtObject: # therefore, we must keep the old one community.pendingRequestsToJoin = self.joinedCommunities[community.id].pendingRequestsToJoin community.declinedRequestsToJoin = self.joinedCommunities[community.id].declinedRequestsToJoin + community.canceledRequestsToJoin = self.joinedCommunities[community.id].canceledRequestsToJoin # Update the joinded community list with the new data self.joinedCommunities[community.id] = community @@ -407,6 +426,7 @@ QtObject: if (community.admin): self.joinedCommunities[community.id].pendingRequestsToJoin = self.pendingRequestsToJoinForCommunity(community.id) self.joinedCommunities[community.id].declinedRequestsToJoin = self.declinedRequestsToJoinForCommunity(community.id) + self.joinedCommunities[community.id].canceledRequestsToJoin = self.canceledRequestsToJoinForCommunity(community.id) let allCommunities = self.loadAllCommunities() for community in allCommunities: @@ -646,6 +666,29 @@ QtObject: except Exception as e: error "Error fetching my community requests", msg = e.msg + proc loadMyCanceledRequestsToJoin*(self: Service) = + try: + let response = status_go.myCanceledRequestsToJoin() + + if response.result.kind != JNull: + for jsonCommunityReqest in response.result: + let communityRequest = jsonCommunityReqest.toCommunityMembershipRequestDto() + self.myCommunityRequests.add(communityRequest) + self.events.emit(SIGNAL_COMMUNITY_MY_REQUEST_ADDED, CommunityRequestArgs(communityRequest: communityRequest)) + except Exception as e: + error "Error fetching my community requests", msg = e.msg + + proc canceledRequestsToJoinForCommunity*(self: Service, communityId: string): seq[CommunityMembershipRequestDto] = + try: + let response = status_go.canceledRequestsToJoinForCommunity(communityId) + + result = @[] + if response.result.kind != JNull: + for jsonCommunityReqest in response.result: + result.add(jsonCommunityReqest.toCommunityMembershipRequestDto()) + except Exception as e: + error "Error fetching community requests", msg = e.msg + proc pendingRequestsToJoinForCommunity*(self: Service, communityId: string): seq[CommunityMembershipRequestDto] = try: let response = status_go.pendingRequestsToJoinForCommunity(communityId) @@ -1215,6 +1258,25 @@ QtObject: self.joinedCommunities[communityId] = community + proc cancelRequestToJoinCommunity*(self: Service, communityId: string) = + try: + var i = 0 + for communityRequest in self.myCommunityRequests: + if (communityRequest.communityId == communityId): + let response = status_go.cancelRequestToJoinCommunity(communityRequest.id) + if (not response.error.isNil): + let msg = response.error.message & " communityId=" & communityId + error "error while cancel membership request ", msg + return + self.myCommunityRequests.delete(i) + self.activityCenterService.parseACNotificationResponse(response) + + i.inc() + + self.events.emit(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED, Args()) + except Exception as e: + error "Error canceled request to join community", msg = e.msg + proc acceptRequestToJoinCommunity*(self: Service, communityId: string, requestId: string) = try: let response = status_go.acceptRequestToJoinCommunity(requestId) diff --git a/src/backend/communities.nim b/src/backend/communities.nim index 5aa185218a..694f5352c0 100644 --- a/src/backend/communities.nim +++ b/src/backend/communities.nim @@ -40,12 +40,23 @@ proc requestToJoinCommunity*(communityId: string, ensName: string): RpcResponse[ proc myPendingRequestsToJoin*(): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("myPendingRequestsToJoin".prefix) +proc myCanceledRequestsToJoin*(): RpcResponse[JsonNode] {.raises: [Exception].} = + result = callPrivateRPC("myCanceledRequestsToJoin".prefix) + proc pendingRequestsToJoinForCommunity*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("pendingRequestsToJoinForCommunity".prefix, %*[communityId]) proc declinedRequestsToJoinForCommunity*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("declinedRequestsToJoinForCommunity".prefix, %*[communityId]) +proc canceledRequestsToJoinForCommunity*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} = + result = callPrivateRPC("canceledRequestsToJoinForCommunity".prefix, %*[communityId]) + +proc cancelRequestToJoinCommunity*(requestId: string): RpcResponse[JsonNode] {.raises: [Exception].} = + result = callPrivateRPC("cancelRequestToJoinCommunity".prefix, %*[{ + "id": requestId + }]) + proc leaveCommunity*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("leaveCommunity".prefix, %*[communityId]) diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index fa10a5c6da..bb69cbf425 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -335,6 +335,10 @@ QtObject { return communitiesModuleInst.isCommunityRequestPending(id) } + function cancelPendingRequest(id: string) { + communitiesModuleInst.cancelRequestToJoinCommunity(id) + } + function getSectionNameById(id) { return communitiesList.getSectionNameById(id) } diff --git a/ui/app/AppLayouts/Chat/views/CommunityColumnView.qml b/ui/app/AppLayouts/Chat/views/CommunityColumnView.qml index a12820ba96..b31851fff1 100644 --- a/ui/app/AppLayouts/Chat/views/CommunityColumnView.qml +++ b/ui/app/AppLayouts/Chat/views/CommunityColumnView.qml @@ -108,15 +108,16 @@ Item { anchors.horizontalCenter: parent.horizontalCenter visible: !communityData.joined - enabled: !invitationPending text: { - if (invitationPending) return qsTr("Pending") + if (invitationPending) return qsTr("Membership request pending...") return root.communityData.access === Constants.communityChatOnRequestAccess ? qsTr("Request to join") : qsTr("Join Community") } - onClicked: communityIntroDialog.open() + onClicked: { + communityIntroDialog.open() + } Connections { target: root.store.communitiesModuleInst @@ -130,12 +131,17 @@ Item { CommunityIntroDialog { id: communityIntroDialog + isInvitationPending: joinCommunityButton.invitationPending name: communityData.name introMessage: communityData.introMessage imageSrc: communityData.image accessType: communityData.access onJoined: root.store.requestToJoinCommunity(communityData.id, root.store.userProfileInst.name) + onCancelMembershipRequest: { + root.store.cancelPendingRequest(communityData.id) + joinCommunityButton.invitationPending = root.store.isCommunityRequestPending(communityData.id) + } } } diff --git a/ui/imports/shared/popups/CommunityIntroDialog.qml b/ui/imports/shared/popups/CommunityIntroDialog.qml index 16aa588fac..35b7ba325f 100644 --- a/ui/imports/shared/popups/CommunityIntroDialog.qml +++ b/ui/imports/shared/popups/CommunityIntroDialog.qml @@ -18,20 +18,31 @@ StatusDialog { property string introMessage property int accessType property url imageSrc + property bool isInvitationPending: false signal joined + signal cancelMembershipRequest title: qsTr("Welcome to %1").arg(name) footer: StatusDialogFooter { rightButtons: ObjectModel { StatusButton { - text: root.accessType === Constants.communityChatOnRequestAccess - ? qsTr("Request to join %1").arg(root.name) - : qsTr("Join %1").arg(root.name) - enabled: checkBox.checked + text: root.isInvitationPending ? qsTr("Cancel Membership Request") + : (root.accessType === Constants.communityChatOnRequestAccess + ? qsTr("Request to join %1").arg(root.name) + : qsTr("Join %1").arg(root.name) ) + type: root.isInvitationPending ? StatusBaseButton.Type.Danger + : StatusBaseButton.Type.Normal + enabled: checkBox.checked || root.isInvitationPending + onClicked: { - root.joined() + if (root.isInvitationPending) { + root.cancelMembershipRequest() + } else { + root.joined() + } + root.close() } } @@ -71,6 +82,7 @@ StatusDialog { StatusCheckBox { id: checkBox Layout.alignment: Qt.AlignCenter + visible: !root.isInvitationPending text: qsTr("I agree with the above") } }