-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: user legalhold enable event - WPB-10195 #2019
base: develop
Are you sure you want to change the base?
Conversation
Test Results166 tests 166 ✅ 1s ⏱️ Results for commit 5d62cda. ♻️ This comment has been updated with latest results. |
Some necessary context here: based on Android implementation, when receiving the However on iOS side, regarding the legacy While this PR is based on Android implementation and adapted to the existing iOS legacy code, I figured it'd make sense that, when receiving the Feel free to share your thoughts on this |
/// | ||
/// - Parameter httpClient: A http client. | ||
|
||
public init(httpClient: any HTTPClient) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought as we go further we would use the APIService here, no?
func getClients(for userIDs: Set<UserID>) async throws -> [UserClients] { | ||
let body = try JSONEncoder.defaultEncoder.encode(UserClientsRequestV0(qualifiedIDs: Array(userIDs))) | ||
let request = HTTPRequest( | ||
path: "/users/list-clients/v2", /// v2 suffix required for api version v0 and v1, suffix removed from next versions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
path: "/users/list-clients/v2", /// v2 suffix required for api version v0 and v1, suffix removed from next versions | |
path: "/users/list-clients/v2", // v2 suffix required for api version v0 and v1, suffix removed from next versions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may be wrong but I would keep ///
for comments documenting functions or params and //
for code comments
} | ||
|
||
func toAPIModel() -> [UserClients] { | ||
let userClients = payload.reduce(into: [UserClients]()) { partialResult, dict in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let userClients = payload.reduce(into: [UserClients]()) { partialResult, dict in | |
let userClients = payload.reduce(into: [UserClients]()) { partialResult, dictionary in |
prefer long form
} | ||
} | ||
|
||
try context.save() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try context.save() | |
if !localUserClient.1 { | |
try context.save() | |
} |
we only need to save when the client is new
with: id, | ||
in: context | ||
) else { | ||
return WireLogger.userClient.error( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error or warn?
in: context | ||
) else { | ||
return WireLogger.userClient.error( | ||
"Failed to find existing client with id: \(id)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we obfuscate the id or is it missing from WireFondation?
selfUser.selfClient()?.updateSecurityLevelAfterDiscovering(Set([localClient])) | ||
} | ||
|
||
try context.save() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
save is outside perform here
|
||
// sourcery: AutoMockable | ||
/// An API access object for endpoints concerning clients. | ||
public protocol ClientAPI { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be consistent with the other APIs:
public protocol ClientAPI { | |
public protocol UserClientsAPI { |
// | ||
|
||
// sourcery: AutoMockable | ||
/// An API access object for endpoints concerning clients. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// An API access object for endpoints concerning clients. | |
/// An API access object for endpoints concerning user clients. |
/// A builder of `ClientAPI`. | ||
|
||
public struct ClientAPIBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// A builder of `ClientAPI`. | |
public struct ClientAPIBuilder { | |
/// A builder of `UserClientsAPI`. | |
public struct UserClientsAPIBuilder { |
/// Errors originating from `ClientAPI`. | ||
|
||
public enum ClientAPIError: Error {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary now?
} | ||
} | ||
|
||
struct ListUserClientV0: Decodable, ToAPIModelConvertible { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary? Can't we decode directly as [UserClientV0].self
?
private func processSelfUserClients() async throws { | ||
let remoteSelfClients = try await clientRepository.fetchSelfClients() | ||
let localSelfClients = await context.perform { | ||
let selfUser = userRepository.fetchSelfUser() | ||
return selfUser.clients | ||
} | ||
|
||
for remoteSelfClient in remoteSelfClients { | ||
let localUserClient = try await clientRepository.fetchOrCreateClient( | ||
with: remoteSelfClient.id | ||
) | ||
|
||
try await clientRepository.updateClient( | ||
with: remoteSelfClient.id, | ||
from: remoteSelfClient, | ||
isNewClient: localUserClient.isNew | ||
) | ||
} | ||
|
||
let deletedSelfClientsIDs = localSelfClients.compactMap(\.remoteIdentifier).filter { !remoteSelfClients.map(\.id).contains($0) | ||
} | ||
|
||
for deletedSelfClientID in deletedSelfClientsIDs { | ||
await clientRepository.deleteClient(with: deletedSelfClientID) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should all be inside the client repository.
public func fetchSelfClients() async throws -> [WireAPI.UserClient] { | ||
try await clientAPI.getSelfClients() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer the convention pullSelfClients
, which doesn't return it but stores them locally. I don't think the repository should leak api models.
public func fetchClients(for userIDs: Set<UserID>) async throws -> [WireAPI.UserClients] { | ||
try await clientAPI.getClients(for: userIDs) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as previous comment.
|
||
/// Errors originating from `ClientRepository`. | ||
|
||
enum ClientRepositoryError: Error {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary now?
import Foundation | ||
import WireAPI | ||
|
||
extension UUID { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should move this (and the ones in WireAPI) to a test utilities target.
Key points
This PR is part of the quick sync refactoring plan and is related to processing the multiple events we receive from the backend or the push channel.
Specifically, this PR is about implementing
UserLegalholdEnableEvent
event.This PR also introduces a new dedicated
ClientAPI
to fetch data related to clients from backend and aClientRepository
to perform client related storage logic.For reference, on Android side, this event is handled in
LegalHoldHandlerImpl
specifically in this method:override suspend fun handleEnable(legalHoldEnabled: Event.User.LegalHoldEnabled): Either<CoreFailure, Unit>
.Testing
UTs cover the following use cases, ensuring that
Checklist
[WPB-XXX]
.UI accessibility checklist
If your PR includes UI changes, please utilize this checklist: