feat: introduce and handle `checkPermissionsToJoinCommunity()`
This is an improved version to check wether a user has permission to join a community and updating the join community view accordingly. We now asynchronously do all the checks in status-go and process a single result upon token permission updates, additions and deletions. Depends on: https://github.com/status-im/status-go/pull/3494 Closes #10481 #4939
This commit is contained in:
parent
3d6a5b1785
commit
fe491aba6e
|
@ -257,6 +257,7 @@ proc init*(self: Controller) =
|
|||
let args = CommunityTokenPermissionArgs(e)
|
||||
if (args.communityId == self.sectionId):
|
||||
self.delegate.onCommunityTokenPermissionCreated(args.communityId, args.tokenPermission)
|
||||
self.communityService.asyncCheckPermissionsToJoin(self.sectionId)
|
||||
|
||||
self.events.on(SIGNAL_COMMUNITY_TOKEN_PERMISSION_CREATION_FAILED) do(e: Args):
|
||||
let args = CommunityTokenPermissionArgs(e)
|
||||
|
@ -267,6 +268,8 @@ proc init*(self: Controller) =
|
|||
let args = CommunityTokenPermissionArgs(e)
|
||||
if (args.communityId == self.sectionId):
|
||||
self.delegate.onCommunityTokenPermissionUpdated(args.communityId, args.tokenPermission)
|
||||
self.communityService.asyncCheckPermissionsToJoin(self.sectionId)
|
||||
|
||||
|
||||
self.events.on(SIGNAL_COMMUNITY_TOKEN_PERMISSION_UPDATE_FAILED) do(e: Args):
|
||||
let args = CommunityTokenPermissionArgs(e)
|
||||
|
@ -277,12 +280,18 @@ proc init*(self: Controller) =
|
|||
let args = CommunityTokenPermissionRemovedArgs(e)
|
||||
if (args.communityId == self.sectionId):
|
||||
self.delegate.onCommunityTokenPermissionDeleted(args.communityId, args.permissionId)
|
||||
self.communityService.asyncCheckPermissionsToJoin(self.sectionId)
|
||||
|
||||
self.events.on(SIGNAL_COMMUNITY_TOKEN_PERMISSION_DELETION_FAILED) do(e: Args):
|
||||
let args = CommunityTokenPermissionArgs(e)
|
||||
if (args.communityId == self.sectionId):
|
||||
self.delegate.onCommunityTokenPermissionDeletionFailed(args.communityId)
|
||||
|
||||
self.events.on(SIGNAL_CHECK_PERMISSIONS_TO_JOIN_RESPONSE) do(e: Args):
|
||||
let args = CheckPermissionsToJoinResponseArgs(e)
|
||||
if (args.communityId == self.sectionId):
|
||||
self.delegate.onCommunityCheckPermissionsToJoinResponse(args.checkPermissionsToJoinResponse)
|
||||
|
||||
self.events.on(SIGNAL_COMMUNITY_TOKEN_METADATA_ADDED) do(e: Args):
|
||||
let args = CommunityTokenMetadataArgs(e)
|
||||
if (args.communityId == self.sectionId):
|
||||
|
@ -660,3 +669,6 @@ proc getContractAddressesForToken*(self: Controller, symbol: string): Table[int,
|
|||
|
||||
proc getCommunityTokenList*(self: Controller): seq[CommunityTokenDto] =
|
||||
return self.communityTokensService.getCommunityTokens(self.getMySectionId())
|
||||
|
||||
proc asyncCheckPermissionsToJoin*(self: Controller) =
|
||||
self.communityService.asyncCheckPermissionsToJoin(self.getMySectionId())
|
||||
|
|
|
@ -396,3 +396,6 @@ method requestToJoinCommunityWithAuthentication*(self: AccessInterface, communit
|
|||
|
||||
method onOwnedcollectiblesUpdated*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onCommunityCheckPermissionsToJoinResponse*(self: AccessInterface, checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
|
|
@ -280,23 +280,14 @@ proc rebuildCommunityTokenPermissionsModel(self: Module) =
|
|||
|
||||
let community = self.controller.getMyCommunity()
|
||||
var tokenPermissionsItems: seq[TokenPermissionItem] = @[]
|
||||
var allTokenRequirementsMet = false
|
||||
|
||||
for id, tokenPermission in community.tokenPermissions:
|
||||
# TODO: for startes we only deal with "become member" permissions
|
||||
if tokenPermission.`type` == TokenPermissionType.BecomeMember:
|
||||
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
|
||||
|
||||
# multiple permissions of the same type act as logical OR
|
||||
# so if at least one of them is fulfilled we can mark the view
|
||||
# as all lights green
|
||||
if tokenPermissionItem.tokenCriteriaMet:
|
||||
allTokenRequirementsMet = true
|
||||
|
||||
tokenPermissionsItems.add(tokenPermissionItem)
|
||||
|
||||
self.view.tokenPermissionsModel().setItems(tokenPermissionsItems)
|
||||
self.view.setAllTokenRequirementsMet(allTokenRequirementsMet)
|
||||
self.view.setRequiresTokenPermissionToJoin(tokenPermissionsItems.len > 0)
|
||||
|
||||
proc initCommunityTokenPermissionsModel(self: Module) =
|
||||
|
@ -397,6 +388,7 @@ method onChatsLoaded*(
|
|||
let community = self.controller.getMyCommunity()
|
||||
self.view.setAmIMember(community.joined)
|
||||
self.initCommunityTokenPermissionsModel()
|
||||
self.controller.asyncCheckPermissionsToJoin()
|
||||
|
||||
let activeChatId = self.controller.getActiveChatId()
|
||||
let isCurrentSectionActive = self.controller.getIsCurrentSectionActive()
|
||||
|
@ -792,33 +784,54 @@ method onCommunityTokenPermissionCreated*(self: Module, communityId: string, tok
|
|||
if tokenPermission.`type` == TokenPermissionType.BecomeMember:
|
||||
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
|
||||
|
||||
if tokenPermissionItem.tokenCriteriaMet:
|
||||
self.view.setAllTokenRequirementsMet(true)
|
||||
|
||||
self.view.tokenPermissionsModel.addItem(tokenPermissionItem)
|
||||
self.view.setRequiresTokenPermissionToJoin(true)
|
||||
singletonInstance.globalEvents.showCommunityTokenPermissionCreatedNotification(communityId, "Community permission created", "A token permission has been added")
|
||||
|
||||
method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) =
|
||||
let community = self.controller.getMyCommunity()
|
||||
|
||||
self.view.setAllTokenRequirementsMet(checkPermissionsToJoinResponse.satisfied)
|
||||
for id, criteriaResult in checkPermissionsToJoinResponse.permissions:
|
||||
if community.tokenPermissions.hasKey(id):
|
||||
|
||||
let tokenPermissionItem = self.view.tokenPermissionsModel.getItemById(id)
|
||||
|
||||
var updatedTokenCriteriaItems: seq[TokenCriteriaItem] = @[]
|
||||
var permissionSatisfied = true
|
||||
|
||||
for index, tokenCriteriaItem in tokenPermissionItem.getTokenCriteria().getItems():
|
||||
|
||||
let updatedTokenCriteriaItem = initTokenCriteriaItem(
|
||||
tokenCriteriaItem.symbol,
|
||||
tokenCriteriaItem.name,
|
||||
tokenCriteriaItem.amount,
|
||||
tokenCriteriaItem.`type`,
|
||||
tokenCriteriaItem.ensPattern,
|
||||
criteriaResult.criteria[index]
|
||||
)
|
||||
|
||||
if criteriaResult.criteria[index] == false:
|
||||
permissionSatisfied = false
|
||||
|
||||
updatedTokenCriteriaItems.add(updatedTokenCriteriaItem)
|
||||
|
||||
let updatedTokenPermissionItem = initTokenPermissionItem(
|
||||
tokenPermissionItem.id,
|
||||
tokenPermissionItem.`type`,
|
||||
updatedTokenCriteriaItems,
|
||||
@[], # TODO: handle chat list items
|
||||
tokenPermissionItem.isPrivate,
|
||||
permissionSatisfied
|
||||
)
|
||||
self.view.tokenPermissionsModel.updateItem(id, updatedTokenPermissionItem)
|
||||
|
||||
|
||||
method onCommunityTokenPermissionUpdated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) =
|
||||
if tokenPermission.`type` == TokenPermissionType.BecomeMember:
|
||||
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
|
||||
self.view.tokenPermissionsModel.updateItem(tokenPermission.id, tokenPermissionItem)
|
||||
if tokenPermissionItem.tokenCriteriaMet:
|
||||
self.view.setAllTokenRequirementsMet(true)
|
||||
return
|
||||
|
||||
# we now need to check whether any other permission criteria where met.
|
||||
let community = self.controller.getMyCommunity()
|
||||
for id, permission in community.tokenPermissions:
|
||||
if id != tokenPermission.id:
|
||||
for tc in permission.tokenCriteria:
|
||||
let balance = self.controller.allAccountsTokenBalance(tc.symbol)
|
||||
let amount = tc.amount.parseFloat
|
||||
let tokenCriteriaMet = balance >= amount
|
||||
if tokenCriteriaMet:
|
||||
return
|
||||
|
||||
self.view.setAllTokenRequirementsMet(false)
|
||||
singletonInstance.globalEvents.showCommunityTokenPermissionUpdatedNotification(communityId, "Community permission updated", "A token permission has been updated")
|
||||
|
||||
method onCommunityTokenPermissionCreationFailed*(self: Module, communityId: string) =
|
||||
|
@ -1283,33 +1296,17 @@ method requestToJoinCommunityWithAuthentication*(self: Module, communityId: stri
|
|||
|
||||
proc buildTokenPermissionItem*(self: Module, tokenPermission: CommunityTokenPermissionDto): TokenPermissionItem =
|
||||
var tokenCriteriaItems: seq[TokenCriteriaItem] = @[]
|
||||
var allTokenCriteriaMet = true
|
||||
|
||||
for tc in tokenPermission.tokenCriteria:
|
||||
|
||||
var tokenCriteriaMet = false
|
||||
let amount = tc.amount.parseFloat
|
||||
|
||||
if tc.`type` == TokenType.ERC20:
|
||||
let balance = self.controller.allAccountsTokenBalance(tc.symbol)
|
||||
tokenCriteriaMet = balance >= amount
|
||||
|
||||
if tc.`type` == TokenType.ERC721:
|
||||
for chainId, address in tc.contractAddresses:
|
||||
tokenCriteriaMet = self.controller.ownsCollectible(chainId, address, tc.tokenIds)
|
||||
if tokenCriteriaMet:
|
||||
break
|
||||
|
||||
let tokenCriteriaItem = initTokenCriteriaItem(
|
||||
tc.symbol,
|
||||
tc.name,
|
||||
amount,
|
||||
tc.amount.parseFloat,
|
||||
tc.`type`.int,
|
||||
tc.ensPattern,
|
||||
tokenCriteriaMet
|
||||
false # tokenCriteriaMet will be updated by a call to checkPermissionsToJoin
|
||||
)
|
||||
if not tokenCriteriaMet:
|
||||
allTokenCriteriaMet = false
|
||||
|
||||
tokenCriteriaItems.add(tokenCriteriaItem)
|
||||
|
||||
|
@ -1319,7 +1316,7 @@ proc buildTokenPermissionItem*(self: Module, tokenPermission: CommunityTokenPerm
|
|||
tokenCriteriaItems,
|
||||
@[], # TODO: handle chat list items
|
||||
tokenPermission.isPrivate,
|
||||
allTokenCriteriaMet
|
||||
false # allTokenCriteriaMet will be update by a call to checkPermissinosToJoin
|
||||
)
|
||||
|
||||
return tokenPermissionItem
|
||||
|
|
|
@ -103,6 +103,13 @@ QtObject:
|
|||
self.endRemoveRows()
|
||||
self.countChanged()
|
||||
|
||||
proc getItemById*(self: TokenPermissionsModel, permissionId: string): TokenPermissionItem =
|
||||
let idx = self.findIndexById(permissionId)
|
||||
if(idx == -1):
|
||||
return
|
||||
|
||||
return self.items[idx]
|
||||
|
||||
proc updateItem*(self: TokenPermissionsModel, permissionId: string, item: TokenPermissionItem) =
|
||||
let idx = self.findIndexById(permissionId)
|
||||
if(idx == -1):
|
||||
|
|
|
@ -101,4 +101,23 @@ const asyncRequestToJoinCommunityTask: Task = proc(argEncoded: string) {.gcsafe,
|
|||
"communityId": arg.communityId,
|
||||
"ensName": arg.ensName,
|
||||
"password": arg.password
|
||||
})
|
||||
})
|
||||
|
||||
type
|
||||
AsyncCheckPermissionsToJoinTaskArg = ref object of QObjectTaskArg
|
||||
communityId: string
|
||||
|
||||
const asyncCheckPermissionsToJoinTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[AsyncCheckPermissionsToJoinTaskArg](argEncoded)
|
||||
try:
|
||||
let response = status_go.checkPermissionsToJoinCommunity(arg.communityId)
|
||||
arg.finish(%* {
|
||||
"response": response,
|
||||
"communityId": arg.communityId,
|
||||
"error": "",
|
||||
})
|
||||
except Exception as e:
|
||||
arg.finish(%* {
|
||||
"communityId": arg.communityId,
|
||||
"error": e.msg,
|
||||
})
|
||||
|
|
|
@ -136,6 +136,18 @@ type DiscordImportTaskProgress* = object
|
|||
stopped*: bool
|
||||
state*: string
|
||||
|
||||
type AccountChainIDsCombinationDto* = object
|
||||
address*: string
|
||||
chainIds*: seq[int]
|
||||
|
||||
type CheckPermissionToJoinResultDto* = object
|
||||
criteria*: seq[bool]
|
||||
|
||||
type CheckPermissionsToJoinResponseDto* = object
|
||||
satisfied*: bool
|
||||
permissions*: Table[string, CheckPermissionToJoinResultDto]
|
||||
validCombinations*: seq[AccountChainIDsCombinationDto]
|
||||
|
||||
proc toCommunityAdminSettingsDto*(jsonObj: JsonNode): CommunityAdminSettingsDto =
|
||||
result = CommunityAdminSettingsDto()
|
||||
discard jsonObj.getProp("pinMessageAllMembersEnabled", result.pinMessageAllMembersEnabled)
|
||||
|
@ -246,6 +258,36 @@ proc toCommunityTokenPermissionDto*(jsonObj: JsonNode): CommunityTokenPermission
|
|||
if jsonObj.hasKey("key"):
|
||||
discard jsonObj.getProp("key", result.id)
|
||||
|
||||
proc toCheckPermissionToJoinResultDto*(jsonObj: JsonNode): CheckPermissionToJoinResultDto =
|
||||
result = CheckPermissionToJoinResultDto()
|
||||
var criteriaObj: JsonNode
|
||||
if(jsonObj.getProp("criteria", criteriaObj) and criteriaObj.kind == JArray):
|
||||
for c in criteriaObj:
|
||||
result.criteria.add(c.getBool)
|
||||
|
||||
proc toAccountChainIDsCombinationDto*(jsonObj: JsonNode): AccountChainIDsCombinationDto =
|
||||
result = AccountChainIDsCombinationDto()
|
||||
discard jsonObj.getProp("address", result.address)
|
||||
var chainIdsObj: JsonNode
|
||||
if(jsonObj.getProp("chainIds", chainIdsObj) and chainIdsObj.kind == JArray):
|
||||
for chainId in chainIdsObj:
|
||||
result.chainIds.add(chainId.getInt)
|
||||
|
||||
proc toCheckPermissionsToJoinResponseDto*(jsonObj: JsonNode): CheckPermissionsToJoinResponseDto =
|
||||
result = CheckPermissionsToJoinResponseDto()
|
||||
discard jsonObj.getProp("satisfied", result.satisfied)
|
||||
|
||||
var validCombinationsObj: JsonNode
|
||||
if(jsonObj.getProp("validCombinations", validCombinationsObj) and validCombinationsObj.kind == JArray):
|
||||
for validCombination in validCombinationsObj:
|
||||
result.validCombinations.add(validCombination.toAccountChainIDsCombinationDto)
|
||||
|
||||
var permissionsObj: JsonNode
|
||||
if(jsonObj.getProp("permissions", permissionsObj) and permissionsObj.kind == JObject):
|
||||
result.permissions = initTable[string, CheckPermissionToJoinResultDto]()
|
||||
for permissionId, permission in permissionsObj:
|
||||
result.permissions[permissionId] = permission.toCheckPermissionToJoinResultDto
|
||||
|
||||
proc toCommunityDto*(jsonObj: JsonNode): CommunityDto =
|
||||
result = CommunityDto()
|
||||
discard jsonObj.getProp("id", result.id)
|
||||
|
|
|
@ -111,6 +111,10 @@ type
|
|||
totalChunksCount*: int
|
||||
currentChunk*: int
|
||||
|
||||
CheckPermissionsToJoinResponseArgs* = ref object of Args
|
||||
communityId*: string
|
||||
checkPermissionsToJoinResponse*: CheckPermissionsToJoinResponseDto
|
||||
|
||||
# Signals which may be emitted by this service:
|
||||
const SIGNAL_COMMUNITY_DATA_LOADED* = "communityDataLoaded"
|
||||
const SIGNAL_COMMUNITY_JOINED* = "communityJoined"
|
||||
|
@ -172,6 +176,8 @@ const SIGNAL_COMMUNITY_INFO_ALREADY_REQUESTED* = "communityInfoAlreadyRequested"
|
|||
const TOKEN_PERMISSIONS_ADDED = "tokenPermissionsAdded"
|
||||
const TOKEN_PERMISSIONS_MODIFIED = "tokenPermissionsModified"
|
||||
|
||||
const SIGNAL_CHECK_PERMISSIONS_TO_JOIN_RESPONSE* = "checkPermissionsToJoinResponse"
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Service* = ref object of QObject
|
||||
|
@ -1362,6 +1368,33 @@ QtObject:
|
|||
|
||||
self.events.emit(SIGNAL_COMMUNITY_DATA_IMPORTED, CommunityArgs(community: community))
|
||||
|
||||
proc asyncCheckPermissionsToJoin*(self: Service, communityId: string) =
|
||||
try:
|
||||
let arg = AsyncCheckPermissionsToJoinTaskArg(
|
||||
tptr: cast[ByteAddress](asyncCheckPermissionsToJoinTask),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onAsyncCheckPermissionsToJoinDone",
|
||||
communityId: communityId
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
except Exception as e:
|
||||
error "Error checking permissions to join community", msg = e.msg
|
||||
|
||||
proc onAsyncCheckPermissionsToJoinDone*(self: Service, rpcResponse: string) {.slot.} =
|
||||
try:
|
||||
let rpcResponseObj = rpcResponse.parseJson
|
||||
if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "":
|
||||
let error = Json.decode($rpcResponseObj["error"], RpcError)
|
||||
error "Error requesting community info", msg = error.message
|
||||
return
|
||||
|
||||
let communityId = rpcResponseObj{"communityId"}.getStr()
|
||||
let checkPermissionsToJoinResponse = rpcResponseObj["response"]["result"].toCheckPermissionsToJoinResponseDto
|
||||
self.events.emit(SIGNAL_CHECK_PERMISSIONS_TO_JOIN_RESPONSE, CheckPermissionsToJoinResponseArgs(communityId: communityId, checkPermissionsToJoinResponse: checkPermissionsToJoinResponse))
|
||||
except Exception as e:
|
||||
let errMsg = e.msg
|
||||
error "error checking permissions to join: ", errMsg
|
||||
|
||||
proc asyncRequestToJoinCommunity*(self: Service, communityId: string, ensName: string, password: string) =
|
||||
try:
|
||||
let arg = AsyncRequestToJoinCommunityTaskArg(
|
||||
|
|
|
@ -39,6 +39,11 @@ proc requestToJoinCommunity*(communityId: string, ensName: string, password: str
|
|||
"password": if passwordToSend != "": utils.hashPassword(password) else: ""
|
||||
}])
|
||||
|
||||
proc checkPermissionsToJoinCommunity*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
result = callPrivateRPC("checkPermissionsToJoinCommunity".prefix, %*[{
|
||||
"communityId": communityId
|
||||
}])
|
||||
|
||||
proc myPendingRequestsToJoin*(): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
result = callPrivateRPC("myPendingRequestsToJoin".prefix)
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 87ce6cfbcd8c6dd9ce3f7dee8b2a3f7b43738e81
|
||||
Subproject commit 1a2ca21070456e153aac27b8a14afa14006652ef
|
Loading…
Reference in New Issue