From 5ebafb1c0c9efd216fb7fede8880e6c95882af16 Mon Sep 17 00:00:00 2001 From: Anthony Laibe Date: Thu, 3 Feb 2022 10:44:35 +0100 Subject: [PATCH] Fix(@chat): add special cases for group chat fixes #4612 fixes #4613 --- .../main/chat_section/chat_content/module.nim | 6 +- .../chat_content/users/controller.nim | 34 ++++++++--- .../users/controller_interface.nim | 9 ++- .../chat_content/users/module.nim | 60 +++++++++++++------ .../module_controller_delegate_interface.nim | 3 + src/app/modules/shared_models/user_item.nim | 34 ++++++++--- src/app/modules/shared_models/user_model.nim | 19 +++++- src/app_service/service/chat/dto/chat.nim | 5 +- src/app_service/service/chat/service.nim | 16 ++++- 9 files changed, 145 insertions(+), 41 deletions(-) diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index 760a5cf4d3..e020e75e45 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -53,8 +53,10 @@ proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitt result.inputAreaModule = input_area_module.newModule(result, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService) result.messagesModule = messages_module.newModule(result, events, sectionId, chatId, belongsToCommunity, contactService, communityService, chatService, messageService, mailserversService) - result.usersModule = users_module.newModule(result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable, - contactService, chatService, communityService, messageService) + result.usersModule = users_module.newModule( + result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable, + contactService, chat_service, communityService, messageService, + ) method delete*(self: Module) = self.inputAreaModule.delete diff --git a/src/app/modules/main/chat_section/chat_content/users/controller.nim b/src/app/modules/main/chat_section/chat_content/users/controller.nim index e7ab79aae1..8a8330c66d 100644 --- a/src/app/modules/main/chat_section/chat_content/users/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/users/controller.nim @@ -25,11 +25,12 @@ type communityService: community_service.Service messageService: message_service.Service -proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter, sectionId: string, chatId: string, +proc newController*( + delegate: io_interface.AccessInterface, events: EventEmitter, sectionId: string, chatId: string, belongsToCommunity: bool, isUsersListAvailable: bool, contactService: contact_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service): - Controller = + messageService: message_service.Service +): Controller = result = Controller() result.delegate = delegate result.events = events @@ -41,6 +42,7 @@ proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter result.chatService = chatService result.communityService = communityService result.messageService = messageService + result.chatService = chatService method delete*(self: Controller) = discard @@ -80,20 +82,36 @@ method init*(self: Controller) = if (args.chatId == self.chatId): self.delegate.onChatMemberRemoved(args.id) + 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) + if (self.belongsToCommunity): self.events.on(SIGNAL_COMMUNITY_MEMBER_APPROVED) do(e: Args): let args = CommunityMemberArgs(e) if (args.communityId == self.sectionId): self.delegate.onChatMembersAdded(@[args.pubKey]) +method getChat*(self: Controller): ChatDto = + return self.chatService.getChatById(self.chatId) + +method getChatMemberInfo*(self: Controller, id: string): (bool, bool) = + let chat = self.getChat() + for member in chat.members: + if (member.id == id): + return (member.admin, member.joined) + + return (false, false) + method getMembersPublicKeys*(self: Controller): seq[string] = - if(not self.belongsToCommunity): - let chatDto = self.chatService.getChatById(self.chatId) - return chatDto.members.map(x => x.id) - else: + if(self.belongsToCommunity): let communityDto = self.communityService.getCommunityById(self.sectionId) return communityDto.members.map(x => x.id) - + else: + let chatDto = self.getChat() + return chatDto.members.map(x => x.id) + method getContactNameAndImage*(self: Controller, contactId: string): tuple[name: string, image: string, isIdenticon: bool] = return self.contactService.getContactNameAndImage(contactId) diff --git a/src/app/modules/main/chat_section/chat_content/users/controller_interface.nim b/src/app/modules/main/chat_section/chat_content/users/controller_interface.nim index f61df0f87e..103691cf9c 100644 --- a/src/app/modules/main/chat_section/chat_content/users/controller_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/users/controller_interface.nim @@ -1,4 +1,5 @@ import ../../../../../../app_service/service/contacts/service as contacts_service +import ../../../../../../app_service/service/chat/service as chat_service type AccessInterface* {.pure inheritable.} = ref object of RootObj @@ -21,4 +22,10 @@ method getContactNameAndImage*(self: AccessInterface, contactId: string): raise newException(ValueError, "No implementation available") method getStatusForContact*(self: AccessInterface, contactId: string): StatusUpdateDto {.base.} = - raise newException(ValueError, "No implementation available") \ No newline at end of file + raise newException(ValueError, "No implementation available") + +method getChat*(self: AccessInterface): ChatDto {.base.} = + raise newException(ValueError, "No implementation available") + +method getChatMemberInfo*(self: AccessInterface, id: string): (bool, bool) = + raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/chat_content/users/module.nim b/src/app/modules/main/chat_section/chat_content/users/module.nim index b4b10076ee..679d17dec0 100644 --- a/src/app/modules/main/chat_section/chat_content/users/module.nim +++ b/src/app/modules/main/chat_section/chat_content/users/module.nim @@ -20,17 +20,20 @@ type controller: controller.AccessInterface moduleLoaded: bool -proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, sectionId: string, chatId: string, +proc newModule*( + delegate: delegate_interface.AccessInterface, events: EventEmitter, sectionId: string, chatId: string, belongsToCommunity: bool, isUsersListAvailable: bool, contactService: contact_service.Service, - chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service): - Module = + chatService: chat_service.Service, communityService: community_service.Service, + messageService: message_service.Service, +): Module = result = Module() result.delegate = delegate result.view = view.newView(result) result.viewVariant = newQVariant(result.view) - result.controller = controller.newController(result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable, - contactService, chatService, communityService, messageService) + result.controller = controller.newController( + result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable, + contactService, chatService, communityService, messageService, + ) result.moduleLoaded = false method delete*(self: Module) = @@ -47,19 +50,29 @@ method isLoaded*(self: Module): bool = method viewDidLoad*(self: Module) = # add me as the first user to the list + let (admin, joined) = self.controller.getChatMemberInfo(singletonInstance.userProfile.getPubKey()) let loggedInUserDisplayName = singletonInstance.userProfile.getName() & "(You)" - self.view.model().addItem(initItem(singletonInstance.userProfile.getPubKey(), loggedInUserDisplayName, - OnlineStatus.Online, singletonInstance.userProfile.getIcon(), singletonInstance.userProfile.getIsIdenticon())) + self.view.model().addItem(initItem( + singletonInstance.userProfile.getPubKey(), + loggedInUserDisplayName, + OnlineStatus.Online, + singletonInstance.userProfile.getIcon(), + singletonInstance.userProfile.getIsIdenticon(), + admin, + joined, + )) - # add other memebers - let usersKeys = self.controller.getMembersPublicKeys() - for k in usersKeys: - if (k == singletonInstance.userProfile.getPubKey()): + # add other memebers + let publicKeys = self.controller.getMembersPublicKeys() + for publicKey in publicKeys: + if (publicKey == singletonInstance.userProfile.getPubKey()): continue - let (name, image, isIdenticon) = self.controller.getContactNameAndImage(k) - let statusUpdateDto = self.controller.getStatusForContact(k) + + let (admin, joined) = self.controller.getChatMemberInfo(publicKey) + let (name, image, isIdenticon) = self.controller.getContactNameAndImage(publicKey) + let statusUpdateDto = self.controller.getStatusForContact(publicKey) let status = statusUpdateDto.statusType.int.OnlineStatus - self.view.model().addItem(initItem(k, name, status, image, isidenticon)) + self.view.model().addItem(initItem(publicKey, name, status, image, isidenticon, admin, joined)) self.moduleLoaded = true self.delegate.usersDidLoad() @@ -67,7 +80,11 @@ method viewDidLoad*(self: Module) = method getModuleAsVariant*(self: Module): QVariant = return self.viewVariant -method newMessagesLoaded*(self: Module, messages: seq[MessageDto]) = +method newMessagesLoaded*(self: Module, messages: seq[MessageDto]) = + let chat = self.controller.getChat() + if not chat.isPublicChat(): + return + for m in messages: if(self.view.model().isContactWithIdAdded(m.`from`)): continue @@ -98,11 +115,16 @@ method onChatMembersAdded*(self: Module, ids: seq[string]) = for id in ids: if(self.view.model().isContactWithIdAdded(id)): continue - + + let (admin, joined) = self.controller.getChatMemberInfo(id) let (name, image, isIdenticon) = self.controller.getContactNameAndImage(id) let statusUpdateDto = self.controller.getStatusForContact(id) let status = statusUpdateDto.statusType.int.OnlineStatus - self.view.model().addItem(initItem(id, name, status, image, isidenticon)) + self.view.model().addItem(initItem(id, name, status, image, isidenticon, admin, joined)) method onChatMemberRemoved*(self: Module, id: string) = - self.view.model().removeItemById(id) \ No newline at end of file + self.view.model().removeItemById(id) + +method onChatMemberUpdated*(self: Module, publicKey: string, admin: bool, joined: bool) = + let (name, image, isIdenticon) = self.controller.getContactNameAndImage(publicKey) + self.view.model().updateItem(publicKey, name, image, isIdenticon, admin, joined) \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/users/private_interfaces/module_controller_delegate_interface.nim b/src/app/modules/main/chat_section/chat_content/users/private_interfaces/module_controller_delegate_interface.nim index e0937a94f1..c4d2446f2d 100644 --- a/src/app/modules/main/chat_section/chat_content/users/private_interfaces/module_controller_delegate_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/users/private_interfaces/module_controller_delegate_interface.nim @@ -20,4 +20,7 @@ method onChatMembersAdded*(self: AccessInterface, ids: seq[string]) {.base.} = raise newException(ValueError, "No implementation available") method onChatMemberRemoved*(self: AccessInterface, ids: string) {.base.} = + raise newException(ValueError, "No implementation available") + +method onChatMemberUpdated*(self: AccessInterface, id: string, admin: bool, joined: bool) {.base.} = raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/shared_models/user_item.nim b/src/app/modules/shared_models/user_item.nim index 25913bc62b..fd2ca1568b 100644 --- a/src/app/modules/shared_models/user_item.nim +++ b/src/app/modules/shared_models/user_item.nim @@ -16,20 +16,26 @@ type onlineStatus: OnlineStatus icon: string isIdenticon: bool + isAdmin: bool + joined: bool proc initItem*( - id: string, - name: string, - onlineStatus: OnlineStatus, - icon: string, - isidenticon: bool - ): Item = + id: string, + name: string, + onlineStatus: OnlineStatus, + icon: string, + isidenticon: bool, + isAdmin: bool = false, + joined: bool = false, +): Item = result = Item() result.id = id result.name = name result.onlineStatus = onlineStatus result.icon = icon result.isIdenticon = isidenticon + result.isAdmin = isAdmin + result.joined = joined proc `$`*(self: Item): string = result = fmt"""User Item( @@ -38,6 +44,8 @@ proc `$`*(self: Item): string = onlineStatus: {$self.onlineStatus.int}, icon: {self.icon}, isIdenticon: {$self.isIdenticon} + isAdmin: {$self.isAdmin} + joined: {$self.joined} ]""" proc id*(self: Item): string {.inline.} = @@ -65,4 +73,16 @@ proc isIdenticon*(self: Item): bool {.inline.} = self.isIdenticon proc `isIdenticon=`*(self: Item, value: bool) {.inline.} = - self.isIdenticon = value \ No newline at end of file + self.isIdenticon = value + +proc isAdmin*(self: Item): bool {.inline.} = + self.isAdmin + +proc `isAdmin=`*(self: Item, value: bool) {.inline.} = + self.isAdmin = value + +proc joined*(self: Item): bool {.inline.} = + self.joined + +proc `joined=`*(self: Item, value: bool) {.inline.} = + self.joined = value diff --git a/src/app/modules/shared_models/user_model.nim b/src/app/modules/shared_models/user_model.nim index b825fdad3d..36a95265ba 100644 --- a/src/app/modules/shared_models/user_model.nim +++ b/src/app/modules/shared_models/user_model.nim @@ -9,6 +9,8 @@ type OnlineStatus Icon IsIdenticon + IsAdmin + Joined QtObject: type @@ -55,6 +57,8 @@ QtObject: ModelRole.OnlineStatus.int:"onlineStatus", ModelRole.Icon.int:"icon", ModelRole.IsIdenticon.int:"isIdenticon", + ModelRole.IsAdmin.int:"isAdmin", + ModelRole.Joined.int:"joined", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -78,6 +82,10 @@ QtObject: result = newQVariant(item.icon) of ModelRole.IsIdenticon: result = newQVariant(item.isIdenticon) + of ModelRole.IsAdmin: + result = newQVariant(item.isAdmin) + of ModelRole.Joined: + result = newQVariant(item.joined) proc addItem*(self: Model, item: Item) = # we need to maintain online contact on top, that means @@ -140,7 +148,10 @@ QtObject: let index = self.createIndex(ind, 0, nil) self.dataChanged(index, index, @[ModelRole.Icon.int, ModelRole.IsIdenticon.int]) - proc updateItem*(self: Model, id: string, name: string, icon: string, isIdenticon: bool) = + proc updateItem*( + self: Model, id: string, name: string, icon: string, isIdenticon: bool, + isAdmin: bool = false, joined: bool = false + ) = let ind = self.findIndexForMessageId(id) if(ind == -1): return @@ -148,9 +159,13 @@ QtObject: self.items[ind].name = name self.items[ind].icon = icon self.items[ind].isIdenticon = isIdenticon + self.items[ind].isAdmin = isAdmin + self.items[ind].joined = joined let index = self.createIndex(ind, 0, nil) - self.dataChanged(index, index, @[ModelRole.Name.int, ModelRole.Icon.int, ModelRole.IsIdenticon.int]) + self.dataChanged(index, index, @[ + ModelRole.Name.int, ModelRole.Icon.int, ModelRole.IsIdenticon.int, ModelRole.IsAdmin.int, ModelRole.Joined.int, + ]) proc setOnlineStatus*(self: Model, id: string, onlineStatus: OnlineStatus) = let ind = self.findIndexForMessageId(id) diff --git a/src/app_service/service/chat/dto/chat.nim b/src/app_service/service/chat/dto/chat.nim index 3cdb4bb8b6..0f041e6e62 100644 --- a/src/app_service/service/chat/dto/chat.nim +++ b/src/app_service/service/chat/dto/chat.nim @@ -112,4 +112,7 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto = var membersObj: JsonNode if(jsonObj.getProp("members", membersObj) and membersObj.kind == JArray): for memberObj in membersObj: - result.members.add(toChatMember(memberObj)) \ No newline at end of file + result.members.add(toChatMember(memberObj)) + +proc isPublicChat*(chatDto: ChatDto): bool = + return chatDto.chatType == ChatType.Public \ No newline at end of file diff --git a/src/app_service/service/chat/service.nim b/src/app_service/service/chat/service.nim index 11effabfe7..8e36d25e75 100644 --- a/src/app_service/service/chat/service.nim +++ b/src/app_service/service/chat/service.nim @@ -56,6 +56,12 @@ type ChatMemberRemovedArgs* = ref object of Args chatId*: string id*: string + + ChatMemberUpdatedArgs* = ref object of Args + chatId*: string + id*: string + admin*: bool + joined*: bool # Signals which may be emitted by this service: @@ -70,6 +76,7 @@ const SIGNAL_CHAT_HISTORY_CLEARED* = "chatHistoryCleared" const SIGNAL_CHAT_RENAMED* = "chatRenamed" const SIGNAL_CHAT_MEMBERS_ADDED* = "chatMemberAdded" const SIGNAL_CHAT_MEMBER_REMOVED* = "chatMemberRemoved" +const SIGNAL_CHAT_MEMBER_UPDATED* = "chatMemberUpdated" QtObject: type Service* = ref object of QObject @@ -405,7 +412,14 @@ QtObject: method makeAdmin*(self: Service, chatId: string, pubKey: string) = try: let response = status_chat.makeAdmin(chatId, pubKey) - self.emitUpdate(response) + for member in self.chats[chatId].members.mitems: + if (member.id == pubKey): + member.admin = true + self.events.emit( + SIGNAL_CHAT_MEMBER_UPDATED, + ChatMemberUpdatedArgs(id: member.id, admin: member.admin, chatId: chatId, joined: member.joined) + ) + break except Exception as e: error "error while making user admin: ", msg = e.msg