From 8a97c0ca3ace919a4d66b72f9be000acd8066df0 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Mon, 17 Jul 2023 14:52:46 -0400 Subject: [PATCH] feat(communities): add API to edit shared addresses Fixes #11153 Adds `editSharedAddressesWithAuthentication` in the chat_section view to be called from QML. Also adds the `communityEditSharedAddressesSucceeded` and `communityEditSharedAddressesFailed` signals in the communities module to be used by QML to know if it worked. --- .../modules/main/chat_section/controller.nim | 50 ++++++++++++++----- .../main/chat_section/io_interface.nim | 5 ++ src/app/modules/main/chat_section/module.nim | 5 +- src/app/modules/main/chat_section/view.nim | 7 +++ .../modules/main/communities/controller.nim | 8 +++ .../modules/main/communities/io_interface.nim | 6 +++ src/app/modules/main/communities/module.nim | 6 +++ src/app/modules/main/communities/view.nim | 2 + .../service/community/async_tasks.nim | 25 +++++++++- src/app_service/service/community/service.nim | 32 ++++++++++++ src/backend/communities.nim | 16 +++++- 11 files changed, 146 insertions(+), 16 deletions(-) diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim index 544d9a0002..413a072520 100644 --- a/src/app/modules/main/chat_section/controller.nim +++ b/src/app/modules/main/chat_section/controller.nim @@ -45,9 +45,10 @@ type collectibleService: collectible_service.Service communityTokensService: community_tokens_service.Service tmpAuthenticationForJoinInProgress: bool + tmpAuthenticationForEditSharedAddresses: bool tmpRequestToJoinEnsName: string - tmpRequestToJoinAddressesToShare: seq[string] - tmpRequestToJoinAirdropAddress: string + tmpAddressesToShare: seq[string] + tmpAirdropAddress: string proc newController*(delegate: io_interface.AccessInterface, sectionId: string, isCommunity: bool, events: EventEmitter, settingsService: settings_service.Service, nodeConfigurationService: node_configuration_service.Service, @@ -77,9 +78,10 @@ proc newController*(delegate: io_interface.AccessInterface, sectionId: string, i result.collectibleService = collectibleService result.communityTokensService = communityTokensService result.tmpAuthenticationForJoinInProgress = false + result.tmpAuthenticationForEditSharedAddresses = false result.tmpRequestToJoinEnsName = "" - result.tmpRequestToJoinAirdropAddress = "" - result.tmpRequestToJoinAddressesToShare = @[] + result.tmpAirdropAddress = "" + result.tmpAddressesToShare = @[] proc delete*(self: Controller) = self.events.disconnect() @@ -95,17 +97,35 @@ proc setIsCurrentSectionActive*(self: Controller, active: bool) = proc userAuthenticationCanceled*(self: Controller) = self.tmpAuthenticationForJoinInProgress = false + self.tmpAuthenticationForEditSharedAddresses = false self.tmpRequestToJoinEnsName = "" - self.tmpRequestToJoinAirdropAddress = "" - self.tmpRequestToJoinAddressesToShare = @[] + self.tmpAirdropAddress = "" + self.tmpAddressesToShare = @[] proc requestToJoinCommunityAuthenticated*(self: Controller, password: string) = self.communityService.asyncRequestToJoinCommunity(self.sectionId, self.tmpRequestToJoinEnsName, - password, self.tmpRequestToJoinAddressesToShare, self.tmpRequestToJoinAirdropAddress) + password, self.tmpAddressesToShare, self.tmpAirdropAddress) self.tmpAuthenticationForJoinInProgress = false self.tmpRequestToJoinEnsName = "" - self.tmpRequestToJoinAirdropAddress = "" - self.tmpRequestToJoinAddressesToShare = @[] + self.tmpAirdropAddress = "" + self.tmpAddressesToShare = @[] + +proc editSharedAddressesAuthenticated*(self: Controller, password: string) = + self.communityService.asyncEditSharedAddresses( + self.sectionId, + password, + self.tmpAddressesToShare, + self.tmpAirdropAddress, + ) + self.tmpAuthenticationForEditSharedAddresses = false + self.tmpAirdropAddress = "" + self.tmpAddressesToShare = @[] + +proc userAuthenticated*(self: Controller, password: string) = + if self.tmpAuthenticationForJoinInProgress: + self.requestToJoinCommunityAuthenticated(password) + elif self.tmpAuthenticationForEditSharedAddresses: + self.editSharedAddressesAuthenticated(password) proc authenticate*(self: Controller, keyUid = "") = let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_MAIN_MODULE_AUTH_IDENTIFIER, @@ -115,8 +135,14 @@ proc authenticate*(self: Controller, keyUid = "") = proc authenticateToRequestToJoinCommunity*(self: Controller, ensName: string, addressesToShare: seq[string], airdropAddress: string) = self.tmpAuthenticationForJoinInProgress = true self.tmpRequestToJoinEnsName = ensName - self.tmpRequestToJoinAirdropAddress = airdropAddress - self.tmpRequestToJoinAddressesToShare = addressesToShare + self.tmpAirdropAddress = airdropAddress + self.tmpAddressesToShare = addressesToShare + self.authenticate() + +proc authenticateToEditSharedAddresses*(self: Controller, addressesToShare: seq[string], airdropAddress: string) = + self.tmpAuthenticationForEditSharedAddresses = true + self.tmpAirdropAddress = airdropAddress + self.tmpAddressesToShare = addressesToShare self.authenticate() proc getMySectionId*(self: Controller): string = @@ -204,7 +230,7 @@ proc init*(self: Controller) = let args = SharedKeycarModuleArgs(e) if args.uniqueIdentifier != UNIQUE_MAIN_MODULE_AUTH_IDENTIFIER: return - if self.tmpAuthenticationForJoinInProgress: + if self.tmpAuthenticationForJoinInProgress or self.tmpAuthenticationForEditSharedAddresses: self.delegate.onUserAuthenticated(args.pin, args.password, args.keyUid) if (self.isCommunitySection): diff --git a/src/app/modules/main/chat_section/io_interface.nim b/src/app/modules/main/chat_section/io_interface.nim index 53e09e8c29..9e791259ec 100644 --- a/src/app/modules/main/chat_section/io_interface.nim +++ b/src/app/modules/main/chat_section/io_interface.nim @@ -386,6 +386,11 @@ method requestToJoinCommunityWithAuthentication*(self: AccessInterface, ensName: airdropAddress: string) {.base.} = raise newException(ValueError, "No implementation available") +method editSharedAddressesWithAuthentication*(self: AccessInterface, addressesToShare: seq[string], airdropAddress: string) + {.base.} = + raise newException(ValueError, "No implementation available") + + method onCommunityCheckPermissionsToJoinResponse*(self: AccessInterface, checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index 7c3383a4a7..d0e98761dd 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -900,7 +900,7 @@ method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid: self.controller.userAuthenticationCanceled() return - self.controller.requestToJoinCommunityAuthenticated(password) + self.controller.userAuthenticated(password) method onMarkAllMessagesRead*(self: Module, chat: ChatDto) = self.updateBadgeNotifications(chat, hasUnreadMessages=false, unviewedMentionsCount=0) @@ -1330,6 +1330,9 @@ method requestToJoinCommunityWithAuthentication*(self: Module, ensName: string, airdropAddress: string) = self.controller.authenticateToRequestToJoinCommunity(ensName, addressesToShare, airdropAddress) +method editSharedAddressesWithAuthentication*(self: Module, addressesToShare: seq[string], airdropAddress: string) = + self.controller.authenticateToEditSharedAddresses(addressesToShare, airdropAddress) + method onDeactivateChatLoader*(self: Module, chatId: string) = self.view.chatsModel().disableChatLoader(chatId) diff --git a/src/app/modules/main/chat_section/view.nim b/src/app/modules/main/chat_section/view.nim index 5e0be57d77..235c3eb61b 100644 --- a/src/app/modules/main/chat_section/view.nim +++ b/src/app/modules/main/chat_section/view.nim @@ -251,6 +251,13 @@ QtObject: except Exception as e: echo "Error requesting to join community with authentication and shared addresses: ", e.msg + proc editSharedAddressesWithAuthentication*(self: View, addressesToShare: string, airdropAddress: string) {.slot.} = + try: + let addressesArray = map(parseJson(addressesToShare).getElems(), proc(x:JsonNode):string = x.getStr()) + self.delegate.editSharedAddressesWithAuthentication(addressesArray, airdropAddress) + except Exception as e: + echo "Error editing shared addresses with authentication: ", e.msg + proc joinGroupChatFromInvitation*(self: View, groupName: string, chatId: string, adminPK: string) {.slot.} = self.delegate.joinGroupChatFromInvitation(groupName, chatId, adminPK) diff --git a/src/app/modules/main/communities/controller.nim b/src/app/modules/main/communities/controller.nim index 7494849344..ed1412cd68 100644 --- a/src/app/modules/main/communities/controller.nim +++ b/src/app/modules/main/communities/controller.nim @@ -94,6 +94,14 @@ proc init*(self: Controller) = let args = CommunityRequestFailedArgs(e) self.delegate.communityAccessFailed(args.communityId, args.error) + self.events.on(SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_SUCCEEDED) do(e:Args): + let args = CommunityIdArgs(e) + self.delegate.communityEditSharedAddressesSucceeded(args.communityId) + + self.events.on(SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_FAILED) do(e:Args): + let args = CommunityRequestFailedArgs(e) + self.delegate.communityEditSharedAddressesFailed(args.communityId, args.error) + self.events.on(SIGNAL_DISCORD_CATEGORIES_AND_CHANNELS_EXTRACTED) do(e:Args): let args = DiscordCategoriesAndChannelsArgs(e) self.delegate.discordCategoriesAndChannelsExtracted(args.categories, args.channels, args.oldestMessageTimestamp, args.errors, args.errorsCount) diff --git a/src/app/modules/main/communities/io_interface.nim b/src/app/modules/main/communities/io_interface.nim index 6c44b9c189..bff31204f4 100644 --- a/src/app/modules/main/communities/io_interface.nim +++ b/src/app/modules/main/communities/io_interface.nim @@ -121,6 +121,12 @@ method communityAccessRequested*(self: AccessInterface, communityId: string) {.b method communityAccessFailed*(self: AccessInterface, communityId: string, error: string) {.base.} = raise newException(ValueError, "No implementation available") +method communityEditSharedAddressesSucceeded*(self: AccessInterface, communityId: string) {.base.} = + raise newException(ValueError, "No implementation available") + +method communityEditSharedAddressesFailed*(self: AccessInterface, communityId: string, error: string) {.base.} = + raise newException(ValueError, "No implementation available") + method requestExtractDiscordChannelsAndCategories*(self: AccessInterface, filesToImport: seq[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 f98246477e..40cd790abc 100644 --- a/src/app/modules/main/communities/module.nim +++ b/src/app/modules/main/communities/module.nim @@ -274,6 +274,12 @@ method communityAccessRequested*(self: Module, communityId: string) = method communityAccessFailed*(self: Module, communityId, error: string) = self.view.communityAccessFailed(communityId, error) +method communityEditSharedAddressesSucceeded*(self: Module, communityId: string) = + self.view.communityEditSharedAddressesSucceeded(communityId) + +method communityEditSharedAddressesFailed*(self: Module, communityId, error: string) = + self.view.communityEditSharedAddressesFailed(communityId, error) + method communityHistoryArchivesDownloadStarted*(self: Module, communityId: string) = self.view.setDownloadingCommunityHistoryArchives(true) diff --git a/src/app/modules/main/communities/view.nim b/src/app/modules/main/communities/view.nim index 22d5caf772..0e28406c81 100644 --- a/src/app/modules/main/communities/view.nim +++ b/src/app/modules/main/communities/view.nim @@ -110,6 +110,8 @@ QtObject: proc discordImportErrorsCountChanged*(self: View) {.signal.} proc communityAccessRequested*(self: View, communityId: string) {.signal.} proc communityAccessFailed*(self: View, communityId: string, error: string) {.signal.} + proc communityEditSharedAddressesSucceeded*(self: View, communityId: string) {.signal.} + proc communityEditSharedAddressesFailed*(self: View, communityId: string, error: string) {.signal.} proc communityInfoAlreadyRequested*(self: View) {.signal.} proc communityTagsChanged*(self: View) {.signal.} diff --git a/src/app_service/service/community/async_tasks.nim b/src/app_service/service/community/async_tasks.nim index bd950f599a..95ce7f4466 100644 --- a/src/app_service/service/community/async_tasks.nim +++ b/src/app_service/service/community/async_tasks.nim @@ -102,8 +102,29 @@ const asyncRequestToJoinCommunityTask: Task = proc(argEncoded: string) {.gcsafe, arg.finish(%* { "error": e.msg, "communityId": arg.communityId, - "ensName": arg.ensName, - "password": arg.password + }) + +type + AsyncEditSharedAddressesTaskArg = ref object of QObjectTaskArg + communityId: string + password: string + addressesToShare: seq[string] + airdropAddress: string + +const asyncEditSharedAddressesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncEditSharedAddressesTaskArg](argEncoded) + try: + let response = status_go.editSharedAddresses(arg.communityId, arg.password, arg.addressesToShare, + arg.airdropAddress) + arg.finish(%* { + "response": response, + "communityId": arg.communityId, + "error": "", + }) + except Exception as e: + arg.finish(%* { + "error": e.msg, + "communityId": arg.communityId, }) type diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index 0b42188358..4c585bb915 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -127,6 +127,8 @@ const SIGNAL_COMMUNITY_JOINED* = "communityJoined" const SIGNAL_COMMUNITY_SPECTATED* = "communitySpectated" const SIGNAL_COMMUNITY_MY_REQUEST_ADDED* = "communityMyRequestAdded" const SIGNAL_COMMUNITY_MY_REQUEST_FAILED* = "communityMyRequestFailed" +const SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_SUCCEEDED* = "communityEditSharedAddressesSucceded" +const SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_FAILED* = "communityEditSharedAddressesFailed" const SIGNAL_COMMUNITY_LEFT* = "communityLeft" const SIGNAL_COMMUNITY_CREATED* = "communityCreated" const SIGNAL_COMMUNITY_ADDED* = "communityAdded" @@ -1438,6 +1440,36 @@ QtObject: error: e.msg )) + proc asyncEditSharedAddresses*(self: Service, communityId: string, password: string, addressesToShare: seq[string], + airdropAddress: string) = + let arg = AsyncEditSharedAddressesTaskArg( + tptr: cast[ByteAddress](asyncEditSharedAddressesTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncEditSharedAddressesDone", + communityId: communityId, + password: password, + addressesToShare: addressesToShare, + airdropAddress: airdropAddress, + ) + self.threadpool.start(arg) + + proc onAsyncEditSharedAddressesDone*(self: Service, communityIdAndRpcResponse: string) {.slot.} = + let rpcResponseObj = communityIdAndRpcResponse.parseJson + try: + if (rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != ""): + raise newException(CatchableError, rpcResponseObj{"error"}.getStr) + + # If we need the returned shared addresses, use the value in members.revealed_accounts of the response + self.events.emit(SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_SUCCEEDED, CommunityIdArgs( + communityId: rpcResponseObj["communityId"].getStr, + )) + except Exception as e: + error "Error editing shared addresses", msg = e.msg + self.events.emit(SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_FAILED, CommunityRequestFailedArgs( + communityId: rpcResponseObj["communityId"].getStr, + error: e.msg + )) + proc asyncAcceptRequestToJoinCommunity*(self: Service, communityId: string, requestId: string) = try: let userKey = self.getUserPubKeyFromPendingRequest(communityId, requestId) diff --git a/src/backend/communities.nim b/src/backend/communities.nim index 7a2a95a4ea..f350b90014 100644 --- a/src/backend/communities.nim +++ b/src/backend/communities.nim @@ -43,7 +43,21 @@ proc requestToJoinCommunity*( "communityId": communityId, "ensName": ensName, "password": if passwordToSend != "": utils.hashPassword(password) else: "", - "addressesToShare": addressesToShare, + "addressesToReveal": addressesToShare, + "airdropAddress": airdropAddress, + }]) + +proc editSharedAddresses*( + communityId: string, + password: string, + addressesToShare: seq[string], + airdropAddress: string, + ): RpcResponse[JsonNode] {.raises: [Exception].} = + var passwordToSend = password + result = callPrivateRPC("editSharedAddressesForCommunity".prefix, %*[{ + "communityId": communityId, + "password": if passwordToSend != "": utils.hashPassword(password) else: "", + "addressesToReveal": addressesToShare, "airdropAddress": airdropAddress, }])