fix: remove filters on leaving chat
This commit is contained in:
parent
c2ed0da1ca
commit
47b88cab95
|
@ -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)):
|
||||||
|
|
|
@ -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 don’t 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)
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue