generated from StanfordBDHG/TemplateApplication
-
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce module for firebase references
- Loading branch information
Showing
4 changed files
with
111 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
TemplateApplication/Firestore/FirestoreConfiguration.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// | ||
// This source file is part of the Stanford Spezi Template Application open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import FirebaseFirestore | ||
import FirebaseStorage | ||
import Spezi | ||
import SpeziAccount | ||
import SpeziFirebaseAccount | ||
|
||
|
||
final class FireConfiguration: Module, DefaultInitializable, @unchecked Sendable { | ||
enum ConfigurationError: Error { | ||
case userNotAuthenticatedYet | ||
} | ||
|
||
static var userCollection: CollectionReference { | ||
Firestore.firestore().collection("users") | ||
} | ||
|
||
|
||
@MainActor var userDocumentReference: DocumentReference { | ||
get throws { | ||
guard let details = account?.details else { | ||
throw ConfigurationError.userNotAuthenticatedYet | ||
} | ||
|
||
return userDocumentReference(for: details.accountId) | ||
} | ||
} | ||
|
||
@MainActor var userBucketReference: StorageReference { | ||
get throws { | ||
guard let details = account?.details else { | ||
throw ConfigurationError.userNotAuthenticatedYet | ||
} | ||
|
||
return Storage.storage().reference().child("users/\(details.accountId)") | ||
} | ||
} | ||
|
||
@Application(\.logger) private var logger | ||
|
||
@Dependency(Account.self) private var account: Account? // optional, as Firebase might be disabled | ||
@Dependency(FirebaseAccountService.self) private var accountService: FirebaseAccountService? | ||
|
||
init() {} | ||
|
||
func userDocumentReference(for accountId: String) -> DocumentReference { | ||
Self.userCollection.document(accountId) | ||
} | ||
|
||
|
||
func configure() { | ||
Task { | ||
await setupTestAccount() | ||
} | ||
} | ||
|
||
|
||
private func setupTestAccount() async { | ||
guard let accountService, FeatureFlags.setupTestAccount else { | ||
return | ||
} | ||
|
||
do { | ||
try await accountService.login(userId: "[email protected]", password: "StanfordRocks!") | ||
return | ||
} catch { | ||
guard let accountError = error as? FirebaseAccountError, | ||
case .invalidCredentials = accountError else { | ||
logger.error("Failed to login into test account: \(error)") | ||
return | ||
} | ||
} | ||
|
||
// account doesn't exist yet, signup | ||
var details = AccountDetails() | ||
details.userId = "[email protected]" | ||
details.password = "StanfordRocks!" | ||
details.name = PersonNameComponents(givenName: "Leland", familyName: "Stanford") | ||
details.genderIdentity = .male | ||
|
||
do { | ||
try await accountService.signUp(with: details) | ||
} catch { | ||
logger.error("Failed to setup test account: \(error)") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,56 +26,13 @@ actor TemplateApplicationStandard: Standard, | |
HealthKitConstraint, | ||
OnboardingConstraint, | ||
AccountNotifyConstraint { | ||
enum TemplateApplicationStandardError: Error { | ||
case userNotAuthenticatedYet | ||
} | ||
|
||
static var userCollection: CollectionReference { | ||
Firestore.firestore().collection("users") | ||
} | ||
|
||
@Application(\.logger) private var logger | ||
|
||
@Dependency(Account.self) private var account: Account? // optional, as Firebase might be disabled | ||
@Dependency(FirebaseAccountService.self) private var accountService: FirebaseAccountService? | ||
|
||
|
||
private var userDocumentReference: DocumentReference { | ||
get async throws { | ||
guard let details = await account?.details else { | ||
throw TemplateApplicationStandardError.userNotAuthenticatedYet | ||
} | ||
|
||
return userDocumentReference(for: details.accountId) | ||
} | ||
} | ||
|
||
private var userBucketReference: StorageReference { | ||
get async throws { | ||
guard let details = await account?.details else { | ||
throw TemplateApplicationStandardError.userNotAuthenticatedYet | ||
} | ||
|
||
return Storage.storage().reference().child("users/\(details.accountId)") | ||
} | ||
} | ||
|
||
@Dependency(FireConfiguration.self) private var configuration | ||
|
||
init() {} | ||
|
||
|
||
private func userDocumentReference(for accountId: String) -> DocumentReference { | ||
Self.userCollection.document(accountId) | ||
} | ||
|
||
|
||
nonisolated func configure() { | ||
Task { | ||
await setupTestAccount() | ||
} | ||
} | ||
|
||
|
||
func add(sample: HKSample) async { | ||
if FeatureFlags.disableFirebase { | ||
logger.debug("Received new HealthKit sample: \(sample)") | ||
|
@@ -113,7 +70,7 @@ actor TemplateApplicationStandard: Standard, | |
} | ||
|
||
do { | ||
try await userDocumentReference | ||
try await configuration.userDocumentReference | ||
.collection("QuestionnaireResponse") // Add all HealthKit sources in a /QuestionnaireResponse collection. | ||
.document(id) // Set the document identifier to the id of the response. | ||
.setData(from: response) | ||
|
@@ -124,15 +81,15 @@ actor TemplateApplicationStandard: Standard, | |
|
||
|
||
private func healthKitDocument(id uuid: UUID) async throws -> DocumentReference { | ||
try await userDocumentReference | ||
try await configuration.userDocumentReference | ||
.collection("HealthKit") // Add all HealthKit sources in a /HealthKit collection. | ||
.document(uuid.uuidString) // Set the document identifier to the UUID of the document. | ||
} | ||
|
||
func respondToEvent(_ event: AccountNotifications.Event) async { | ||
if case let .deletingAccount(accountId) = event { | ||
do { | ||
try await userDocumentReference(for: accountId).delete() | ||
try await configuration.userDocumentReference(for: accountId).delete() | ||
} catch { | ||
logger.error("Could not delete user document: \(error)") | ||
} | ||
|
@@ -168,41 +125,11 @@ actor TemplateApplicationStandard: Standard, | |
|
||
let metadata = StorageMetadata() | ||
metadata.contentType = "application/pdf" | ||
_ = try await userBucketReference | ||
_ = try await configuration.userBucketReference | ||
.child("consent/\(dateString).pdf") | ||
.putDataAsync(consentData, metadata: metadata) { @Sendable _ in } | ||
} catch { | ||
await logger.error("Could not store consent form: \(error)") | ||
} | ||
} | ||
|
||
private func setupTestAccount() async { | ||
guard let accountService, FeatureFlags.setupTestAccount else { | ||
return | ||
} | ||
|
||
do { | ||
try await accountService.login(userId: "[email protected]", password: "StanfordRocks!") | ||
return | ||
} catch { | ||
guard let accountError = error as? FirebaseAccountError, | ||
case .invalidCredentials = accountError else { | ||
logger.error("Failed to login into test account: \(error)") | ||
return | ||
} | ||
} | ||
|
||
// account doesn't exist yet, signup | ||
var details = AccountDetails() | ||
details.userId = "[email protected]" | ||
details.password = "StanfordRocks!" | ||
details.name = PersonNameComponents(givenName: "Leland", familyName: "Stanford") | ||
details.genderIdentity = .male | ||
|
||
do { | ||
try await accountService.signUp(with: details) | ||
} catch { | ||
logger.error("Failed to setup test account: \(error)") | ||
} | ||
} | ||
} |