mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-24 10:55:33 +00:00
core: decrease membersRequireAttention counter when member is deleted or leaves (#5919)
This commit is contained in:
@@ -1646,9 +1646,9 @@ func apiAcceptMember(_ groupId: Int64, _ groupMemberId: Int64, _ memberRole: Gro
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
func apiRemoveMembers(_ groupId: Int64, _ memberIds: [Int64], _ withMessages: Bool = false) async throws -> [GroupMember] {
|
||||
func apiRemoveMembers(_ groupId: Int64, _ memberIds: [Int64], _ withMessages: Bool = false) async throws -> (GroupInfo, [GroupMember]) {
|
||||
let r: ChatResponse2 = try await chatSendCmd(.apiRemoveMembers(groupId: groupId, memberIds: memberIds, withMessages: withMessages), bgTask: false)
|
||||
if case let .userDeletedMembers(_, _, members, withMessages) = r { return members }
|
||||
if case let .userDeletedMembers(_, updatedGroupInfo, members, _withMessages) = r { return (updatedGroupInfo, members) }
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
@@ -2267,6 +2267,7 @@ func processReceivedMsg(_ res: ChatEvent) async {
|
||||
case let .deletedMember(user, groupInfo, byMember, deletedMember, withMessages):
|
||||
if active(user) {
|
||||
await MainActor.run {
|
||||
m.updateGroup(groupInfo)
|
||||
_ = m.upsertGroupMember(groupInfo, deletedMember)
|
||||
if withMessages {
|
||||
m.removeMemberItems(deletedMember, byMember: byMember, groupInfo)
|
||||
@@ -2276,6 +2277,7 @@ func processReceivedMsg(_ res: ChatEvent) async {
|
||||
case let .leftMember(user, groupInfo, member):
|
||||
if active(user) {
|
||||
await MainActor.run {
|
||||
m.updateGroup(groupInfo)
|
||||
_ = m.upsertGroupMember(groupInfo, member)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ struct GroupChatInfoView: View {
|
||||
if groupInfo.canDelete {
|
||||
deleteGroupButton()
|
||||
}
|
||||
if groupInfo.membership.memberCurrent {
|
||||
if groupInfo.membership.memberCurrentOrPending {
|
||||
leaveGroupButton()
|
||||
}
|
||||
}
|
||||
@@ -797,10 +797,11 @@ struct GroupChatInfoView: View {
|
||||
func removeMember(_ groupInfo: GroupInfo, _ mem: GroupMember, dismiss: DismissAction? = nil) {
|
||||
Task {
|
||||
do {
|
||||
let updatedMembers = try await apiRemoveMembers(groupInfo.groupId, [mem.groupMemberId])
|
||||
let (updatedGroupInfo, updatedMembers) = try await apiRemoveMembers(groupInfo.groupId, [mem.groupMemberId])
|
||||
await MainActor.run {
|
||||
ChatModel.shared.updateGroup(updatedGroupInfo)
|
||||
updatedMembers.forEach { updatedMember in
|
||||
_ = ChatModel.shared.upsertGroupMember(groupInfo, updatedMember)
|
||||
_ = ChatModel.shared.upsertGroupMember(updatedGroupInfo, updatedMember)
|
||||
}
|
||||
dismiss?()
|
||||
}
|
||||
|
||||
@@ -640,10 +640,11 @@ struct GroupMemberInfoView: View {
|
||||
primaryButton: .destructive(Text("Remove")) {
|
||||
Task {
|
||||
do {
|
||||
let updatedMembers = try await apiRemoveMembers(groupInfo.groupId, [mem.groupMemberId])
|
||||
let (updatedGroupInfo, updatedMembers) = try await apiRemoveMembers(groupInfo.groupId, [mem.groupMemberId])
|
||||
await MainActor.run {
|
||||
chatModel.updateGroup(updatedGroupInfo)
|
||||
updatedMembers.forEach { updatedMember in
|
||||
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
|
||||
_ = chatModel.upsertGroupMember(updatedGroupInfo, updatedMember)
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ struct ChatListNavLink: View {
|
||||
}
|
||||
.swipeActions(edge: .trailing) {
|
||||
tagChatButton(chat)
|
||||
if (groupInfo.membership.memberCurrent) {
|
||||
if (groupInfo.membership.memberCurrentOrPending) {
|
||||
leaveGroupChatButton(groupInfo)
|
||||
}
|
||||
if groupInfo.canDelete {
|
||||
@@ -214,7 +214,7 @@ struct ChatListNavLink: View {
|
||||
let showReportsButton = chat.chatStats.reportsCount > 0 && groupInfo.membership.memberRole >= .moderator
|
||||
let showClearButton = !chat.chatItems.isEmpty
|
||||
let showDeleteGroup = groupInfo.canDelete
|
||||
let showLeaveGroup = groupInfo.membership.memberCurrent
|
||||
let showLeaveGroup = groupInfo.membership.memberCurrentOrPending
|
||||
let totalNumberOfButtons = 1 + (showReportsButton ? 1 : 0) + (showClearButton ? 1 : 0) + (showDeleteGroup ? 1 : 0) + (showLeaveGroup ? 1 : 0)
|
||||
|
||||
if showClearButton && totalNumberOfButtons <= 3 {
|
||||
|
||||
@@ -179,8 +179,8 @@
|
||||
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; };
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh.a */; };
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; };
|
||||
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
|
||||
64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; };
|
||||
@@ -543,8 +543,8 @@
|
||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a"; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh.a"; sourceTree = "<group>"; };
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
|
||||
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
|
||||
@@ -702,8 +702,8 @@
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh.a in Frameworks */,
|
||||
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -788,8 +788,8 @@
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */,
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */,
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.1-Cm6JGiMgJjo4088oWn41JO.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.0-Adp18CY8iMhDelg0G0VSjh.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -2043,7 +2043,7 @@ public struct GroupInfo: Identifiable, Decodable, NamedChat, Hashable {
|
||||
}
|
||||
|
||||
public var canDelete: Bool {
|
||||
return membership.memberRole == .owner || !membership.memberCurrent
|
||||
return membership.memberRole == .owner || !membership.memberCurrentOrPending
|
||||
}
|
||||
|
||||
public var canAddMembers: Bool {
|
||||
@@ -2275,6 +2275,10 @@ public struct GroupMember: Identifiable, Decodable, Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
public var memberCurrentOrPending: Bool {
|
||||
memberCurrent || memberPending
|
||||
}
|
||||
|
||||
public func canBeRemoved(groupInfo: GroupInfo) -> Bool {
|
||||
let userRole = groupInfo.membership.memberRole
|
||||
return memberStatus != .memRemoved && memberStatus != .memLeft
|
||||
|
||||
+4
-1
@@ -1883,7 +1883,7 @@ data class GroupInfo (
|
||||
get() = membership.memberRole == GroupMemberRole.Owner && membership.memberCurrent
|
||||
|
||||
val canDelete: Boolean
|
||||
get() = membership.memberRole == GroupMemberRole.Owner || !membership.memberCurrent
|
||||
get() = membership.memberRole == GroupMemberRole.Owner || !membership.memberCurrentOrPending
|
||||
|
||||
val canAddMembers: Boolean
|
||||
get() = membership.memberRole >= GroupMemberRole.Admin && membership.memberActive
|
||||
@@ -2090,6 +2090,9 @@ data class GroupMember (
|
||||
else -> false
|
||||
}
|
||||
|
||||
val memberCurrentOrPending: Boolean get() =
|
||||
memberCurrent || memberPending
|
||||
|
||||
fun canBeRemoved(groupInfo: GroupInfo): Boolean {
|
||||
val userRole = groupInfo.membership.memberRole
|
||||
return memberStatus != GroupMemberStatus.MemRemoved && memberStatus != GroupMemberStatus.MemLeft
|
||||
|
||||
+4
-2
@@ -1911,9 +1911,9 @@ object ChatController {
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiRemoveMembers(rh: Long?, groupId: Long, memberIds: List<Long>, withMessages: Boolean = false): List<GroupMember>? {
|
||||
suspend fun apiRemoveMembers(rh: Long?, groupId: Long, memberIds: List<Long>, withMessages: Boolean = false): Pair<GroupInfo, List<GroupMember>>? {
|
||||
val r = sendCmd(rh, CC.ApiRemoveMembers(groupId, memberIds, withMessages))
|
||||
if (r is API.Result && r.res is CR.UserDeletedMembers) return r.res.members
|
||||
if (r is API.Result && r.res is CR.UserDeletedMembers) return r.res.groupInfo to r.res.members
|
||||
if (!(networkErrorAlert(r))) {
|
||||
apiErrorAlert("apiRemoveMembers", generalGetString(MR.strings.error_removing_member), r)
|
||||
}
|
||||
@@ -2603,6 +2603,7 @@ object ChatController {
|
||||
is CR.DeletedMember ->
|
||||
if (active(r.user)) {
|
||||
withContext(Dispatchers.Main) {
|
||||
chatModel.chatsContext.updateGroup(rhId, r.groupInfo)
|
||||
chatModel.chatsContext.upsertGroupMember(rhId, r.groupInfo, r.deletedMember)
|
||||
if (r.withMessages) {
|
||||
chatModel.chatsContext.removeMemberItems(rhId, r.deletedMember, byMember = r.byMember, r.groupInfo)
|
||||
@@ -2618,6 +2619,7 @@ object ChatController {
|
||||
is CR.LeftMember ->
|
||||
if (active(r.user)) {
|
||||
withContext(Dispatchers.Main) {
|
||||
chatModel.chatsContext.updateGroup(rhId, r.groupInfo)
|
||||
chatModel.chatsContext.upsertGroupMember(rhId, r.groupInfo, r.member)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
|
||||
+7
-5
@@ -596,7 +596,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
val titleId = if (groupInfo.businessChat == null) MR.strings.button_delete_group else MR.strings.button_delete_chat
|
||||
DeleteGroupButton(titleId, deleteGroup)
|
||||
}
|
||||
if (groupInfo.membership.memberCurrent) {
|
||||
if (groupInfo.membership.memberCurrentOrPending) {
|
||||
val titleId = if (groupInfo.businessChat == null) MR.strings.button_leave_group else MR.strings.button_leave_chat
|
||||
LeaveGroupButton(titleId, leaveGroup)
|
||||
}
|
||||
@@ -1055,16 +1055,18 @@ private fun setGroupAlias(chat: Chat, localAlias: String, chatModel: ChatModel)
|
||||
|
||||
fun removeMembers(rhId: Long?, groupInfo: GroupInfo, memberIds: List<Long>, onSuccess: () -> Unit = {}) {
|
||||
withBGApi {
|
||||
val updatedMembers = chatModel.controller.apiRemoveMembers(rhId, groupInfo.groupId, memberIds)
|
||||
if (updatedMembers != null) {
|
||||
val r = chatModel.controller.apiRemoveMembers(rhId, groupInfo.groupId, memberIds)
|
||||
if (r != null) {
|
||||
val (updatedGroupInfo, updatedMembers) = r
|
||||
withContext(Dispatchers.Main) {
|
||||
chatModel.chatsContext.updateGroup(rhId, updatedGroupInfo)
|
||||
updatedMembers.forEach { updatedMember ->
|
||||
chatModel.chatsContext.upsertGroupMember(rhId, groupInfo, updatedMember)
|
||||
chatModel.chatsContext.upsertGroupMember(rhId, updatedGroupInfo, updatedMember)
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
updatedMembers.forEach { updatedMember ->
|
||||
chatModel.secondaryChatsContext.value?.upsertGroupMember(rhId, groupInfo, updatedMember)
|
||||
chatModel.secondaryChatsContext.value?.upsertGroupMember(rhId, updatedGroupInfo, updatedMember)
|
||||
}
|
||||
}
|
||||
onSuccess()
|
||||
|
||||
+6
-4
@@ -246,16 +246,18 @@ fun removeMemberDialog(rhId: Long?, groupInfo: GroupInfo, member: GroupMember, c
|
||||
confirmText = generalGetString(MR.strings.remove_member_confirmation),
|
||||
onConfirm = {
|
||||
withBGApi {
|
||||
val removedMembers = chatModel.controller.apiRemoveMembers(rhId, member.groupId, listOf(member.groupMemberId))
|
||||
if (removedMembers != null) {
|
||||
val r = chatModel.controller.apiRemoveMembers(rhId, member.groupId, listOf(member.groupMemberId))
|
||||
if (r != null) {
|
||||
val (updatedGroupInfo, removedMembers) = r
|
||||
withContext(Dispatchers.Main) {
|
||||
chatModel.chatsContext.updateGroup(rhId, updatedGroupInfo)
|
||||
removedMembers.forEach { removedMember ->
|
||||
chatModel.chatsContext.upsertGroupMember(rhId, groupInfo, removedMember)
|
||||
chatModel.chatsContext.upsertGroupMember(rhId, updatedGroupInfo, removedMember)
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
removedMembers.forEach { removedMember ->
|
||||
chatModel.secondaryChatsContext.value?.upsertGroupMember(rhId, groupInfo, removedMember)
|
||||
chatModel.secondaryChatsContext.value?.upsertGroupMember(rhId, updatedGroupInfo, removedMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -304,7 +304,7 @@ fun GroupMenuItems(
|
||||
}
|
||||
}
|
||||
GroupMemberStatus.MemAccepted -> {
|
||||
if (groupInfo.membership.memberCurrent) {
|
||||
if (groupInfo.membership.memberCurrentOrPending) {
|
||||
LeaveGroupAction(chat.remoteHostId, groupInfo, chatModel, showMenu)
|
||||
}
|
||||
if (groupInfo.canDelete) {
|
||||
@@ -326,7 +326,7 @@ fun GroupMenuItems(
|
||||
}
|
||||
}
|
||||
ClearChatAction(chat, showMenu)
|
||||
if (groupInfo.membership.memberCurrent) {
|
||||
if (groupInfo.membership.memberCurrentOrPending) {
|
||||
LeaveGroupAction(chat.remoteHostId, groupInfo, chatModel, showMenu)
|
||||
}
|
||||
if (groupInfo.canDelete) {
|
||||
|
||||
@@ -2077,8 +2077,8 @@ processChatCommand' vr = \case
|
||||
void $ sendGroupMessage user gInfo scope ([m] <> rcpModMs') msg
|
||||
when (maxVersion (memberChatVRange m) < groupKnockingVersion) $
|
||||
forM_ (memberConn m) $ \mConn -> do
|
||||
let msg = XMsgNew $ MCSimple $ extMsgContent (MCText acceptedToGroupMessage) Nothing
|
||||
void $ sendDirectMemberMessage mConn msg groupId
|
||||
let msg2 = XMsgNew $ MCSimple $ extMsgContent (MCText acceptedToGroupMessage) Nothing
|
||||
void $ sendDirectMemberMessage mConn msg2 groupId
|
||||
(m', gInfo') <- withFastStore' $ \db -> do
|
||||
m' <- updateGroupMemberAccepted db user m newMemberStatus role
|
||||
gInfo' <- updateGroupMembersRequireAttention db user gInfo m m'
|
||||
@@ -2227,10 +2227,13 @@ processChatCommand' vr = \case
|
||||
let acis = acis2 <> acis3 <> acis4
|
||||
errs = errs1 <> errs2 <> errs3 <> errs4
|
||||
deleted = deleted1 <> deleted2 <> deleted3 <> deleted4
|
||||
unless (null acis) $ toView $ CEvtNewChatItems user acis
|
||||
-- Read group info with updated membersRequireAttention
|
||||
gInfo' <- withFastStore $ \db -> getGroupInfo db vr user groupId
|
||||
let acis' = map (updateCIGroupInfo gInfo') acis
|
||||
unless (null acis') $ toView $ CEvtNewChatItems user acis'
|
||||
unless (null errs) $ toView $ CEvtChatErrors errs
|
||||
when withMessages $ deleteMessages user gInfo deleted
|
||||
pure $ CRUserDeletedMembers user gInfo deleted withMessages -- same order is not guaranteed
|
||||
when withMessages $ deleteMessages user gInfo' deleted
|
||||
pure $ CRUserDeletedMembers user gInfo' deleted withMessages -- same order is not guaranteed
|
||||
where
|
||||
selectMembers :: [GroupMember] -> (Int, [GroupMember], [GroupMember], [GroupMember], [GroupMember], GroupMemberRole, Bool)
|
||||
selectMembers = foldl' addMember (0, [], [], [], [], GRObserver, False)
|
||||
@@ -2280,8 +2283,17 @@ processChatCommand' vr = \case
|
||||
ts = ciContentTexts content
|
||||
in NewSndChatItemData msg content ts M.empty Nothing Nothing Nothing
|
||||
delMember db m = do
|
||||
deleteOrUpdateMemberRecordIO db user m
|
||||
-- We're in a function used in batch member deletion, and since we're passing same gInfo for each member,
|
||||
-- voided result (updated group info) may have incorrect state of membersRequireAttention.
|
||||
-- To avoid complicating code by chaining group info updates,
|
||||
-- instead we re-read it once after deleting all members before response.
|
||||
void $ deleteOrUpdateMemberRecordIO db user gInfo m
|
||||
pure m {memberStatus = GSMemRemoved}
|
||||
updateCIGroupInfo :: GroupInfo -> AChatItem -> AChatItem
|
||||
updateCIGroupInfo gInfo' = \case
|
||||
AChatItem SCTGroup SMDSnd (GroupChat _gInfo chatScopeInfo) ci ->
|
||||
AChatItem SCTGroup SMDSnd (GroupChat gInfo' chatScopeInfo) ci
|
||||
aci -> aci
|
||||
deleteMessages user gInfo@GroupInfo {membership} ms
|
||||
| groupFeatureMemberAllowed SGFFullDelete membership gInfo = deleteGroupMembersCIs user gInfo ms membership
|
||||
| otherwise = markGroupMembersCIsDeleted user gInfo ms membership
|
||||
|
||||
@@ -1564,15 +1564,20 @@ deleteMemberConnection' GroupMember {activeConn} waitDelivery = do
|
||||
deleteAgentConnectionAsync' (aConnId conn) waitDelivery
|
||||
withStore' $ \db -> updateConnectionStatus db conn ConnDeleted
|
||||
|
||||
deleteOrUpdateMemberRecord :: User -> GroupMember -> CM ()
|
||||
deleteOrUpdateMemberRecord user member =
|
||||
withStore' $ \db -> deleteOrUpdateMemberRecordIO db user member
|
||||
deleteOrUpdateMemberRecord :: User -> GroupInfo -> GroupMember -> CM GroupInfo
|
||||
deleteOrUpdateMemberRecord user gInfo member =
|
||||
withStore' $ \db -> deleteOrUpdateMemberRecordIO db user gInfo member
|
||||
|
||||
deleteOrUpdateMemberRecordIO :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
deleteOrUpdateMemberRecordIO db user@User {userId} member =
|
||||
deleteOrUpdateMemberRecordIO :: DB.Connection -> User -> GroupInfo -> GroupMember -> IO GroupInfo
|
||||
deleteOrUpdateMemberRecordIO db user@User {userId} gInfo member = do
|
||||
gInfo' <-
|
||||
if gmRequiresAttention member
|
||||
then decreaseGroupMembersRequireAttention db user gInfo
|
||||
else pure gInfo
|
||||
checkGroupMemberHasItems db user member >>= \case
|
||||
Just _ -> updateGroupMemberStatus db userId member GSMemRemoved
|
||||
Nothing -> deleteGroupMember db user member
|
||||
pure gInfo'
|
||||
|
||||
sendDirectContactMessages :: MsgEncodingI e => User -> Contact -> NonEmpty (ChatMsgEvent e) -> CM [Either ChatError SndMessage]
|
||||
sendDirectContactMessages user ct events = do
|
||||
|
||||
@@ -2697,10 +2697,10 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
-- ? prohibit deleting member if it's the sender - sender should use x.grp.leave
|
||||
deleteMemberConnection member
|
||||
-- undeleted "member connected" chat item will prevent deletion of member record
|
||||
deleteOrUpdateMemberRecord user member
|
||||
gInfo' <- deleteOrUpdateMemberRecord user gInfo member
|
||||
when withMessages $ deleteMessages member SMDRcv
|
||||
deleteMemberItem $ RGEMemberDeleted groupMemberId (fromLocalProfile memberProfile)
|
||||
toView $ CEvtDeletedMember user gInfo m member {memberStatus = GSMemRemoved} withMessages
|
||||
toView $ CEvtDeletedMember user gInfo' m member {memberStatus = GSMemRemoved} withMessages
|
||||
where
|
||||
checkRole GroupMember {memberRole} a
|
||||
| senderRole < GRAdmin || senderRole < memberRole =
|
||||
@@ -2719,11 +2719,15 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
xGrpLeave gInfo m msg brokerTs = do
|
||||
deleteMemberConnection m
|
||||
-- member record is not deleted to allow creation of "member left" chat item
|
||||
withStore' $ \db -> updateGroupMemberStatus db userId m GSMemLeft
|
||||
(gInfo', m', scopeInfo) <- mkGroupChatScope gInfo m
|
||||
(ci, cInfo) <- saveRcvChatItemNoParse user (CDGroupRcv gInfo' scopeInfo m') msg brokerTs (CIRcvGroupEvent RGEMemberLeft)
|
||||
gInfo' <- withStore' $ \db -> do
|
||||
updateGroupMemberStatus db userId m GSMemLeft
|
||||
if gmRequiresAttention m
|
||||
then decreaseGroupMembersRequireAttention db user gInfo
|
||||
else pure gInfo
|
||||
(gInfo'', m', scopeInfo) <- mkGroupChatScope gInfo' m
|
||||
(ci, cInfo) <- saveRcvChatItemNoParse user (CDGroupRcv gInfo'' scopeInfo m') msg brokerTs (CIRcvGroupEvent RGEMemberLeft)
|
||||
groupMsgToView cInfo ci
|
||||
toView $ CEvtLeftMember user gInfo' m' {memberStatus = GSMemLeft}
|
||||
toView $ CEvtLeftMember user gInfo'' m' {memberStatus = GSMemLeft}
|
||||
|
||||
xGrpDel :: GroupInfo -> GroupMember -> RcvMessage -> UTCTime -> CM ()
|
||||
xGrpDel gInfo@GroupInfo {membership} m@GroupMember {memberRole} msg brokerTs = do
|
||||
|
||||
@@ -81,6 +81,7 @@ module Simplex.Chat.Store.Groups
|
||||
updateGroupMemberStatusById,
|
||||
updateGroupMemberAccepted,
|
||||
updateGroupMembersRequireAttention,
|
||||
decreaseGroupMembersRequireAttention,
|
||||
increaseGroupMembersRequireAttention,
|
||||
createNewGroupMember,
|
||||
checkGroupMemberHasItems,
|
||||
@@ -1231,24 +1232,28 @@ updateGroupMemberAccepted db User {userId} m@GroupMember {groupMemberId} status
|
||||
pure m {memberStatus = status, memberRole = role, updatedAt = currentTs}
|
||||
|
||||
updateGroupMembersRequireAttention :: DB.Connection -> User -> GroupInfo -> GroupMember -> GroupMember -> IO GroupInfo
|
||||
updateGroupMembersRequireAttention db user@User {userId} g@GroupInfo {groupId, membersRequireAttention} member member'
|
||||
updateGroupMembersRequireAttention db user g member member'
|
||||
| nowRequires && not didRequire =
|
||||
increaseGroupMembersRequireAttention db user g
|
||||
| not nowRequires && didRequire = do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE groups
|
||||
SET members_require_attention = members_require_attention - 1
|
||||
WHERE user_id = ? AND group_id = ?
|
||||
|]
|
||||
(userId, groupId)
|
||||
pure g {membersRequireAttention = membersRequireAttention - 1}
|
||||
| not nowRequires && didRequire =
|
||||
decreaseGroupMembersRequireAttention db user g
|
||||
| otherwise = pure g
|
||||
where
|
||||
didRequire = gmRequiresAttention member
|
||||
nowRequires = gmRequiresAttention member'
|
||||
|
||||
decreaseGroupMembersRequireAttention :: DB.Connection -> User -> GroupInfo -> IO GroupInfo
|
||||
decreaseGroupMembersRequireAttention db User {userId} g@GroupInfo {groupId, membersRequireAttention} = do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE groups
|
||||
SET members_require_attention = members_require_attention - 1
|
||||
WHERE user_id = ? AND group_id = ?
|
||||
|]
|
||||
(userId, groupId)
|
||||
pure g {membersRequireAttention = membersRequireAttention - 1}
|
||||
|
||||
increaseGroupMembersRequireAttention :: DB.Connection -> User -> GroupInfo -> IO GroupInfo
|
||||
increaseGroupMembersRequireAttention db User {userId} g@GroupInfo {groupId, membersRequireAttention} = do
|
||||
DB.execute
|
||||
|
||||
@@ -1335,14 +1335,6 @@ SEARCH group_profiles USING INTEGER PRIMARY KEY (rowid=?)
|
||||
LIST SUBQUERY 1
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE groups
|
||||
SET members_require_attention = members_require_attention - 1
|
||||
WHERE user_id = ? AND group_id = ?
|
||||
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE user_contact_links
|
||||
SET auto_accept = ?, business_address = ?, auto_accept_incognito = ?, auto_reply_msg_content = ?
|
||||
@@ -4451,6 +4443,14 @@ Query:
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE groups
|
||||
SET members_require_attention = members_require_attention - 1
|
||||
WHERE user_id = ? AND group_id = ?
|
||||
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE groups
|
||||
SET via_group_link_uri_hash = (SELECT via_contact_uri_hash FROM connections WHERE connection_id = ?)
|
||||
|
||||
Reference in New Issue
Block a user