feat(@desktop/community): allow owner delete all messages during the ban and ban/unban AC notifications (#13653)

This commit is contained in:
Mykhailo Prakhov 2024-02-22 12:01:01 +01:00 committed by GitHub
parent 34f801231c
commit 12569d795f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 305 additions and 118 deletions

View File

@ -1,4 +1,4 @@
import json, chronicles
import json, chronicles, tables
import base
@ -28,7 +28,8 @@ type MessageSignal* = ref object of Signal
membershipRequests*: seq[CommunityMembershipRequestDto]
activityCenterNotifications*: seq[ActivityCenterNotificationDto]
statusUpdates*: seq[StatusUpdateDto]
deletedMessages*: seq[RemovedMessageDto]
removedMessages*: seq[RemovedMessageDto]
deletedMessages*: Table[string, seq[string]]
removedChats*: seq[string]
currentStatus*: seq[StatusUpdateDto]
settings*: seq[SettingsFieldDto]
@ -117,7 +118,15 @@ proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal =
if e.contains("removedMessages"):
for jsonRemovedMessage in e["removedMessages"]:
signal.deletedMessages.add(jsonRemovedMessage.toRemovedMessageDto())
signal.removedMessages.add(jsonRemovedMessage.toRemovedMessageDto())
if e.contains("deletedMessages"):
let deletedMessagesObj = e["deletedMessages"]
for chatId, messageIdsArrayJson in deletedMessagesObj:
if not signal.deletedMessages.hasKey(chatId):
signal.deletedMessages[chatId] = @[]
for messageId in messageIdsArrayJson:
signal.deletedMessages[chatId].add(messageId.getStr())
if e.contains("removedChats"):
for removedChatID in e["removedChats"]:
@ -161,6 +170,5 @@ proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal =
if e.contains("updatedProfileShowcases"):
for jsonProfileShowcase in e["updatedProfileShowcases"]:
signal.updatedProfileShowcases.add(jsonProfileShowcase.toProfileShowcaseDto())
result = signal

View File

@ -1,5 +1,4 @@
import NimQml
import json
import NimQml, tables, json
import io_interface
import ../../../../../app_service/service/settings/service as settings_service
@ -153,13 +152,20 @@ proc init*(self: Controller) =
self.delegate.onMutualContactChanged()
self.delegate.onContactDetailsUpdated(args.contactId)
self.events.on(SIGNAL_MESSAGE_DELETION) do(e: Args):
let args = MessageDeletedArgs(e)
self.events.on(SIGNAL_MESSAGE_REMOVED) do(e: Args):
let args = MessageRemovedArgs(e)
if(self.chatId != args.chatId):
return
# remove from pinned messages model
self.delegate.onUnpinMessage(args.messageId)
self.events.on(SIGNAL_MESSAGES_DELETED) do(e: Args):
let args = MessagesDeletedArgs(e)
if self.chatId in args.deletedMessages:
for deletedMessage in args.deletedMessages[self.chatId]:
# delete from pinned messages model
self.delegate.onUnpinMessage(deletedMessage)
self.events.on(SIGNAL_COMMUNITY_CHANNEL_EDITED) do(e:Args):
let args = CommunityChatArgs(e)
if(args.chat.communityId != self.sectionId or args.chat.id != self.chatId):

View File

@ -131,7 +131,7 @@ proc getChatId*(self: Controller): string =
proc belongsToCommunity*(self: Controller): bool =
return self.belongsToCommunity
proc setLinkPreviewEnabledForThisMessage*(self: Controller, enabled: bool) =
self.linkPreviewCurrentMessageSetting = if enabled: UrlUnfurlingMode.Enabled else: UrlUnfurlingMode.Disabled
self.delegate.setAskToEnableLinkPreview(false)
@ -142,18 +142,18 @@ proc resetLinkPreviews(self: Controller) =
self.linkPreviewCurrentMessageSetting = self.linkPreviewPersistentSetting
self.delegate.setAskToEnableLinkPreview(false)
proc sendImages*(self: Controller,
imagePathsAndDataJson: string,
msg: string,
replyTo: string,
proc sendImages*(self: Controller,
imagePathsAndDataJson: string,
msg: string,
replyTo: string,
preferredUsername: string = "",
linkPreviews: seq[LinkPreview]): string =
self.resetLinkPreviews()
self.chatService.sendImages(
self.chatId,
imagePathsAndDataJson,
msg,
replyTo,
self.chatId,
imagePathsAndDataJson,
msg,
replyTo,
preferredUsername,
linkPreviews
)
@ -165,10 +165,10 @@ proc sendChatMessage*(self: Controller,
preferredUsername: string = "",
linkPreviews: seq[LinkPreview]) =
self.resetLinkPreviews()
self.chatService.sendChatMessage(self.chatId,
msg,
replyTo,
contentType,
self.chatService.sendChatMessage(self.chatId,
msg,
replyTo,
contentType,
preferredUsername,
linkPreviews
)
@ -288,7 +288,7 @@ proc asyncUnfurlUrls(self: Controller, urls: seq[string]) =
proc asyncUnfurlUnknownUrls(self: Controller, urls: seq[string]) =
let newUrls = self.linkPreviewCache.unknownUrls(urls)
self.asyncUnfurlUrls(newUrls)
proc linkPreviewsFromCache*(self: Controller, urls: seq[string]): Table[string, LinkPreview] =
return self.linkPreviewCache.linkPreviews(urls)

View File

@ -1,4 +1,4 @@
import chronicles, uuids, times
import chronicles, uuids, times, tables
import io_interface
import ../../../../../../app/global/global_singleton
@ -182,11 +182,16 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_LOGGEDIN_USER_IMAGE_CHANGED) do(e: Args):
self.delegate.updateContactDetails(singletonInstance.userProfile.getPubKey())
self.events.on(SIGNAL_MESSAGE_DELETION) do(e: Args):
let args = MessageDeletedArgs(e)
self.events.on(SIGNAL_MESSAGE_REMOVED) do(e: Args):
let args = MessageRemovedArgs(e)
if(self.chatId != args.chatId):
return
self.delegate.onMessageDeleted(args.messageId, args.deletedBy)
self.delegate.onMessageRemoved(args.messageId, args.deletedBy)
self.events.on(SIGNAL_MESSAGES_DELETED) do(e: Args):
let args = MessagesDeletedArgs(e)
if self.chatId in args.deletedMessages:
self.delegate.onMessagesDeleted(args.deletedMessages[self.chatId])
self.events.on(SIGNAL_MESSAGE_EDITED) do(e: Args):
let args = MessageEditedArgs(e)
@ -296,7 +301,7 @@ proc deleteMessage*(self: Controller, messageId: string) =
proc editMessage*(self: Controller, messageId: string, contentType: int, updatedMsg: string) =
self.messageService.editMessage(messageId, contentType, updatedMsg)
proc getSearchedMessageId*(self: Controller): string =
return self.searchedMessageId

View File

@ -123,7 +123,10 @@ method getNumberOfPinnedMessages*(self: AccessInterface): int {.base.} =
method deleteMessage*(self: AccessInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onMessageDeleted*(self: AccessInterface, messageId, deletedBy: string) {.base.} =
method onMessageRemoved*(self: AccessInterface, messageId, removedBy: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onMessagesDeleted*(self: AccessInterface, messageIds: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")
method editMessage*(self: AccessInterface, messageId: string, contentType: int, updatedMsg: string) {.base.} =

View File

@ -378,7 +378,7 @@ proc currentUserWalletContainsAddress(self: Module, address: string): bool =
return false
method reevaluateViewLoadingState*(self: Module) =
self.view.setLoading(not self.initialMessagesLoaded or
self.view.setLoading(not self.initialMessagesLoaded or
not self.firstUnseenMessageState.initialized or
self.firstUnseenMessageState.fetching or
self.view.getMessageSearchOngoing())
@ -564,16 +564,20 @@ method updateContactDetails*(self: Module, contactId: string) =
method deleteMessage*(self: Module, messageId: string) =
self.controller.deleteMessage(messageId)
method onMessageDeleted*(self: Module, messageId, deletedBy: string) =
var deletedByValue = deletedBy
if deletedBy == "":
# deletedBy is empty if it was deleted by the sender
method onMessageRemoved*(self: Module, messageId, removedBy: string) =
var removedByValue = removedBy
if removedBy == "":
# removedBy is empty if it was removed by the sender
let messageItem = self.view.model().getItemWithMessageId(messageId)
if messageItem.id == "":
return
deletedByValue = messageItem.senderId
var deletedByContactDetails = self.controller.getContactDetails(deletedByValue)
self.view.model().messageDeleted(messageId, deletedByValue, deletedByContactDetails)
removedByValue = messageItem.senderId
var removedByContactDetails = self.controller.getContactDetails(removedByValue)
self.view.model().messageRemoved(messageId, removedByValue, removedByContactDetails)
method onMessagesDeleted*(self: Module, messageIds: seq[string]) =
for messageId in messageIds:
self.view.model().removeItem(messageId)
method editMessage*(self: Module, messageId: string, contentType: int, updatedMsg: string) =
self.controller.editMessage(messageId, contentType, updatedMsg)
@ -730,7 +734,7 @@ proc updateItemsByAlbum(self: Module, items: var seq[Item], message: MessageDto)
for j in 0 ..< item.albumMessageIds.len:
if item.albumMessageIds[j] == message.id:
return true
var albumImages = item.albumMessageImages
var albumMessagesIds = item.albumMessageIds
albumMessagesIds.add(message.id)
@ -770,21 +774,21 @@ proc updateLinkPreviewsContacts(self: Module, item: Item, requestFromMailserver:
if not requestFromMailserver:
continue
debug "updateLinkPreviewsContacts: contact not found, requesting from mailserver", contactId
item.linkPreviewModel.onContactDataRequested(contactId)
self.controller.requestContactInfo(contactId)
proc updateLinkPreviewsCommunities(self: Module, item: Item, requestFromMailserver: bool) =
for communityId, url in item.linkPreviewModel.getCommunityLinks().pairs:
let community = self.controller.getCommunityById(communityId)
if community.id != "":
item.linkPreviewModel.setCommunityInfo(community)
if not requestFromMailserver:
continue
debug "updateLinkPreviewsCommunites: requesting from mailserver", communityId
let urlData = self.controller.parseSharedUrl(url)
item.linkPreviewModel.onCommunityInfoRequested(communityId)

View File

@ -600,8 +600,8 @@ proc leaveCommunity*(self: Controller) =
proc removeUserFromCommunity*(self: Controller, pubKey: string) =
self.communityService.asyncRemoveUserFromCommunity(self.sectionId, pubKey)
proc banUserFromCommunity*(self: Controller, pubKey: string) =
self.communityService.asyncBanUserFromCommunity(self.sectionId, pubKey)
proc banUserFromCommunity*(self: Controller, pubKey: string, deleteAllMessages: bool) =
self.communityService.asyncBanUserFromCommunity(self.sectionId, pubKey, deleteAllMessages)
proc unbanUserFromCommunity*(self: Controller, pubKey: string) =
self.communityService.asyncUnbanUserFromCommunity(self.sectionId, pubKey)

View File

@ -279,7 +279,7 @@ method leaveCommunity*(self: AccessInterface) {.base.} =
method removeUserFromCommunity*(self: AccessInterface, pubKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method banUserFromCommunity*(self: AccessInterface, pubKey: string) {.base.} =
method banUserFromCommunity*(self: AccessInterface, pubKey: string, deleteAllMessages: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method editCommunity*(self: AccessInterface, name: string, description, introMessage, outroMessage: string,

View File

@ -1097,8 +1097,8 @@ method leaveCommunity*(self: Module) =
method removeUserFromCommunity*(self: Module, pubKey: string) =
self.controller.removeUserFromCommunity(pubKey)
method banUserFromCommunity*(self: Module, pubKey: string) =
self.controller.banUserFromCommunity(pubkey)
method banUserFromCommunity*(self: Module, pubKey: string, deleteAllMessages: bool) =
self.controller.banUserFromCommunity(pubkey, deleteAllMessages)
method unbanUserFromCommunity*(self: Module, pubKey: string) =
self.controller.unbanUserFromCommunity(pubkey)

View File

@ -298,8 +298,8 @@ QtObject:
proc removeUserFromCommunity*(self: View, pubKey: string) {.slot.} =
self.delegate.removeUserFromCommunity(pubKey)
proc banUserFromCommunity*(self: View, pubKey: string) {.slot.} =
self.delegate.banUserFromCommunity(pubKey)
proc banUserFromCommunity*(self: View, pubKey: string, deleteAllMessages: bool) {.slot.} =
self.delegate.banUserFromCommunity(pubKey, deleteAllMessages)
proc editCommunity*(self: View, name: string, description: string, introMessage: string, outroMessage: string, access: int,
color: string, tags: string, logoJsonData: string, bannerJsonData: string, historyArchiveSupportEnabled: bool,

View File

@ -498,7 +498,7 @@ QtObject:
self.countChanged()
self.updateMessagesWhenQuotedMessageDeleted(messageId)
proc messageDeleted*(self: Model, messageId: string, deletedBy: string, deletedByContactDetails: ContactDetails) =
proc messageRemoved*(self: Model, messageId: string, deletedBy: string, deletedByContactDetails: ContactDetails) =
let i = self.findIndexForMessageId(messageId)
if(i == -1):
return
@ -846,7 +846,7 @@ QtObject:
albumImages.add(messageImage)
item.albumMessageImages = albumImages
item.albumMessageIds = albumMessagesIds
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.AlbumMessageImages.int])

View File

@ -30,6 +30,8 @@ type ActivityCenterNotificationType* {.pure.}= enum
ShareAccounts = 18
CommunityTokenReceived = 19
FirstCommunityTokenReceived = 20
CommunityBanned = 21
CommunityUnbanned = 22
type ActivityCenterGroup* {.pure.}= enum
All = 0,
@ -174,7 +176,9 @@ proc activityCenterNotificationTypesByGroup*(group: ActivityCenterGroup) : seq[i
ActivityCenterNotificationType.OwnershipLost.int,
ActivityCenterNotificationType.ShareAccounts.int,
ActivityCenterNotificationType.CommunityTokenReceived.int,
ActivityCenterNotificationType.FirstCommunityTokenReceived.int
ActivityCenterNotificationType.FirstCommunityTokenReceived.int,
ActivityCenterNotificationType.CommunityBanned.int,
ActivityCenterNotificationType.CommunityUnbanned.int
]
of ActivityCenterGroup.Mentions:
return @[ActivityCenterNotificationType.Mention.int]
@ -186,7 +190,9 @@ proc activityCenterNotificationTypesByGroup*(group: ActivityCenterGroup) : seq[i
ActivityCenterNotificationType.CommunityInvitation.int,
ActivityCenterNotificationType.CommunityRequest.int,
ActivityCenterNotificationType.CommunityMembershipRequest.int,
ActivityCenterNotificationType.CommunityKicked.int
ActivityCenterNotificationType.CommunityKicked.int,
ActivityCenterNotificationType.CommunityBanned.int,
ActivityCenterNotificationType.CommunityUnbanned.int
]
of ActivityCenterGroup.Admin:
return @[ActivityCenterNotificationType.CommunityMembershipRequest.int]

View File

@ -240,9 +240,9 @@ proc toChannelMember*(jsonObj: JsonNode, memberId: string, joined: bool): ChatMe
if(jsonObj.getProp("roles", rolesObj)):
for roleObj in rolesObj:
roles.add(roleObj.getInt)
result.role = MemberRole.None
if roles.contains(MemberRole.Owner.int):
if roles.contains(MemberRole.Owner.int):
result.role = MemberRole.Owner
elif roles.contains(MemberRole.Admin.int):
result.role = MemberRole.Admin

View File

@ -108,7 +108,7 @@ const SIGNAL_CHAT_UPDATE* = "chatUpdate"
const SIGNAL_CHAT_LEFT* = "channelLeft"
const SIGNAL_SENDING_FAILED* = "messageSendingFailed"
const SIGNAL_SENDING_SUCCESS* = "messageSendingSuccess"
const SIGNAL_MESSAGE_DELETED* = "messageDeleted"
const SIGNAL_MESSAGE_REMOVE* = "messageRemove"
const SIGNAL_CHAT_MUTED* = "chatMuted"
const SIGNAL_CHAT_UNMUTED* = "chatUnmuted"
const SIGNAL_CHAT_HISTORY_CLEARED* = "chatHistoryCleared"
@ -271,7 +271,7 @@ QtObject:
return i
i.inc()
return -1
proc chatsWithCategoryHaveUnreadMessages*(self: Service, communityId: string, categoryId: string): bool =
if communityId == "" or categoryId == "":
return false
@ -336,7 +336,7 @@ QtObject:
self.channelGroups[channelGroupId].chats[index] = self.chats[chat.id]
proc updateMissingFieldsInCommunityChat(self: Service, channelGroupId: string, newChat: ChatDto): ChatDto =
if not self.channelGroups.contains(channelGroupId):
warn "unknown channel group", channelGroupId
return
@ -359,11 +359,11 @@ QtObject:
# We need to update missing fields in the chats seq before saving
let newChats = channelGroup.chats.mapIt(self.updateMissingFieldsInCommunityChat(channelGroup.id, it))
newChannelGroup.chats = newChats
self.channelGroups[channelGroup.id] = newChannelGroup
for chat in newChannelGroup.chats:
self.updateOrAddChat(chat)
proc updateChannelMembers*(self: Service, channel: ChatDto) =
if not self.chats.hasKey(channel.id):
return
@ -412,7 +412,8 @@ QtObject:
proc processUpdateForTransaction*(self: Service, messageId: string, response: RpcResponse[JsonNode]) =
var (chats, _) = self.processMessageUpdateAfterSend(response)
self.events.emit(SIGNAL_MESSAGE_DELETED, MessageArgs(id: messageId, channel: chats[0].id))
# TODO: Signal is not handled anywhere
self.events.emit(SIGNAL_MESSAGE_REMOVE, MessageArgs(id: messageId, channel: chats[0].id))
proc emitUpdate(self: Service, response: RpcResponse[JsonNode]) =
var (chats, _) = self.parseChatResponse(response)
@ -502,10 +503,10 @@ QtObject:
error "Error deleting channel", chatId, msg = e.msg
return
proc sendImages*(self: Service,
chatId: string,
imagePathsAndDataJson: string,
msg: string,
proc sendImages*(self: Service,
chatId: string,
imagePathsAndDataJson: string,
msg: string,
replyTo: string,
preferredUsername: string = "",
linkPreviews: seq[LinkPreview] = @[]): string =

View File

@ -110,6 +110,7 @@ type
AsyncCommunityMemberActionTaskArg = ref object of QObjectTaskArg
communityId: string
pubKey: string
deleteAllMessages: bool
const asyncRemoveUserFromCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncCommunityMemberActionTaskArg](argEncoded)
@ -131,14 +132,15 @@ const asyncRemoveUserFromCommunityTask: Task = proc(argEncoded: string) {.gcsafe
const asyncBanUserFromCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncCommunityMemberActionTaskArg](argEncoded)
try:
let response = status_go.banUserFromCommunity(arg.communityId, arg.pubKey)
let response = status_go.banUserFromCommunity(arg.communityId, arg.pubKey, arg.deleteAllMessages)
let tpl: tuple[communityId: string, pubKey: string, response: RpcResponse[JsonNode], error: string] = (arg.communityId, arg.pubKey, response, "")
arg.finish(tpl)
except Exception as e:
arg.finish(%* {
"error": e.msg,
"communityId": arg.communityId,
"pubKey": arg.pubKey
"pubKey": arg.pubKey,
"deleteAllMessages": arg.deleteAllMessages
})
const asyncUnbanUserFromCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =

View File

@ -2059,13 +2059,14 @@ QtObject:
)
self.threadpool.start(arg)
proc asyncBanUserFromCommunity*(self: Service, communityId, pubKey: string) =
proc asyncBanUserFromCommunity*(self: Service, communityId, pubKey: string, deleteAllMessages: bool) =
let arg = AsyncCommunityMemberActionTaskArg(
tptr: cast[ByteAddress](asyncBanUserFromCommunityTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncCommunityMemberActionCompleted",
communityId: communityId,
pubKey: pubKey,
deleteAllMessages: deleteAllMessages
)
self.threadpool.start(arg)

View File

@ -54,7 +54,8 @@ const SIGNAL_MESSAGES_MARKED_AS_READ* = "messagesMarkedAsRead"
const SIGNAL_MESSAGE_REACTION_ADDED* = "messageReactionAdded"
const SIGNAL_MESSAGE_REACTION_REMOVED* = "messageReactionRemoved"
const SIGNAL_MESSAGE_REACTION_FROM_OTHERS* = "messageReactionFromOthers"
const SIGNAL_MESSAGE_DELETION* = "messageDeleted"
const SIGNAL_MESSAGE_REMOVED* = "messageRemoved"
const SIGNAL_MESSAGES_DELETED* = "messagesDeleted"
const SIGNAL_MESSAGE_DELIVERED* = "messageDelivered"
const SIGNAL_MESSAGE_EDITED* = "messageEdited"
const SIGNAL_ENVELOPE_SENT* = "envelopeSent"
@ -111,11 +112,14 @@ type
reactionId*: string
reactionFrom*: string
MessageDeletedArgs* = ref object of Args
MessageRemovedArgs* = ref object of Args
chatId*: string
messageId*: string
deletedBy*: string
MessagesDeletedArgs* = ref object of Args
deletedMessages*: Table[string, seq[string]]
MessageDeliveredArgs* = ref object of Args
chatId*: string
messageId*: string
@ -348,10 +352,14 @@ QtObject:
self.numOfPinnedMessagesPerChat[chatId] = self.getNumOfPinnedMessages(chatId) - 1
self.events.emit(SIGNAL_MESSAGE_UNPINNED, data)
proc handleDeletedMessagesUpdate(self: Service, deletedMessages: seq[RemovedMessageDto]) =
for dm in deletedMessages:
let data = MessageDeletedArgs(chatId: dm.chatId, messageId: dm.messageId, deletedBy: dm.deletedBy)
self.events.emit(SIGNAL_MESSAGE_DELETION, data)
proc handleRemovedMessagesUpdate(self: Service, removedMessages: seq[RemovedMessageDto]) =
for rm in removedMessages:
let data = MessageRemovedArgs(chatId: rm.chatId, messageId: rm.messageId, deletedBy: rm.deletedBy)
self.events.emit(SIGNAL_MESSAGE_REMOVED, data)
proc handleDeletedMessagesUpdate(self: Service, deletedMessages: Table[string, seq[string]]) =
let data = MessagesDeletedArgs(deletedMessages: deletedMessages)
self.events.emit(SIGNAL_MESSAGES_DELETED, data)
proc handleEmojiReactionsUpdate(self: Service, emojiReactions: seq[ReactionDto]) =
for r in emojiReactions:
@ -416,6 +424,9 @@ QtObject:
# Handling pinned messages updates
if (receivedData.pinnedMessages.len > 0):
self.handlePinnedMessagesUpdate(receivedData.pinnedMessages)
# Handling removed messages updates
if (receivedData.removedMessages.len > 0):
self.handleRemovedMessagesUpdate(receivedData.removedMessages)
# Handling deleted messages updates
if (receivedData.deletedMessages.len > 0):
self.handleDeletedMessagesUpdate(receivedData.deletedMessages)
@ -430,12 +441,12 @@ QtObject:
self.events.on(SignalType.DiscordCommunityImportFinished.event) do(e: Args):
var receivedData = DiscordCommunityImportFinishedSignal(e)
self.handleMessagesReload(receivedData.communityId)
self.events.on(SignalType.DiscordChannelImportFinished.event) do(e: Args):
var receivedData = DiscordChannelImportFinishedSignal(e)
self.resetMessageCursor(receivedData.channelId)
self.asyncLoadMoreMessagesForChat(receivedData.channelId)
self.events.on(SIGNAL_CHAT_LEFT) do(e: Args):
var chatArg = ChatArgs(e)
self.resetMessageCursor(chatArg.chatId)
@ -637,7 +648,7 @@ QtObject:
messageId: responseObj["messageId"].getStr,
error: responseObj["error"].getStr,
)
if signalData.error == "":
signalData.message = responseObj["message"].toMessageDto()
@ -942,7 +953,7 @@ QtObject:
if responseObj.kind != JObject:
warn "expected response is not a json object", methodName = "onAsyncUnfurlUrlsFinished"
return
let errMessage = responseObj["error"].getStr
if errMessage != "":
error "asyncUnfurlUrls failed", errMessage
@ -1057,28 +1068,28 @@ proc deleteMessage*(self: Service, messageId: string) =
try:
let response = status_go.deleteMessageAndSend(messageId)
var deletesMessagesObj: JsonNode
if(not response.result.getProp("removedMessages", deletesMessagesObj) or deletesMessagesObj.kind != JArray):
error "error: ", procName="deleteMessage", errDesription = "no messages deleted or it's not an array"
var removesMessagesObj: JsonNode
if(not response.result.getProp("removedMessages", removesMessagesObj) or removesMessagesObj.kind != JArray):
error "error: ", procName="removeMessage", errDesription = "no messages remove or it's not an array"
return
let deletedMessagesArr = deletesMessagesObj.getElems()
if(deletedMessagesArr.len == 0): # an array is returned
error "error: ", procName="deleteMessage", errDesription = "array has no message to delete"
let removedMessagesArr = removesMessagesObj.getElems()
if(removedMessagesArr.len == 0): # an array is returned
error "error: ", procName="removeMessage", errDesription = "array has no message to remove"
return
let deletedMessageObj = deletedMessagesArr[0]
let removedMessageObj = removedMessagesArr[0]
var chat_Id, message_Id: string
if not deletedMessageObj.getProp("chatId", chat_Id) or not deletedMessageObj.getProp("messageId", message_Id):
error "error: ", procName="deleteMessage", errDesription = "there is no set chat id or message id in response"
if not removedMessageObj.getProp("chatId", chat_Id) or not removedMessageObj.getProp("messageId", message_Id):
error "error: ", procName="removeMessage", errDesription = "there is no set chat id or message id in response"
return
let data = MessageDeletedArgs(
let data = MessageRemovedArgs(
chatId: chat_Id,
messageId: message_Id,
deletedBy: singletonInstance.userProfile.getPubKey(),
)
self.events.emit(SIGNAL_MESSAGE_DELETION, data)
self.events.emit(SIGNAL_MESSAGE_REMOVED, data)
except Exception as e:
error "error: ", procName="deleteMessage", errName = e.name, errDesription = e.msg

View File

@ -86,9 +86,9 @@ proc sendChatMessage*(
}
])
proc sendImages*(chatId: string,
images: var seq[string],
msg: string,
proc sendImages*(chatId: string,
images: var seq[string],
msg: string,
replyTo: string,
preferredUsername: string,
linkPreviews: seq[LinkPreview],

View File

@ -460,10 +460,11 @@ proc declineRequestToJoinCommunity*(requestId: string): RpcResponse[JsonNode] {.
"id": requestId
}])
proc banUserFromCommunity*(communityId: string, pubKey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
proc banUserFromCommunity*(communityId: string, pubKey: string, deleteAllMessages: bool): RpcResponse[JsonNode] {.raises: [Exception].} =
return callPrivateRPC("banUserFromCommunity".prefix, %*[{
"communityId": communityId,
"user": pubKey
"user": pubKey,
"deleteAllMessages": deleteAllMessages,
}])
proc unbanUserFromCommunity*(communityId: string, pubKey: string): RpcResponse[JsonNode] {.raises: [Exception].} =

View File

@ -327,8 +327,8 @@ QtObject {
chatCommunitySectionModule.removeUserFromCommunity(pubKey);
}
function banUserFromCommunity(pubKey) {
chatCommunitySectionModule.banUserFromCommunity(pubKey);
function banUserFromCommunity(pubKey, deleteAllMessages) {
chatCommunitySectionModule.banUserFromCommunity(pubKey, deleteAllMessages);
}
function unbanUserFromCommunity(pubKey) {

View File

@ -22,7 +22,7 @@ SettingsPage {
signal membershipRequestsClicked()
signal kickUserClicked(string id)
signal banUserClicked(string id)
signal banUserClicked(string id, bool deleteAllMessages)
signal unbanUserClicked(string id)
signal acceptRequestToJoin(string id)
signal declineRequestToJoin(string id)
@ -193,11 +193,7 @@ SettingsPage {
communityName: root.communityName
onAccepted: {
if (mode === KickBanPopup.Mode.Kick)
root.kickUserClicked(userId)
else
root.banUserClicked(userId)
}
onBanUserClicked: root.banUserClicked(userId, deleteAllMessages)
onKickUserClicked: root.kickUserClicked(userId)
}
}

View File

@ -1,9 +1,11 @@
import QtQuick 2.15
import QtQml.Models 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Components 0.1
import utils 1.0
@ -15,6 +17,9 @@ StatusDialog {
property string communityName: ""
property int mode: KickBanPopup.Mode.Kick
signal banUserClicked(bool deleteAllMessages)
signal kickUserClicked()
enum Mode {
Kick, Ban
}
@ -25,17 +30,40 @@ StatusDialog {
? qsTr("Kick %1").arg(root.username)
: qsTr("Ban %1").arg(root.username)
contentItem: StatusBaseText {
contentItem: ColumnLayout {
anchors.centerIn: parent
font.pixelSize: Style.current.primaryTextFontSize
wrapMode: Text.Wrap
text: root.mode === KickBanPopup.Mode.Kick
? qsTr("Are you sure you kick <b>%1</b> from %2?")
.arg(root.username).arg(root.communityName)
: qsTr("Are you sure you ban <b>%1</b> from %2?")
.arg(root.username).arg(root.communityName)
}
StatusBaseText {
Layout.fillWidth: true
Layout.fillHeight: true
font.pixelSize: Style.current.primaryTextFontSize
wrapMode: Text.Wrap
text: root.mode === KickBanPopup.Mode.Kick
? qsTr("Are you sure you want to kick <b>%1</b> from %2?")
.arg(root.username).arg(root.communityName)
: qsTr("Are you sure you want to ban <b>%1</b> from %2? This means that they will be kicked from this community and banned from re-joining.")
.arg(root.username).arg(root.communityName)
}
RowLayout {
visible: root.mode === KickBanPopup.Mode.Ban
StatusBaseText {
Layout.fillWidth: true
text: qsTr("Delete all messages posted by the user")
font.pixelSize: Style.current.primaryTextFontSize
}
StatusSwitch {
id: deleteAllMessagesSwitch
checked: false
}
}
}
footer: StatusDialogFooter {
rightButtons: ObjectModel {
@ -51,14 +79,17 @@ StatusDialog {
? "CommunityMembers_KickModal_KickButton"
: "CommunityMembers_BanModal_BanButton"
text: root.mode === KickBanPopup.Mode.Kick ? qsTr("Kick")
: qsTr("Ban")
text: root.mode === KickBanPopup.Mode.Kick ? qsTr("Kick %1").arg(root.username)
: qsTr("Ban %1").arg(root.username)
type: StatusBaseButton.Type.Danger
onClicked: {
root.accept()
root.mode === KickBanPopup.Mode.Kick ? root.kickUserClicked()
: root.banUserClicked(deleteAllMessagesSwitch.checked)
root.close()
}
}
}
}
onClosed: deleteAllMessagesSwitch.checked = false
}

View File

@ -72,6 +72,8 @@ Item {
property bool invitationPending: root.store.isMyCommunityRequestPending(communityData.id)
property bool joiningCommunityInProgress: false
onShowJoinButtonChanged: invitationPending = root.store.isMyCommunityRequestPending(communityData.id)
}
ColumnHeaderPanel {

View File

@ -273,7 +273,7 @@ StatusSectionLayout {
communityName: root.community.name
onKickUserClicked: root.rootStore.removeUserFromCommunity(id)
onBanUserClicked: root.rootStore.banUserFromCommunity(id)
onBanUserClicked: root.rootStore.banUserFromCommunity(id, deleteAllMessages)
onUnbanUserClicked: root.rootStore.unbanUserFromCommunity(id)
onAcceptRequestToJoin: root.rootStore.acceptRequestToJoinCommunity(id, root.community.id)
onDeclineRequestToJoin: root.rootStore.declineRequestToJoinCommunity(id, root.community.id)

View File

@ -140,6 +140,10 @@ Popup {
return ownerTokenReceivedNotificationComponent
case ActivityCenterStore.ActivityCenterNotificationType.ShareAccounts:
return shareAccountsNotificationComponent
case ActivityCenterStore.ActivityCenterNotificationType.CommunityBanned:
return communityBannedNotificationComponent
case ActivityCenterStore.ActivityCenterNotificationType.CommunityUnbanned:
return communityUnbannedNotificationComponent
default:
return null
}
@ -236,6 +240,32 @@ Popup {
}
}
Component {
id: communityBannedNotificationComponent
ActivityNotificationCommunityBanUnban {
banned: true
filteredIndex: parent.filteredIndex
notification: parent.notification
store: root.store
activityCenterStore: root.activityCenterStore
onCloseActivityCenter: root.close()
}
}
Component {
id: communityUnbannedNotificationComponent
ActivityNotificationCommunityBanUnban {
banned: false
filteredIndex: parent.filteredIndex
notification: parent.notification
store: root.store
activityCenterStore: root.activityCenterStore
onCloseActivityCenter: root.close()
}
}
Component {
id: contactRemovedComponent

View File

@ -38,7 +38,9 @@ QtObject {
OwnershipDeclined = 17,
ShareAccounts = 18,
CommunityTokenReceived = 19,
FirstCommunityTokenReceived = 20
FirstCommunityTokenReceived = 20,
CommunityBanned = 21,
CommunityUnbanned = 22
}
enum ActivityCenterReadType {

View File

@ -0,0 +1,78 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import shared 1.0
import shared.panels 1.0
import shared.controls 1.0
import utils 1.0
import "../controls"
ActivityNotificationBase {
id: root
property bool banned: true
bodyComponent: RowLayout {
width: parent.width
height: 50
readonly property var community: notification ?
root.store.getCommunityDetailsAsJson(notification.communityId) :
null
StatusSmartIdenticon {
Layout.preferredWidth: 40
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignTop
Layout.leftMargin: Style.current.padding
Layout.topMargin: 2
asset {
width: 24
height: width
name: "communities"
color: root.banned ? "red" : "green"
bgWidth: 40
bgHeight: 40
bgColor: Theme.palette.getColor(asset.color, 0.1)
}
}
StatusBaseText {
text: root.banned ? qsTr("You were banned from") : qsTr("You've been unbanned from")
Layout.alignment: Qt.AlignVCenter
font.italic: true
color: Theme.palette.baseColor1
}
CommunityBadge {
communityName: community ? community.name : ""
communityImage: community ? community.image : ""
communityColor: community ? community.color : "black"
onCommunityNameClicked: root.store.setActiveCommunity(notification.communityId)
Layout.alignment: Qt.AlignVCenter
Layout.maximumWidth: 190
}
Item {
Layout.fillWidth: true
}
}
ctaComponent: root.banned ? undefined : visitCommunityCta
Component {
id: visitCommunityCta
StatusLinkText {
text: qsTr("Visit Community")
onClicked: {
root.store.setActiveCommunity(notification.communityId)
root.closeActivityCenter()
}
}
}
}

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 9b17fd66734f810d465a1e463451260c0c0fd762
Subproject commit 3959948c4c5ab560ae528c2d331241f2cc94fed1