diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Service/MatrixSDK/UserSessionsDataProvider.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Service/MatrixSDK/UserSessionsDataProvider.swift index a5c90d65dd..d54d865ac3 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Service/MatrixSDK/UserSessionsDataProvider.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/Service/MatrixSDK/UserSessionsDataProvider.swift @@ -37,7 +37,16 @@ class UserSessionsDataProvider: UserSessionsDataProviderProtocol { } func devices(completion: @escaping (MXResponse<[MXDevice]>) -> Void) { - session.matrixRestClient.devices(completion: completion) + session.matrixRestClient.devices { [weak self] response in + switch response { + case .success(let devices): + self?.deleteAccountDataIfNeeded(deviceList: devices) + case .failure: + break + } + + completion(response) + } } func device(withDeviceId deviceId: String, ofUser userId: String) -> MXDeviceInfo? { @@ -66,3 +75,29 @@ class UserSessionsDataProvider: UserSessionsDataProviderProtocol { return try await service.isServiceAvailable() } } + +extension UserSessionsDataProvider { + private func deleteAccountDataIfNeeded(deviceList: [MXDevice]) { + let obsoletedDeviceAccountDataKeys = obsoletedDeviceAccountData(deviceList: deviceList, + accountDataEvents: session.accountData.allAccountDataEvents()) + + for accountDataKey in obsoletedDeviceAccountDataKeys { + session.deleteAccountData(withType: accountDataKey, success: {}, failure: { _ in }) + } + } + + // internal just to facilitate tests + func obsoletedDeviceAccountData(deviceList: [MXDevice], accountDataEvents: [String: Any]) -> Set { + let deviceAccountDataKeys = Set( + accountDataEvents + .map(\.key) + .filter { $0.hasPrefix(kMXAccountDataTypeClientInformation) } + ) + + let expectedDeviceAccountDataKeys = Set(deviceList.map { + "\(kMXAccountDataTypeClientInformation).\($0.deviceId)" + }) + + return deviceAccountDataKeys.subtracting(expectedDeviceAccountDataKeys) + } +} diff --git a/RiotTests/UserSessionsDataProviderTests.swift b/RiotTests/UserSessionsDataProviderTests.swift index 4695d9fc31..69b1b02295 100644 --- a/RiotTests/UserSessionsDataProviderTests.swift +++ b/RiotTests/UserSessionsDataProviderTests.swift @@ -100,10 +100,69 @@ class UserSessionCardViewDataTests: XCTestCase { XCTAssertEqual(verificationState, .permanentlyUnverified) } + + func testObsoletedDeviceInformation_someMatch() { + let mxSession = MockSession(canCrossSign: true) + let dataProvider = UserSessionsDataProvider(session: mxSession) + + let accountDataEvents: [String: Any] = [ + "io.element.matrix_client_information.D": "", + "foo": "" + ] + + let expectedObsoletedEvents: Set = [ + "io.element.matrix_client_information.D" + ] + + let obsoletedEvents = dataProvider.obsoletedDeviceAccountData(deviceList: .mockDevices, accountDataEvents: accountDataEvents) + + XCTAssertEqual(obsoletedEvents, expectedObsoletedEvents) + } + + func testObsoletedDeviceInformation_noMatch() { + let mxSession = MockSession(canCrossSign: true) + let dataProvider = UserSessionsDataProvider(session: mxSession) + + let accountDataEvents: [String: Any] = [ + "io.element.matrix_client_information.C": "", + "foo": "" + ] + + let expectedObsoletedEvents: Set = [] + let obsoletedEvents = dataProvider.obsoletedDeviceAccountData(deviceList: .mockDevices, accountDataEvents: accountDataEvents) + + XCTAssertEqual(obsoletedEvents, expectedObsoletedEvents) + } + + func testObsoletedDeviceInformation_allMatch() { + let mxSession = MockSession(canCrossSign: true) + let dataProvider = UserSessionsDataProvider(session: mxSession) + + let expectedObsoletedEvents = Set(["D", "E", "F"].map { "io.element.matrix_client_information.\($0)"}) + + let accountDataEvents: [String: Any] = expectedObsoletedEvents.reduce(into: ["foo": ""]) { partialResult, value in + partialResult[value] = "" + } + + let obsoletedEvents = dataProvider.obsoletedDeviceAccountData(deviceList: .mockDevices, accountDataEvents: accountDataEvents) + + XCTAssertEqual(obsoletedEvents, expectedObsoletedEvents) + } } // MARK: Mocks +private extension Array where Element == MXDevice { + static let mockDevices: [MXDevice] = { + ["A", "B", "C"] + .map { + let device = MXDevice() + device.deviceId = $0 + return device + } + }() +} + // Device ID constants. private extension String { static var otherDeviceA: String { "abcdef" } diff --git a/changelog.d/pr-7164.change b/changelog.d/pr-7164.change new file mode 100644 index 0000000000..48a618f9d7 --- /dev/null +++ b/changelog.d/pr-7164.change @@ -0,0 +1 @@ +Add old device data from user's account data events.