From 4939888dd5eb0a334167a5d2f85d792bc15f7f84 Mon Sep 17 00:00:00 2001 From: Laurent Date: Wed, 14 Feb 2024 17:03:52 +0100 Subject: [PATCH] Adds user uuid system to use with subscriptions --- LeStorage.xcodeproj/project.pbxproj | 26 ++++++++++++--- LeStorage/{ => Codables}/ApiCall.swift | 0 LeStorage/Codables/Settings.swift | 22 ++++++++++++ LeStorage/MicroStorage.swift | 46 ++++++++++++++++++++++++++ LeStorage/Services.swift | 21 ++++++++++-- LeStorage/Store.swift | 17 ++++++++++ LeStorage/StoredCollection.swift | 1 + 7 files changed, 125 insertions(+), 8 deletions(-) rename LeStorage/{ => Codables}/ApiCall.swift (100%) create mode 100644 LeStorage/Codables/Settings.swift create mode 100644 LeStorage/MicroStorage.swift diff --git a/LeStorage.xcodeproj/project.pbxproj b/LeStorage.xcodeproj/project.pbxproj index 3a775f4..34d6f8a 100644 --- a/LeStorage.xcodeproj/project.pbxproj +++ b/LeStorage.xcodeproj/project.pbxproj @@ -18,12 +18,14 @@ C4A47D552B6D2DBF00ADC637 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D542B6D2DBF00ADC637 /* FileUtils.swift */; }; C4A47D612B6D3C1300ADC637 /* Services.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D602B6D3C1300ADC637 /* Services.swift */; }; C4A47D652B6E92FE00ADC637 /* Storable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D642B6E92FE00ADC637 /* Storable.swift */; }; - C4A47D672B6FF83A00ADC637 /* ApiCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D662B6FF83A00ADC637 /* ApiCall.swift */; }; C4A47D6B2B71244100ADC637 /* Collection+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D6A2B71244100ADC637 /* Collection+Extension.swift */; }; C4A47D6D2B71364600ADC637 /* ModelObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D6C2B71364600ADC637 /* ModelObject.swift */; }; C4A47D6F2B7154F600ADC637 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = C4A47D6E2B7154F600ADC637 /* README.md */; }; C4A47D812B7665AD00ADC637 /* Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D802B76658F00ADC637 /* Migration.swift */; }; C4A47D842B7B97F000ADC637 /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D832B7B97F000ADC637 /* KeychainStore.swift */; }; + C4A47D942B7CF7C500ADC637 /* MicroStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D932B7CF7C500ADC637 /* MicroStorage.swift */; }; + C4A47D9B2B7CFFDA00ADC637 /* ApiCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D992B7CFFC500ADC637 /* ApiCall.swift */; }; + C4A47D9C2B7CFFE000ADC637 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47D9A2B7CFFC500ADC637 /* Settings.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -49,12 +51,14 @@ C4A47D542B6D2DBF00ADC637 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = ""; }; C4A47D602B6D3C1300ADC637 /* Services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Services.swift; sourceTree = ""; }; C4A47D642B6E92FE00ADC637 /* Storable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storable.swift; sourceTree = ""; }; - C4A47D662B6FF83A00ADC637 /* ApiCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiCall.swift; sourceTree = ""; }; C4A47D6A2B71244100ADC637 /* Collection+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Extension.swift"; sourceTree = ""; }; C4A47D6C2B71364600ADC637 /* ModelObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelObject.swift; sourceTree = ""; }; C4A47D6E2B7154F600ADC637 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; C4A47D802B76658F00ADC637 /* Migration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Migration.swift; sourceTree = ""; }; C4A47D832B7B97F000ADC637 /* KeychainStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainStore.swift; sourceTree = ""; }; + C4A47D932B7CF7C500ADC637 /* MicroStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MicroStorage.swift; sourceTree = ""; }; + C4A47D992B7CFFC500ADC637 /* ApiCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiCall.swift; sourceTree = ""; }; + C4A47D9A2B7CFFC500ADC637 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -100,12 +104,13 @@ C4A47D6E2B7154F600ADC637 /* README.md */, C425D4372B6D24E1002A7B48 /* LeStorage.h */, C425D4382B6D24E1002A7B48 /* LeStorage.docc */, - C4A47D602B6D3C1300ADC637 /* Services.swift */, - C4A47D662B6FF83A00ADC637 /* ApiCall.swift */, + C4A47D9D2B7CFFF500ADC637 /* Codables */, C4A47D6C2B71364600ADC637 /* ModelObject.swift */, + C4A47D602B6D3C1300ADC637 /* Services.swift */, C425D4572B6D2519002A7B48 /* Store.swift */, C4A47D642B6E92FE00ADC637 /* Storable.swift */, C4A47D4E2B6D280200ADC637 /* StoredCollection.swift */, + C4A47D932B7CF7C500ADC637 /* MicroStorage.swift */, C4A47D822B7665BC00ADC637 /* Wip */, C4A47D582B6D352900ADC637 /* Utils */, ); @@ -140,6 +145,15 @@ path = Wip; sourceTree = ""; }; + C4A47D9D2B7CFFF500ADC637 /* Codables */ = { + isa = PBXGroup; + children = ( + C4A47D9A2B7CFFC500ADC637 /* Settings.swift */, + C4A47D992B7CFFC500ADC637 /* ApiCall.swift */, + ); + path = Codables; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -259,8 +273,10 @@ C4A47D652B6E92FE00ADC637 /* Storable.swift in Sources */, C4A47D6D2B71364600ADC637 /* ModelObject.swift in Sources */, C4A47D4F2B6D280200ADC637 /* StoredCollection.swift in Sources */, + C4A47D9C2B7CFFE000ADC637 /* Settings.swift in Sources */, C4A47D812B7665AD00ADC637 /* Migration.swift in Sources */, - C4A47D672B6FF83A00ADC637 /* ApiCall.swift in Sources */, + C4A47D9B2B7CFFDA00ADC637 /* ApiCall.swift in Sources */, + C4A47D942B7CF7C500ADC637 /* MicroStorage.swift in Sources */, C425D4582B6D2519002A7B48 /* Store.swift in Sources */, C4A47D6B2B71244100ADC637 /* Collection+Extension.swift in Sources */, ); diff --git a/LeStorage/ApiCall.swift b/LeStorage/Codables/ApiCall.swift similarity index 100% rename from LeStorage/ApiCall.swift rename to LeStorage/Codables/ApiCall.swift diff --git a/LeStorage/Codables/Settings.swift b/LeStorage/Codables/Settings.swift new file mode 100644 index 0000000..1528280 --- /dev/null +++ b/LeStorage/Codables/Settings.swift @@ -0,0 +1,22 @@ +// +// Settings.swift +// LeStorage +// +// Created by Laurent Morvillier on 14/02/2024. +// + +import Foundation + +class Settings: MicroStorable { + + static var fileName: String { "settings.json" } + + required init() { + + } + + var id: String = Store.randomId() + + var userUUID: UUID? = nil + +} diff --git a/LeStorage/MicroStorage.swift b/LeStorage/MicroStorage.swift new file mode 100644 index 0000000..f40a8a9 --- /dev/null +++ b/LeStorage/MicroStorage.swift @@ -0,0 +1,46 @@ +// +// StoredItem.swift +// LeStorage +// +// Created by Laurent Morvillier on 14/02/2024. +// + +import Foundation + +protocol MicroStorable : Codable { + init() + static var fileName: String { get } +} + +class MicroStorage { + + fileprivate(set) var item: T + + init() { + var instance: T? = nil + do { + let jsonString = try FileUtils.readDocumentFile(fileName: T.fileName) + if let decoded: T = try jsonString.decode() { + instance = decoded + } + } catch { + Logger.error(error) + } + self.item = instance ?? T() + } + + func update(handler: (T) -> ()) { + handler(self.item) + self._write() + } + + fileprivate func _write() { + do { + let jsonString: String = try self.item.jsonString() + let _ = try FileUtils.writeToDocumentDirectory(content: jsonString, fileName: T.fileName) + } catch { + Logger.error(error) + } + } + +} diff --git a/LeStorage/Services.swift b/LeStorage/Services.swift index 089b7a1..871dea9 100644 --- a/LeStorage/Services.swift +++ b/LeStorage/Services.swift @@ -16,6 +16,7 @@ enum Method: String { enum ServiceError: Error { case urlCreationError(url: String) + case cantConvertToUUID(id: String) } public class Services { @@ -119,7 +120,6 @@ public class Services { // MARK: - Authentication public func createAccount(username: String, password: String, email: String) async throws { - var postRequest = try self._baseRequest(servicePath: "users/", method: .post) let user = User(username: username, password: password, email: email) postRequest.httpBody = try jsonEncoder.encode(user) @@ -135,6 +135,13 @@ public class Services { return response.token } + public func login(username: String, password: String) async throws -> User { + var postRequest = try self._baseRequest(servicePath: "users/", method: .post) + let credentials = Credentials(username: username, password: password) + postRequest.httpBody = try jsonEncoder.encode(credentials) + return try await self.runRequest(postRequest) + } + func forgotPassword(user: User) async throws { // var postRequest = try self._baseRequest(servicePath: "forgot-password/", method: .post) @@ -157,9 +164,17 @@ struct Credentials: Codable { var password: String } -struct User: Codable { - var id: Int = 0 +public struct User: Codable { + var id: String = Store.randomId() var username: String var password: String? var email: String? + + func uuid() throws -> UUID { + if let uuid = UUID(uuidString: self.id) { + return uuid + } + throw ServiceError.cantConvertToUUID(id: self.id) + } + } diff --git a/LeStorage/Store.swift b/LeStorage/Store.swift index 99da9d8..75def72 100644 --- a/LeStorage/Store.swift +++ b/LeStorage/Store.swift @@ -6,6 +6,7 @@ // import Foundation +import UIKit enum StoreError: Error { case missingService @@ -20,6 +21,8 @@ public class Store { /// The Store singleton public static let main = Store() +// public fileprivate(set) var currentUser: User? = nil + /// A method to provide ids corresponding to the django storage public static func randomId() -> String { return UUID().uuidString.lowercased() @@ -50,6 +53,8 @@ public class Store { fileprivate lazy var _migrationCollection: StoredCollection = { StoredCollection(synchronized: false, store: Store.main, asynchronousIO: false) }() + fileprivate var settingsStorage: MicroStorage = MicroStorage() + public init() { } /// Registers a collection @@ -70,6 +75,18 @@ public class Store { return collection } + public func currentUserUUID() throws -> UUID { + if let uuid = self.settingsStorage.item.userUUID { + return uuid + } else { + let uuid = UIDevice.current.identifierForVendor ?? UUID() + self.settingsStorage.update { settings in + settings.userUUID = uuid + } + return uuid + } + } + /// The service instance public var service: Services? { return self._services diff --git a/LeStorage/StoredCollection.swift b/LeStorage/StoredCollection.swift index db263d3..688fb46 100644 --- a/LeStorage/StoredCollection.swift +++ b/LeStorage/StoredCollection.swift @@ -10,6 +10,7 @@ import Foundation enum StoredCollectionError : Error { case unmanagedHTTPMethod(method: String) case missingApiCallCollection + case missingInstance } protocol SomeCollection : Identifiable {