feat(chat): implement new getChats API for the backend

Fixes #4878 but new issues will be created to split the implementation
This commit is contained in:
Jonathan Rainville 2022-03-23 09:21:57 -04:00
parent e26befb6c2
commit 666c865112
16 changed files with 356 additions and 258 deletions

View File

@ -1,4 +1,3 @@
const CHAT_SECTION_ID* = "chat"
const CHAT_SECTION_NAME* = "Chat" const CHAT_SECTION_NAME* = "Chat"
const CHAT_SECTION_ICON* = "chat" const CHAT_SECTION_ICON* = "chat"

View File

@ -65,7 +65,7 @@ const DEFAULT_SHOW_DELETE_MESSAGE_WARNING = true
const LSS_KEY_DOWNLOAD_CHANNEL_MESSAGES_ENABLED* = "downloadChannelMessagesEnabled" const LSS_KEY_DOWNLOAD_CHANNEL_MESSAGES_ENABLED* = "downloadChannelMessagesEnabled"
const DEFAULT_DOWNLOAD_CHANNEL_MESSAGES_ENABLED = false const DEFAULT_DOWNLOAD_CHANNEL_MESSAGES_ENABLED = false
const LSS_KEY_ACTIVE_SECTION* = "activeSection" const LSS_KEY_ACTIVE_SECTION* = "activeSection"
const DEFAULT_ACTIVE_SECTION = "chat" const DEFAULT_ACTIVE_SECTION = ""
const LSS_KEY_SHOW_BROWSER_SELECTOR* = "showBrowserSelector" const LSS_KEY_SHOW_BROWSER_SELECTOR* = "showBrowserSelector"
const DEFAULT_SHOW_BROWSER_SELECTOR = true const DEFAULT_SHOW_BROWSER_SELECTOR = true
const LSS_KEY_OPEN_LINKS_IN_STATUS* = "openLinksInStatus" const LSS_KEY_OPEN_LINKS_IN_STATUS* = "openLinksInStatus"

View File

@ -78,7 +78,10 @@ method convertToItems*(
let chatDetails = self.controller.getChatDetails(n.chatId) let chatDetails = self.controller.getChatDetails(n.chatId)
# default section id is `Chat` section # default section id is `Chat` section
let sectionId = if(chatDetails.communityId.len > 0): chatDetails.communityId else: conf.CHAT_SECTION_ID let sectionId = if(chatDetails.communityId.len > 0):
chatDetails.communityId
else:
singletonInstance.userProfile.getPubKey()
if (n.message.id != ""): if (n.message.id != ""):
# If there is a message in the Notification, transfer it to a MessageItem (QObject) # If there is a message in the Notification, transfer it to a MessageItem (QObject)

View File

@ -2,7 +2,7 @@ import Tables, chronicles
import io_interface import io_interface
import ../../../global/app_signals import ../../../global/app_signals
import ../../../global/app_sections_config as conf import ../../../global/global_singleton
import ../../../../app_service/service/contacts/service as contact_service import ../../../../app_service/service/contacts/service as contact_service
import ../../../../app_service/service/chat/service as chat_service import ../../../../app_service/service/chat/service as chat_service
import ../../../../app_service/service/community/service as community_service import ../../../../app_service/service/community/service as community_service
@ -90,7 +90,7 @@ proc getJoinedCommunities*(self: Controller): seq[CommunityDto] =
proc getCommunityById*(self: Controller, communityId: string): CommunityDto = proc getCommunityById*(self: Controller, communityId: string): CommunityDto =
return self.communityService.getCommunityById(communityId) return self.communityService.getCommunityById(communityId)
proc getAllChatsForCommunity*(self: Controller, communityId: string): seq[Chat] = proc getAllChatsForCommunity*(self: Controller, communityId: string): seq[ChatDto] =
return self.communityService.getAllChats(communityId) return self.communityService.getAllChats(communityId)
proc getChatDetailsForChatTypes*(self: Controller, types: seq[ChatType]): seq[ChatDto] = proc getChatDetailsForChatTypes*(self: Controller, types: seq[ChatType]): seq[ChatDto] =
@ -110,8 +110,8 @@ proc searchMessages*(self: Controller, searchTerm: string) =
if (self.searchSubLocation.len > 0): if (self.searchSubLocation.len > 0):
chats.add(self.searchSubLocation) chats.add(self.searchSubLocation)
elif (self.searchLocation.len > 0): elif (self.searchLocation.len > 0):
# If "Chat" is set for the meassgeSearchLocation that means we need to search in all chats from the chat section. # If user's pubkey is set for the meassgeSearchLocation that means we need to search in all chats from the personal chat section.
if (self.searchLocation != conf.CHAT_SECTION_ID): if (self.searchLocation != singletonInstance.userProfile.getPubKey()):
communities.add(self.searchLocation) communities.add(self.searchLocation)
else: else:
let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat] let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat]

View File

@ -67,8 +67,8 @@ method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant return self.viewVariant
proc buildLocationMenuForChat(self: Module): location_menu_item.Item = proc buildLocationMenuForChat(self: Module): location_menu_item.Item =
var item = location_menu_item.initItem(conf.CHAT_SECTION_ID, SEARCH_MENU_LOCATION_CHAT_SECTION_NAME, "", "chat", "", var item = location_menu_item.initItem(singletonInstance.userProfile.getPubKey(),
false) SEARCH_MENU_LOCATION_CHAT_SECTION_NAME, "", "chat", "", false)
let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat] let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat]
let displayedChats = self.controller.getChatDetailsForChatTypes(types) let displayedChats = self.controller.getChatDetailsForChatTypes(types)
@ -176,7 +176,8 @@ method onSearchMessagesDone*(self: Module, messages: seq[MessageDto]) =
channels.add(item) channels.add(item)
# Add chats # Add chats
if(self.controller.searchLocation().len == 0 or self.controller.searchLocation() == conf.CHAT_SECTION_ID and if(self.controller.searchLocation().len == 0 or
self.controller.searchLocation() == singletonInstance.userProfile.getPubKey() and
self.controller.searchSubLocation().len == 0): self.controller.searchSubLocation().len == 0):
let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat] let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat]
let displayedChats = self.controller.getChatDetailsForChatTypes(types) let displayedChats = self.controller.getChatDetailsForChatTypes(types)
@ -196,7 +197,7 @@ method onSearchMessagesDone*(self: Module, messages: seq[MessageDto]) =
let item = result_item.initItem(c.id, "", "", c.id, chatName, SEARCH_RESULT_CHATS_SECTION_NAME, chatImage, let item = result_item.initItem(c.id, "", "", c.id, chatName, SEARCH_RESULT_CHATS_SECTION_NAME, chatImage,
c.color, "", "", chatImage, c.color, isIdenticon) c.color, "", "", chatImage, c.color, isIdenticon)
self.controller.addResultItemDetails(c.id, conf.CHAT_SECTION_ID, c.id) self.controller.addResultItemDetails(c.id, singletonInstance.userProfile.getPubKey(), c.id)
items.add(item) items.add(item)
# Add channels in order as requested by the design # Add channels in order as requested by the design
@ -222,7 +223,8 @@ method onSearchMessagesDone*(self: Module, messages: seq[MessageDto]) =
let item = result_item.initItem(m.id, m.text, $m.timestamp, m.`from`, senderName, let item = result_item.initItem(m.id, m.text, $m.timestamp, m.`from`, senderName,
SEARCH_RESULT_MESSAGES_SECTION_NAME, senderImage, "", chatName, "", chatImage, chatDto.color, isIdenticon) SEARCH_RESULT_MESSAGES_SECTION_NAME, senderImage, "", chatName, "", chatImage, chatDto.color, isIdenticon)
self.controller.addResultItemDetails(m.id, conf.CHAT_SECTION_ID, chatDto.id, m.id) self.controller.addResultItemDetails(m.id, singletonInstance.userProfile.getPubKey(),
chatDto.id, m.id)
items.add(item) items.add(item)
else: else:
let community = self.controller.getCommunityById(chatDto.communityId) let community = self.controller.getCommunityById(chatDto.communityId)

View File

@ -207,7 +207,7 @@ proc getMyCommunity*(self: Controller): CommunityDto =
proc getCategories*(self: Controller, communityId: string): seq[Category] = proc getCategories*(self: Controller, communityId: string): seq[Category] =
return self.communityService.getCategories(communityId) return self.communityService.getCategories(communityId)
proc getChats*(self: Controller, communityId: string, categoryId: string): seq[Chat] = proc getChats*(self: Controller, communityId: string, categoryId: string): seq[ChatDto] =
return self.communityService.getChats(communityId, categoryId) return self.communityService.getChats(communityId, categoryId)
proc getChatDetails*(self: Controller, communityId, chatId: string): ChatDto = proc getChatDetails*(self: Controller, communityId, chatId: string): ChatDto =

View File

@ -148,69 +148,66 @@ proc buildCommunityUI(self: Module, events: EventEmitter,
mailserversService: mailservers_service.Service) = mailserversService: mailservers_service.Service) =
var selectedItemId = "" var selectedItemId = ""
var selectedSubItemId = "" var selectedSubItemId = ""
let communities = self.controller.getJoinedCommunities() let comm = self.controller.getMyCommunity()
for comm in communities:
if(self.controller.getMySectionId() != comm.id):
continue
# handle channels which don't belong to any category # handle channels which don't belong to any category
let chats = self.controller.getChats(comm.id, "") let chats = self.controller.getChats(comm.id, "")
for c in chats: for c in chats:
let chatDto = self.controller.getChatDetails(comm.id, c.id)
let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0
let notificationsCount = chatDto.unviewedMentionsCount
let amIChatAdmin = comm.admin
let channelItem = initItem(chatDto.id, chatDto.name, chatDto.identicon, false, chatDto.color,
chatDto.emoji, chatDto.description, chatDto.chatType.int, amIChatAdmin, hasNotification,
notificationsCount, chatDto.muted, blocked=false, active = false, c.position, c.categoryId)
self.view.chatsModel().appendItem(channelItem)
self.addSubmodule(chatDto.id, true, true, events, settingsService, contactService, chatService, communityService,
messageService, gifService, mailserversService)
# make the first channel which doesn't belong to any category active when load the app
if(selectedItemId.len == 0):
selectedItemId = channelItem.id
# handle categories and channels for each category
let categories = self.controller.getCategories(comm.id)
for cat in categories:
var hasNotificationPerCategory = false
var notificationsCountPerCategory = 0
var categoryChannels: seq[SubItem]
let categoryChats = self.controller.getChats(comm.id, cat.id)
for c in categoryChats:
let chatDto = self.controller.getChatDetails(comm.id, c.id) let chatDto = self.controller.getChatDetails(comm.id, c.id)
let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0 let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0
let notificationsCount = chatDto.unviewedMentionsCount let notificationsCount = chatDto.unviewedMentionsCount
hasNotificationPerCategory = hasNotificationPerCategory or hasNotification
notificationsCountPerCategory += notificationsCount
let amIChatAdmin = comm.admin let amIChatAdmin = comm.admin
let channelItem = initItem(chatDto.id, chatDto.name, chatDto.identicon, false, chatDto.color,
chatDto.emoji, chatDto.description, chatDto.chatType.int, amIChatAdmin, hasNotification, let channelItem = initSubItem(chatDto.id, cat.id, chatDto.name, chatDto.identicon,
notificationsCount, chatDto.muted, blocked=false, active = false, c.position, c.categoryId) isIdenticon=false, chatDto.color, chatDto.emoji, chatDto.description, chatDto.chatType.int,
self.view.chatsModel().appendItem(channelItem) amIChatAdmin, hasNotification, notificationsCount, chatDto.muted, blocked=false,
active=false, c.position)
categoryChannels.add(channelItem)
self.addSubmodule(chatDto.id, true, true, events, settingsService, contactService, chatService, communityService, self.addSubmodule(chatDto.id, true, true, events, settingsService, contactService, chatService, communityService,
messageService, gifService, mailserversService) messageService, gifService, mailserversService)
# make the first channel which doesn't belong to any category active when load the app # in case there is no channels beyond categories,
# make the first channel of the first category active when load the app
if(selectedItemId.len == 0): if(selectedItemId.len == 0):
selectedItemId = channelItem.id selectedItemId = cat.id
selectedSubItemId = channelItem.id
# handle categories and channels for each category var categoryItem = initItem(cat.id, cat.name, icon="", isIdenticon=false, color="", emoji="",
let categories = self.controller.getCategories(comm.id) description="", ChatType.Unknown.int, amIChatAdmin=false, hasNotificationPerCategory,
for cat in categories: notificationsCountPerCategory, muted=false, blocked=false, active=false,
var hasNotificationPerCategory = false cat.position, cat.id)
var notificationsCountPerCategory = 0 categoryItem.prependSubItems(categoryChannels)
var categoryChannels: seq[SubItem] self.view.chatsModel().appendItem(categoryItem)
let categoryChats = self.controller.getChats(comm.id, cat.id)
for c in categoryChats:
let chatDto = self.controller.getChatDetails(comm.id, c.id)
let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0
let notificationsCount = chatDto.unviewedMentionsCount
hasNotificationPerCategory = hasNotificationPerCategory or hasNotification
notificationsCountPerCategory += notificationsCount
let amIChatAdmin = comm.admin
let channelItem = initSubItem(chatDto.id, cat.id, chatDto.name, chatDto.identicon,
isIdenticon=false, chatDto.color, chatDto.emoji, chatDto.description, chatDto.chatType.int,
amIChatAdmin, hasNotification, notificationsCount, chatDto.muted, blocked=false,
active=false, c.position)
categoryChannels.add(channelItem)
self.addSubmodule(chatDto.id, true, true, events, settingsService, contactService, chatService, communityService,
messageService, gifService, mailserversService)
# in case there is no channels beyond categories,
# make the first channel of the first category active when load the app
if(selectedItemId.len == 0):
selectedItemId = cat.id
selectedSubItemId = channelItem.id
var categoryItem = initItem(cat.id, cat.name, icon="", isIdenticon=false, color="", emoji="",
description="", ChatType.Unknown.int, amIChatAdmin=false, hasNotificationPerCategory,
notificationsCountPerCategory, muted=false, blocked=false, active=false,
cat.position, cat.id)
categoryItem.prependSubItems(categoryChannels)
self.view.chatsModel().appendItem(categoryItem)
self.setActiveItemSubItem(selectedItemId, selectedSubItemId) self.setActiveItemSubItem(selectedItemId, selectedSubItemId)
@ -635,7 +632,8 @@ method onContactDetailsUpdated*(self: Module, publicKey: string) =
self.view.contactRequestsModel().addItem(item) self.view.contactRequestsModel().addItem(item)
self.updateParentBadgeNotifications() self.updateParentBadgeNotifications()
singletonInstance.globalEvents.showNewContactRequestNotification("New Contact Request", singletonInstance.globalEvents.showNewContactRequestNotification("New Contact Request",
fmt "{contactDetails.displayName} added you as contact", conf.CHAT_SECTION_ID) fmt "{contactDetails.displayName} added you as contact",
singletonInstance.userProfile.getPubKey())
let chatName = contactDetails.displayName let chatName = contactDetails.displayName
let chatImage = contactDetails.icon let chatImage = contactDetails.icon
@ -663,8 +661,10 @@ method onNewMessagesReceived*(self: Module, chatId: string, unviewedMessagesCoun
self.controller.getMySectionId(), chatId, m.id) self.controller.getMySectionId(), chatId, m.id)
method onMeMentionedInEditedMessage*(self: Module, chatId: string, editedMessage : MessageDto) = method onMeMentionedInEditedMessage*(self: Module, chatId: string, editedMessage : MessageDto) =
if(editedMessage.communityId.len == 0 and self.controller.getMySectionId() != conf.CHAT_SECTION_ID or if((editedMessage.communityId.len == 0 and
editedMessage.communityId.len > 0 and self.controller.getMySectionId() != editedMessage.communityId): self.controller.getMySectionId() != singletonInstance.userProfile.getPubKey()) or
(editedMessage.communityId.len > 0 and
self.controller.getMySectionId() != editedMessage.communityId)):
return return
var (sectionHasUnreadMessages, sectionNotificationCount) = self.view.chatsModel().getAllNotifications() var (sectionHasUnreadMessages, sectionNotificationCount) = self.view.chatsModel().getAllNotifications()
self.updateBadgeNotifications(chatId, sectionHasUnreadMessages, sectionNotificationCount + 1) self.updateBadgeNotifications(chatId, sectionHasUnreadMessages, sectionNotificationCount + 1)
@ -777,7 +777,7 @@ method addChatIfDontExist*(self: Module,
let sectionId = self.controller.getMySectionId() let sectionId = self.controller.getMySectionId()
if(belongsToCommunity and sectionId != chat.communityId or if(belongsToCommunity and sectionId != chat.communityId or
not belongsToCommunity and sectionId != conf.CHAT_SECTION_ID): not belongsToCommunity and sectionId != singletonInstance.userProfile.getPubKey()):
return return
if self.doesCatOrChatExist(chat.id): if self.doesCatOrChatExist(chat.id):

View File

@ -9,6 +9,7 @@ import ../../../global/global_singleton
import ../../../core/eventemitter import ../../../core/eventemitter
import ../../../../app_service/service/community/service as community_service import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/contacts/service as contacts_service import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/chat/dto/chat
export io_interface export io_interface

View File

@ -171,7 +171,10 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_MAKE_SECTION_CHAT_ACTIVE) do(e: Args): self.events.on(SIGNAL_MAKE_SECTION_CHAT_ACTIVE) do(e: Args):
var args = ActiveSectionChatArgs(e) var args = ActiveSectionChatArgs(e)
let sectionType = if args.sectionId == conf.CHAT_SECTION_ID: SectionType.Chat else: SectionType.Community let sectionType = if args.sectionId == singletonInstance.userProfile.getPubKey():
SectionType.Chat
else:
SectionType.Community
self.setActiveSection(args.sectionId, sectionType) self.setActiveSection(args.sectionId, sectionType)
self.events.on(SIGNAL_OS_NOTIFICATION_CLICKED) do(e: Args): self.events.on(SIGNAL_OS_NOTIFICATION_CLICKED) do(e: Args):
@ -194,6 +197,9 @@ proc isConnected*(self: Controller): bool =
proc getJoinedCommunities*(self: Controller): seq[CommunityDto] = proc getJoinedCommunities*(self: Controller): seq[CommunityDto] =
return self.communityService.getJoinedCommunities() return self.communityService.getJoinedCommunities()
proc getChannelGroups*(self: Controller): seq[ChannelGroupDto] =
return self.chatService.getChannelGroups()
proc checkForStoringPassword*(self: Controller) = proc checkForStoringPassword*(self: Controller) =
# This proc is called once user is logged in irrespective he is logged in # This proc is called once user is logged in irrespective he is logged in
# through the onboarding or login view. # through the onboarding or login view.

View File

@ -62,8 +62,7 @@ type
view: View view: View
viewVariant: QVariant viewVariant: QVariant
controller: Controller controller: Controller
chatSectionModule: chat_section_module.AccessInterface channelGroupModules: OrderedTable[string, chat_section_module.AccessInterface]
communitySectionsModule: OrderedTable[string, chat_section_module.AccessInterface]
walletSectionModule: wallet_section_module.AccessInterface walletSectionModule: wallet_section_module.AccessInterface
browserSectionModule: browser_section_module.AccessInterface browserSectionModule: browser_section_module.AccessInterface
profileSectionModule: profile_section_module.AccessInterface profileSectionModule: profile_section_module.AccessInterface
@ -133,9 +132,7 @@ proc newModule*[T](
result.moduleLoaded = false result.moduleLoaded = false
# Submodules # Submodules
result.chatSectionModule = chat_section_module.newModule(result, events, conf.CHAT_SECTION_ID, false, settingsService, result.channelGroupModules = initOrderedTable[string, chat_section_module.AccessInterface]()
contactsService, chatService, communityService, messageService, gifService, mailserversService)
result.communitySectionsModule = initOrderedTable[string, chat_section_module.AccessInterface]()
result.walletSectionModule = wallet_section_module.newModule( result.walletSectionModule = wallet_section_module.newModule(
result, events, tokenService, result, events, tokenService,
transactionService, collectible_service, walletAccountService, transactionService, collectible_service, walletAccountService,
@ -158,14 +155,13 @@ proc newModule*[T](
result.networksModule = networks_module.newModule(result, events, networkService, walletAccountService, settingsService) result.networksModule = networks_module.newModule(result, events, networkService, walletAccountService, settingsService)
method delete*[T](self: Module[T]) = method delete*[T](self: Module[T]) =
self.chatSectionModule.delete
self.profileSectionModule.delete self.profileSectionModule.delete
self.stickersModule.delete self.stickersModule.delete
self.activityCenterModule.delete self.activityCenterModule.delete
self.communitiesModule.delete self.communitiesModule.delete
for cModule in self.communitySectionsModule.values: for cModule in self.channelGroupModules.values:
cModule.delete cModule.delete
self.communitySectionsModule.clear self.channelGroupModules.clear
self.walletSectionModule.delete self.walletSectionModule.delete
self.browserSectionModule.delete self.browserSectionModule.delete
self.appSearchModule.delete self.appSearchModule.delete
@ -175,32 +171,43 @@ method delete*[T](self: Module[T]) =
self.viewVariant.delete self.viewVariant.delete
self.controller.delete self.controller.delete
proc createCommunityItem[T](self: Module[T], c: CommunityDto): SectionItem = proc createChannelGroupItem[T](self: Module[T], c: ChannelGroupDto): SectionItem =
let (unviewedCount, mentionsCount) = self.controller.getNumOfNotificationsForCommunity(c.id) let isCommunity = c.channelGroupType == ChannelGroupType.Community
var communityDetails: CommunityDto
var unviewedCount, mentionsCount: int
if (isCommunity):
(unviewedCount, mentionsCount) = self.controller.getNumOfNotificationsForCommunity(c.id)
communityDetails = self.controller.getCommunityById(c.id)
else:
let receivedContactRequests = self.controller.getContacts(ContactsGroup.IncomingPendingContactRequests)
(unviewedCount, mentionsCount) = self.controller.getNumOfNotificaitonsForChat()
mentionsCount = mentionsCount + receivedContactRequests.len
let hasNotification = unviewedCount > 0 or mentionsCount > 0 let hasNotification = unviewedCount > 0 or mentionsCount > 0
let notificationsCount = mentionsCount # we need to add here number of requests let notificationsCount = mentionsCount # we need to add here number of requests
let active = self.getActiveSectionId() == c.id # We must pass on if the current item section is currently active to keep that property as it is let active = self.getActiveSectionId() == c.id # We must pass on if the current item section is currently active to keep that property as it is
result = initItem( result = initItem(
c.id, c.id,
SectionType.Community, if isCommunity: SectionType.Community else: SectionType.Chat,
c.name, c.name,
c.admin, c.admin,
c.description, c.description,
c.images.thumbnail, c.images.thumbnail,
icon = "", icon = if (isCommunity): "" else: conf.CHAT_SECTION_ICON,
c.color, c.color,
hasNotification, hasNotification,
notificationsCount, notificationsCount,
active, active,
enabled = singletonInstance.localAccountSensitiveSettings.getCommunitiesEnabled(), enabled = (not isCommunity or
c.joined, singletonInstance.localAccountSensitiveSettings.getCommunitiesEnabled()),
c.canJoin, if (isCommunity): communityDetails.joined else: true,
if (isCommunity): communityDetails.canJoin else: true,
c.canManageUsers, c.canManageUsers,
c.canRequestAccess, if (isCommunity): communityDetails.canRequestAccess else: true,
c.isMember, if (isCommunity): communityDetails.isMember else: true,
c.permissions.access, c.permissions.access,
c.permissions.ensOnly, c.permissions.ensOnly,
c.members.map(proc(member: Member): user_item.Item = c.members.map(proc(member: ChatMember): user_item.Item =
let contactDetails = self.controller.getContactDetails(member.id) let contactDetails = self.controller.getContactDetails(member.id)
result = user_item.initItem( result = user_item.initItem(
member.id, member.id,
@ -214,14 +221,14 @@ proc createCommunityItem[T](self: Module[T], c: CommunityDto): SectionItem =
contactDetails.isidenticon, contactDetails.isidenticon,
contactDetails.details.added contactDetails.details.added
)), )),
c.pendingRequestsToJoin.map(x => pending_request_item.initItem( if (isCommunity): communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem(
x.id, x.id,
x.publicKey, x.publicKey,
x.chatId, x.chatId,
x.communityId, x.communityId,
x.state, x.state,
x.our x.our
)) )) else: @[]
) )
method load*[T]( method load*[T](
@ -239,15 +246,18 @@ method load*[T](
self.controller.init() self.controller.init()
self.view.load() self.view.load()
# Create community modules here, since we don't know earlier how many joined communities we have. var activeSection: SectionItem
let joinedCommunities = self.controller.getJoinedCommunities() var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection()
if (activeSectionId == ""):
activeSectionId = singletonInstance.userProfile.getPubKey()
for c in joinedCommunities: let channelGroups = self.controller.getChannelGroups()
self.communitySectionsModule[c.id] = chat_section_module.newModule( for channelGroup in channelGroups:
self.channelGroupModules[channelGroup.id] = chat_section_module.newModule(
self, self,
events, events,
c.id, channelGroup.id,
isCommunity = true, isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community,
settingsService, settingsService,
contactsService, contactsService,
chatService, chatService,
@ -256,35 +266,10 @@ method load*[T](
gifService, gifService,
mailserversService mailserversService
) )
let channelGroupItem = self.createChannelGroupItem(channelGroup)
var activeSection: SectionItem self.view.model().addItem(channelGroupItem)
var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection() if(activeSectionId == channelGroupItem.id):
activeSection = channelGroupItem
# Chat Section
let receivedContactRequests = self.controller.getContacts(ContactsGroup.IncomingPendingContactRequests)
let (unviewedCount, mentionsCount) = self.controller.getNumOfNotificaitonsForChat()
let notificationsCount = mentionsCount + receivedContactRequests.len
let hasNotification = unviewedCount > 0 or notificationsCount > 0
let chatSectionItem = initItem(conf.CHAT_SECTION_ID, SectionType.Chat, conf.CHAT_SECTION_NAME,
amISectionAdmin = false,
description = "",
image = "",
conf.CHAT_SECTION_ICON,
color = "",
hasNotification,
notificationsCount,
active = false,
enabled = true)
self.view.model().addItem(chatSectionItem)
if(activeSectionId == chatSectionItem.id):
activeSection = chatSectionItem
# Community Section
for c in joinedCommunities:
let communitySectionItem = self.createCommunityItem(c)
self.view.model().addItem(communitySectionItem)
if(activeSectionId == communitySectionItem.id):
activeSection = communitySectionItem
# Wallet Section # Wallet Section
let walletSectionItem = initItem(conf.WALLET_SECTION_ID, SectionType.Wallet, conf.WALLET_SECTION_NAME, let walletSectionItem = initItem(conf.WALLET_SECTION_ID, SectionType.Wallet, conf.WALLET_SECTION_NAME,
@ -349,9 +334,9 @@ method load*[T](
activeSection = profileSettingsSectionItem activeSection = profileSettingsSectionItem
# Load all sections # Load all sections
self.chatSectionModule.load(events, settingsService, contactsService, chatService, communityService, messageService, gifService, mailserversService) for cModule in self.channelGroupModules.values:
for cModule in self.communitySectionsModule.values: cModule.load(events, settingsService, contactsService, chatService, communityService,
cModule.load(events, settingsService, contactsService, chatService, communityService, messageService, gifService, mailserversService) messageService, gifService, mailserversService)
self.browserSectionModule.load() self.browserSectionModule.load()
# self.nodeManagementSectionModule.load() # self.nodeManagementSectionModule.load()
@ -372,10 +357,7 @@ proc checkIfModuleDidLoad [T](self: Module[T]) =
if self.moduleLoaded: if self.moduleLoaded:
return return
if(not self.chatSectionModule.isLoaded()): for cModule in self.channelGroupModules.values:
return
for cModule in self.communitySectionsModule.values:
if(not cModule.isLoaded()): if(not cModule.isLoaded()):
return return
@ -471,9 +453,7 @@ method setActiveSection*[T](self: Module[T], item: SectionItem) =
self.controller.setActiveSection(item.id, item.sectionType) self.controller.setActiveSection(item.id, item.sectionType)
proc notifySubModulesAboutChange[T](self: Module[T], sectionId: string) = proc notifySubModulesAboutChange[T](self: Module[T], sectionId: string) =
self.chatSectionModule.onActiveSectionChange(sectionId) for cModule in self.channelGroupModules.values:
for cModule in self.communitySectionsModule.values:
cModule.onActiveSectionChange(sectionId) cModule.onActiveSectionChange(sectionId)
# If there is a need other section may be notified the same way from here... # If there is a need other section may be notified the same way from here...
@ -518,14 +498,14 @@ method setUserStatus*[T](self: Module[T], status: bool) =
self.controller.setUserStatus(status) self.controller.setUserStatus(status)
method getChatSectionModule*[T](self: Module[T]): QVariant = method getChatSectionModule*[T](self: Module[T]): QVariant =
return self.chatSectionModule.getModuleAsVariant() return self.channelGroupModules[singletonInstance.userProfile.getPubKey()].getModuleAsVariant()
method getCommunitySectionModule*[T](self: Module[T], communityId: string): QVariant = method getCommunitySectionModule*[T](self: Module[T], communityId: string): QVariant =
if(not self.communitySectionsModule.contains(communityId)): if(not self.channelGroupModules.contains(communityId)):
echo "main-module, unexisting community key: ", communityId echo "main-module, unexisting community key: ", communityId
return return
return self.communitySectionsModule[communityId].getModuleAsVariant() return self.channelGroupModules[communityId].getModuleAsVariant()
method rebuildChatSearchModel*[T](self: Module[T]) = method rebuildChatSearchModel*[T](self: Module[T]) =
let transformItem = proc(item: chat_section_base_item.BaseItem, sectionId, sectionName: string): chat_search_item.Item = let transformItem = proc(item: chat_section_base_item.BaseItem, sectionId, sectionName: string): chat_search_item.Item =
@ -539,9 +519,10 @@ method rebuildChatSearchModel*[T](self: Module[T]) =
for subItem in item.subItems().items(): for subItem in item.subItems().items():
result.add(transformItem(subItem, sectionId, sectionName)) result.add(transformItem(subItem, sectionId, sectionName))
var items = transform(self.chatSectionModule.chatsModel().items(), conf.CHAT_SECTION_ID, conf.CHAT_SECTION_NAME) var items: seq[chat_search_item.Item] = @[]
for cId in self.communitySectionsModule.keys: for cId in self.channelGroupModules.keys:
items.add(transform(self.communitySectionsModule[cId].chatsModel().items(), cId, self.view.model().getItemById(cId).name())) items.add(transform(self.channelGroupModules[cId].chatsModel().items(), cId,
self.view.model().getItemById(cId).name()))
self.view.chatSearchModel().setItems(items) self.view.chatSearchModel().setItems(items)
@ -580,9 +561,9 @@ method communityJoined*[T](
mailserversService: mailservers_service.Service, mailserversService: mailservers_service.Service,
) = ) =
var firstCommunityJoined = false var firstCommunityJoined = false
if (self.communitySectionsModule.len == 0): if (self.channelGroupModules.len == 1): # First one is personal chat section
firstCommunityJoined = true firstCommunityJoined = true
self.communitySectionsModule[community.id] = chat_section_module.newModule( self.channelGroupModules[community.id] = chat_section_module.newModule(
self, self,
events, events,
community.id, community.id,
@ -595,33 +576,37 @@ method communityJoined*[T](
gifService, gifService,
mailserversService mailserversService
) )
self.communitySectionsModule[community.id].load(events, settingsService, contactsService, chatService, communityService, messageService, gifService, mailserversService) self.channelGroupModules[community.id].load(events, settingsService, contactsService, chatService,
communityService, messageService, gifService, mailserversService)
let communitySectionItem = self.createCommunityItem(community) let channelGroup = community.toChannelGroupDto()
let communitySectionItem = self.createChannelGroupItem(channelGroup)
if (firstCommunityJoined): if (firstCommunityJoined):
# If there are no other communities, add the first community after the Chat section in the model so that the order is respected # If there are no other communities, add the first community after the Chat section in the model so that the order is respected
self.view.model().addItem(communitySectionItem, self.view.model().getItemIndex(conf.CHAT_SECTION_ID) + 1) self.view.model().addItem(communitySectionItem,
self.view.model().getItemIndex(singletonInstance.userProfile.getPubKey()) + 1)
else: else:
self.view.model().addItem(communitySectionItem) self.view.model().addItem(communitySectionItem)
self.setActiveSection(communitySectionItem) self.setActiveSection(communitySectionItem)
method communityLeft*[T](self: Module[T], communityId: string) = method communityLeft*[T](self: Module[T], communityId: string) =
if(not self.communitySectionsModule.contains(communityId)): if(not self.channelGroupModules.contains(communityId)):
echo "main-module, unexisting community key to leave: ", communityId echo "main-module, unexisting community key to leave: ", communityId
return return
self.communitySectionsModule.del(communityId) self.channelGroupModules.del(communityId)
self.view.model().removeItem(communityId) self.view.model().removeItem(communityId)
if (self.controller.getActiveSectionId() == communityId): if (self.controller.getActiveSectionId() == communityId):
let item = self.view.model().getItemById(conf.CHAT_SECTION_ID) let item = self.view.model().getItemById(singletonInstance.userProfile.getPubKey())
self.setActiveSection(item) self.setActiveSection(item)
method communityEdited*[T]( method communityEdited*[T](
self: Module[T], self: Module[T],
community: CommunityDto) = community: CommunityDto) =
self.view.editItem(self.createCommunityItem(community)) let channelGroup = community.toChannelGroupDto()
self.view.editItem(self.createChannelGroupItem(channelGroup))
method getContactDetailsAsJson*[T](self: Module[T], publicKey: string): string = method getContactDetailsAsJson*[T](self: Module[T], publicKey: string): string =
let contact = self.controller.getContact(publicKey) let contact = self.controller.getContact(publicKey)

View File

@ -1,6 +1,6 @@
{.used.} {.used.}
import json, strformat import json, strformat, strutils
include ../../../common/json_utils include ../../../common/json_utils
@ -12,6 +12,26 @@ type ChatType* {.pure.}= enum
Profile = 4, Profile = 4,
CommunityChat = 6 CommunityChat = 6
type ChannelGroupType* {.pure.}= enum
Unknown = "unknown",
Personal = "personal",
Community = "community"
type Category* = object
id*: string
name*: string
position*: int
type
Permission* = object
access*: int
ensOnly*: bool
type
Images* = object
thumbnail*: string
large*: string
type ChatMember* = object type ChatMember* = object
id*: string id*: string
admin*: bool admin*: bool
@ -48,6 +68,24 @@ type ChatDto* = object
position*: int position*: int
categoryId*: string categoryId*: string
highlight*: bool highlight*: bool
permissions*: Permission
type ChannelGroupDto* = object
id*: string
channelGroupType*: ChannelGroupType
admin*: bool
verified*: bool
name*: string
ensName*: string
description*: string
chats*: seq[ChatDto]
categories*: seq[Category]
images*: Images
permissions*: Permission
members*: seq[ChatMember]
canManageUsers*: bool
color*: string
muted*: bool
proc `$`*(self: ChatDto): string = proc `$`*(self: ChatDto): string =
result = fmt"""ChatDto( result = fmt"""ChatDto(
@ -64,12 +102,14 @@ proc `$`*(self: ChatDto): string =
readMessagesAtClockValue: {self.readMessagesAtClockValue}, readMessagesAtClockValue: {self.readMessagesAtClockValue},
unviewedMessagesCount: {self.unviewedMessagesCount}, unviewedMessagesCount: {self.unviewedMessagesCount},
unviewedMentionsCount: {self.unviewedMentionsCount}, unviewedMentionsCount: {self.unviewedMentionsCount},
members: {self.members},
alias: {self.alias}, alias: {self.alias},
identicon: {self.identicon}, identicon: {self.identicon},
muted: {self.muted}, muted: {self.muted},
communityId: {self.communityId}, communityId: {self.communityId},
profile: {self.profile}, profile: {self.profile},
joined: {self.joined}, joined: {self.joined},
canPost: {self.canPost},
syncedTo: {self.syncedTo}, syncedTo: {self.syncedTo},
syncedFrom: {self.syncedFrom}, syncedFrom: {self.syncedFrom},
categoryId: {self.categoryId}, categoryId: {self.categoryId},
@ -77,12 +117,41 @@ proc `$`*(self: ChatDto): string =
highlight: {self.highlight} highlight: {self.highlight}
)""" )"""
proc toPermission*(jsonObj: JsonNode): Permission =
result = Permission()
discard jsonObj.getProp("access", result.access)
discard jsonObj.getProp("ens_only", result.ensOnly)
proc toImages*(jsonObj: JsonNode): Images =
result = Images()
var largeObj: JsonNode
if(jsonObj.getProp("large", largeObj)):
discard largeObj.getProp("uri", result.large)
var thumbnailObj: JsonNode
if(jsonObj.getProp("thumbnail", thumbnailObj)):
discard thumbnailObj.getProp("uri", result.thumbnail)
proc toCategory*(jsonObj: JsonNode): Category =
result = Category()
if (not jsonObj.getProp("category_id", result.id)):
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("position", result.position)
proc toChatMember*(jsonObj: JsonNode): ChatMember = proc toChatMember*(jsonObj: JsonNode): ChatMember =
result = ChatMember() result = ChatMember()
discard jsonObj.getProp("id", result.id) discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("admin", result.admin) discard jsonObj.getProp("admin", result.admin)
discard jsonObj.getProp("joined", result.joined) discard jsonObj.getProp("joined", result.joined)
proc toChatMember(jsonObj: JsonNode, memberId: string): ChatMember =
# Mapping this DTO is not strightforward since only keys are used for id. We
# handle it a bit different.
result = jsonObj.toChatMember()
result.id = memberId
proc toChatDto*(jsonObj: JsonNode): ChatDto = proc toChatDto*(jsonObj: JsonNode): ChatDto =
result = ChatDto() result = ChatDto()
discard jsonObj.getProp("id", result.id) discard jsonObj.getProp("id", result.id)
@ -94,13 +163,18 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
discard jsonObj.getProp("timestamp", result.timestamp) discard jsonObj.getProp("timestamp", result.timestamp)
discard jsonObj.getProp("lastClockValue", result.lastClockValue) discard jsonObj.getProp("lastClockValue", result.lastClockValue)
discard jsonObj.getProp("deletedAtClockValue", result.deletedAtClockValue) discard jsonObj.getProp("deletedAtClockValue", result.deletedAtClockValue)
discard jsonObj.getProp("ReadMessagesAtClockValue", result.readMessagesAtClockValue) discard jsonObj.getProp("readMessagesAtClockValue", result.readMessagesAtClockValue)
discard jsonObj.getProp("unviewedMessagesCount", result.unviewedMessagesCount) discard jsonObj.getProp("unviewedMessagesCount", result.unviewedMessagesCount)
discard jsonObj.getProp("unviewedMentionsCount", result.unviewedMentionsCount) discard jsonObj.getProp("unviewedMentionsCount", result.unviewedMentionsCount)
discard jsonObj.getProp("canPost", result.canPost)
discard jsonObj.getProp("alias", result.alias) discard jsonObj.getProp("alias", result.alias)
discard jsonObj.getProp("identicon", result.identicon) discard jsonObj.getProp("identicon", result.identicon)
discard jsonObj.getProp("muted", result.muted) discard jsonObj.getProp("muted", result.muted)
discard jsonObj.getProp("categoryId", result.categoryId) discard jsonObj.getProp("categoryId", result.categoryId)
if (result.categoryId == ""):
# Communities have `categoryID` and chats have `categoryId`
# This should be fixed in status-go, but would be a breaking change
discard jsonObj.getProp("categoryID", result.categoryId)
discard jsonObj.getProp("position", result.position) discard jsonObj.getProp("position", result.position)
discard jsonObj.getProp("communityId", result.communityId) discard jsonObj.getProp("communityId", result.communityId)
discard jsonObj.getProp("profile", result.profile) discard jsonObj.getProp("profile", result.profile)
@ -108,6 +182,9 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
discard jsonObj.getProp("syncedTo", result.syncedTo) discard jsonObj.getProp("syncedTo", result.syncedTo)
discard jsonObj.getProp("syncedFrom", result.syncedFrom) discard jsonObj.getProp("syncedFrom", result.syncedFrom)
discard jsonObj.getProp("highlight", result.highlight) discard jsonObj.getProp("highlight", result.highlight)
var permissionObj: JsonNode
if(jsonObj.getProp("permissions", permissionObj)):
result.permissions = toPermission(permissionObj)
result.chatType = ChatType.Unknown result.chatType = ChatType.Unknown
var chatTypeInt: int var chatTypeInt: int
@ -120,5 +197,54 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
for memberObj in membersObj: for memberObj in membersObj:
result.members.add(toChatMember(memberObj)) result.members.add(toChatMember(memberObj))
# Add community ID if needed
if (result.communityId != "" and not result.id.contains(result.communityId)):
result.id = result.communityId & result.id
proc toChannelGroupDto*(jsonObj: JsonNode): ChannelGroupDto =
result = ChannelGroupDto()
discard jsonObj.getProp("admin", result.admin)
discard jsonObj.getProp("verified", result.verified)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("description", result.description)
result.channelGroupType = ChannelGroupType.Unknown
var channelGroupTypeString: string
if (jsonObj.getProp("channelGroupType", channelGroupTypeString)):
result.channelGroupType = parseEnum[ChannelGroupType](channelGroupTypeString)
var chatsObj: JsonNode
if(jsonObj.getProp("chats", chatsObj)):
for _, chatObj in chatsObj:
result.chats.add(toChatDto(chatObj))
var categoriesObj: JsonNode
if(jsonObj.getProp("categories", categoriesObj)):
for _, categoryObj in categoriesObj:
result.categories.add(toCategory(categoryObj))
var imagesObj: JsonNode
if(jsonObj.getProp("images", imagesObj)):
result.images = toImages(imagesObj)
var permissionObj: JsonNode
if(jsonObj.getProp("permissions", permissionObj)):
result.permissions = toPermission(permissionObj)
var membersObj: JsonNode
if(jsonObj.getProp("members", membersObj) and membersObj.kind == JObject):
for memberId, memberObj in membersObj:
result.members.add(toChatMember(memberObj, memberId))
discard jsonObj.getProp("canManageUsers", result.canManageUsers)
discard jsonObj.getProp("color", result.color)
discard jsonObj.getProp("muted", result.muted)
# To parse Community chats to ChatDto, we need to add the commuity ID and type
proc toChatDto*(jsonObj: JsonNode, communityId: string): ChatDto =
result = jsonObj.toChatDto()
result.chatType = ChatType.CommunityChat
result.communityId = communityId
proc isPublicChat*(chatDto: ChatDto): bool = proc isPublicChat*(chatDto: ChatDto): bool =
return chatDto.chatType == ChatType.Public return chatDto.chatType == ChatType.Public

View File

@ -90,6 +90,7 @@ QtObject:
type Service* = ref object of QObject type Service* = ref object of QObject
events: EventEmitter events: EventEmitter
chats: Table[string, ChatDto] # [chat_id, ChatDto] chats: Table[string, ChatDto] # [chat_id, ChatDto]
channelGroups: OrderedTable[string, ChannelGroupDto] # [chatGroup_id, ChannelGroupDto]
contactService: contact_service.Service contactService: contact_service.Service
proc delete*(self: Service) = proc delete*(self: Service) =
@ -117,23 +118,39 @@ QtObject:
self.updateOrAddChat(chatDto) self.updateOrAddChat(chatDto)
self.events.emit(SIGNAL_CHAT_UPDATE, ChatUpdateArgsNew(messages: receivedData.messages, chats: chats)) self.events.emit(SIGNAL_CHAT_UPDATE, ChatUpdateArgsNew(messages: receivedData.messages, chats: chats))
proc sortPersonnalChatAsFirst[T, D](x, y: (T, D)): int =
if (x[1].channelGroupType == Personal): return -1
if (y[1].channelGroupType == Personal): return 1
return 0
proc init*(self: Service) = proc init*(self: Service) =
self.doConnect() self.doConnect()
try: try:
let response = status_chat.getChats() let response = status_chat.getChats()
let chats = map(response.result.getElems(), proc(x: JsonNode): ChatDto = x.toChatDto()) var chats: seq[ChatDto] = @[]
for (sectionId, section) in response.result.pairs:
var channelGroup = section.toChannelGroupDto()
channelGroup.id = sectionId
self.channelGroups[sectionId] = channelGroup
for (chatId, chat) in section["chats"].pairs:
chats.add(chat.toChatDto())
# Make the personal channelGroup the first one
self.channelGroups.sort(sortPersonnalChatAsFirst[string, ChannelGroupDto], SortOrder.Ascending)
for chat in chats: for chat in chats:
if chat.active and chat.chatType != chat_dto.ChatType.Unknown: if chat.active and chat.chatType != chat_dto.ChatType.Unknown:
self.chats[chat.id] = chat self.chats[chat.id] = chat
except Exception as e: except Exception as e:
let errDesription = e.msg let errDesription = e.msg
error "error: ", errDesription error "error: ", errDesription
return return
proc getChannelGroups*(self: Service): seq[ChannelGroupDto] =
return toSeq(self.channelGroups.values)
proc hasChannel*(self: Service, chatId: string): bool = proc hasChannel*(self: Service, chatId: string): bool =
self.chats.hasKey(chatId) self.chats.hasKey(chatId)

View File

@ -1,41 +1,32 @@
{.used.} {.used.}
import json, sequtils import json, sequtils, sugar
import ../../../../backend/communities import ../../../../backend/communities
include ../../../common/json_utils include ../../../common/json_utils
type import ../../chat/dto/chat
Permission* = object
access*: int
ensOnly*: bool
type type
Images* = object CommunityMemberRoles* {.pure.} = enum
thumbnail*: string Unknown = 0,
large*: string All = 1,
ManagerUsers = 2
type Chat* = object
id*: string
name*: string
color*: string
emoji*: string
description*: string
#members*: seq[ChatMember] ???? It's always null and a question is why do we need it here within this context ????
permissions*: Permission
canPost*: bool
position*: int
categoryId*: string
type Category* = object
id*: string
name*: string
position*: int
type Member* = object type Member* = object
id*: string id*: string
roles*: seq[int] roles*: seq[int]
proc toMember*(jsonObj: JsonNode, memberId: string): Member =
# Mapping this DTO is not strightforward since only keys are used for id. We
# handle it a bit different.
result = Member()
result.id = memberId
var rolesObj: JsonNode
if(jsonObj.getProp("roles", rolesObj)):
for roleObj in rolesObj:
result.roles.add(roleObj.getInt)
type CommunityMembershipRequestDto* = object type CommunityMembershipRequestDto* = object
id*: string id*: string
publicKey*: string publicKey*: string
@ -52,7 +43,7 @@ type CommunityDto* = object
requestedAccessAt: int64 requestedAccessAt: int64
name*: string name*: string
description*: string description*: string
chats*: seq[Chat] chats*: seq[ChatDto]
categories*: seq[Category] categories*: seq[Category]
images*: Images images*: Images
permissions*: Permission permissions*: Permission
@ -66,53 +57,6 @@ type CommunityDto* = object
muted*: bool muted*: bool
pendingRequestsToJoin*: seq[CommunityMembershipRequestDto] pendingRequestsToJoin*: seq[CommunityMembershipRequestDto]
proc toPermission(jsonObj: JsonNode): Permission =
result = Permission()
discard jsonObj.getProp("access", result.access)
discard jsonObj.getProp("ens_only", result.ensOnly)
proc toImages(jsonObj: JsonNode): Images =
result = Images()
var largeObj: JsonNode
if(jsonObj.getProp("large", largeObj)):
discard largeObj.getProp("uri", result.large)
var thumbnailObj: JsonNode
if(jsonObj.getProp("thumbnail", thumbnailObj)):
discard thumbnailObj.getProp("uri", result.thumbnail)
proc toChat*(jsonObj: JsonNode): Chat =
result = Chat()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("color", result.color)
discard jsonObj.getProp("emoji", result.emoji)
discard jsonObj.getProp("description", result.description)
var permissionObj: JsonNode
if(jsonObj.getProp("permissions", permissionObj)):
result.permissions = toPermission(permissionObj)
discard jsonObj.getProp("canPost", result.canPost)
discard jsonObj.getProp("position", result.position)
discard jsonObj.getProp("categoryID", result.categoryId)
proc toCategory*(jsonObj: JsonNode): Category =
result = Category()
if (not jsonObj.getProp("category_id", result.id)):
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("position", result.position)
proc toMember*(jsonObj: JsonNode, memberId: string): Member =
# Mapping this DTO is not strightforward since only keys are used for id. We
# handle it a bit different.
result = Member()
result.id = memberId
var rolesObj: JsonNode
if(jsonObj.getProp("roles", rolesObj)):
for roleObj in rolesObj:
result.roles.add(roleObj.getInt)
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)
@ -126,7 +70,7 @@ proc toCommunityDto*(jsonObj: JsonNode): CommunityDto =
var chatsObj: JsonNode var chatsObj: JsonNode
if(jsonObj.getProp("chats", chatsObj)): if(jsonObj.getProp("chats", chatsObj)):
for _, chatObj in chatsObj: for _, chatObj in chatsObj:
result.chats.add(toChat(chatObj)) result.chats.add(chatObj.toChatDto(result.id))
var categoriesObj: JsonNode var categoriesObj: JsonNode
if(jsonObj.getProp("categories", categoriesObj)): if(jsonObj.getProp("categories", categoriesObj)):
@ -166,3 +110,33 @@ proc toCommunityMembershipRequestDto*(jsonObj: JsonNode): CommunityMembershipReq
proc parseCommunities*(response: RpcResponse[JsonNode]): seq[CommunityDto] = proc parseCommunities*(response: RpcResponse[JsonNode]): seq[CommunityDto] =
result = map(response.result.getElems(), result = map(response.result.getElems(),
proc(x: JsonNode): CommunityDto = x.toCommunityDto()) proc(x: JsonNode): CommunityDto = x.toCommunityDto())
proc contains(arrayToSearch: seq[int], searched: int): bool =
for element in arrayToSearch:
if element == searched:
return true
return false
proc toChannelGroupDto*(communityDto: CommunityDto): ChannelGroupDto =
ChannelGroupDto(
id: communityDto.id,
channelGroupType: ChannelGroupType.Community,
name: communityDto.name,
images: communityDto.images,
chats: communityDto.chats,
categories: communityDto.categories,
# Community doesn't have an ensName yet. Add this when it is added in status-go
# ensName: communityDto.ensName,
admin: communityDto.admin,
verified: communityDto.verified,
description: communityDto.description,
color: communityDto.color,
permissions: communityDto.permissions,
members: communityDto.members.map(m => ChatMember(
id: m.id,
joined: true,
admin: m.roles.contains(CommunityMemberRoles.ManagerUsers.int)
)),
canManageUsers: communityDto.canManageUsers,
muted: communityDto.muted
)

View File

@ -144,22 +144,8 @@ QtObject:
self.events.emit(SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY, CommunityRequestArgs(communityRequest: membershipRequest)) self.events.emit(SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY, CommunityRequestArgs(communityRequest: membershipRequest))
proc mapChatToChatDto(chat: Chat, communityId: string): ChatDto = proc updateMissingFields(chatDto: var ChatDto, chat: ChatDto) =
result = ChatDto() # This proc sets fields of `chatDto` which are available only for community channels.
result.id = chat.id
result.communityId = communityId
result.name = chat.name
result.chatType = ChatType.CommunityChat
result.color = chat.color
result.emoji = chat.emoji
result.description = chat.description
result.canPost = chat.canPost
result.position = chat.position
result.categoryId = chat.categoryId
result.communityId = communityId
proc updateMissingFields(chatDto: var ChatDto, chat: Chat) =
# This proc sets fields of `chatDto` which are available only for comminity channels.
chatDto.position = chat.position chatDto.position = chat.position
chatDto.canPost = chat.canPost chatDto.canPost = chat.canPost
chatDto.categoryId = chat.categoryId chatDto.categoryId = chat.categoryId
@ -169,7 +155,7 @@ QtObject:
if(chat.id == id): if(chat.id == id):
return chat return chat
proc findIndexById(id: string, chats: seq[Chat]): int = proc findIndexById(id: string, chats: seq[ChatDto]): int =
var idx = -1 var idx = -1
for chat in chats: for chat in chats:
inc idx inc idx
@ -199,7 +185,6 @@ QtObject:
if (chat.categoryId == categoryId): if (chat.categoryId == categoryId):
let fullChatId = community.id & chat.id let fullChatId = community.id & chat.id
var chatDetails = self.chatService.getChatById(fullChatId) var chatDetails = self.chatService.getChatById(fullChatId)
chatDetails.updateMissingFields(chat)
result.add(chatDetails) result.add(chatDetails)
proc handleCommunityUpdates(self: Service, communities: seq[CommunityDto], updatedChats: seq[ChatDto]) = proc handleCommunityUpdates(self: Service, communities: seq[CommunityDto], updatedChats: seq[ChatDto]) =
@ -368,7 +353,7 @@ QtObject:
else: else:
result.sort(sortDesc[Category]) result.sort(sortDesc[Category])
proc getChats*(self: Service, communityId: string, categoryId = "", order = SortOrder.Ascending): seq[Chat] = proc getChats*(self: Service, communityId: string, categoryId = "", order = SortOrder.Ascending): seq[ChatDto] =
## By default returns chats which don't belong to any category, for passed `communityId`. ## By default returns chats which don't belong to any category, for passed `communityId`.
## If `categoryId` is set then only chats belonging to that category for passed `communityId` will be returned. ## If `categoryId` is set then only chats belonging to that category for passed `communityId` will be returned.
## Returned chats are sorted by position following set `order` parameter. ## Returned chats are sorted by position following set `order` parameter.
@ -383,11 +368,11 @@ QtObject:
result.add(chat) result.add(chat)
if(order == SortOrder.Ascending): if(order == SortOrder.Ascending):
result.sort(sortAsc[Chat]) result.sort(sortAsc[ChatDto])
else: else:
result.sort(sortDesc[Chat]) result.sort(sortDesc[ChatDto])
proc getAllChats*(self: Service, communityId: string, order = SortOrder.Ascending): seq[Chat] = proc getAllChats*(self: Service, communityId: string, order = SortOrder.Ascending): seq[ChatDto] =
## Returns all chats belonging to the community with passed `communityId`, sorted by position. ## Returns all chats belonging to the community with passed `communityId`, sorted by position.
## Returned chats are sorted by position following set `order` parameter. ## Returned chats are sorted by position following set `order` parameter.
if(not self.joinedCommunities.contains(communityId)): if(not self.joinedCommunities.contains(communityId)):
@ -397,9 +382,9 @@ QtObject:
result = self.joinedCommunities[communityId].chats result = self.joinedCommunities[communityId].chats
if(order == SortOrder.Ascending): if(order == SortOrder.Ascending):
result.sort(sortAsc[Chat]) result.sort(sortAsc[ChatDto])
else: else:
result.sort(sortDesc[Chat]) result.sort(sortDesc[ChatDto])
proc isUserMemberOfCommunity*(self: Service, communityId: string): bool = proc isUserMemberOfCommunity*(self: Service, communityId: string): bool =
if(not self.allCommunities.contains(communityId)): if(not self.allCommunities.contains(communityId)):
@ -439,7 +424,7 @@ QtObject:
if (currentChat.id != ""): if (currentChat.id != ""):
# The chat service already knows that about that chat # The chat service already knows that about that chat
continue continue
var chatDto = mapChatToChatDto(chat, communityId) var chatDto = chat
chatDto.id = fullChatId chatDto.id = fullChatId
# TODO find a way to populate missing infos like the color # TODO find a way to populate missing infos like the color
self.chatService.updateOrAddChat(chatDto) self.chatService.updateOrAddChat(chatDto)
@ -602,7 +587,7 @@ QtObject:
raise newException(RpcException, fmt"createCommunityChannel; there is no `chats` key in the response for community id: {communityId}") raise newException(RpcException, fmt"createCommunityChannel; there is no `chats` key in the response for community id: {communityId}")
for chatObj in chatsJArr: for chatObj in chatsJArr:
var chatDto = chatObj.toChatDto() var chatDto = chatObj.toChatDto(communityId)
self.chatService.updateOrAddChat(chatDto) self.chatService.updateOrAddChat(chatDto)
let data = CommunityChatArgs(chat: chatDto) let data = CommunityChatArgs(chat: chatDto)
self.events.emit(SIGNAL_COMMUNITY_CHANNEL_CREATED, data) self.events.emit(SIGNAL_COMMUNITY_CHANNEL_CREATED, data)
@ -642,7 +627,7 @@ QtObject:
raise newException(RpcException, fmt"editCommunityChannel; there is no `chats` key in the response for community id: {communityId}") raise newException(RpcException, fmt"editCommunityChannel; there is no `chats` key in the response for community id: {communityId}")
for chatObj in chatsJArr: for chatObj in chatsJArr:
var chatDto = chatObj.toChatDto() var chatDto = chatObj.toChatDto(communityId)
self.chatService.updateOrAddChat(chatDto) # we have to update chats stored in the chat service. self.chatService.updateOrAddChat(chatDto) # we have to update chats stored in the chat service.
@ -863,7 +848,7 @@ QtObject:
self.joinedCommunities[communityDto.id] = communityDto self.joinedCommunities[communityDto.id] = communityDto
for chatObj in chatsJArr: for chatObj in chatsJArr:
let chatDto = chatObj.toChatDto() let chatDto = chatObj.toChatDto(communityDto.id)
self.chatService.updateOrAddChat(chatDto) # we have to update chats stored in the chat service. self.chatService.updateOrAddChat(chatDto) # we have to update chats stored in the chat service.
for chat in communityDto.chats: for chat in communityDto.chats:

View File

@ -33,7 +33,7 @@ proc saveChat*(
proc getChats*(): RpcResponse[JsonNode] {.raises: [Exception].} = proc getChats*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [] let payload = %* []
result = callPrivateRPC("chats".prefix, payload) result = callPrivateRPC("chat_getChats", payload)
proc createPublicChat*(chatId: string): RpcResponse[JsonNode] {.raises: [Exception].} = proc createPublicChat*(chatId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let communityId = "" let communityId = ""

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 16311512cbf66c9eeaf03194707faa19c9390649 Subproject commit c342c8bb1af9183795f652a41065244c0a0bbe09