feat(airdrop): get revealed accounts using new API instead of desc

Fixes #11817

Instead of getting revealed accounts from the community description (it's no longer available), uses the new `getRevealedAccountsForAllMembers` API. Uses it async so that we do not slow the start process. The model is updated correctly when we finish loading them.
This commit is contained in:
Jonathan Rainville 2023-08-07 15:27:56 -04:00
parent 9e89bd4f1a
commit 24d26cc038
13 changed files with 156 additions and 45 deletions

View File

@ -133,7 +133,6 @@ proc addChatMember(self: Module, member: ChatMember) =
memberRole = member.role,
joined = member.joined,
isUntrustworthy = contactDetails.dto.trustStatus == TrustStatus.Untrustworthy,
airdropAddress = member.airdropAccount.address,
))
method onChatMembersAdded*(self: Module, ids: seq[string]) =

View File

@ -1,4 +1,4 @@
import chronicles, stint
import chronicles, stint, tables
import ../../global/app_sections_config as conf
import ../../global/global_singleton
import ../../global/app_signals
@ -248,6 +248,10 @@ proc init*(self: Controller) =
let args = CommunityArgs(e)
self.delegate.communityEdited(args.community)
self.events.on(SIGNAL_COMMUNITY_MEMBERS_REVEALED_ACCOUNTS_LOADED) do(e:Args):
let args = CommunityMembersRevealedAccountsArgs(e)
self.delegate.communityMembersRevealedAccountsLoaded(args.communityId, args.membersRevealedAccounts)
self.events.on(SIGNAL_COMMUNITY_PRIVATE_KEY_REMOVED) do(e:Args):
let args = CommunityArgs(e)
self.delegate.communityEdited(args.community)
@ -524,3 +528,6 @@ proc getColorHash*(self: Controller, pubkey: string): ColorHashDto =
proc getColorId*(self: Controller, pubkey: string): int =
procs_from_visual_identity_service.colorIdOf(pubkey)
proc asyncGetRevealedAccountsForAllMembers*(self: Controller, communityId: string) =
self.communityService.asyncGetRevealedAccountsForAllMembers(communityId)

View File

@ -330,6 +330,9 @@ method windowActivated*(self: AccessInterface) {.base.} =
method windowDeactivated*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method communityMembersRevealedAccountsLoaded*(self: AccessInterface, communityId: string, membersRevealedAccounts: MembersRevealedAccounts) {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c

View File

@ -262,6 +262,11 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
communityTokensItems = communityTokens.map(proc(tokenDto: CommunityTokenDto): TokenItem =
result = self.createTokenItem(tokenDto)
)
# Get community members' revealed accounts
# We will update the model later when we finish loading the accounts
# TODO add TokenMaster here too when it's available
if communityDetails.memberRole == MemberRole.Owner:
self.controller.asyncGetRevealedAccountsForAllMembers(channelGroup.id)
let unviewedCount = channelGroup.unviewedMessagesCount
let notificationsCount = channelGroup.unviewedMentionsCount
@ -312,9 +317,8 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
isContact = contactDetails.dto.isContact,
isVerified = contactDetails.dto.isContactVerified(),
memberRole = member.role,
airdropAddress = member.airdropAccount.address,
membershipRequestState = MembershipRequestState.Accepted
)),
)),
# pendingRequestsToJoin
if (isCommunity): communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem(
x.id,
@ -1305,3 +1309,13 @@ method windowActivated*[T](self: Module[T]) =
method windowDeactivated*[T](self: Module[T]) =
self.controller.speedupArchivesImport()
method communityMembersRevealedAccountsLoaded*[T](self: Module[T], communityId: string, membersRevealedAccounts: MembersRevealedAccounts) =
var communityMembersAirdropAddress: Table[string, string]
for pubkey, revealedAccounts in membersRevealedAccounts.pairs:
for revealedAccount in revealedAccounts:
if revealedAccount.isAirdropAddress:
communityMembersAirdropAddress[pubkey] = revealedAccount.address
discard
self.view.model.setMembersAirdropAddress(communityId, communityMembersAirdropAddress)

View File

@ -298,19 +298,33 @@ QtObject:
ModelRole.IsUntrustworthy.int,
])
proc setOnlineStatus*(self: Model, pubKey: string,
onlineStatus: OnlineStatus) =
let ind = self.findIndexForMember(pubKey)
if(ind == -1):
proc setOnlineStatus*(self: Model, pubKey: string, onlineStatus: OnlineStatus) =
let idx = self.findIndexForMember(pubKey)
if(idx == -1):
return
if(self.items[ind].onlineStatus == onlineStatus):
if(self.items[idx].onlineStatus == onlineStatus):
return
var item = self.items[ind]
item.onlineStatus = onlineStatus
self.removeItemWithIndex(ind)
self.addItem(item)
self.items[idx].onlineStatus = onlineStatus
let index = self.createIndex(idx, 0, nil)
self.dataChanged(index, index, @[
ModelRole.OnlineStatus.int
])
proc setAirdropAddress*(self: Model, pubKey: string, airdropAddress: string) =
let idx = self.findIndexForMember(pubKey)
if(idx == -1):
return
if(self.items[idx].airdropAddress == airdropAddress):
return
self.items[idx].airdropAddress = airdropAddress
let index = self.createIndex(idx, 0, nil)
self.dataChanged(index, index, @[
ModelRole.AirdropAddress.int
])
# TODO: rename me to removeItemByPubkey
proc removeItemById*(self: Model, pubKey: string) =

View File

@ -445,4 +445,13 @@ QtObject:
"nbMembers": item.members.getCount(),
"encrypted": item.encrypted,
}
return $jsonObj
return $jsonObj
proc setMembersAirdropAddress*(self: SectionModel, id: string, communityMembersAirdropAddress: Table[string, string]) =
let index = self.getItemIndex(id)
if (index == -1):
return
for pubkey, revealedAccounts in communityMembersAirdropAddress.pairs:
self.items[index].members.setAirdropAddress(pubkey, revealedAccounts)

View File

@ -35,16 +35,10 @@ type
large*: string
banner*: string
type RevealedAccount* = object
address*: string
chainIds*: seq[int]
isAirdropAddress*: bool
type ChatMember* = object
id*: string
joined*: bool
role*: MemberRole
airdropAccount*: RevealedAccount
type CheckPermissionsResultDto* = object
criteria*: seq[bool]
@ -242,22 +236,6 @@ proc toChannelMember*(jsonObj: JsonNode, memberId: string, joined: bool): ChatMe
if(jsonObj.getProp("roles", rolesObj)):
for roleObj in rolesObj:
roles.add(roleObj.getInt)
var revealedAccountsObj: JsonNode
if jsonObj.getProp("revealed_accounts", revealedAccountsObj):
for revealedAccountObj in revealedAccountsObj:
if revealedAccountObj{"isAirdropAddress"}.getBool:
var chainIdsObj: JsonNode
var chainIds: seq[int] = @[]
if revealedAccountObj.getProp("chain_ids", chainIdsObj):
for chainIdObj in chainIdsObj:
chainIds.add(chainIdObj.getInt)
result.airdropAccount = RevealedAccount(
address: revealedAccountObj["address"].getStr,
chainIds: chainIds,
isAirdropAddress: true,
)
result.role = MemberRole.None
if roles.contains(MemberRole.Owner.int):

View File

@ -185,3 +185,22 @@ const asyncImportCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcal
arg.finish(%* {
"error": e.msg,
})
type
AsyncGetRevealedAccountsForAllMembersArg = ref object of QObjectTaskArg
communityId: string
const asyncGetRevealedAccountsForAllMembersTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncGetRevealedAccountsForAllMembersArg](argEncoded)
try:
let response = status_go.getRevealedAccountsForAllMembers(arg.communityId)
arg.finish(%* {
"communityId": arg.communityId,
"response": response,
"error": "",
})
except Exception as e:
arg.finish(%* {
"communityId": arg.communityId,
"error": e.msg,
})

View File

@ -106,6 +106,13 @@ type CommunityMetricsDto* = object
metricsType*: CommunityMetricsType
intervals*: seq[MetricsIntervalDto]
type RevealedAccount* = object
address*: string
chainIds*: seq[int]
isAirdropAddress*: bool
type MembersRevealedAccounts* = Table[string, seq[RevealedAccount]]
type CommunityDto* = object
id*: string
memberRole*: MemberRole
@ -524,3 +531,26 @@ proc parseDiscordChannels*(response: JsonNode): seq[DiscordChannelDto] =
if (response["discordChannels"].kind == JArray):
for channel in response["discordChannels"].items():
result.add(channel.toDiscordChannelDto())
proc toRevealedAccount*(revealedAccountObj: JsonNode): RevealedAccount =
var chainIdsObj: JsonNode
var chainIds: seq[int] = @[]
if revealedAccountObj.getProp("chain_ids", chainIdsObj):
for chainIdObj in chainIdsObj:
chainIds.add(chainIdObj.getInt)
result = RevealedAccount(
address: revealedAccountObj["address"].getStr,
chainIds: chainIds,
isAirdropAddress: revealedAccountObj{"isAirdropAddress"}.getBool,
)
proc toRevealedAccounts*(revealedAccountsObj: JsonNode): seq[RevealedAccount] =
result = @[]
for revealedAccountObj in revealedAccountsObj:
result.add(revealedAccountObj.toRevealedAccount())
proc toMembersRevealedAccounts*(membersRevealedAccountsObj: JsonNode): MembersRevealedAccounts =
result = initTable[string, seq[RevealedAccount]]()
for (pubkey, revealedAccountsObj) in membersRevealedAccountsObj.pairs:
result[pubkey] = revealedAccountsObj.toRevealedAccounts()

View File

@ -125,6 +125,10 @@ type
communityId*: string
metricsType*: CommunityMetricsType
CommunityMembersRevealedAccountsArgs* = ref object of Args
communityId*: string
membersRevealedAccounts*: MembersRevealedAccounts
# Signals which may be emitted by this service:
const SIGNAL_COMMUNITY_DATA_LOADED* = "communityDataLoaded"
const SIGNAL_COMMUNITY_JOINED* = "communityJoined"
@ -133,6 +137,7 @@ 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_MEMBERS_REVEALED_ACCOUNTS_LOADED* = "communityMembersRevealedAccountsLoaded"
const SIGNAL_COMMUNITY_LEFT* = "communityLeft"
const SIGNAL_COMMUNITY_CREATED* = "communityCreated"
const SIGNAL_COMMUNITY_ADDED* = "communityAdded"
@ -2011,3 +2016,32 @@ QtObject:
result = response.result.getStr
except Exception as e:
error "error while getting community public key", msg = e.msg
proc asyncGetRevealedAccountsForAllMembers*(self: Service, communityId: string) =
let arg = AsyncGetRevealedAccountsForAllMembersArg(
tptr: cast[ByteAddress](asyncGetRevealedAccountsForAllMembersTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncGetRevealedAccountsForAllMembersCompleted",
communityId: communityId,
)
self.threadpool.start(arg)
proc onAsyncGetRevealedAccountsForAllMembersCompleted*(self: Service, response: string) {.slot.} =
try:
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 revealedAccounts = rpcResponseObj["response"]["result"].toMembersRevealedAccounts
self.events.emit(SIGNAL_COMMUNITY_MEMBERS_REVEALED_ACCOUNTS_LOADED, CommunityMembersRevealedAccountsArgs(
communityId: rpcResponseObj["communityId"].getStr,
membersRevealedAccounts: revealedAccounts
))
except Exception as e:
error "error while getting the community members' revealed addressesses", msg = e.msg

View File

@ -61,6 +61,17 @@ proc editSharedAddresses*(
"airdropAddress": airdropAddress,
}])
proc getRevealedAccountsForMember*(
communityId: string,
memberPubkey: string,
): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("getRevealedAccounts".prefix, %*[communityId, memberPubkey])
proc getRevealedAccountsForAllMembers*(
communityId: string,
): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("getRevealedAccountsForAllMembers".prefix, %*[communityId])
proc checkPermissionsToJoinCommunity*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("checkPermissionsToJoinCommunity".prefix, %*[{
"communityId": communityId

View File

@ -504,14 +504,7 @@ StatusSectionLayout {
assetsModel: assetsModelLoader.item
collectiblesModel: collectiblesModelLoader.item
membersModel: {
const chatContentModule = root.rootStore.currentChatContentModule()
if (!chatContentModule || !chatContentModule.usersModule) {
// New communities have no chats, so no chatContentModule
return null
}
return chatContentModule.usersModule.model
}
membersModel: community.members
accountsModel: SortFilterProxyModel {
sourceModel: root.rootStore.accounts

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit a63e417f9f6c779300f35b51998770742f5e363f
Subproject commit b4b0d26aa4c3f11ee66e3aeb404834cd8c5e48c8