Aug 19 - Fixed photo-loss issue

This commit is contained in:
Nguyen Ngo
2026-08-19 10:31:20 -04:00
parent 7cbc514c39
commit e31cd7e1ff
13 changed files with 856 additions and 149 deletions
+37
View File
@@ -34,6 +34,7 @@ class AuthManager: ObservableObject {
do {
let response: MeResponseData = try await APIClient.shared.request("/api/v1/auth/me")
applyUser(response.user)
reconcileSessionScope(userId: response.user.id)
isAuthenticated = true
} catch APIError.notAuthenticated {
KeychainHelper.clearAll()
@@ -57,6 +58,9 @@ class AuthManager: ObservableObject {
KeychainHelper.set(response.accessToken, forKey: Constants.Keychain.accessToken)
KeychainHelper.set(response.refreshToken, forKey: Constants.Keychain.refreshToken)
applyUser(response.user)
// BEFORE isAuthenticated flips, so DashboardView is never rendered
// holding the previous inspector's data.
reconcileSessionScope(userId: response.user.id)
isAuthenticated = true
// Register device immediately after login the .task {} and
// .onChange(scenePhase) paths both miss this case because they run
@@ -97,6 +101,39 @@ class AuthManager: ObservableObject {
KeychainHelper.set(user.displayName, forKey: Constants.Keychain.displayName)
}
/// Purge local data when this session is scoped to a different
/// `(server, user)` pair than the database currently holds.
///
/// This is the check that was missing: logout deliberately keeps the cache
/// so the same inspector can work offline after signing back in, but
/// nothing verified that the next sign-in *was* the same inspector. A
/// different one inherited their issues; see `SessionScope` and rule 88.
///
/// Runs on both `login()` and `restoreSession()` a session can also be
/// restored into a changed scope after a server switch.
private func reconcileSessionScope(userId: Int) {
let server = ServerConfig.current
let stored = SessionScope.stored
// No marker: either a genuinely fresh install, or an upgrade from a
// build that predates this. Those are indistinguishable, and purging on
// the guess would delete an in-progress draft belonging to the user
// signing in right now so adopt the existing data and start tracking
// from here. Every subsequent identity change is then covered.
guard let stored else {
SessionScope.record(userId: userId)
return
}
guard stored.server != server || stored.userId != userId else { return }
SyncManager.shared.purgeSessionScopedData(
keepingUserId: userId,
sameServer: stored.server == server
)
SessionScope.record(userId: userId)
}
private func restoreUserFromKeychain() {
currentUserId = Int(KeychainHelper.get(Constants.Keychain.userId) ?? "0") ?? 0
currentUserRole = KeychainHelper.get(Constants.Keychain.userRole) ?? ""