Fix(@chat): add special cases for group chat

fixes #4612
fixes #4613
This commit is contained in:
Anthony Laibe 2022-02-03 10:44:35 +01:00 committed by Anthony Laibe
parent 5c034f545d
commit 5ebafb1c0c
9 changed files with 145 additions and 41 deletions

View File

@ -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.inputAreaModule = input_area_module.newModule(result, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService)
result.messagesModule = messages_module.newModule(result, events, sectionId, chatId, belongsToCommunity, result.messagesModule = messages_module.newModule(result, events, sectionId, chatId, belongsToCommunity,
contactService, communityService, chatService, messageService, mailserversService) contactService, communityService, chatService, messageService, mailserversService)
result.usersModule = users_module.newModule(result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable, result.usersModule = users_module.newModule(
contactService, chatService, communityService, messageService) result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable,
contactService, chat_service, communityService, messageService,
)
method delete*(self: Module) = method delete*(self: Module) =
self.inputAreaModule.delete self.inputAreaModule.delete

View File

@ -25,11 +25,12 @@ type
communityService: community_service.Service communityService: community_service.Service
messageService: message_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, belongsToCommunity: bool, isUsersListAvailable: bool, contactService: contact_service.Service,
chatService: chat_service.Service, communityService: community_service.Service, chatService: chat_service.Service, communityService: community_service.Service,
messageService: message_service.Service): messageService: message_service.Service
Controller = ): Controller =
result = Controller() result = Controller()
result.delegate = delegate result.delegate = delegate
result.events = events result.events = events
@ -41,6 +42,7 @@ proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter
result.chatService = chatService result.chatService = chatService
result.communityService = communityService result.communityService = communityService
result.messageService = messageService result.messageService = messageService
result.chatService = chatService
method delete*(self: Controller) = method delete*(self: Controller) =
discard discard
@ -80,20 +82,36 @@ method init*(self: Controller) =
if (args.chatId == self.chatId): if (args.chatId == self.chatId):
self.delegate.onChatMemberRemoved(args.id) 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): if (self.belongsToCommunity):
self.events.on(SIGNAL_COMMUNITY_MEMBER_APPROVED) do(e: Args): self.events.on(SIGNAL_COMMUNITY_MEMBER_APPROVED) do(e: Args):
let args = CommunityMemberArgs(e) let args = CommunityMemberArgs(e)
if (args.communityId == self.sectionId): if (args.communityId == self.sectionId):
self.delegate.onChatMembersAdded(@[args.pubKey]) 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] = method getMembersPublicKeys*(self: Controller): seq[string] =
if(not self.belongsToCommunity): if(self.belongsToCommunity):
let chatDto = self.chatService.getChatById(self.chatId)
return chatDto.members.map(x => x.id)
else:
let communityDto = self.communityService.getCommunityById(self.sectionId) let communityDto = self.communityService.getCommunityById(self.sectionId)
return communityDto.members.map(x => x.id) 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): method getContactNameAndImage*(self: Controller, contactId: string):
tuple[name: string, image: string, isIdenticon: bool] = tuple[name: string, image: string, isIdenticon: bool] =
return self.contactService.getContactNameAndImage(contactId) return self.contactService.getContactNameAndImage(contactId)

View File

@ -1,4 +1,5 @@
import ../../../../../../app_service/service/contacts/service as contacts_service import ../../../../../../app_service/service/contacts/service as contacts_service
import ../../../../../../app_service/service/chat/service as chat_service
type type
AccessInterface* {.pure inheritable.} = ref object of RootObj AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -21,4 +22,10 @@ method getContactNameAndImage*(self: AccessInterface, contactId: string):
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method getStatusForContact*(self: AccessInterface, contactId: string): StatusUpdateDto {.base.} = method getStatusForContact*(self: AccessInterface, contactId: string): StatusUpdateDto {.base.} =
raise newException(ValueError, "No implementation available") 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")

View File

@ -20,17 +20,20 @@ type
controller: controller.AccessInterface controller: controller.AccessInterface
moduleLoaded: bool 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, belongsToCommunity: bool, isUsersListAvailable: bool, contactService: contact_service.Service,
chatService: chat_service.Service, communityService: community_service.Service, chatService: chat_service.Service, communityService: community_service.Service,
messageService: message_service.Service): messageService: message_service.Service,
Module = ): Module =
result = Module() result = Module()
result.delegate = delegate result.delegate = delegate
result.view = view.newView(result) result.view = view.newView(result)
result.viewVariant = newQVariant(result.view) result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable, result.controller = controller.newController(
contactService, chatService, communityService, messageService) result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable,
contactService, chatService, communityService, messageService,
)
result.moduleLoaded = false result.moduleLoaded = false
method delete*(self: Module) = method delete*(self: Module) =
@ -47,19 +50,29 @@ method isLoaded*(self: Module): bool =
method viewDidLoad*(self: Module) = method viewDidLoad*(self: Module) =
# add me as the first user to the list # add me as the first user to the list
let (admin, joined) = self.controller.getChatMemberInfo(singletonInstance.userProfile.getPubKey())
let loggedInUserDisplayName = singletonInstance.userProfile.getName() & "(You)" let loggedInUserDisplayName = singletonInstance.userProfile.getName() & "(You)"
self.view.model().addItem(initItem(singletonInstance.userProfile.getPubKey(), loggedInUserDisplayName, self.view.model().addItem(initItem(
OnlineStatus.Online, singletonInstance.userProfile.getIcon(), singletonInstance.userProfile.getIsIdenticon())) singletonInstance.userProfile.getPubKey(),
loggedInUserDisplayName,
OnlineStatus.Online,
singletonInstance.userProfile.getIcon(),
singletonInstance.userProfile.getIsIdenticon(),
admin,
joined,
))
# add other memebers # add other memebers
let usersKeys = self.controller.getMembersPublicKeys() let publicKeys = self.controller.getMembersPublicKeys()
for k in usersKeys: for publicKey in publicKeys:
if (k == singletonInstance.userProfile.getPubKey()): if (publicKey == singletonInstance.userProfile.getPubKey()):
continue 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 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.moduleLoaded = true
self.delegate.usersDidLoad() self.delegate.usersDidLoad()
@ -67,7 +80,11 @@ method viewDidLoad*(self: Module) =
method getModuleAsVariant*(self: Module): QVariant = method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant 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: for m in messages:
if(self.view.model().isContactWithIdAdded(m.`from`)): if(self.view.model().isContactWithIdAdded(m.`from`)):
continue continue
@ -98,11 +115,16 @@ method onChatMembersAdded*(self: Module, ids: seq[string]) =
for id in ids: for id in ids:
if(self.view.model().isContactWithIdAdded(id)): if(self.view.model().isContactWithIdAdded(id)):
continue continue
let (admin, joined) = self.controller.getChatMemberInfo(id)
let (name, image, isIdenticon) = self.controller.getContactNameAndImage(id) let (name, image, isIdenticon) = self.controller.getContactNameAndImage(id)
let statusUpdateDto = self.controller.getStatusForContact(id) let statusUpdateDto = self.controller.getStatusForContact(id)
let status = statusUpdateDto.statusType.int.OnlineStatus 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) = method onChatMemberRemoved*(self: Module, id: string) =
self.view.model().removeItemById(id) 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)

View File

@ -20,4 +20,7 @@ method onChatMembersAdded*(self: AccessInterface, ids: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onChatMemberRemoved*(self: AccessInterface, ids: string) {.base.} = method onChatMemberRemoved*(self: AccessInterface, ids: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatMemberUpdated*(self: AccessInterface, id: string, admin: bool, joined: bool) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -16,20 +16,26 @@ type
onlineStatus: OnlineStatus onlineStatus: OnlineStatus
icon: string icon: string
isIdenticon: bool isIdenticon: bool
isAdmin: bool
joined: bool
proc initItem*( proc initItem*(
id: string, id: string,
name: string, name: string,
onlineStatus: OnlineStatus, onlineStatus: OnlineStatus,
icon: string, icon: string,
isidenticon: bool isidenticon: bool,
): Item = isAdmin: bool = false,
joined: bool = false,
): Item =
result = Item() result = Item()
result.id = id result.id = id
result.name = name result.name = name
result.onlineStatus = onlineStatus result.onlineStatus = onlineStatus
result.icon = icon result.icon = icon
result.isIdenticon = isidenticon result.isIdenticon = isidenticon
result.isAdmin = isAdmin
result.joined = joined
proc `$`*(self: Item): string = proc `$`*(self: Item): string =
result = fmt"""User Item( result = fmt"""User Item(
@ -38,6 +44,8 @@ proc `$`*(self: Item): string =
onlineStatus: {$self.onlineStatus.int}, onlineStatus: {$self.onlineStatus.int},
icon: {self.icon}, icon: {self.icon},
isIdenticon: {$self.isIdenticon} isIdenticon: {$self.isIdenticon}
isAdmin: {$self.isAdmin}
joined: {$self.joined}
]""" ]"""
proc id*(self: Item): string {.inline.} = proc id*(self: Item): string {.inline.} =
@ -65,4 +73,16 @@ proc isIdenticon*(self: Item): bool {.inline.} =
self.isIdenticon self.isIdenticon
proc `isIdenticon=`*(self: Item, value: bool) {.inline.} = proc `isIdenticon=`*(self: Item, value: bool) {.inline.} =
self.isIdenticon = value 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

View File

@ -9,6 +9,8 @@ type
OnlineStatus OnlineStatus
Icon Icon
IsIdenticon IsIdenticon
IsAdmin
Joined
QtObject: QtObject:
type type
@ -55,6 +57,8 @@ QtObject:
ModelRole.OnlineStatus.int:"onlineStatus", ModelRole.OnlineStatus.int:"onlineStatus",
ModelRole.Icon.int:"icon", ModelRole.Icon.int:"icon",
ModelRole.IsIdenticon.int:"isIdenticon", ModelRole.IsIdenticon.int:"isIdenticon",
ModelRole.IsAdmin.int:"isAdmin",
ModelRole.Joined.int:"joined",
}.toTable }.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant = method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -78,6 +82,10 @@ QtObject:
result = newQVariant(item.icon) result = newQVariant(item.icon)
of ModelRole.IsIdenticon: of ModelRole.IsIdenticon:
result = newQVariant(item.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) = proc addItem*(self: Model, item: Item) =
# we need to maintain online contact on top, that means # we need to maintain online contact on top, that means
@ -140,7 +148,10 @@ QtObject:
let index = self.createIndex(ind, 0, nil) let index = self.createIndex(ind, 0, nil)
self.dataChanged(index, index, @[ModelRole.Icon.int, ModelRole.IsIdenticon.int]) 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) let ind = self.findIndexForMessageId(id)
if(ind == -1): if(ind == -1):
return return
@ -148,9 +159,13 @@ QtObject:
self.items[ind].name = name self.items[ind].name = name
self.items[ind].icon = icon self.items[ind].icon = icon
self.items[ind].isIdenticon = isIdenticon self.items[ind].isIdenticon = isIdenticon
self.items[ind].isAdmin = isAdmin
self.items[ind].joined = joined
let index = self.createIndex(ind, 0, nil) 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) = proc setOnlineStatus*(self: Model, id: string, onlineStatus: OnlineStatus) =
let ind = self.findIndexForMessageId(id) let ind = self.findIndexForMessageId(id)

View File

@ -112,4 +112,7 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
var membersObj: JsonNode var membersObj: JsonNode
if(jsonObj.getProp("members", membersObj) and membersObj.kind == JArray): if(jsonObj.getProp("members", membersObj) and membersObj.kind == JArray):
for memberObj in membersObj: for memberObj in membersObj:
result.members.add(toChatMember(memberObj)) result.members.add(toChatMember(memberObj))
proc isPublicChat*(chatDto: ChatDto): bool =
return chatDto.chatType == ChatType.Public

View File

@ -56,6 +56,12 @@ type
ChatMemberRemovedArgs* = ref object of Args ChatMemberRemovedArgs* = ref object of Args
chatId*: string chatId*: string
id*: string id*: string
ChatMemberUpdatedArgs* = ref object of Args
chatId*: string
id*: string
admin*: bool
joined*: bool
# Signals which may be emitted by this service: # 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_RENAMED* = "chatRenamed"
const SIGNAL_CHAT_MEMBERS_ADDED* = "chatMemberAdded" const SIGNAL_CHAT_MEMBERS_ADDED* = "chatMemberAdded"
const SIGNAL_CHAT_MEMBER_REMOVED* = "chatMemberRemoved" const SIGNAL_CHAT_MEMBER_REMOVED* = "chatMemberRemoved"
const SIGNAL_CHAT_MEMBER_UPDATED* = "chatMemberUpdated"
QtObject: QtObject:
type Service* = ref object of QObject type Service* = ref object of QObject
@ -405,7 +412,14 @@ QtObject:
method makeAdmin*(self: Service, chatId: string, pubKey: string) = method makeAdmin*(self: Service, chatId: string, pubKey: string) =
try: try:
let response = status_chat.makeAdmin(chatId, pubKey) 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: except Exception as e:
error "error while making user admin: ", msg = e.msg error "error while making user admin: ", msg = e.msg