fix: remove filters on leaving chat

This commit is contained in:
Richard Ramos 2020-06-18 13:57:29 -04:00 committed by Iuri Matias
parent c2ed0da1ca
commit 47b88cab95
3 changed files with 95 additions and 47 deletions

View File

@ -1,11 +1,9 @@
import eventemitter, json import eventemitter, json, strutils, sequtils, tables
import sequtils
import libstatus/chat as status_chat import libstatus/chat as status_chat
import chronicles import chronicles
import profile/profile import profile/profile
import chat/[chat, message] import chat/[chat, message]
import ../signals/messages import ../signals/messages
import tables
import ens import ens
type type
@ -33,15 +31,15 @@ type
events*: EventEmitter events*: EventEmitter
contacts*: Table[string, Profile] contacts*: Table[string, Profile]
channels*: Table[string, Chat] channels*: Table[string, Chat]
filters*: Table[string, string]
msgCursor*: Table[string, string] msgCursor*: Table[string, string]
include chat/utils
proc newChatModel*(events: EventEmitter): ChatModel = proc newChatModel*(events: EventEmitter): ChatModel =
result = ChatModel() result = ChatModel()
result.events = events result.events = events
result.contacts = initTable[string, Profile]() result.contacts = initTable[string, Profile]()
result.channels = initTable[string, Chat]() result.channels = initTable[string, Chat]()
result.filters = initTable[string, string]()
result.msgCursor = initTable[string, string]() result.msgCursor = initTable[string, string]()
proc delete*(self: ChatModel) = proc delete*(self: ChatModel) =
@ -73,7 +71,6 @@ proc join*(self: ChatModel, chatId: string, chatType: ChatType) =
for topicObj in parsedResult: for topicObj in parsedResult:
if ($topicObj["chatId"].getStr == chatId): if ($topicObj["chatId"].getStr == chatId):
topics.add($topicObj["topic"].getStr) topics.add($topicObj["topic"].getStr)
if(not self.filters.hasKey(chatId)): self.filters[chatId] = topicObj["filterId"].getStr
if (topics.len == 0): if (topics.len == 0):
warn "No topics found for chats. Cannot load past messages" warn "No topics found for chats. Cannot load past messages"
@ -103,40 +100,22 @@ proc init*(self: ChatModel) =
let parsedResult = parseJson(filterResult)["result"] let parsedResult = parseJson(filterResult)["result"]
for topicObj in parsedResult: for topicObj in parsedResult:
topics.add($topicObj["topic"].getStr) topics.add($topicObj["topic"].getStr)
self.filters[$topicObj["chatId"].getStr] = topicObj["filterId"].getStr
if (topics.len == 0): if (topics.len == 0):
warn "No topics found for chats. Cannot load past messages" warn "No topics found for chats. Cannot load past messages"
else: else:
self.events.emit("mailserverTopics", TopicArgs(topics: topics)); self.events.emit("mailserverTopics", TopicArgs(topics: topics));
proc processChatUpdate(self: ChatModel,response: JsonNode): (seq[Chat], seq[Message]) =
var chats: seq[Chat] = @[]
var messages: seq[Message] = @[]
if response["result"]{"chats"} != nil:
for jsonMsg in response["result"]["messages"]:
messages.add(jsonMsg.toMessage)
if response["result"]{"chats"} != nil:
for jsonChat in response["result"]["chats"]:
let chat = jsonChat.toChat
self.channels[chat.id] = chat
chats.add(chat)
result = (chats, messages)
proc leave*(self: ChatModel, chatId: string) = proc leave*(self: ChatModel, chatId: string) =
self.removeChatFilters(chatId)
if self.channels[chatId].chatType == ChatType.PrivateGroupChat: if self.channels[chatId].chatType == ChatType.PrivateGroupChat:
let leaveGroupResponse = status_chat.leaveGroupChat(chatId) let leaveGroupResponse = status_chat.leaveGroupChat(chatId)
var (chats, messages) = self.processChatUpdate(parseJson(leaveGroupResponse)) self.emitUpdate(leaveGroupResponse)
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
# We still want to be able to receive messages unless we block the 1:1 sender
if self.filters.hasKey(chatId) and self.channels[chatId].chatType == ChatType.Public:
status_chat.removeFilters(chatId, self.filters[chatId])
status_chat.deactivateChat(self.channels[chatId]) status_chat.deactivateChat(self.channels[chatId])
# TODO: REMOVE MAILSERVER TOPIC # TODO: REMOVE MAILSERVER TOPIC
self.filters.del(chatId)
self.channels.del(chatId) self.channels.del(chatId)
discard status_chat.clearChatHistory(chatId) discard status_chat.clearChatHistory(chatId)
self.events.emit("channelLeft", ChatIdArg(chatId: chatId)) self.events.emit("channelLeft", ChatIdArg(chatId: chatId))
@ -151,21 +130,9 @@ proc clearHistory*(self: ChatModel, chatId: string) =
proc setActiveChannel*(self: ChatModel, chatId: string) = proc setActiveChannel*(self: ChatModel, chatId: string) =
self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId)) self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId))
proc formatChatUpdate(response: JsonNode): (seq[Chat], seq[Message]) =
var chats: seq[Chat] = @[]
var messages: seq[Message] = @[]
if response["result"]{"chats"} != nil:
for jsonMsg in response["result"]["messages"]:
messages.add(jsonMsg.toMessage)
if response["result"]{"chats"} != nil:
for jsonChat in response["result"]["chats"]:
chats.add(jsonChat.toChat)
result = (chats, messages)
proc sendMessage*(self: ChatModel, chatId: string, msg: string): string = proc sendMessage*(self: ChatModel, chatId: string, msg: string): string =
var sentMessage = status_chat.sendChatMessage(chatId, msg) var sentMessage = status_chat.sendChatMessage(chatId, msg)
var (chats, messages) = self.processChatUpdate(parseJson(sentMessage)) self.emitUpdate(sentMessage)
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
sentMessage sentMessage
proc chatMessages*(self: ChatModel, chatId: string, initialLoad:bool = true) = proc chatMessages*(self: ChatModel, chatId: string, initialLoad:bool = true) =
@ -185,14 +152,12 @@ proc markAllChannelMessagesRead*(self: ChatModel, chatId: string): JsonNode =
result = parseJson(response) result = parseJson(response)
proc confirmJoiningGroup*(self: ChatModel, chatId: string) = proc confirmJoiningGroup*(self: ChatModel, chatId: string) =
var response = parseJson(status_chat.confirmJoiningGroup(chatId)) var response = status_chat.confirmJoiningGroup(chatId)
var (chats, messages) = self.processChatUpdate(response) self.emitUpdate(response)
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
proc renameGroup*(self: ChatModel, chatId: string, newName: string) = proc renameGroup*(self: ChatModel, chatId: string, newName: string) =
var response = parseJson(status_chat.renameGroup(chatId, newName)) var response = status_chat.renameGroup(chatId, newName)
var (chats, messages) = formatChatUpdate(response) self.emitUpdate(response)
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
proc getUserName*(self: ChatModel, id: string, defaultUserName: string):string = proc getUserName*(self: ChatModel, id: string, defaultUserName: string):string =
if(self.contacts.hasKey(id)): if(self.contacts.hasKey(id)):

81
src/status/chat/utils.nim Normal file
View File

@ -0,0 +1,81 @@
proc formatChatUpdate(response: JsonNode): (seq[Chat], seq[Message]) =
var chats: seq[Chat] = @[]
var messages: seq[Message] = @[]
if response["result"]{"chats"} != nil:
for jsonMsg in response["result"]["messages"]:
messages.add(jsonMsg.toMessage)
if response["result"]{"chats"} != nil:
for jsonChat in response["result"]["chats"]:
chats.add(jsonChat.toChat)
result = (chats, messages)
proc processChatUpdate(self: ChatModel, response: JsonNode): (seq[Chat], seq[Message]) =
var chats: seq[Chat] = @[]
var messages: seq[Message] = @[]
if response["result"]{"chats"} != nil:
for jsonMsg in response["result"]["messages"]:
messages.add(jsonMsg.toMessage)
if response["result"]{"chats"} != nil:
for jsonChat in response["result"]["chats"]:
let chat = jsonChat.toChat
self.channels[chat.id] = chat
chats.add(chat)
result = (chats, messages)
proc emitUpdate(self: ChatModel, response: string) =
var (chats, messages) = self.processChatUpdate(parseJson(response))
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
proc removeFiltersByChatId(self: ChatModel, chatId: string, filters: JsonNode)
proc removeChatFilters(self: ChatModel, chatId: string) =
# TODO: this code should be handled by status-go / stimbus instead of the client
# Clients should not have to care about filters. For more info about filters:
# https://github.com/status-im/specs/blob/master/docs/stable/3-whisper-usage.md#keys-management
let filters = parseJson(status_chat.loadFilters(@[]))["result"]
case self.channels[chatId].chatType
of ChatType.Public:
for filter in filters:
if filter["chatId"].getStr == chatId:
status_chat.removeFilters(chatId, filter["filterId"].getStr)
of ChatType.OneToOne:
# Check if user does not belong to any active chat group
var inGroup = false
for channel in self.channels.values:
if channel.isActive and channel.id != chatId and channel.chatType == ChatType.PrivateGroupChat:
inGroup = true
break
if not inGroup: self.removeFiltersByChatId(chatId, filters)
of ChatType.PrivateGroupChat:
for member in self.channels[chatId].members:
# Check that any of the members are not in other active group chats, or that you dont have a one-to-one open.
var hasConversation = false
for channel in self.channels.values:
if (channel.isActive and channel.chatType == ChatType.OneToOne and channel.id == member.id) or
(channel.isActive and channel.id != chatId and channel.chatType == ChatType.PrivateGroupChat and channel.isMember(member.id)):
hasConversation = true
break
if not hasConversation: self.removeFiltersByChatId(member.id, filters)
else:
error "Unknown chat type removed", chatId
proc removeFiltersByChatId(self: ChatModel, chatId: string, filters: JsonNode) =
var partitionedTopic = ""
for filter in filters:
# Contact code filter should be removed
if filter["identity"].getStr == chatId and filter["chatId"].getStr.endsWith("-contact-code"):
status_chat.removeFilters(chatId, filter["filterId"].getStr)
# Remove partitioned topic if no other user in an active group chat or one-to-one is from the
# same partitioned topic
if filter["identity"].getStr == chatId and filter["chatId"].getStr.startsWith("contact-discovery-"):
partitionedTopic = filter["topic"].getStr
var samePartitionedTopic = false
for f in filters.filterIt(it["topic"].getStr == partitionedTopic and it["filterId"].getStr != filter["filterId"].getStr):
let fIdentity = f["identity"].getStr;
if self.channels.hasKey(fIdentity) and self.channels[fIdentity].isActive:
samePartitionedTopic = true
break
if not samePartitionedTopic:
status_chat.removeFilters(chatId, filter["filterId"].getStr)

View File

@ -28,6 +28,8 @@ proc removeFilters*(chatId: string, filterId: string) =
]) ])
proc saveChat*(chatId: string, oneToOne: bool = false, active: bool = true, color: string) = proc saveChat*(chatId: string, oneToOne: bool = false, active: bool = true, color: string) =
# TODO: ideally status-go/stimbus should handle some of these fields instead of having the client
# send them: lastMessage, unviewedMEssagesCount, timestamp, lastClockValue, name?
discard callPrivateRPC("saveChat".prefix, %* [ discard callPrivateRPC("saveChat".prefix, %* [
{ {
"lastClockValue": 0, # TODO: "lastClockValue": 0, # TODO: