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

View File

@ -206,7 +206,7 @@ proc init*(self: Controller) =
let args = ChatMemberUpdatedArgs(e) let args = ChatMemberUpdatedArgs(e)
if (args.chatId != self.chatId): if (args.chatId != self.chatId):
return 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): self.events.on(SIGNAL_MAILSERVER_SYNCED) do(e: Args):
let args = MailserverSyncedArgs(e) 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/message/dto/[message, reaction, pinned_message]
import ../../../../../../app_service/service/community/dto/community import ../../../../../../app_service/service/community/dto/community
import ../../../../shared_models/message_item import ../../../../shared_models/message_item
import ../../../../../../app_service/common/types
type type
AccessInterface* {.pure inheritable.} = ref object of RootObj 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.} = method scrollToMessage*(self: AccessInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available") 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") raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} = 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/chat/service as chat_service
import ../../../../../../app_service/service/message/service as message_service import ../../../../../../app_service/service/message/service as message_service
import ../../../../../../app_service/service/mailservers/service as mailservers_service import ../../../../../../app_service/service/mailservers/service as mailservers_service
import ../../../../../../app_service/common/types
export io_interface export io_interface
@ -556,12 +557,12 @@ method amIChatAdmin*(self: Module): bool =
if(not self.controller.belongsToCommunity()): if(not self.controller.belongsToCommunity()):
let chatDto = self.controller.getChatDetails() let chatDto = self.controller.getChatDetails()
for member in chatDto.members: for member in chatDto.members:
if (member.id == singletonInstance.userProfile.getPubKey() and member.admin): if (member.id == singletonInstance.userProfile.getPubKey()):
return true return member.role == MemberRole.Owner or member.role == MemberRole.Admin
return false return false
else: else:
let communityDto = self.controller.getCommunityDetails() let communityDto = self.controller.getCommunityDetails()
return communityDto.admin return communityDto.memberRole == MemberRole.Owner or communityDto.memberRole == MemberRole.Admin
method pinMessageAllowedForMembers*(self: Module): bool = method pinMessageAllowedForMembers*(self: Module): bool =
if(self.controller.belongsToCommunity()): if(self.controller.belongsToCommunity()):
@ -676,7 +677,7 @@ method fillGaps*(self: Module, messageId: string) =
method leaveChat*(self: Module) = method leaveChat*(self: Module) =
self.controller.leaveChat() 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() let chatDto = self.controller.getChatDetails()
if(chatDto.chatType != ChatType.PrivateGroupChat): if(chatDto.chatType != ChatType.PrivateGroupChat):
return return
@ -719,7 +720,7 @@ method markMessagesAsRead*(self: Module, messages: seq[string]) =
self.view.model().markAsSeen(messages) self.view.model().markAsSeen(messages)
method updateCommunityDetails*(self: Module, community: CommunityDto) = 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) self.view.setIsPinMessageAllowedForMembers(community.adminSettings.pinMessageAllMembersEnabled)
proc setChatDetails(self: Module, chatDetails: ChatDto) = 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/gif/service as gif_service
import ../../../../../app_service/service/message/service as message_service import ../../../../../app_service/service/message/service as message_service
import ../../../../../app_service/service/mailservers/service as mailservers_service import ../../../../../app_service/service/mailservers/service as mailservers_service
import ../../../../../app_service/common/types
export io_interface export io_interface
@ -324,17 +325,6 @@ method toggleReactionFromOthers*(self: Module, messageId: string, emojiId: int,
method getCurrentFleet*(self: Module): string = method getCurrentFleet*(self: Module): string =
return self.controller.getCurrentFleet() 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) = method onContactDetailsUpdated*(self: Module, contactId: string) =
let updatedContact = self.controller.getContactDetails(contactId) let updatedContact = self.controller.getContactDetails(contactId)
for item in self.view.pinnedModel().modelContactUpdateIterator(contactId): for item in self.view.pinnedModel().modelContactUpdateIterator(contactId):
@ -399,3 +389,14 @@ method onMadeInactive*(self: Module) =
if self.controller.getChatDetails().unviewedMessagesCount == 0: if self.controller.getChatDetails().unviewedMessagesCount == 0:
self.messagesModule.removeNewMessagesMarker() self.messagesModule.removeNewMessagesMarker()
self.view.setInactive() 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): self.events.on(SIGNAL_CHAT_MEMBER_UPDATED) do(e: Args):
let args = ChatMemberUpdatedArgs(e) let args = ChatMemberUpdatedArgs(e)
if (args.chatId == self.chatId): 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 # Events only for community channel
if (self.belongsToCommunity): if (self.belongsToCommunity):

View File

@ -3,6 +3,7 @@ import NimQml
import ../../../../../../app_service/service/chat/service as chat_service import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../../app_service/service/message/dto/[message] import ../../../../../../app_service/service/message/dto/[message]
import ../../../../../../app_service/service/contacts/dto/[status_update] import ../../../../../../app_service/service/contacts/dto/[status_update]
import ../../../../../../app_service/common/types
type type
AccessInterface* {.pure inheritable.} = ref object of RootObj 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.} = method onChatMemberRemoved*(self: AccessInterface, ids: string) {.base.} =
raise newException(ValueError, "No implementation available") 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") raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} = method viewDidLoad*(self: AccessInterface) {.base.} =

View File

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

View File

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

View File

@ -8,7 +8,7 @@ type
ModelRole {.pure.} = enum ModelRole {.pure.} = enum
Id = UserRole + 1 Id = UserRole + 1
Name Name
AmIChatAdmin MemberRole
Icon Icon
Color Color
ColorId ColorId
@ -76,7 +76,7 @@ QtObject:
{ {
ModelRole.Id.int:"itemId", ModelRole.Id.int:"itemId",
ModelRole.Name.int:"name", ModelRole.Name.int:"name",
ModelRole.AmIChatAdmin.int:"amIChatAdmin", ModelRole.MemberRole.int:"memberRole",
ModelRole.Icon.int:"icon", ModelRole.Icon.int:"icon",
ModelRole.Color.int:"color", ModelRole.Color.int:"color",
ModelRole.ColorId.int:"colorId", ModelRole.ColorId.int:"colorId",
@ -116,8 +116,8 @@ QtObject:
result = newQVariant(item.id) result = newQVariant(item.id)
of ModelRole.Name: of ModelRole.Name:
result = newQVariant(item.name) result = newQVariant(item.name)
of ModelRole.AmIChatAdmin: of ModelRole.MemberRole:
result = newQVariant(item.amIChatAdmin) result = newQVariant(item.memberRole.int)
of ModelRole.Icon: of ModelRole.Icon:
result = newQVariant(item.icon) result = newQVariant(item.icon)
of ModelRole.Color: 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/visual_identity/service as visual_identity
import ../../../../app_service/service/contacts/dto/contacts as contacts_dto import ../../../../app_service/service/contacts/dto/contacts as contacts_dto
import ../../../../app_service/service/community/dto/community as community_dto import ../../../../app_service/service/community/dto/community as community_dto
import ../../../../app_service/common/types
export io_interface export io_interface
@ -140,11 +141,11 @@ method isCommunity*(self: Module): bool =
method getMySectionId*(self: Module): string = method getMySectionId*(self: Module): string =
return self.controller.getMySectionId() return self.controller.getMySectionId()
proc amIMarkedAsAdminUser(self: Module, members: seq[ChatMember]): bool = proc getUserMemberRole(self: Module, members: seq[ChatMember]): MemberRole =
for m in members: for m in members:
if (m.id == singletonInstance.userProfile.getPubKey() and m.admin): if m.id == singletonInstance.userProfile.getPubKey():
return true return m.role
return false return MemberRole.None
proc addSubmodule(self: Module, chatId: string, belongToCommunity: bool, isUsersListAvailable: bool, events: EventEmitter, proc addSubmodule(self: Module, chatId: string, belongToCommunity: bool, isUsersListAvailable: bool, events: EventEmitter,
settingsService: settings_service.Service, settingsService: settings_service.Service,
@ -165,7 +166,7 @@ proc removeSubmodule(self: Module, chatId: string) =
self.chatContentModules.del(chatId) 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) let hasUnreadMessages = self.controller.chatsWithCategoryHaveUnreadMessages(communityId, category.id)
result = chat_item.initItem( result = chat_item.initItem(
id = category.id, id = category.id,
@ -175,7 +176,7 @@ proc addCategoryItem(self: Module, category: Category, amIAdmin: bool, community
emoji = "", emoji = "",
description = "", description = "",
`type` = chat_item.CATEGORY_TYPE, `type` = chat_item.CATEGORY_TYPE,
amIAdmin, memberRole,
lastMessageTimestamp = 0, lastMessageTimestamp = 0,
hasUnreadMessages, hasUnreadMessages,
notificationsCount = 0, notificationsCount = 0,
@ -207,7 +208,7 @@ proc buildChatSectionUI(
var items: seq[Item] = @[] var items: seq[Item] = @[]
for categoryDto in channelGroup.categories: for categoryDto in channelGroup.categories:
# Add items for the categories. We use a special type to identify 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: for chatDto in channelGroup.chats:
var categoryPosition = -1 var categoryPosition = -1
@ -282,13 +283,17 @@ proc rebuildCommunityTokenPermissionsModel(self: Module) =
var tokenPermissionsItems: seq[TokenPermissionItem] = @[] var tokenPermissionsItems: seq[TokenPermissionItem] = @[]
for id, tokenPermission in community.tokenPermissions: for id, tokenPermission in community.tokenPermissions:
# TODO: for startes we only deal with "become member" permissions let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
if tokenPermission.`type` == TokenPermissionType.BecomeMember: 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.tokenPermissionsModel().setItems(tokenPermissionsItems)
self.view.setRequiresTokenPermissionToJoin(tokenPermissionsItems.len > 0) self.view.setRequiresTokenPermissionToJoin(len(memberPermissions) > 0 or len(adminPermissions) > 0)
proc initCommunityTokenPermissionsModel(self: Module) = proc initCommunityTokenPermissionsModel(self: Module) =
self.rebuildCommunityTokenPermissionsModel() self.rebuildCommunityTokenPermissionsModel()
@ -574,12 +579,12 @@ method addNewChat*(
elif chatDto.chatType == ChatType.PrivateGroupChat: elif chatDto.chatType == ChatType.PrivateGroupChat:
chatImage = chatDto.icon chatImage = chatDto.icon
var amIChatAdmin = self.amIMarkedAsAdminUser(chatDto.members) var memberRole = self.getUserMemberRole(chatDto.members)
if not amIChatAdmin and len(chatDto.communityId) != 0:
let community = communityService.getCommunityById(chatDto.communityId) if memberRole == MemberRole.None and len(chatDto.communityId) != 0:
amIChatAdmin = amIChatAdmin or community.admin memberRole = channelGroup.memberRole
if chatDto.chatType != ChatType.PrivateGroupChat: if chatDto.chatType != ChatType.PrivateGroupChat:
amIChatAdmin = amIChatAdmin or channelGroup.admin memberRole = channelGroup.memberRole
var categoryOpened = true var categoryOpened = true
if chatDto.categoryId != "": if chatDto.categoryId != "":
@ -605,7 +610,7 @@ method addNewChat*(
chatDto.emoji, chatDto.emoji,
chatDto.description, chatDto.description,
ChatType(chatDto.chatType).int, ChatType(chatDto.chatType).int,
amIChatAdmin, memberRole,
chatDto.timestamp.int, chatDto.timestamp.int,
hasNotification, hasNotification,
notificationsCount, notificationsCount,
@ -680,8 +685,8 @@ method onCommunityCategoryCreated*(self: Module, cat: Category, chats: seq[ChatD
if (self.doesCatOrChatExist(cat.id)): if (self.doesCatOrChatExist(cat.id)):
return return
# TODO get admin status let community = self.controller.getCommunityById(communityId)
discard self.addCategoryItem(cat, false, communityId) discard self.addCategoryItem(cat, community.memberRole, communityId)
# Update chat items that now belong to that category # Update chat items that now belong to that category
self.view.chatsModel().updateItemsWithCategoryDetailsById( self.view.chatsModel().updateItemsWithCategoryDetailsById(
chats, 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") singletonInstance.globalEvents.showCommunityTokenPermissionDeletedNotification(communityId, "Community permission deleted", "A token permission has been removed")
method onCommunityTokenPermissionCreated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) = 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") singletonInstance.globalEvents.showCommunityTokenPermissionCreatedNotification(communityId, "Community permission created", "A token permission has been added")
method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) = method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) =
let community = self.controller.getMyCommunity() let community = self.controller.getMyCommunity()
self.view.setAllTokenRequirementsMet(checkPermissionsToJoinResponse.satisfied)
for id, criteriaResult in checkPermissionsToJoinResponse.permissions: for id, criteriaResult in checkPermissionsToJoinResponse.permissions:
if community.tokenPermissions.hasKey(id): if community.tokenPermissions.hasKey(id):
let tokenPermissionItem = self.view.tokenPermissionsModel.getItemById(id) let tokenPermissionItem = self.view.tokenPermissionsModel.getItemById(id)
var updatedTokenCriteriaItems: seq[TokenCriteriaItem] = @[] var updatedTokenCriteriaItems: seq[TokenCriteriaItem] = @[]
@ -824,13 +828,34 @@ method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissions
tokenPermissionItem.isPrivate, tokenPermissionItem.isPrivate,
permissionSatisfied 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) = method onCommunityTokenPermissionUpdated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) =
if tokenPermission.`type` == TokenPermissionType.BecomeMember: let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission) self.view.tokenPermissionsModel.updateItem(tokenPermission.id, tokenPermissionItem)
self.view.tokenPermissionsModel.updateItem(tokenPermission.id, tokenPermissionItem)
singletonInstance.globalEvents.showCommunityTokenPermissionUpdatedNotification(communityId, "Community permission updated", "A token permission has been updated") 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.emoji,
c.description, c.description,
c.chatType.int, c.chatType.int,
amIChatAdmin=false, memberRole=MemberRole.None,
lastMessageTimestamp=(-1), lastMessageTimestamp=(-1),
hasUnreadMessages=false, hasUnreadMessages=false,
notificationsCount=0, notificationsCount=0,
@ -1121,7 +1146,7 @@ method prepareEditCategoryModel*(self: Module, categoryId: string) =
c.emoji, c.emoji,
c.description, c.description,
c.chatType.int, c.chatType.int,
amIChatAdmin=false, memberRole=MemberRole.None,
lastMessageTimestamp=(-1), lastMessageTimestamp=(-1),
hasUnreadMessages=false, hasUnreadMessages=false,
notificationsCount=0, notificationsCount=0,

View File

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

View File

@ -19,7 +19,6 @@ QtObject:
delegate: io_interface.AccessInterface delegate: io_interface.AccessInterface
model: SectionModel model: SectionModel
modelVariant: QVariant modelVariant: QVariant
observedItem: SectionDetails
curatedCommunitiesModel: CuratedCommunityModel curatedCommunitiesModel: CuratedCommunityModel
curatedCommunitiesModelVariant: QVariant curatedCommunitiesModelVariant: QVariant
curatedCommunitiesLoading: bool curatedCommunitiesLoading: bool
@ -50,7 +49,6 @@ QtObject:
proc delete*(self: View) = proc delete*(self: View) =
self.model.delete self.model.delete
self.modelVariant.delete self.modelVariant.delete
self.observedItem.delete
self.curatedCommunitiesModel.delete self.curatedCommunitiesModel.delete
self.curatedCommunitiesModelVariant.delete self.curatedCommunitiesModelVariant.delete
self.discordFileListModel.delete self.discordFileListModel.delete
@ -90,7 +88,6 @@ QtObject:
result.discordImportHasCommunityImage = false result.discordImportHasCommunityImage = false
result.discordImportTasksModel = newDiscordDiscordImportTasksModel() result.discordImportTasksModel = newDiscordDiscordImportTasksModel()
result.discordImportTasksModelVariant = newQVariant(result.discordImportTasksModel) result.discordImportTasksModelVariant = newQVariant(result.discordImportTasksModel)
result.observedItem = newActiveSection()
result.downloadingCommunityHistoryArchives = false result.downloadingCommunityHistoryArchives = false
proc load*(self: View) = proc load*(self: View) =
@ -338,22 +335,6 @@ QtObject:
QtProperty[QVariant] discordImportTasks: QtProperty[QVariant] discordImportTasks:
read = getDiscordImportTasksModel 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 discordDataExtractionInProgressChanged*(self: View) {.signal.}
proc getDiscordDataExtractionInProgress(self: View): bool {.slot.} = 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 notificationsCount = channelGroup.unviewedMentionsCount
let hasNotification = unviewedCount > 0 or notificationsCount > 0 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 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( result = initItem(
channelGroup.id, channelGroup.id,
if isCommunity: SectionType.Community else: SectionType.Chat, if isCommunity: SectionType.Community else: SectionType.Chat,
if isCommunity: channelGroup.name else: conf.CHAT_SECTION_NAME, if isCommunity: channelGroup.name else: conf.CHAT_SECTION_NAME,
channelGroup.admin, channelGroup.memberRole,
channelGroup.description, channelGroup.description,
channelGroup.introMessage, channelGroup.introMessage,
channelGroup.outroMessage, channelGroup.outroMessage,
@ -296,7 +297,7 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(member.id).statusType), onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(member.id).statusType),
isContact = contactDetails.dto.isContact, isContact = contactDetails.dto.isContact,
isVerified = contactDetails.dto.isContactVerified(), isVerified = contactDetails.dto.isContactVerified(),
isAdmin = member.admin memberRole = member.role
)), )),
# pendingRequestsToJoin # pendingRequestsToJoin
if (isCommunity): communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem( if (isCommunity): communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem(
@ -395,7 +396,7 @@ method load*[T](
conf.COMMUNITIESPORTAL_SECTION_ID, conf.COMMUNITIESPORTAL_SECTION_ID,
SectionType.CommunitiesPortal, SectionType.CommunitiesPortal,
conf.COMMUNITIESPORTAL_SECTION_NAME, conf.COMMUNITIESPORTAL_SECTION_NAME,
amISectionAdmin = false, memberRole = MemberRole.Owner,
description = "", description = "",
image = "", image = "",
icon = conf.COMMUNITIESPORTAL_SECTION_ICON, icon = conf.COMMUNITIESPORTAL_SECTION_ICON,
@ -414,7 +415,7 @@ method load*[T](
conf.WALLET_SECTION_ID, conf.WALLET_SECTION_ID,
SectionType.Wallet, SectionType.Wallet,
conf.WALLET_SECTION_NAME, conf.WALLET_SECTION_NAME,
amISectionAdmin = false, memberRole = MemberRole.Owner,
description = "", description = "",
introMessage = "", introMessage = "",
outroMessage = "", outroMessage = "",
@ -435,7 +436,7 @@ method load*[T](
conf.BROWSER_SECTION_ID, conf.BROWSER_SECTION_ID,
SectionType.Browser, SectionType.Browser,
conf.BROWSER_SECTION_NAME, conf.BROWSER_SECTION_NAME,
amISectionAdmin = false, memberRole = MemberRole.Owner,
description = "", description = "",
introMessage = "", introMessage = "",
outroMessage = "", outroMessage = "",
@ -456,7 +457,7 @@ method load*[T](
conf.NODEMANAGEMENT_SECTION_ID, conf.NODEMANAGEMENT_SECTION_ID,
SectionType.NodeManagement, SectionType.NodeManagement,
conf.NODEMANAGEMENT_SECTION_NAME, conf.NODEMANAGEMENT_SECTION_NAME,
amISectionAdmin = false, memberRole = MemberRole.Owner,
description = "", description = "",
introMessage = "", introMessage = "",
outroMessage = "", outroMessage = "",
@ -477,7 +478,7 @@ method load*[T](
conf.SETTINGS_SECTION_ID, conf.SETTINGS_SECTION_ID,
SectionType.ProfileSettings, SectionType.ProfileSettings,
conf.SETTINGS_SECTION_NAME, conf.SETTINGS_SECTION_NAME,
amISectionAdmin = false, memberRole = MemberRole.Owner,
description = "", description = "",
introMessage = "", introMessage = "",
outroMessage = "", outroMessage = "",
@ -512,7 +513,7 @@ method load*[T](
LOADING_SECTION_ID, LOADING_SECTION_ID,
SectionType.LoadingSection, SectionType.LoadingSection,
name = "", name = "",
amISectionAdmin = false, memberRole = MemberRole.Owner,
description = "", description = "",
image = "", image = "",
icon = "", icon = "",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
import json import json
import web3/ethtypes import web3/ethtypes
import types
template getProp(obj: JsonNode, prop: string, value: var typedesc[int]): bool = template getProp(obj: JsonNode, prop: string, value: var typedesc[int]): bool =
var success = false var success = false
@ -72,3 +73,11 @@ template getProp(obj: JsonNode, prop: string, value: var typedesc[Address]): boo
success = true success = true
success 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 return OnlineStatus.Online
else: else:
return OnlineStatus.Inactive 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 import ../../community/dto/community
include ../../../common/json_utils include ../../../common/json_utils
import ../../../../app_service/common/types
type ChatType* {.pure.}= enum type ChatType* {.pure.}= enum
Unknown = 0, Unknown = 0,
@ -18,14 +19,6 @@ type ChannelGroupType* {.pure.}= enum
Personal = "personal", Personal = "personal",
Community = "community" 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 type Category* = object
id*: string id*: string
name*: string name*: string
@ -44,9 +37,8 @@ type
type ChatMember* = object type ChatMember* = object
id*: string id*: string
admin*: bool
joined*: bool joined*: bool
roles*: seq[int] role*: MemberRole
type ChatDto* = object type ChatDto* = object
id*: string # ID is the id of the chat, for public chats it is the name e.g. status, 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 type ChannelGroupDto* = object
id*: string id*: string
channelGroupType*: ChannelGroupType channelGroupType*: ChannelGroupType
admin*: bool memberRole*: MemberRole
verified*: bool verified*: bool
name*: string name*: string
ensName*: 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 # Mapping this DTO is not strightforward since only keys are used for id
result = ChatMember() result = ChatMember()
result.id = memberId result.id = memberId
discard jsonObj.getProp("admin", result.admin)
discard jsonObj.getProp("joined", result.joined) discard jsonObj.getProp("joined", result.joined)
var rolesObj: JsonNode discard jsonObj.getProp("role", result.role)
if(jsonObj.getProp("roles", rolesObj) and rolesObj.kind == JArray):
for role in rolesObj:
result.roles.add(role.getInt)
proc toGroupChatMember*(jsonObj: JsonNode): ChatMember = proc toGroupChatMember*(jsonObj: JsonNode): ChatMember =
# parse status-go "ChatMember" type # parse status-go "ChatMember" type
result = ChatMember() result = ChatMember()
discard jsonObj.getProp("id", result.id) 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 result.joined = true
proc toChannelMember*(jsonObj: JsonNode, memberId: string, joined: bool): ChatMember = 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 = ChatMember()
result.id = memberId result.id = memberId
var rolesObj: JsonNode var rolesObj: JsonNode
var roles: seq[int] = @[]
if(jsonObj.getProp("roles", rolesObj)): if(jsonObj.getProp("roles", rolesObj)):
for roleObj in 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.joined = joined
result.admin = isMemberAdmin(result.roles)
proc toChatDto*(jsonObj: JsonNode): ChatDto = proc toChatDto*(jsonObj: JsonNode): ChatDto =
result = ChatDto() result = ChatDto()
@ -268,8 +268,9 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
proc toChannelGroupDto*(jsonObj: JsonNode): ChannelGroupDto = proc toChannelGroupDto*(jsonObj: JsonNode): ChannelGroupDto =
result = ChannelGroupDto() result = ChannelGroupDto()
discard jsonObj.getProp("admin", result.admin)
discard jsonObj.getProp("verified", result.verified) discard jsonObj.getProp("verified", result.verified)
discard jsonObj.getProp("memberRole", result.memberRole)
discard jsonObj.getProp("name", result.name) discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("description", result.description) discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("introMessage", result.introMessage) discard jsonObj.getProp("introMessage", result.introMessage)

View File

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

View File

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

View File

@ -15,6 +15,8 @@ import ../../../app/core/[main]
import ../../../app/core/tasks/[qt, threadpool] import ../../../app/core/tasks/[qt, threadpool]
import ../../../backend/communities as status_go import ../../../backend/communities as status_go
import ../../../app_service/common/types
include ./async_tasks include ./async_tasks
export community_dto export community_dto
@ -641,7 +643,7 @@ QtObject:
let communities = parseCommunities(responseObj["communities"]) let communities = parseCommunities(responseObj["communities"])
for community in communities: for community in communities:
self.communities[community.id] = community 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].pendingRequestsToJoin = self.pendingRequestsToJoinForCommunity(community.id)
self.communities[community.id].declinedRequestsToJoin = self.declinedRequestsToJoinForCommunity(community.id) self.communities[community.id].declinedRequestsToJoin = self.declinedRequestsToJoinForCommunity(community.id)
self.communities[community.id].canceledRequestsToJoin = self.canceledRequestsToJoinForCommunity(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_EDITED, CommunityArgs(community: self.communities[communityId]))
self.events.emit(SIGNAL_COMMUNITY_MEMBER_APPROVED, CommunityMemberArgs(communityId: communityId, pubKey: userKey, requestId: requestId)) 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: except Exception as e:
let errMsg = e.msg let errMsg = e.msg

View File

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

View File

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

View File

@ -89,7 +89,7 @@ Item {
isContact: model.isContact isContact: model.isContact
isVerified: model.isVerified isVerified: model.isVerified
isUntrustworthy: model.isUntrustworthy isUntrustworthy: model.isUntrustworthy
isAdmin: model.isAdmin isAdmin: model.memberRole === Constants.memberRole.owner
asset.name: model.icon asset.name: model.icon
asset.isImage: (asset.name !== "") asset.isImage: (asset.name !== "")
asset.isLetterIdenticon: (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 itsMe: model.pubKey.toLowerCase() === userProfile.pubKey.toLowerCase()
readonly property bool isHovered: memberItem.sensor.containsMouse 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 statusListItemComponentsSlot.spacing: 16
statusListItemTitleArea.anchors.rightMargin: 0 statusListItemTitleArea.anchors.rightMargin: 0

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -396,6 +396,14 @@ QtObject {
readonly property int communityChat: 6 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 QtObject messageContentType: QtObject {
readonly property int newMessagesMarker: -3 readonly property int newMessagesMarker: -3
readonly property int fetchMoreMessagesButton: -2 readonly property int fetchMoreMessagesButton: -2

2
vendor/status-go vendored

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