feat(@desktop/community): Community admin permissions (#10909)

* chore:
- replaced admin bool to memberRole
- activate admin permissions
- configured admin restrictions
This commit is contained in:
Mykhailo Prakhov 2023-06-14 18:00:41 +02:00 committed by GitHub
parent 4849230054
commit 82a1ed2f7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 268 additions and 208 deletions

View File

@ -1,5 +1,6 @@
import NimQml
import item
import ../../../../app_service/common/types
QtObject:
type ActiveItem* = ref object of QObject
@ -46,13 +47,13 @@ QtObject:
QtProperty[string] name:
read = getName
proc getAmIChatAdmin(self: ActiveItem): bool {.slot.} =
proc getMemberRole(self: ActiveItem): int {.slot.} =
if(self.item.isNil):
return false
return self.item.amIChatAdmin
return MemberRole.None.int
return self.item.memberRole.int
QtProperty[bool] amIChatAdmin:
read = getAmIChatAdmin
QtProperty[int] memberRole:
read = getMemberRole
proc getIcon(self: ActiveItem): string {.slot.} =
if(self.item.isNil):

View File

@ -206,7 +206,7 @@ proc init*(self: Controller) =
let args = ChatMemberUpdatedArgs(e)
if (args.chatId != self.chatId):
return
self.delegate.onChatMemberUpdated(args.id, args.admin, args.joined)
self.delegate.onChatMemberUpdated(args.id, args.role, args.joined)
self.events.on(SIGNAL_MAILSERVER_SYNCED) do(e: Args):
let args = MailserverSyncedArgs(e)

View File

@ -3,6 +3,7 @@ import NimQml
import ../../../../../../app_service/service/message/dto/[message, reaction, pinned_message]
import ../../../../../../app_service/service/community/dto/community
import ../../../../shared_models/message_item
import ../../../../../../app_service/common/types
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -74,7 +75,7 @@ method onMessageEdited*(self: AccessInterface, message: MessageDto) {.base.} =
method scrollToMessage*(self: AccessInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatMemberUpdated*(self: AccessInterface, id: string, admin: bool, joined: bool) {.base.} =
method onChatMemberUpdated*(self: AccessInterface, id: string, memberRole: MemberRole, joined: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =

View File

@ -14,6 +14,7 @@ import ../../../../../../app_service/service/community/service as community_serv
import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../../app_service/service/message/service as message_service
import ../../../../../../app_service/service/mailservers/service as mailservers_service
import ../../../../../../app_service/common/types
export io_interface
@ -556,12 +557,12 @@ method amIChatAdmin*(self: Module): bool =
if(not self.controller.belongsToCommunity()):
let chatDto = self.controller.getChatDetails()
for member in chatDto.members:
if (member.id == singletonInstance.userProfile.getPubKey() and member.admin):
return true
if (member.id == singletonInstance.userProfile.getPubKey()):
return member.role == MemberRole.Owner or member.role == MemberRole.Admin
return false
else:
let communityDto = self.controller.getCommunityDetails()
return communityDto.admin
return communityDto.memberRole == MemberRole.Owner or communityDto.memberRole == MemberRole.Admin
method pinMessageAllowedForMembers*(self: Module): bool =
if(self.controller.belongsToCommunity()):
@ -676,7 +677,7 @@ method fillGaps*(self: Module, messageId: string) =
method leaveChat*(self: Module) =
self.controller.leaveChat()
method onChatMemberUpdated*(self: Module, publicKey: string, admin: bool, joined: bool) =
method onChatMemberUpdated*(self: Module, publicKey: string, memberRole: MemberRole, joined: bool) =
let chatDto = self.controller.getChatDetails()
if(chatDto.chatType != ChatType.PrivateGroupChat):
return
@ -719,7 +720,7 @@ method markMessagesAsRead*(self: Module, messages: seq[string]) =
self.view.model().markAsSeen(messages)
method updateCommunityDetails*(self: Module, community: CommunityDto) =
self.view.setAmIChatAdmin(community.admin)
self.view.setAmIChatAdmin(community.memberRole == MemberRole.Owner or community.memberRole == MemberRole.Admin)
self.view.setIsPinMessageAllowedForMembers(community.adminSettings.pinMessageAllMembersEnabled)
proc setChatDetails(self: Module, chatDetails: ChatDto) =

View File

@ -23,6 +23,7 @@ import ../../../../../app_service/service/community/service as community_service
import ../../../../../app_service/service/gif/service as gif_service
import ../../../../../app_service/service/message/service as message_service
import ../../../../../app_service/service/mailservers/service as mailservers_service
import ../../../../../app_service/common/types
export io_interface
@ -324,17 +325,6 @@ method toggleReactionFromOthers*(self: Module, messageId: string, emojiId: int,
method getCurrentFleet*(self: Module): string =
return self.controller.getCurrentFleet()
method amIChatAdmin*(self: Module): bool =
if(not self.controller.belongsToCommunity()):
let chatDto = self.controller.getChatDetails()
for member in chatDto.members:
if (member.id == singletonInstance.userProfile.getPubKey() and member.admin):
return true
return false
else:
let communityDto = self.controller.getCommunityDetails()
return communityDto.admin
method onContactDetailsUpdated*(self: Module, contactId: string) =
let updatedContact = self.controller.getContactDetails(contactId)
for item in self.view.pinnedModel().modelContactUpdateIterator(contactId):
@ -399,3 +389,14 @@ method onMadeInactive*(self: Module) =
if self.controller.getChatDetails().unviewedMessagesCount == 0:
self.messagesModule.removeNewMessagesMarker()
self.view.setInactive()
method amIChatAdmin*(self: Module): bool =
if not self.controller.belongsToCommunity():
let chatDto = self.controller.getChatDetails()
for member in chatDto.members:
if member.id == singletonInstance.userProfile.getPubKey():
return member.role == MemberRole.Owner or member.role == MemberRole.Admin
return false
else:
let communityDto = self.controller.getCommunityDetails()
return communityDto.memberRole == MemberRole.Owner or communityDto.memberRole == MemberRole.Admin

View File

@ -130,7 +130,7 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_CHAT_MEMBER_UPDATED) do(e: Args):
let args = ChatMemberUpdatedArgs(e)
if (args.chatId == self.chatId):
self.delegate.onChatMemberUpdated(args.id, args.admin, args.joined)
self.delegate.onChatMemberUpdated(args.id, args.role, args.joined)
# Events only for community channel
if (self.belongsToCommunity):

View File

@ -3,6 +3,7 @@ import NimQml
import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../../app_service/service/message/dto/[message]
import ../../../../../../app_service/service/contacts/dto/[status_update]
import ../../../../../../app_service/common/types
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -46,7 +47,7 @@ method onChatMembersAdded*(self: AccessInterface, ids: seq[string]) {.base.} =
method onChatMemberRemoved*(self: AccessInterface, ids: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatMemberUpdated*(self: AccessInterface, id: string, admin: bool, joined: bool) {.base.} =
method onChatMemberUpdated*(self: AccessInterface, id: string, memberRole: MemberRole, joined: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =

View File

@ -130,14 +130,14 @@ proc addChatMember(self: Module, member: ChatMember) =
onlineStatus = status,
isContact = contactDetails.dto.isContact,
isVerified = contactDetails.dto.isContactVerified(),
isAdmin = member.admin,
memberRole = member.role,
joined = member.joined,
isUntrustworthy = contactDetails.dto.trustStatus == TrustStatus.Untrustworthy
))
method onChatMembersAdded*(self: Module, ids: seq[string]) =
for memberId in ids:
self.addChatMember(ChatMember(id: memberId, admin: false, joined: true, roles: @[]))
self.addChatMember(ChatMember(id: memberId, role: MemberRole.None, joined: true))
method onChatMemberRemoved*(self: Module, id: string) =
self.view.model().removeItemById(id)
@ -154,7 +154,7 @@ method onMembersChanged*(self: Module, members: seq[ChatMember]) =
self.onChatMemberRemoved(id)
method onChatMemberUpdated*(self: Module, publicKey: string, admin: bool, joined: bool) =
method onChatMemberUpdated*(self: Module, publicKey: string, memberRole: MemberRole, joined: bool) =
let contactDetails = self.controller.getContactDetails(publicKey)
self.view.model().updateItem(
pubKey = publicKey,
@ -166,7 +166,7 @@ method onChatMemberUpdated*(self: Module, publicKey: string, admin: bool, joined
icon = contactDetails.icon,
isContact = contactDetails.dto.isContact,
isVerified = contactDetails.dto.isContactVerified(),
isAdmin = admin,
memberRole = memberRole,
joined = joined,
isUntrustworthy = contactDetails.dto.trustStatus == TrustStatus.Untrustworthy,
)

View File

@ -12,7 +12,7 @@ type
id: string
name: string
`type`: int
amIChatAdmin: bool
memberRole: MemberRole
icon: string
color: string
colorId: int # only for oneToOne sections
@ -42,7 +42,7 @@ proc initItem*(
emoji,
description: string,
`type`: int,
amIChatAdmin: bool,
memberRole: MemberRole,
lastMessageTimestamp: int,
hasUnreadMessages: bool,
notificationsCount: int,
@ -63,7 +63,7 @@ proc initItem*(
result = Item()
result.id = id
result.name = name
result.amIChatAdmin = amIChatAdmin
result.memberRole = memberRole
result.icon = icon
result.color = color
result.colorId = colorId
@ -91,7 +91,7 @@ proc `$`*(self: Item): string =
result = fmt"""chat_section/Item(
id: {self.id},
name: {$self.name},
amIChatAdmin: {$self.amIChatAdmin},
memberRole: {$self.memberRole},
icon: {$self.icon},
color: {$self.color},
colorId: {$self.colorId},
@ -118,7 +118,7 @@ proc toJsonNode*(self: Item): JsonNode =
result = %* {
"itemId": self.id,
"name": self.name,
"amIChatAdmin": self.amIChatAdmin,
"memberRole": self.memberRole,
"icon": self.icon,
"color": self.color,
"emoji": self.emoji,
@ -152,8 +152,8 @@ proc name*(self: Item): string =
proc `name=`*(self: var Item, value: string) =
self.name = value
proc amIChatAdmin*(self: Item): bool =
self.amIChatAdmin
proc memberRole*(self: Item): MemberRole =
self.memberRole
proc icon*(self: Item): string =
self.icon

View File

@ -8,7 +8,7 @@ type
ModelRole {.pure.} = enum
Id = UserRole + 1
Name
AmIChatAdmin
MemberRole
Icon
Color
ColorId
@ -76,7 +76,7 @@ QtObject:
{
ModelRole.Id.int:"itemId",
ModelRole.Name.int:"name",
ModelRole.AmIChatAdmin.int:"amIChatAdmin",
ModelRole.MemberRole.int:"memberRole",
ModelRole.Icon.int:"icon",
ModelRole.Color.int:"color",
ModelRole.ColorId.int:"colorId",
@ -116,8 +116,8 @@ QtObject:
result = newQVariant(item.id)
of ModelRole.Name:
result = newQVariant(item.name)
of ModelRole.AmIChatAdmin:
result = newQVariant(item.amIChatAdmin)
of ModelRole.MemberRole:
result = newQVariant(item.memberRole.int)
of ModelRole.Icon:
result = newQVariant(item.icon)
of ModelRole.Color:

View File

@ -38,6 +38,7 @@ import ../../../../app_service/service/community_tokens/service as community_tok
import ../../../../app_service/service/visual_identity/service as visual_identity
import ../../../../app_service/service/contacts/dto/contacts as contacts_dto
import ../../../../app_service/service/community/dto/community as community_dto
import ../../../../app_service/common/types
export io_interface
@ -140,11 +141,11 @@ method isCommunity*(self: Module): bool =
method getMySectionId*(self: Module): string =
return self.controller.getMySectionId()
proc amIMarkedAsAdminUser(self: Module, members: seq[ChatMember]): bool =
proc getUserMemberRole(self: Module, members: seq[ChatMember]): MemberRole =
for m in members:
if (m.id == singletonInstance.userProfile.getPubKey() and m.admin):
return true
return false
if m.id == singletonInstance.userProfile.getPubKey():
return m.role
return MemberRole.None
proc addSubmodule(self: Module, chatId: string, belongToCommunity: bool, isUsersListAvailable: bool, events: EventEmitter,
settingsService: settings_service.Service,
@ -165,7 +166,7 @@ proc removeSubmodule(self: Module, chatId: string) =
self.chatContentModules.del(chatId)
proc addCategoryItem(self: Module, category: Category, amIAdmin: bool, communityId: string, insertIntoModel: bool = true): Item =
proc addCategoryItem(self: Module, category: Category, memberRole: MemberRole, communityId: string, insertIntoModel: bool = true): Item =
let hasUnreadMessages = self.controller.chatsWithCategoryHaveUnreadMessages(communityId, category.id)
result = chat_item.initItem(
id = category.id,
@ -175,7 +176,7 @@ proc addCategoryItem(self: Module, category: Category, amIAdmin: bool, community
emoji = "",
description = "",
`type` = chat_item.CATEGORY_TYPE,
amIAdmin,
memberRole,
lastMessageTimestamp = 0,
hasUnreadMessages,
notificationsCount = 0,
@ -207,7 +208,7 @@ proc buildChatSectionUI(
var items: seq[Item] = @[]
for categoryDto in channelGroup.categories:
# Add items for the categories. We use a special type to identify categories
items.add(self.addCategoryItem(categoryDto, channelGroup.admin, channelGroup.id))
items.add(self.addCategoryItem(categoryDto, channelGroup.memberRole, channelGroup.id))
for chatDto in channelGroup.chats:
var categoryPosition = -1
@ -282,13 +283,17 @@ proc rebuildCommunityTokenPermissionsModel(self: Module) =
var tokenPermissionsItems: seq[TokenPermissionItem] = @[]
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)
tokenPermissionsItems.add(tokenPermissionItem)
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
tokenPermissionsItems.add(tokenPermissionItem)
let memberPermissions = filter(tokenPermissionsItems, tokenPermissionsItem =>
tokenPermissionsItem.getType() == TokenPermissionType.BecomeMember.int)
let adminPermissions = filter(tokenPermissionsItems, tokenPermissionsItem =>
tokenPermissionsItem.getType() == TokenPermissionType.BecomeAdmin.int)
self.view.tokenPermissionsModel().setItems(tokenPermissionsItems)
self.view.setRequiresTokenPermissionToJoin(tokenPermissionsItems.len > 0)
self.view.setRequiresTokenPermissionToJoin(len(memberPermissions) > 0 or len(adminPermissions) > 0)
proc initCommunityTokenPermissionsModel(self: Module) =
self.rebuildCommunityTokenPermissionsModel()
@ -574,12 +579,12 @@ method addNewChat*(
elif chatDto.chatType == ChatType.PrivateGroupChat:
chatImage = chatDto.icon
var amIChatAdmin = self.amIMarkedAsAdminUser(chatDto.members)
if not amIChatAdmin and len(chatDto.communityId) != 0:
let community = communityService.getCommunityById(chatDto.communityId)
amIChatAdmin = amIChatAdmin or community.admin
var memberRole = self.getUserMemberRole(chatDto.members)
if memberRole == MemberRole.None and len(chatDto.communityId) != 0:
memberRole = channelGroup.memberRole
if chatDto.chatType != ChatType.PrivateGroupChat:
amIChatAdmin = amIChatAdmin or channelGroup.admin
memberRole = channelGroup.memberRole
var categoryOpened = true
if chatDto.categoryId != "":
@ -605,7 +610,7 @@ method addNewChat*(
chatDto.emoji,
chatDto.description,
ChatType(chatDto.chatType).int,
amIChatAdmin,
memberRole,
chatDto.timestamp.int,
hasNotification,
notificationsCount,
@ -680,8 +685,8 @@ method onCommunityCategoryCreated*(self: Module, cat: Category, chats: seq[ChatD
if (self.doesCatOrChatExist(cat.id)):
return
# TODO get admin status
discard self.addCategoryItem(cat, false, communityId)
let community = self.controller.getCommunityById(communityId)
discard self.addCategoryItem(cat, community.memberRole, communityId)
# Update chat items that now belong to that category
self.view.chatsModel().updateItemsWithCategoryDetailsById(
chats,
@ -781,20 +786,19 @@ method onCommunityTokenPermissionDeleted*(self: Module, communityId: string, per
singletonInstance.globalEvents.showCommunityTokenPermissionDeletedNotification(communityId, "Community permission deleted", "A token permission has been removed")
method onCommunityTokenPermissionCreated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) =
if tokenPermission.`type` == TokenPermissionType.BecomeMember:
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
if tokenPermissionItem.tokenCriteriaMet:
self.view.setAllTokenRequirementsMet(true)
self.view.tokenPermissionsModel.addItem(tokenPermissionItem)
self.view.setRequiresTokenPermissionToJoin(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] = @[]
@ -824,13 +828,34 @@ method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissions
tokenPermissionItem.isPrivate,
permissionSatisfied
)
self.view.tokenPermissionsModel.updateItem(id, updatedTokenPermissionItem)
self.view.tokenPermissionsModel().updateItem(id, updatedTokenPermissionItem)
let tokenPermissionsItems = self.view.tokenPermissionsModel().getItems()
let memberPermissions = filter(tokenPermissionsItems, tokenPermissionsItem =>
tokenPermissionsItem.getType() == TokenPermissionType.BecomeMember.int)
let adminPermissions = filter(tokenPermissionsItems, tokenPermissionsItem =>
tokenPermissionsItem.getType() == TokenPermissionType.BecomeAdmin.int)
# 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
let memberRequirementMet = memberPermissions.len() > 0 and any(memberPermissions,
proc (item: TokenPermissionItem): bool = item.tokenCriteriaMet)
let adminRequirementMet = adminPermissions.len() > 0 and any(adminPermissions, proc (item: TokenPermissionItem): bool = item.tokenCriteriaMet)
let requiresPermissionToJoin = (adminPermissions.len() > 0 and adminRequirementMet) or memberPermissions.len() > 0
let tokenRequirementsMet = if requiresPermissionToJoin: adminRequirementMet or memberRequirementMet else: false
self.view.setAllTokenRequirementsMet(tokenRequirementsMet)
self.view.setRequiresTokenPermissionToJoin(requiresPermissionToJoin)
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)
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
self.view.tokenPermissionsModel.updateItem(tokenPermission.id, tokenPermissionItem)
singletonInstance.globalEvents.showCommunityTokenPermissionUpdatedNotification(communityId, "Community permission updated", "A token permission has been updated")
@ -1099,7 +1124,7 @@ method prepareEditCategoryModel*(self: Module, categoryId: string) =
c.emoji,
c.description,
c.chatType.int,
amIChatAdmin=false,
memberRole=MemberRole.None,
lastMessageTimestamp=(-1),
hasUnreadMessages=false,
notificationsCount=0,
@ -1121,7 +1146,7 @@ method prepareEditCategoryModel*(self: Module, categoryId: string) =
c.emoji,
c.description,
c.chatType.int,
amIChatAdmin=false,
memberRole=MemberRole.None,
lastMessageTimestamp=(-1),
hasUnreadMessages=false,
notificationsCount=0,

View File

@ -134,7 +134,7 @@ method getCommunityItem(self: Module, c: CommunityDto): SectionItem =
c.id,
SectionType.Community,
c.name,
c.admin,
c.memberRole,
c.description,
c.introMessage,
c.outroMessage,

View File

@ -19,7 +19,6 @@ QtObject:
delegate: io_interface.AccessInterface
model: SectionModel
modelVariant: QVariant
observedItem: SectionDetails
curatedCommunitiesModel: CuratedCommunityModel
curatedCommunitiesModelVariant: QVariant
curatedCommunitiesLoading: bool
@ -50,7 +49,6 @@ QtObject:
proc delete*(self: View) =
self.model.delete
self.modelVariant.delete
self.observedItem.delete
self.curatedCommunitiesModel.delete
self.curatedCommunitiesModelVariant.delete
self.discordFileListModel.delete
@ -90,7 +88,6 @@ QtObject:
result.discordImportHasCommunityImage = false
result.discordImportTasksModel = newDiscordDiscordImportTasksModel()
result.discordImportTasksModelVariant = newQVariant(result.discordImportTasksModel)
result.observedItem = newActiveSection()
result.downloadingCommunityHistoryArchives = false
proc load*(self: View) =
@ -338,22 +335,6 @@ QtObject:
QtProperty[QVariant] discordImportTasks:
read = getDiscordImportTasksModel
proc observedItemChanged*(self:View) {.signal.}
proc getObservedItem(self: View): QVariant {.slot.} =
return newQVariant(self.observedItem)
QtProperty[QVariant] observedCommunity:
read = getObservedItem
notify = observedItemChanged
proc setObservedCommunity*(self: View, itemId: string) {.slot.} =
let item = self.model.getItemById(itemId)
if (item.id == ""):
return
self.observedItem.setActiveSectionData(item)
self.observedItemChanged()
proc discordDataExtractionInProgressChanged*(self: View) {.signal.}
proc getDiscordDataExtractionInProgress(self: View): bool {.slot.} =

View File

@ -254,11 +254,12 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
let notificationsCount = channelGroup.unviewedMentionsCount
let hasNotification = unviewedCount > 0 or notificationsCount > 0
let active = self.getActiveSectionId() == channelGroup.id # We must pass on if the current item section is currently active to keep that property as it is
result = initItem(
channelGroup.id,
if isCommunity: SectionType.Community else: SectionType.Chat,
if isCommunity: channelGroup.name else: conf.CHAT_SECTION_NAME,
channelGroup.admin,
channelGroup.memberRole,
channelGroup.description,
channelGroup.introMessage,
channelGroup.outroMessage,
@ -296,7 +297,7 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(member.id).statusType),
isContact = contactDetails.dto.isContact,
isVerified = contactDetails.dto.isContactVerified(),
isAdmin = member.admin
memberRole = member.role
)),
# pendingRequestsToJoin
if (isCommunity): communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem(
@ -395,7 +396,7 @@ method load*[T](
conf.COMMUNITIESPORTAL_SECTION_ID,
SectionType.CommunitiesPortal,
conf.COMMUNITIESPORTAL_SECTION_NAME,
amISectionAdmin = false,
memberRole = MemberRole.Owner,
description = "",
image = "",
icon = conf.COMMUNITIESPORTAL_SECTION_ICON,
@ -414,7 +415,7 @@ method load*[T](
conf.WALLET_SECTION_ID,
SectionType.Wallet,
conf.WALLET_SECTION_NAME,
amISectionAdmin = false,
memberRole = MemberRole.Owner,
description = "",
introMessage = "",
outroMessage = "",
@ -435,7 +436,7 @@ method load*[T](
conf.BROWSER_SECTION_ID,
SectionType.Browser,
conf.BROWSER_SECTION_NAME,
amISectionAdmin = false,
memberRole = MemberRole.Owner,
description = "",
introMessage = "",
outroMessage = "",
@ -456,7 +457,7 @@ method load*[T](
conf.NODEMANAGEMENT_SECTION_ID,
SectionType.NodeManagement,
conf.NODEMANAGEMENT_SECTION_NAME,
amISectionAdmin = false,
memberRole = MemberRole.Owner,
description = "",
introMessage = "",
outroMessage = "",
@ -477,7 +478,7 @@ method load*[T](
conf.SETTINGS_SECTION_ID,
SectionType.ProfileSettings,
conf.SETTINGS_SECTION_NAME,
amISectionAdmin = false,
memberRole = MemberRole.Owner,
description = "",
introMessage = "",
outroMessage = "",
@ -512,7 +513,7 @@ method load*[T](
LOADING_SECTION_ID,
SectionType.LoadingSection,
name = "",
amISectionAdmin = false,
memberRole = MemberRole.Owner,
description = "",
image = "",
icon = "",

View File

@ -7,7 +7,7 @@ export user_item
type
MemberItem* = ref object of UserItem
isAdmin: bool
memberRole: MemberRole
joined: bool
requestToJoinId: string
requestToJoinLoading*: bool
@ -31,13 +31,13 @@ proc initMemberItem*(
contactRequest: ContactRequest = ContactRequest.None,
incomingVerificationStatus: VerificationRequestStatus = VerificationRequestStatus.None,
outgoingVerificationStatus: VerificationRequestStatus = VerificationRequestStatus.None,
isAdmin: bool = false,
memberRole: MemberRole = MemberRole.None,
joined: bool = false,
requestToJoinId: string = "",
requestToJoinLoading: bool = false
): MemberItem =
result = MemberItem()
result.isAdmin = isAdmin
result.memberRole = memberRole
result.joined = joined
result.requestToJoinId = requestToJoinId
result.requestToJoinLoading = requestToJoinLoading
@ -80,16 +80,16 @@ proc `$`*(self: MemberItem): string =
contactRequest: {$self.contactRequest.int},
incomingVerificationStatus: {$self.incomingVerificationStatus.int},
outgoingVerificationStatus: {$self.outgoingVerificationStatus.int},
isAdmin: {self.isAdmin},
memberRole: {self.memberRole},
joined: {self.joined},
requestToJoinId: {self.requestToJoinId}
]"""
proc isAdmin*(self: MemberItem): bool {.inline.} =
self.isAdmin
proc memberRole*(self: MemberItem): MemberRole {.inline.} =
self.memberRole
proc `isAdmin=`*(self: MemberItem, value: bool) {.inline.} =
self.isAdmin = value
proc `memberRole=`*(self: MemberItem, value: MemberRole) {.inline.} =
self.memberRole = value
proc joined*(self: MemberItem): bool {.inline.} =
self.joined

View File

@ -25,7 +25,7 @@ type
ContactRequest
IncomingVerificationStatus
OutgoingVerificationStatus
IsAdmin
MemberRole
Joined
RequestToJoinId
RequestToJoinLoading
@ -92,7 +92,7 @@ QtObject:
ModelRole.ContactRequest.int: "contactRequest",
ModelRole.IncomingVerificationStatus.int: "incomingVerificationStatus",
ModelRole.OutgoingVerificationStatus.int: "outgoingVerificationStatus",
ModelRole.IsAdmin.int: "isAdmin",
ModelRole.MemberRole.int: "memberRole",
ModelRole.Joined.int: "joined",
ModelRole.RequestToJoinId.int: "requestToJoinId",
ModelRole.RequestToJoinLoading.int: "requestToJoinLoading",
@ -143,8 +143,8 @@ QtObject:
result = newQVariant(item.incomingVerificationStatus.int)
of ModelRole.OutgoingVerificationStatus:
result = newQVariant(item.outgoingVerificationStatus.int)
of ModelRole.IsAdmin:
result = newQVariant(item.isAdmin)
of ModelRole.MemberRole:
result = newQVariant(item.memberRole.int)
of ModelRole.Joined:
result = newQVariant(item.joined)
of ModelRole.RequestToJoinId:
@ -215,7 +215,7 @@ QtObject:
icon: string,
isContact: bool,
isVerified: bool,
isAdmin: bool,
memberRole: MemberRole,
joined: bool,
isUntrustworthy: bool,
) =
@ -231,7 +231,7 @@ QtObject:
self.items[ind].icon = icon
self.items[ind].isContact = isContact
self.items[ind].isVerified = isVerified
self.items[ind].isAdmin = isAdmin
self.items[ind].memberRole = memberRole
self.items[ind].joined = joined
self.items[ind].isUntrustworthy = isUntrustworthy
@ -245,7 +245,7 @@ QtObject:
ModelRole.Icon.int,
ModelRole.IsContact.int,
ModelRole.IsVerified.int,
ModelRole.IsAdmin.int,
ModelRole.MemberRole.int,
ModelRole.Joined.int,
ModelRole.IsUntrustworthy.int,
])

View File

@ -52,11 +52,11 @@ QtObject:
QtProperty[string] name:
read = getName
proc getAmISectionAdmin(self: SectionDetails): bool {.slot.} =
return self.item.amISectionAdmin
proc getMemberRole(self: SectionDetails): int {.slot.} =
return self.item.memberRole.int
QtProperty[bool] amISectionAdmin:
read = getAmISectionAdmin
QtProperty[int] memberRole:
read = getMemberRole
proc description(self: SectionDetails): string {.slot.} =
return self.item.description

View File

@ -25,7 +25,7 @@ type
sectionType: SectionType
id: string
name: string
amISectionAdmin: bool
memberRole: MemberRole
description: string
introMessage: string
outroMessage: string
@ -61,7 +61,7 @@ proc initItem*(
id: string,
sectionType: SectionType,
name: string,
amISectionAdmin = false,
memberRole = MemberRole.None,
description = "",
introMessage = "",
outroMessage = "",
@ -96,7 +96,7 @@ proc initItem*(
result.id = id
result.sectionType = sectionType
result.name = name
result.amISectionAdmin = amISectionAdmin
result.memberRole = memberRole
result.description = description
result.introMessage = introMessage
result.outroMessage = outroMessage
@ -142,7 +142,7 @@ proc `$`*(self: SectionItem): string =
id: {self.id},
sectionType: {self.sectionType.int},
name: {self.name},
amISectionAdmin: {self.amISectionAdmin},
memberRole: {self.memberRole},
description: {self.description},
introMessage: {self.introMessage},
outroMessage: {self.outroMessage},
@ -183,8 +183,11 @@ proc sectionType*(self: SectionItem): SectionType {.inline.} =
proc name*(self: SectionItem): string {.inline.} =
self.name
proc amISectionAdmin*(self: SectionItem): bool {.inline.} =
self.amISectionAdmin
proc memberRole*(self: SectionItem): MemberRole {.inline.} =
self.memberRole
proc `memberRole=`*(self: var SectionItem, value: MemberRole) {.inline.} =
self.memberRole = value
proc description*(self: SectionItem): string {.inline.} =
self.description

View File

@ -5,12 +5,14 @@ import json
import section_item, member_model
import ../main/communities/tokens/models/token_item
import ../../../app_service/common/types
type
ModelRole {.pure.} = enum
Id = UserRole + 1
SectionType
Name
AmISectionAdmin
MemberRole
Description
IntroMessage
OutroMessage
@ -82,7 +84,7 @@ QtObject:
ModelRole.Id.int:"id",
ModelRole.SectionType.int:"sectionType",
ModelRole.Name.int:"name",
ModelRole.AmISectionAdmin.int: "amISectionAdmin",
ModelRole.MemberRole.int: "memberRole",
ModelRole.Description.int:"description",
ModelRole.IntroMessage.int:"introMessage",
ModelRole.OutroMessage.int:"outroMessage",
@ -133,8 +135,8 @@ QtObject:
result = newQVariant(item.sectionType.int)
of ModelRole.Name:
result = newQVariant(item.name)
of ModelRole.AmISectionAdmin:
result = newQVariant(item.amISectionAdmin)
of ModelRole.MemberRole:
result = newQVariant(item.memberRole.int)
of ModelRole.Description:
result = newQVariant(item.description)
of ModelRole.IntroMessage:
@ -270,6 +272,7 @@ QtObject:
defer: dataIndex.delete
self.dataChanged(dataIndex, dataIndex, @[
ModelRole.Name.int,
ModelRole.MemberRole.int,
ModelRole.Description.int,
ModelRole.IntroMessage.int,
ModelRole.OutroMessage.int,
@ -411,7 +414,7 @@ QtObject:
let jsonObj = %* {
"id": item.id,
"name": item.name,
"amISectionAdmin": item.amISectionAdmin,
"memberRole": item.memberRole.int,
"description": item.description,
"introMessage": item.introMessage,
"outroMessage": item.outroMessage,
@ -436,4 +439,4 @@ QtObject:
"nbMembers": item.members.getCount(),
"encrypted": item.encrypted,
}
return $jsonObj
return $jsonObj

View File

@ -118,6 +118,7 @@ QtObject:
self.items[idx].`type` = item.`type`
self.items[idx].tokenCriteria.setItems(item.tokenCriteria.getItems())
self.items[idx].isPrivate = item.isPrivate
self.items[idx].tokenCriteriaMet = item.tokenCriteriaMet
let index = self.createIndex(idx, 0, nil)
self.dataChanged(index, index, @[

View File

@ -1,5 +1,6 @@
import json
import web3/ethtypes
import types
template getProp(obj: JsonNode, prop: string, value: var typedesc[int]): bool =
var success = false
@ -72,3 +73,11 @@ template getProp(obj: JsonNode, prop: string, value: var typedesc[Address]): boo
success = true
success
template getProp(obj: JsonNode, prop: string, value: var typedesc[MemberRole]): bool =
var success = false
if (obj.kind == JObject and obj.contains(prop)):
value = MemberRole(obj[prop].getInt)
success = true
success

View File

@ -44,3 +44,10 @@ proc toOnlineStatus*(statusType: StatusType): OnlineStatus =
return OnlineStatus.Online
else:
return OnlineStatus.Inactive
type MemberRole* {.pure} = enum
None = 0
Owner
ManageUsers
ModerateContent
Admin

View File

@ -4,6 +4,7 @@ import json, strformat, strutils
import ../../community/dto/community
include ../../../common/json_utils
import ../../../../app_service/common/types
type ChatType* {.pure.}= enum
Unknown = 0,
@ -18,14 +19,6 @@ type ChannelGroupType* {.pure.}= enum
Personal = "personal",
Community = "community"
type CommunityMemberRoles* {.pure.} = enum
Unknown = 0,
All = 1,
ManagerUsers = 2
proc isMemberAdmin*(roles: seq[int]): bool =
return roles.contains(CommunityMemberRoles.All.int)
type Category* = object
id*: string
name*: string
@ -44,9 +37,8 @@ type
type ChatMember* = object
id*: string
admin*: bool
joined*: bool
roles*: seq[int]
role*: MemberRole
type ChatDto* = object
id*: string # ID is the id of the chat, for public chats it is the name e.g. status,
@ -85,7 +77,7 @@ type ChatDto* = object
type ChannelGroupDto* = object
id*: string
channelGroupType*: ChannelGroupType
admin*: bool
memberRole*: MemberRole
verified*: bool
name*: string
ensName*: string
@ -179,18 +171,15 @@ proc toChatMember*(jsonObj: JsonNode, memberId: string): ChatMember =
# Mapping this DTO is not strightforward since only keys are used for id
result = ChatMember()
result.id = memberId
discard jsonObj.getProp("admin", result.admin)
discard jsonObj.getProp("joined", result.joined)
var rolesObj: JsonNode
if(jsonObj.getProp("roles", rolesObj) and rolesObj.kind == JArray):
for role in rolesObj:
result.roles.add(role.getInt)
discard jsonObj.getProp("role", result.role)
proc toGroupChatMember*(jsonObj: JsonNode): ChatMember =
# parse status-go "ChatMember" type
result = ChatMember()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("admin", result.admin)
let admin = jsonObj["admin"].getBool(false)
result.role = if admin: MemberRole.Owner else: MemberRole.None
result.joined = true
proc toChannelMember*(jsonObj: JsonNode, memberId: string, joined: bool): ChatMember =
@ -200,11 +189,22 @@ proc toChannelMember*(jsonObj: JsonNode, memberId: string, joined: bool): ChatMe
result = ChatMember()
result.id = memberId
var rolesObj: JsonNode
var roles: seq[int] = @[]
if(jsonObj.getProp("roles", rolesObj)):
for roleObj in rolesObj:
result.roles.add(roleObj.getInt)
roles.add(roleObj.getInt)
result.role = MemberRole.None
if roles.contains(MemberRole.Owner.int):
result.role = MemberRole.Owner
elif roles.contains(MemberRole.Admin.int):
result.role = MemberRole.Admin
elif roles.contains(MemberRole.ManageUsers.int):
result.role = MemberRole.ManageUsers
elif roles.contains(MemberRole.ModerateContent.int):
result.role = MemberRole.ModerateContent
result.joined = joined
result.admin = isMemberAdmin(result.roles)
proc toChatDto*(jsonObj: JsonNode): ChatDto =
result = ChatDto()
@ -268,8 +268,9 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
proc toChannelGroupDto*(jsonObj: JsonNode): ChannelGroupDto =
result = ChannelGroupDto()
discard jsonObj.getProp("admin", result.admin)
discard jsonObj.getProp("verified", result.verified)
discard jsonObj.getProp("memberRole", result.memberRole)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("introMessage", result.introMessage)

View File

@ -80,7 +80,7 @@ type
ChatMemberUpdatedArgs* = ref object of Args
chatId*: string
id*: string
admin*: bool
role*: MemberRole
joined*: bool
RpcResponseArgs* = ref object of Args
@ -674,10 +674,10 @@ QtObject:
discard status_group_chat.makeAdmin(communityID, chatId, memberId)
for member in self.chats[chatId].members.mitems:
if (member.id == memberId):
member.admin = true
member.role = MemberRole.Admin
self.events.emit(
SIGNAL_CHAT_MEMBER_UPDATED,
ChatMemberUpdatedArgs(id: member.id, admin: member.admin, chatId: chatId, joined: member.joined)
ChatMemberUpdatedArgs(id: member.id, role: member.role, chatId: chatId, joined: member.joined)
)
break
except Exception as e:

View File

@ -8,6 +8,7 @@ include ../../../common/json_utils
import ../../../common/conversion
import ../../chat/dto/chat
import ../../../../app_service/common/types
type RequestToJoinType* {.pure.}= enum
Pending = 1,
@ -34,7 +35,10 @@ type CommunityAdminSettingsDto* = object
type TokenPermissionType* {.pure.}= enum
Unknown = 0,
BecomeAdmin = 1,
BecomeMember = 2
BecomeMember = 2,
View = 3,
ViewAndPost = 4,
type TokenType* {.pure.}= enum
Unknown = 0,
@ -69,7 +73,7 @@ type CommunityTokensMetadataDto* = object
type CommunityDto* = object
id*: string
admin*: bool
memberRole*: MemberRole
verified*: bool
joined*: bool
spectated*: bool
@ -291,7 +295,7 @@ proc toCheckPermissionsToJoinResponseDto*(jsonObj: JsonNode): CheckPermissionsTo
proc toCommunityDto*(jsonObj: JsonNode): CommunityDto =
result = CommunityDto()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("admin", result.admin)
discard jsonObj.getProp("memberRole", result.memberRole)
discard jsonObj.getProp("verified", result.verified)
discard jsonObj.getProp("joined", result.joined)
discard jsonObj.getProp("spectated", result.spectated)
@ -421,7 +425,7 @@ proc toChannelGroupDto*(communityDto: CommunityDto): ChannelGroupDto =
categories: communityDto.categories,
# Community doesn't have an ensName yet. Add this when it is added in status-go
# ensName: communityDto.ensName,
admin: communityDto.admin,
memberRole: communityDto.memberRole,
verified: communityDto.verified,
description: communityDto.description,
introMessage: communityDto.introMessage,
@ -432,8 +436,7 @@ proc toChannelGroupDto*(communityDto: CommunityDto): ChannelGroupDto =
members: communityDto.members.map(m => ChatMember(
id: m.id,
joined: true,
admin: isMemberAdmin(m.roles),
roles: m.roles
role: m.role
)),
canManageUsers: communityDto.canManageUsers,
muted: communityDto.muted,

View File

@ -15,6 +15,8 @@ import ../../../app/core/[main]
import ../../../app/core/tasks/[qt, threadpool]
import ../../../backend/communities as status_go
import ../../../app_service/common/types
include ./async_tasks
export community_dto
@ -641,7 +643,7 @@ QtObject:
let communities = parseCommunities(responseObj["communities"])
for community in communities:
self.communities[community.id] = community
if (community.admin):
if community.memberRole == MemberRole.Owner or community.memberRole == MemberRole.Admin:
self.communities[community.id].pendingRequestsToJoin = self.pendingRequestsToJoinForCommunity(community.id)
self.communities[community.id].declinedRequestsToJoin = self.declinedRequestsToJoinForCommunity(community.id)
self.communities[community.id].canceledRequestsToJoin = self.canceledRequestsToJoinForCommunity(community.id)
@ -1469,7 +1471,9 @@ QtObject:
self.events.emit(SIGNAL_COMMUNITY_EDITED, CommunityArgs(community: self.communities[communityId]))
self.events.emit(SIGNAL_COMMUNITY_MEMBER_APPROVED, CommunityMemberArgs(communityId: communityId, pubKey: userKey, requestId: requestId))
self.activityCenterService.parseActivityCenterNotifications(rpcResponseObj["response"]["result"]["activityCenterNotifications"])
if rpcResponseObj["response"]["result"]{"activityCenterNotifications"}.kind != JNull:
self.activityCenterService.parseActivityCenterNotifications(rpcResponseObj["response"]["result"]["activityCenterNotifications"])
except Exception as e:
let errMsg = e.msg

View File

@ -48,7 +48,8 @@ StackLayout {
membersCount: communityData.members.count
accessType: communityData.access
joinCommunity: true
amISectionAdmin: communityData.amISectionAdmin
amISectionAdmin: communityData.memberRole === Constants.memberRole.owner ||
communityData.memberRole === Constants.memberRole.admin
communityItemsModel: root.rootStore.communityItemsModel
requirementsMet: root.permissionsStore.allTokenRequirementsMet
communityHoldingsModel: root.permissionsStore.permissionsModel

View File

@ -16,6 +16,7 @@ Control{
property int permissionType: PermissionTypes.Type.None
property bool isPrivate: false
property bool showButtons: true
signal editClicked
signal duplicateClicked
@ -174,6 +175,7 @@ Control{
RowLayout {
id: footer
visible: root.showButtons
spacing: 85
Layout.fillWidth: true
Layout.bottomMargin: d.commonMargin

View File

@ -89,7 +89,7 @@ Item {
isContact: model.isContact
isVerified: model.isVerified
isUntrustworthy: model.isUntrustworthy
isAdmin: model.isAdmin
isAdmin: model.memberRole === Constants.memberRole.owner
asset.name: model.icon
asset.isImage: (asset.name !== "")
asset.isLetterIdenticon: (asset.name === "")

View File

@ -70,7 +70,7 @@ Item {
readonly property bool itsMe: model.pubKey.toLowerCase() === userProfile.pubKey.toLowerCase()
readonly property bool isHovered: memberItem.sensor.containsMouse
readonly property bool canBeBanned: !memberItem.itsMe && !model.isAdmin
readonly property bool canBeBanned: !memberItem.itsMe && model.memberRole !== Constants.memberRole.owner
statusListItemComponentsSlot.spacing: 16
statusListItemTitleArea.anchors.rightMargin: 0

View File

@ -147,6 +147,7 @@ StackLayout {
}
CommunityBanner {
objectName: "airdropBanner"
visible: root.owned
text: qsTr("Try an airdrop to reward your community for engagement!")
buttonText: qsTr("Airdrop Tokens")
icon.name: "airdrop"
@ -159,6 +160,7 @@ StackLayout {
CommunityBanner {
objectName: "backUpBanner"
visible: root.owned
text: qsTr("Back up community key")
buttonText: qsTr("Back up")
icon.name: "objects"

View File

@ -16,11 +16,9 @@ SettingsPageLayout {
required property var collectiblesModel
required property var channelsModel
// name, image, color properties expected
// name, image, color, owner properties expected
required property var communityDetails
property bool isOwner: false
property int viewWidth: 560 // by design
// TODO: temporary property, to be removed when no need to hide the switch
@ -173,7 +171,6 @@ SettingsPageLayout {
collectiblesModel: root.collectiblesModel
channelsModel: root.channelsModel
communityDetails: root.communityDetails
isOwner: root.isOwner
isEditState: root.state === d.editPermissionViewState

View File

@ -64,7 +64,7 @@ Column {
StatusListItem {
anchors.horizontalCenter: parent.horizontalCenter
visible: root.community.amISectionAdmin
visible: root.community.memberRole === Constants.memberRole.owner
title: qsTr("Transfer ownership")
asset.name: "exchange"
type: StatusListItem.Type.Secondary

View File

@ -37,6 +37,10 @@ Item {
property bool hasAddedContacts: false
property var communityData
readonly property bool isSectionAdmin:
communityData.memberRole === Constants.memberRole.owner ||
communityData.memberRole === Constants.memberRole.admin
signal infoButtonClicked
signal manageButtonClicked
@ -50,7 +54,7 @@ Item {
membersCount: communityData.members.count
image: communityData.image
color: communityData.color
amISectionAdmin: communityData.amISectionAdmin
amISectionAdmin: root.isSectionAdmin
openCreateChat: root.store.openCreateChat
onInfoButtonClicked: root.infoButtonClicked()
onAdHocChatButtonClicked: root.store.openCloseCreateChatView()
@ -121,7 +125,7 @@ Item {
StatusMenu {
id: adminPopupMenu
enabled: communityData.amISectionAdmin
enabled: root.isSectionAdmin
property bool showInviteButton: false
@ -177,8 +181,8 @@ Item {
StatusChatListAndCategories {
id: communityChatListAndCategories
width: scrollView.availableWidth
draggableItems: communityData.amISectionAdmin
draggableCategories: communityData.amISectionAdmin
draggableItems: root.isSectionAdmin
draggableCategories: root.isSectionAdmin
model: root.communitySectionModule.model
highlightItem: !root.store.openCreateChat
@ -188,8 +192,8 @@ Item {
root.communitySectionModule.setActiveItem(id)
}
showCategoryActionButtons: communityData.amISectionAdmin
showPopupMenu: communityData.amISectionAdmin && communityData.canManageUsers
showCategoryActionButtons: root.isSectionAdmin
showPopupMenu: root.isSectionAdmin && communityData.canManageUsers
onChatItemUnmuted: root.communitySectionModule.unmuteChat(id)
onChatItemReordered: function(categoryId, chatId, to) {
@ -205,14 +209,14 @@ Item {
StatusAction {
text: qsTr("Create channel")
icon.name: "channel"
enabled: communityData.amISectionAdmin
enabled: root.isSectionAdmin
onTriggered: Global.openPopup(createChannelPopup)
}
StatusAction {
text: qsTr("Create category")
icon.name: "channel-category"
enabled: communityData.amISectionAdmin
enabled: root.isSectionAdmin
onTriggered: Global.openPopup(createCategoryPopup)
}
@ -254,7 +258,7 @@ Item {
StatusAction {
objectName: "editCategoryMenuItem"
enabled: communityData.amISectionAdmin
enabled: root.isSectionAdmin
text: qsTr("Edit Category")
icon.name: "edit"
onTriggered: {
@ -268,12 +272,12 @@ Item {
}
StatusMenuSeparator {
visible: communityData.amISectionAdmin
visible: root.isSectionAdmin
}
StatusAction {
objectName: "deleteCategoryMenuItem"
enabled: communityData.amISectionAdmin
enabled: root.isSectionAdmin
text: qsTr("Delete Category")
icon.name: "delete"
type: StatusAction.Type.Danger
@ -305,7 +309,7 @@ Item {
currentFleet = root.communitySectionModule.getCurrentFleet()
isCommunityChat = root.communitySectionModule.isCommunity()
amIChatAdmin = obj.amIChatAdmin
amIChatAdmin = root.isSectionAdmin
chatId = obj.itemId
chatName = obj.name
chatDescription = obj.description
@ -379,7 +383,7 @@ Item {
spacing: Style.current.bigPadding
Loader {
active: communityData.amISectionAdmin &&
active: root.isSectionAdmin &&
(!localAccountSensitiveSettings.hiddenCommunityWelcomeBanners ||
!localAccountSensitiveSettings.hiddenCommunityWelcomeBanners.includes(communityData.id))
width: parent.width
@ -396,7 +400,7 @@ Item {
} // Loader
Loader {
active: communityData.amISectionAdmin &&
active: root.isSectionAdmin &&
(!localAccountSensitiveSettings.hiddenCommunityChannelAndCategoriesBanners ||
!localAccountSensitiveSettings.hiddenCommunityChannelAndCategoriesBanners.includes(communityData.id))
width: parent.width
@ -416,7 +420,7 @@ Item {
} // Loader
Loader {
active: communityData.amISectionAdmin &&
active: root.communityData.memberRole === Constants.memberRole.owner &&
(!localAccountSensitiveSettings.hiddenCommunityBackUpBanners ||
!localAccountSensitiveSettings.hiddenCommunityBackUpBanners.includes(communityData.id))
width: parent.width
@ -438,7 +442,7 @@ Item {
background: Item {
TapHandler {
enabled: communityData.amISectionAdmin
enabled: root.isSectionAdmin
acceptedButtons: Qt.RightButton
onTapped: {
adminPopupMenu.showInviteButton = true
@ -455,7 +459,7 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: active ? Style.current.padding : 0
active: communityData.amISectionAdmin
active: root.isSectionAdmin
sourceComponent: Component {
StatusBaseText {
id: createChannelOrCategoryBtn

View File

@ -37,9 +37,11 @@ StatusSectionLayout {
// TODO: get this model from backend?
property var settingsMenuModel: [{id: Constants.CommunitySettingsSections.Overview, name: qsTr("Overview"), icon: "show", enabled: true},
{id: Constants.CommunitySettingsSections.Members, name: qsTr("Members"), icon: "group-chat", enabled: true, },
{id: Constants.CommunitySettingsSections.Permissions, name: qsTr("Permissions"), icon: "objects", enabled: true},
{id: Constants.CommunitySettingsSections.MintTokens, name: qsTr("Mint Tokens"), icon: "token", enabled: true},
{id: Constants.CommunitySettingsSections.Airdrops, name: qsTr("Airdrops"), icon: "airdrop", enabled: true}]
{id: Constants.CommunitySettingsSections.MintTokens, name: qsTr("Mint Tokens"), icon: "token", enabled: root.community.memberRole === Constants.memberRole.owner},
{id: Constants.CommunitySettingsSections.Airdrops, name: qsTr("Airdrops"), icon: "airdrop", enabled: root.community.memberRole === Constants.memberRole.owner}]
// TODO: Next community settings options:
// {name: qsTr("Token sales"), icon: "token-sale"},
// {name: qsTr("Subscriptions"), icon: "subscription"},
@ -49,6 +51,9 @@ StatusSectionLayout {
property bool hasAddedContacts: false
property var transactionStore: TransactionStore {}
property bool isAdmin: community.memberRole === Constants.memberRole.owner ||
community.memberRole === Constants.memberRole.admin
readonly property string filteredSelectedTags: {
var tagsArray = []
if (community && community.tags) {
@ -177,7 +182,8 @@ StatusSectionLayout {
archiveSupportEnabled: root.community.historyArchiveSupportEnabled
requestToJoinEnabled: root.community.access === Constants.communityChatOnRequestAccess
pinMessagesEnabled: root.community.pinMessageAllMembersEnabled
editable: root.community.amISectionAdmin
editable: true
owned: root.community.memberRole === Constants.memberRole.owner
onEdited: {
const error = root.chatCommunitySectionModule.editCommunity(
@ -219,7 +225,7 @@ StatusSectionLayout {
bannedMembersModel: root.community.bannedMembers
pendingMemberRequestsModel: root.community.pendingMemberRequests
declinedMemberRequestsModel: root.community.declinedMemberRequests
editable: root.community.amISectionAdmin
editable: root.isAdmin
communityName: root.community.name
onKickUserClicked: root.rootStore.removeUserFromCommunity(id)
@ -245,12 +251,10 @@ StatusSectionLayout {
channelsModel: rootStore.chatCommunitySectionModule.model
communityDetails: QtObject {
readonly property var _activeSection:
rootStore.mainModuleInst.activeSection
readonly property string name: _activeSection.name
readonly property string image: _activeSection.image
readonly property string color: _activeSection.color
readonly property string name: root.community.name
readonly property string image: root.community.image
readonly property string color: root.community.color
readonly property bool owner: root.community.memberRole === Constants.memberRole.owner
}
onCreatePermissionRequested:

View File

@ -152,7 +152,7 @@ Item {
currentFleet = root.chatSectionModule.getCurrentFleet()
isCommunityChat = root.chatSectionModule.isCommunity()
amIChatAdmin = obj.amIChatAdmin
amIChatAdmin = obj.memberRole === Constants.memberRole.owner || obj.memberRole === Constants.memberRole.admin
chatId = obj.itemId
chatName = obj.name
chatDescription = obj.description

View File

@ -46,7 +46,7 @@ MembersSelectorBase {
model: SortFilterProxyModel {
sourceModel: root.usersStore.temporaryModel
sorters: RoleSorter {
roleName: "isAdmin"
roleName: "memberRole"
sortOrder: Qt.DescendingOrder
}
}
@ -58,11 +58,11 @@ MembersSelectorBase {
text: root.tagText(model.localNickname, model.displayName, model.alias)
isReadonly: {
if (model.isAdmin) return true
if (model.memberRole === Constants.memberRole.owner) return true
if (root.rootStore.amIChatAdmin()) return false
return index < root.usersStore.usersModel.count
}
icon: model.isAdmin ? "crown" : ""
icon: model.memberRole === Constants.memberRole.owner ? "crown" : ""
onClosed: root.entryRemoved(this)
}

View File

@ -23,11 +23,9 @@ StatusScrollView {
required property var collectiblesModel
required property var channelsModel
// name, image, color properties expected
// name, image, color, owner properties expected
required property var communityDetails
property bool isOwner: false
property int viewWidth: 560 // by design
property bool isEditState: false
@ -432,7 +430,7 @@ StatusScrollView {
id: permissionsDropdown
initialPermissionType: d.dirtyValues.permissionType
enableAdminPermission: root.isOwner
enableAdminPermission: root.communityDetails.owner
onDone: {
if (d.dirtyValues.permissionType === permissionType) {

View File

@ -16,7 +16,7 @@ StatusScrollView {
required property var collectiblesModel
required property var channelsModel
// name, image, color properties expected
// name, image, color, owner properties expected
required property var communityDetails
property int viewWidth: 560 // by design
@ -73,6 +73,8 @@ StatusScrollView {
? channelsSelectionModel : communityItemModel
isPrivate: model.isPrivate
showButtons: root.communityDetails.owner
onEditClicked: root.editPermissionRequested(model.index)
onDuplicateClicked: root.duplicatePermissionRequested(model.index)

View File

@ -10,7 +10,6 @@ QtObject {
property var mainModuleInst: mainModule
property var aboutModuleInst: aboutModule
property var communitiesModuleInst: communitiesModule
property var observedCommunity: communitiesModuleInst.observedCommunity
property bool newVersionAvailable: false
property string latestVersion

View File

@ -396,6 +396,14 @@ QtObject {
readonly property int communityChat: 6
}
readonly property QtObject memberRole: QtObject{
readonly property int none: 0
readonly property int owner: 1
readonly property int manageUsers: 2
readonly property int moderateContent: 3
readonly property int admin: 4
}
readonly property QtObject messageContentType: QtObject {
readonly property int newMessagesMarker: -3
readonly property int fetchMoreMessagesButton: -2

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 2b029688191f008f900ced65bbb9d8724a077cd3
Subproject commit e058b50a2e33887a5f5f0ff2b6e2358de161d413