diff --git a/Session/Closed Groups/EditGroupViewModel.swift b/Session/Closed Groups/EditGroupViewModel.swift index 0efe6b738..348a063d6 100644 --- a/Session/Closed Groups/EditGroupViewModel.swift +++ b/Session/Closed Groups/EditGroupViewModel.swift @@ -636,6 +636,8 @@ class EditGroupViewModel: SessionTableViewModel, NavigatableStateHolder, Editabl currentName: String, currentDescription: String? ) { + /// Set `newDisplayName` to `currentName` so we can disable the "save" button when there are no changes + self.newDisplayName = currentName self.transitionToScreen( ConfirmationModal( info: ConfirmationModal.Info( @@ -672,6 +674,7 @@ class EditGroupViewModel: SessionTableViewModel, NavigatableStateHolder, Editabl }(), confirmTitle: "save".localized(), confirmEnabled: .afterChange { [weak self] _ in + self?.newDisplayName != currentName && self?.newDisplayName?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false }, cancelStyle: .danger, @@ -690,7 +693,7 @@ class EditGroupViewModel: SessionTableViewModel, NavigatableStateHolder, Editabl let maybeErrorString: String? = { guard !Profile.isTooLong(profileName: finalName) else { return "groupNameEnterShorter".localized() } - return "deleteAfterLegacyGroupsGroupUpdateErrorTitle".localized() + return nil // No error has occurred }() if let errorString: String = maybeErrorString { diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index fb8fd4b52..6af8380a7 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -2585,7 +2585,6 @@ extension ConversationVC { db, group: group, calledFromConfig: nil, - cacheToLoadStateInto: nil, using: dependencies ) .map { _ in () } diff --git a/Session/Conversations/Settings/ThreadSettingsViewModel.swift b/Session/Conversations/Settings/ThreadSettingsViewModel.swift index 2c3ec00ed..479c5b9b2 100644 --- a/Session/Conversations/Settings/ThreadSettingsViewModel.swift +++ b/Session/Conversations/Settings/ThreadSettingsViewModel.swift @@ -572,7 +572,6 @@ class ThreadSettingsViewModel: SessionTableViewModel, NavigationItemSource, Navi threadVariant: threadViewModel.threadVariant, groupLeaveType: .standard, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } diff --git a/Session/Home/Message Requests/MessageRequestsViewModel.swift b/Session/Home/Message Requests/MessageRequestsViewModel.swift index f1f10c1e8..2e783dffd 100644 --- a/Session/Home/Message Requests/MessageRequestsViewModel.swift +++ b/Session/Home/Message Requests/MessageRequestsViewModel.swift @@ -232,7 +232,6 @@ class MessageRequestsViewModel: SessionTableViewModel, NavigatableStateHolder, O threadVariant: .contact, groupLeaveType: .silent, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) @@ -245,7 +244,6 @@ class MessageRequestsViewModel: SessionTableViewModel, NavigatableStateHolder, O threadVariant: .group, groupLeaveType: .silent, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } diff --git a/Session/Utilities/UIContextualAction+Utilities.swift b/Session/Utilities/UIContextualAction+Utilities.swift index d2ba554a8..71498fd2d 100644 --- a/Session/Utilities/UIContextualAction+Utilities.swift +++ b/Session/Utilities/UIContextualAction+Utilities.swift @@ -151,7 +151,6 @@ public extension UIContextualAction { threadVariant: threadViewModel.threadVariant, groupLeaveType: .silent, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } @@ -206,7 +205,6 @@ public extension UIContextualAction { threadVariant: threadViewModel.threadVariant, groupLeaveType: .silent, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } @@ -423,7 +421,6 @@ public extension UIContextualAction { threadVariant: threadViewModel.threadVariant, groupLeaveType: .silent, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } @@ -518,7 +515,6 @@ public extension UIContextualAction { threadVariant: threadViewModel.threadVariant, groupLeaveType: .standard, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } catch { @@ -626,7 +622,6 @@ public extension UIContextualAction { threadVariant: threadViewModel.threadVariant, groupLeaveType: (isMessageRequest ? .silent : .forced), calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } diff --git a/SessionMessagingKit/Database/Models/ClosedGroup.swift b/SessionMessagingKit/Database/Models/ClosedGroup.swift index e8398e7c8..2769de0ab 100644 --- a/SessionMessagingKit/Database/Models/ClosedGroup.swift +++ b/SessionMessagingKit/Database/Models/ClosedGroup.swift @@ -187,7 +187,6 @@ public extension ClosedGroup { _ db: Database, group: ClosedGroup, calledFromConfig configTriggeringChange: ConfigDump.Variant?, - cacheToLoadStateInto: LibSessionCacheType?, using dependencies: Dependencies ) throws -> AnyPublisher { guard let userED25519KeyPair: KeyPair = Identity.fetchUserEd25519KeyPair(db) else { @@ -207,15 +206,17 @@ public extension ClosedGroup { ) } - /// Create the libSession state for the group - try LibSession.createGroupState( - groupSessionId: SessionId(.group, hex: group.id), - userED25519KeyPair: userED25519KeyPair, - groupIdentityPrivateKey: group.groupIdentityPrivateKey, - shouldLoadState: true, - cacheToLoadStateInto: cacheToLoadStateInto, - using: dependencies - ) + /// Wait until after the transaction completes before creating the group state (this is needed as it's possible that + /// we are already mutating the `libSessionCache` when this function gets called) + db.afterNextTransaction { db in + _ = try? LibSession.createGroupState( + groupSessionId: SessionId(.group, hex: group.id), + userED25519KeyPair: userED25519KeyPair, + groupIdentityPrivateKey: group.groupIdentityPrivateKey, + shouldLoadState: true, + using: dependencies + ) + } /// Update the `USER_GROUPS` config if configTriggeringChange != .userGroups { @@ -254,7 +255,6 @@ public extension ClosedGroup { threadIds: [String], dataToRemove: [RemovableGroupData], calledFromConfig configTriggeringChange: ConfigDump.Variant?, - cacheToRemoveStateFrom: LibSessionCacheType?, using dependencies: Dependencies ) throws { guard !threadIds.isEmpty && !dataToRemove.isEmpty else { return } @@ -302,28 +302,22 @@ public extension ClosedGroup { } } - // Ignore if called from the config handling - let configsToIgnore: [ConfigDump.Variant?] = [.groupInfo, .groupMembers, .groupKeys] - - if dataToRemove.contains(.libSessionState) && !configsToIgnore.contains(configTriggeringChange) { - threadVariants - .filter { $0.variant == .group } - .forEach { threadIdVariant in - let groupSessionId: SessionId = SessionId(.group, hex: threadIdVariant.id) - - // We can't mutate a cache if it's already being mutated (which would be happening - // when merging a config) so in that case we need to pass the mutable cache along - // and modify it directly - switch cacheToRemoveStateFrom { - case .some(let cache): cache.removeGroupStateIfNeeded(db, groupSessionId: groupSessionId) - case .none: - LibSession.removeGroupStateIfNeeded( - db, - groupSessionId: groupSessionId, - using: dependencies - ) + if dataToRemove.contains(.libSessionState) { + /// Wait until after the transaction completes before removing the group state (this is needed as it's possible that + /// we are already mutating the `libSessionCache` when this function gets called) + db.afterNextTransaction { db in + threadVariants + .filter { $0.variant == .group } + .forEach { threadIdVariant in + let groupSessionId: SessionId = SessionId(.group, hex: threadIdVariant.id) + + LibSession.removeGroupStateIfNeeded( + db, + groupSessionId: groupSessionId, + using: dependencies + ) } - } + } } } @@ -363,14 +357,6 @@ public extension ClosedGroup { ClosedGroup.Columns.groupIdentityPrivateKey.set(to: nil), ClosedGroup.Columns.authData.set(to: nil) ) - - if configTriggeringChange != .userGroups { - try LibSession.markAsKicked( - db, - groupSessionIds: threadIds, - using: dependencies - ) - } } if dataToRemove.contains(.messages) { diff --git a/SessionMessagingKit/Database/Models/SessionThread.swift b/SessionMessagingKit/Database/Models/SessionThread.swift index 5f4e715b7..ae7455de9 100644 --- a/SessionMessagingKit/Database/Models/SessionThread.swift +++ b/SessionMessagingKit/Database/Models/SessionThread.swift @@ -294,7 +294,6 @@ public extension SessionThread { threadVariant: Variant, groupLeaveType: ClosedGroup.LeaveType, calledFromConfig configTriggeringChange: ConfigDump.Variant?, - cacheToRemoveStateFrom: LibSessionCacheType?, using dependencies: Dependencies ) throws { try deleteOrLeave( @@ -303,7 +302,6 @@ public extension SessionThread { threadVariant: threadVariant, groupLeaveType: groupLeaveType, calledFromConfig: configTriggeringChange, - cacheToRemoveStateFrom: cacheToRemoveStateFrom, using: dependencies ) } @@ -314,7 +312,6 @@ public extension SessionThread { threadVariant: Variant, groupLeaveType: ClosedGroup.LeaveType, calledFromConfig configTriggeringChange: ConfigDump.Variant?, - cacheToRemoveStateFrom: LibSessionCacheType?, using dependencies: Dependencies ) throws { let userSessionId: SessionId = dependencies[cache: .general].sessionId @@ -375,7 +372,6 @@ public extension SessionThread { threadIds: threadIds, dataToRemove: .allData, calledFromConfig: configTriggeringChange, - cacheToRemoveStateFrom: cacheToRemoveStateFrom, using: dependencies ) diff --git a/SessionMessagingKit/Jobs/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/GroupLeavingJob.swift index 9b1b98861..46235c3b3 100644 --- a/SessionMessagingKit/Jobs/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/GroupLeavingJob.swift @@ -192,7 +192,6 @@ public enum GroupLeavingJob: JobExecutor { threadIds: [threadId], dataToRemove: .allData, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } diff --git a/SessionMessagingKit/LibSession/Config Handling/LibSession+Contacts.swift b/SessionMessagingKit/LibSession/Config Handling/LibSession+Contacts.swift index 1c999cc06..4971235a4 100644 --- a/SessionMessagingKit/LibSession/Config Handling/LibSession+Contacts.swift +++ b/SessionMessagingKit/LibSession/Config Handling/LibSession+Contacts.swift @@ -264,7 +264,6 @@ internal extension LibSessionCacheType { threadVariant: .contact, groupLeaveType: .forced, calledFromConfig: .contacts, - cacheToRemoveStateFrom: self, using: dependencies ) diff --git a/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupInfo.swift b/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupInfo.swift index 2c64946d9..33ff5efc0 100644 --- a/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupInfo.swift +++ b/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupInfo.swift @@ -42,7 +42,7 @@ internal extension LibSessionCacheType { guard configNeedsDump(config) else { return } guard case .object(let conf) = config else { throw LibSessionError.invalidConfigObject } - // If the group is destroyed then remove the group date (want to keep the group itself around because + // If the group is destroyed then remove the group data (want to keep the group itself around because // the UX of conversations randomly disappearing isn't great) - no other changes matter and this // can't be reversed guard !groups_info_is_destroyed(conf) else { @@ -54,7 +54,6 @@ internal extension LibSessionCacheType { .encryptionKeys, .authDetails, .libSessionState ], calledFromConfig: .groupInfo, - cacheToRemoveStateFrom: self, using: dependencies ) return diff --git a/SessionMessagingKit/LibSession/Config Handling/LibSession+SharedGroup.swift b/SessionMessagingKit/LibSession/Config Handling/LibSession+SharedGroup.swift index 886daae8c..2e18ca50f 100644 --- a/SessionMessagingKit/LibSession/Config Handling/LibSession+SharedGroup.swift +++ b/SessionMessagingKit/LibSession/Config Handling/LibSession+SharedGroup.swift @@ -51,7 +51,6 @@ internal extension LibSession { userED25519KeyPair: userED25519KeyPair, groupIdentityPrivateKey: Data(groupIdentityKeyPair.secretKey), shouldLoadState: false, // We manually load the state after populating the configs - cacheToLoadStateInto: nil, using: dependencies ) @@ -222,7 +221,6 @@ internal extension LibSession { userED25519KeyPair: KeyPair, groupIdentityPrivateKey: Data?, shouldLoadState: Bool, - cacheToLoadStateInto: LibSessionCacheType?, using dependencies: Dependencies ) throws -> [ConfigDump.Variant: Config] { var secretKey: [UInt8] = userED25519KeyPair.secretKey @@ -320,21 +318,10 @@ internal extension LibSession { // load the state after populating the different configs incase invalid data // was provided) if shouldLoadState { - // We can't mutate a cache if it's already being mutated (which would be happening - // when merging a config) so in that case we need to pass the mutable cache along - // and modify it directly - switch cacheToLoadStateInto { - case .some(let cache): - groupState.forEach { variant, config in - cache.setConfig(for: variant, sessionId: groupSessionId, to: config) - } - - case .none: - dependencies.mutate(cache: .libSession) { cache in - groupState.forEach { variant, config in - cache.setConfig(for: variant, sessionId: groupSessionId, to: config) - } - } + dependencies.mutate(cache: .libSession) { cache in + groupState.forEach { variant, config in + cache.setConfig(for: variant, sessionId: groupSessionId, to: config) + } } } diff --git a/SessionMessagingKit/LibSession/Config Handling/LibSession+UserGroups.swift b/SessionMessagingKit/LibSession/Config Handling/LibSession+UserGroups.swift index 7e9ea2ed5..edb3a367c 100644 --- a/SessionMessagingKit/LibSession/Config Handling/LibSession+UserGroups.swift +++ b/SessionMessagingKit/LibSession/Config Handling/LibSession+UserGroups.swift @@ -212,7 +212,6 @@ internal extension LibSessionCacheType { threadVariant: .community, groupLeaveType: .forced, calledFromConfig: .userGroups, - cacheToRemoveStateFrom: self, using: dependencies ) } @@ -410,7 +409,6 @@ internal extension LibSessionCacheType { threadVariant: .legacyGroup, groupLeaveType: .forced, calledFromConfig: .userGroups, - cacheToRemoveStateFrom: self, using: dependencies ) } @@ -438,9 +436,8 @@ internal extension LibSessionCacheType { authData: group.authData, joinedAt: group.joinedAt, invited: group.invited, + hasAlreadyBeenKicked: group.wasKickedFromGroup, calledFromConfig: .userGroups, - cacheToLoadStateInto: self, - config: config, using: dependencies ) @@ -544,7 +541,6 @@ internal extension LibSessionCacheType { threadVariant: .group, groupLeaveType: .forced, calledFromConfig: .userGroups, - cacheToRemoveStateFrom: self, using: dependencies ) diff --git a/SessionMessagingKit/LibSession/Config Handling/LibSession+UserProfile.swift b/SessionMessagingKit/LibSession/Config Handling/LibSession+UserProfile.swift index f2589890e..a38afc77f 100644 --- a/SessionMessagingKit/LibSession/Config Handling/LibSession+UserProfile.swift +++ b/SessionMessagingKit/LibSession/Config Handling/LibSession+UserProfile.swift @@ -131,7 +131,6 @@ internal extension LibSessionCacheType { threadVariant: .contact, groupLeaveType: .silent, calledFromConfig: .userProfile, - cacheToRemoveStateFrom: self, using: dependencies ) } diff --git a/SessionMessagingKit/LibSession/LibSession+SessionMessagingKit.swift b/SessionMessagingKit/LibSession/LibSession+SessionMessagingKit.swift index a746555d0..40e55f1c2 100644 --- a/SessionMessagingKit/LibSession/LibSession+SessionMessagingKit.swift +++ b/SessionMessagingKit/LibSession/LibSession+SessionMessagingKit.swift @@ -203,7 +203,6 @@ public extension LibSession { userED25519KeyPair: userEd25519KeyPair, groupIdentityPrivateKey: group.groupIdentityPrivateKey, shouldLoadState: true, - cacheToLoadStateInto: nil, using: dependencies ) } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Groups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Groups.swift index f56ef23c3..12253013f 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Groups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Groups.swift @@ -152,6 +152,7 @@ extension MessageReceiver { ) } + /// This returns the `resultPublisher` for the group poller so can be ignored if we don't need to wait for the first poll to succeed @discardableResult internal static func handleNewGroup( _ db: Database, groupSessionId: String, @@ -160,9 +161,8 @@ extension MessageReceiver { authData: Data?, joinedAt: TimeInterval, invited: Bool, + hasAlreadyBeenKicked: Bool, calledFromConfig configTriggeringChange: ConfigDump.Variant?, - cacheToLoadStateInto: LibSessionCacheType?, - config: LibSession.Config?, using dependencies: Dependencies ) throws -> AnyPublisher { // Create the group @@ -201,24 +201,13 @@ extension MessageReceiver { ) } - let wasKickedFromGroup: Bool = { - switch (cacheToLoadStateInto, config) { - case (.some(let cache), .some(let config)): - return cache.wasKickedFromGroup(groupSessionId: SessionId(.group, hex: groupSessionId), config: config) - - default: - return LibSession.wasKickedFromGroup(groupSessionId: SessionId(.group, hex: groupSessionId), using: dependencies) - } - }() - /// If the group wasn't already approved, is not in the invite state and the user hasn't been kicked from it then handle the approval process - guard !groupAlreadyApproved && !invited && !wasKickedFromGroup else { return Just([]).eraseToAnyPublisher() } + guard !groupAlreadyApproved && !invited && !hasAlreadyBeenKicked else { return Just([]).eraseToAnyPublisher() } return try ClosedGroup.approveGroup( db, group: closedGroup, calledFromConfig: configTriggeringChange, - cacheToLoadStateInto: cacheToLoadStateInto, using: dependencies ) } @@ -705,31 +694,40 @@ extension MessageReceiver { keysGen >= currentKeysGen else { throw MessageReceiverError.invalidMessage } - /// Update the name of the group in `USER_GROUPS` so that if the user doesn't delete the group and links a new device, the group will have - /// the same name as on the current device - let groupName: String? = try? dependencies[cache: .libSession] - .config(for: .groupInfo, sessionId: groupSessionId) - .wrappedValue - .map { config in try LibSession.groupName(in: config) } - - switch groupName { - case .none: Log.warn(.messageReceiver, "Failed to update group name before being kicked.") - case .some(let name): - try dependencies[cache: .libSession] - .config(for: .userGroups, sessionId: userSessionId) - .wrappedValue - .map { config in - try LibSession.upsert( - groups: [ - LibSession.GroupUpdateInfo( - groupSessionId: groupSessionId.hexString, - name: name - ) - ], - in: config, - using: dependencies - ) - } + /// If we haven't already handled being kicked from the group then update the name of the group in `USER_GROUPS` so + /// that if the user doesn't delete the group and links a new device, the group will have the same name as on the current device + if !LibSession.wasKickedFromGroup(groupSessionId: groupSessionId, using: dependencies) { + let groupName: String? = try? dependencies[cache: .libSession] + .config(for: .groupInfo, sessionId: groupSessionId) + .wrappedValue + .map { config in try LibSession.groupName(in: config) } + + switch groupName { + case .none: Log.warn(.messageReceiver, "Failed to update group name before being kicked.") + case .some(let name): + try dependencies[cache: .libSession] + .config(for: .userGroups, sessionId: userSessionId) + .wrappedValue + .map { config in + try LibSession.upsert( + groups: [ + LibSession.GroupUpdateInfo( + groupSessionId: groupSessionId.hexString, + name: name + ) + ], + in: config, + using: dependencies + ) + } + } + + /// Mark the group as kicked in libSession + try LibSession.markAsKicked( + db, + groupSessionIds: [groupSessionId.hexString], + using: dependencies + ) } /// Delete the group data (if the group is a message request then delete it entirely, otherwise we want to keep a shell of group around because @@ -753,7 +751,6 @@ extension MessageReceiver { ] }(), calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } @@ -794,9 +791,8 @@ extension MessageReceiver { authData: memberAuthData, joinedAt: TimeInterval(Double(sentTimestampMs) / 1000), invited: !inviteSenderIsApproved, + hasAlreadyBeenKicked: wasKickedFromGroup, calledFromConfig: nil, - cacheToLoadStateInto: nil, - config: nil, using: dependencies ) diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+LegacyClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+LegacyClosedGroups.swift index 89b5383e1..4557499a4 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+LegacyClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+LegacyClosedGroups.swift @@ -572,7 +572,6 @@ extension MessageReceiver { threadIds: [threadId], dataToRemove: .allData, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } @@ -647,7 +646,6 @@ extension MessageReceiver { threadIds: [threadId], dataToRemove: (sender == userSessionId.hexString ? .allData : .noData), calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift index 94ee25f11..afadc87c6 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift @@ -121,7 +121,6 @@ extension MessageReceiver { threadVariant: .contact, groupLeaveType: .forced, calledFromConfig: nil, - cacheToRemoveStateFrom: nil, using: dependencies ) }