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, memberRole = member.role,
joined = member.joined, joined = member.joined,
isUntrustworthy = contactDetails.dto.trustStatus == TrustStatus.Untrustworthy, isUntrustworthy = contactDetails.dto.trustStatus == TrustStatus.Untrustworthy,
airdropAddress = member.airdropAccount.address,
)) ))
method onChatMembersAdded*(self: Module, ids: seq[string]) = 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/app_sections_config as conf
import ../../global/global_singleton import ../../global/global_singleton
import ../../global/app_signals import ../../global/app_signals
@ -248,6 +248,10 @@ proc init*(self: Controller) =
let args = CommunityArgs(e) let args = CommunityArgs(e)
self.delegate.communityEdited(args.community) 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): self.events.on(SIGNAL_COMMUNITY_PRIVATE_KEY_REMOVED) do(e:Args):
let args = CommunityArgs(e) let args = CommunityArgs(e)
self.delegate.communityEdited(args.community) self.delegate.communityEdited(args.community)
@ -524,3 +528,6 @@ proc getColorHash*(self: Controller, pubkey: string): ColorHashDto =
proc getColorId*(self: Controller, pubkey: string): int = proc getColorId*(self: Controller, pubkey: string): int =
procs_from_visual_identity_service.colorIdOf(pubkey) 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.} = method windowDeactivated*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") 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 # This way (using concepts) is used only for the modules managed by AppController
type type
DelegateInterface* = concept c DelegateInterface* = concept c

View File

@ -262,6 +262,11 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
communityTokensItems = communityTokens.map(proc(tokenDto: CommunityTokenDto): TokenItem = communityTokensItems = communityTokens.map(proc(tokenDto: CommunityTokenDto): TokenItem =
result = self.createTokenItem(tokenDto) 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 unviewedCount = channelGroup.unviewedMessagesCount
let notificationsCount = channelGroup.unviewedMentionsCount let notificationsCount = channelGroup.unviewedMentionsCount
@ -312,7 +317,6 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
isContact = contactDetails.dto.isContact, isContact = contactDetails.dto.isContact,
isVerified = contactDetails.dto.isContactVerified(), isVerified = contactDetails.dto.isContactVerified(),
memberRole = member.role, memberRole = member.role,
airdropAddress = member.airdropAccount.address,
membershipRequestState = MembershipRequestState.Accepted membershipRequestState = MembershipRequestState.Accepted
)), )),
# pendingRequestsToJoin # pendingRequestsToJoin
@ -1305,3 +1309,13 @@ method windowActivated*[T](self: Module[T]) =
method windowDeactivated*[T](self: Module[T]) = method windowDeactivated*[T](self: Module[T]) =
self.controller.speedupArchivesImport() 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, ModelRole.IsUntrustworthy.int,
]) ])
proc setOnlineStatus*(self: Model, pubKey: string, proc setOnlineStatus*(self: Model, pubKey: string, onlineStatus: OnlineStatus) =
onlineStatus: OnlineStatus) = let idx = self.findIndexForMember(pubKey)
let ind = self.findIndexForMember(pubKey) if(idx == -1):
if(ind == -1):
return return
if(self.items[ind].onlineStatus == onlineStatus): if(self.items[idx].onlineStatus == onlineStatus):
return return
var item = self.items[ind] self.items[idx].onlineStatus = onlineStatus
item.onlineStatus = onlineStatus let index = self.createIndex(idx, 0, nil)
self.removeItemWithIndex(ind) self.dataChanged(index, index, @[
self.addItem(item) 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 # TODO: rename me to removeItemByPubkey
proc removeItemById*(self: Model, pubKey: string) = proc removeItemById*(self: Model, pubKey: string) =

View File

@ -446,3 +446,12 @@ QtObject:
"encrypted": item.encrypted, "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 large*: string
banner*: string banner*: string
type RevealedAccount* = object
address*: string
chainIds*: seq[int]
isAirdropAddress*: bool
type ChatMember* = object type ChatMember* = object
id*: string id*: string
joined*: bool joined*: bool
role*: MemberRole role*: MemberRole
airdropAccount*: RevealedAccount
type CheckPermissionsResultDto* = object type CheckPermissionsResultDto* = object
criteria*: seq[bool] criteria*: seq[bool]
@ -243,22 +237,6 @@ proc toChannelMember*(jsonObj: JsonNode, memberId: string, joined: bool): ChatMe
for roleObj in rolesObj: for roleObj in rolesObj:
roles.add(roleObj.getInt) 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 result.role = MemberRole.None
if roles.contains(MemberRole.Owner.int): if roles.contains(MemberRole.Owner.int):
result.role = MemberRole.Owner result.role = MemberRole.Owner

View File

@ -185,3 +185,22 @@ const asyncImportCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcal
arg.finish(%* { arg.finish(%* {
"error": e.msg, "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 metricsType*: CommunityMetricsType
intervals*: seq[MetricsIntervalDto] intervals*: seq[MetricsIntervalDto]
type RevealedAccount* = object
address*: string
chainIds*: seq[int]
isAirdropAddress*: bool
type MembersRevealedAccounts* = Table[string, seq[RevealedAccount]]
type CommunityDto* = object type CommunityDto* = object
id*: string id*: string
memberRole*: MemberRole memberRole*: MemberRole
@ -524,3 +531,26 @@ proc parseDiscordChannels*(response: JsonNode): seq[DiscordChannelDto] =
if (response["discordChannels"].kind == JArray): if (response["discordChannels"].kind == JArray):
for channel in response["discordChannels"].items(): for channel in response["discordChannels"].items():
result.add(channel.toDiscordChannelDto()) 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 communityId*: string
metricsType*: CommunityMetricsType metricsType*: CommunityMetricsType
CommunityMembersRevealedAccountsArgs* = ref object of Args
communityId*: string
membersRevealedAccounts*: MembersRevealedAccounts
# Signals which may be emitted by this service: # Signals which may be emitted by this service:
const SIGNAL_COMMUNITY_DATA_LOADED* = "communityDataLoaded" const SIGNAL_COMMUNITY_DATA_LOADED* = "communityDataLoaded"
const SIGNAL_COMMUNITY_JOINED* = "communityJoined" 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_MY_REQUEST_FAILED* = "communityMyRequestFailed"
const SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_SUCCEEDED* = "communityEditSharedAddressesSucceded" const SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_SUCCEEDED* = "communityEditSharedAddressesSucceded"
const SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_FAILED* = "communityEditSharedAddressesFailed" const SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_FAILED* = "communityEditSharedAddressesFailed"
const SIGNAL_COMMUNITY_MEMBERS_REVEALED_ACCOUNTS_LOADED* = "communityMembersRevealedAccountsLoaded"
const SIGNAL_COMMUNITY_LEFT* = "communityLeft" const SIGNAL_COMMUNITY_LEFT* = "communityLeft"
const SIGNAL_COMMUNITY_CREATED* = "communityCreated" const SIGNAL_COMMUNITY_CREATED* = "communityCreated"
const SIGNAL_COMMUNITY_ADDED* = "communityAdded" const SIGNAL_COMMUNITY_ADDED* = "communityAdded"
@ -2011,3 +2016,32 @@ QtObject:
result = response.result.getStr result = response.result.getStr
except Exception as e: except Exception as e:
error "error while getting community public key", msg = e.msg 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, "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].} = proc checkPermissionsToJoinCommunity*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("checkPermissionsToJoinCommunity".prefix, %*[{ result = callPrivateRPC("checkPermissionsToJoinCommunity".prefix, %*[{
"communityId": communityId "communityId": communityId

View File

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

2
vendor/status-go vendored

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