Use UUID instead of string for identity id
This commit is contained in:
parent
a92d95d229
commit
c8b4e86019
|
@ -7,7 +7,7 @@ import Combine
|
||||||
private let decoder = MastodonDecoder()
|
private let decoder = MastodonDecoder()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
private let devInstanceURL = URL(string: "https://mastodon.social")!
|
private let devInstanceURL = URL(string: "https://mastodon.social")!
|
||||||
private let devIdentityID = "DEVELOPMENT_IDENTITY_ID"
|
private let devIdentityID = UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E5F")!
|
||||||
private let devAccessToken = "DEVELOPMENT_ACCESS_TOKEN"
|
private let devAccessToken = "DEVELOPMENT_ACCESS_TOKEN"
|
||||||
|
|
||||||
extension Secrets {
|
extension Secrets {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct Identity: Codable, Hashable, Identifiable {
|
struct Identity: Codable, Hashable, Identifiable {
|
||||||
let id: String
|
let id: UUID
|
||||||
let url: URL
|
let url: URL
|
||||||
let lastUsedAt: Date
|
let lastUsedAt: Date
|
||||||
let preferences: Identity.Preferences
|
let preferences: Identity.Preferences
|
||||||
|
@ -21,7 +21,7 @@ extension Identity {
|
||||||
|
|
||||||
struct Account: Codable, Hashable {
|
struct Account: Codable, Hashable {
|
||||||
let id: String
|
let id: String
|
||||||
let identityID: String
|
let identityID: UUID
|
||||||
let username: String
|
let username: String
|
||||||
let url: URL
|
let url: URL
|
||||||
let avatar: URL
|
let avatar: URL
|
||||||
|
|
|
@ -30,7 +30,7 @@ struct IdentityDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension IdentityDatabase {
|
extension IdentityDatabase {
|
||||||
func createIdentity(id: String, url: URL) -> AnyPublisher<Void, Error> {
|
func createIdentity(id: UUID, url: URL) -> AnyPublisher<Void, Error> {
|
||||||
databaseQueue.writePublisher(
|
databaseQueue.writePublisher(
|
||||||
updates: StoredIdentity(
|
updates: StoredIdentity(
|
||||||
id: id,
|
id: id,
|
||||||
|
@ -41,7 +41,7 @@ extension IdentityDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLastUsedAt(identityID: String) -> AnyPublisher<Void, Error> {
|
func updateLastUsedAt(identityID: UUID) -> AnyPublisher<Void, Error> {
|
||||||
databaseQueue.writePublisher {
|
databaseQueue.writePublisher {
|
||||||
try StoredIdentity
|
try StoredIdentity
|
||||||
.filter(Column("id") == identityID)
|
.filter(Column("id") == identityID)
|
||||||
|
@ -50,7 +50,7 @@ extension IdentityDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateInstance(_ instance: Instance, forIdentityID identityID: String) -> AnyPublisher<Void, Error> {
|
func updateInstance(_ instance: Instance, forIdentityID identityID: UUID) -> AnyPublisher<Void, Error> {
|
||||||
databaseQueue.writePublisher {
|
databaseQueue.writePublisher {
|
||||||
try Identity.Instance(
|
try Identity.Instance(
|
||||||
uri: instance.uri,
|
uri: instance.uri,
|
||||||
|
@ -65,7 +65,7 @@ extension IdentityDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAccount(_ account: Account, forIdentityID identityID: String) -> AnyPublisher<Void, Error> {
|
func updateAccount(_ account: Account, forIdentityID identityID: UUID) -> AnyPublisher<Void, Error> {
|
||||||
databaseQueue.writePublisher(
|
databaseQueue.writePublisher(
|
||||||
updates: Identity.Account(
|
updates: Identity.Account(
|
||||||
id: account.id,
|
id: account.id,
|
||||||
|
@ -81,7 +81,7 @@ extension IdentityDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePreferences(_ preferences: Identity.Preferences,
|
func updatePreferences(_ preferences: Identity.Preferences,
|
||||||
forIdentityID identityID: String) -> AnyPublisher<Void, Error> {
|
forIdentityID identityID: UUID) -> AnyPublisher<Void, Error> {
|
||||||
databaseQueue.writePublisher {
|
databaseQueue.writePublisher {
|
||||||
let data = try StoredIdentity.databaseJSONEncoder(for: "preferences").encode(preferences)
|
let data = try StoredIdentity.databaseJSONEncoder(for: "preferences").encode(preferences)
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ extension IdentityDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
func identityObservation(id: String) -> AnyPublisher<Identity, Error> {
|
func identityObservation(id: UUID) -> AnyPublisher<Identity, Error> {
|
||||||
ValueObservation.tracking(
|
ValueObservation.tracking(
|
||||||
StoredIdentity
|
StoredIdentity
|
||||||
.filter(Column("id") == id)
|
.filter(Column("id") == id)
|
||||||
|
@ -110,7 +110,7 @@ extension IdentityDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
func identitiesObservation(excluding: String) -> AnyPublisher<[Identity], Error> {
|
func identitiesObservation(excluding: UUID) -> AnyPublisher<[Identity], Error> {
|
||||||
ValueObservation.tracking(Self.identitiesRequest(excluding: excluding).fetchAll)
|
ValueObservation.tracking(Self.identitiesRequest(excluding: excluding).fetchAll)
|
||||||
.removeDuplicates()
|
.removeDuplicates()
|
||||||
.publisher(in: databaseQueue, scheduling: .immediate)
|
.publisher(in: databaseQueue, scheduling: .immediate)
|
||||||
|
@ -118,7 +118,7 @@ extension IdentityDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
func recentIdentitiesObservation(excluding: String) -> AnyPublisher<[Identity], Error> {
|
func recentIdentitiesObservation(excluding: UUID) -> AnyPublisher<[Identity], Error> {
|
||||||
ValueObservation.tracking(Self.identitiesRequest(excluding: excluding).limit(9).fetchAll)
|
ValueObservation.tracking(Self.identitiesRequest(excluding: excluding).limit(9).fetchAll)
|
||||||
.removeDuplicates()
|
.removeDuplicates()
|
||||||
.publisher(in: databaseQueue, scheduling: .immediate)
|
.publisher(in: databaseQueue, scheduling: .immediate)
|
||||||
|
@ -126,13 +126,13 @@ extension IdentityDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
var mostRecentlyUsedIdentityID: String? {
|
var mostRecentlyUsedIdentityID: UUID? {
|
||||||
try? databaseQueue.read(StoredIdentity.select(Column("id")).order(Column("lastUsedAt").desc).fetchOne)
|
try? databaseQueue.read(StoredIdentity.select(Column("id")).order(Column("lastUsedAt").desc).fetchOne)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension IdentityDatabase {
|
private extension IdentityDatabase {
|
||||||
private static func identitiesRequest(excluding: String) -> QueryInterfaceRequest<IdentityResult> {
|
private static func identitiesRequest(excluding: UUID) -> QueryInterfaceRequest<IdentityResult> {
|
||||||
StoredIdentity
|
StoredIdentity
|
||||||
.filter(Column("id") != excluding)
|
.filter(Column("id") != excluding)
|
||||||
.order(Column("lastUsedAt").desc)
|
.order(Column("lastUsedAt").desc)
|
||||||
|
@ -182,7 +182,7 @@ private extension IdentityDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct StoredIdentity: Codable, Hashable, TableRecord, FetchableRecord, PersistableRecord {
|
private struct StoredIdentity: Codable, Hashable, TableRecord, FetchableRecord, PersistableRecord {
|
||||||
let id: String
|
let id: UUID
|
||||||
let url: URL
|
let url: URL
|
||||||
let lastUsedAt: Date
|
let lastUsedAt: Date
|
||||||
let preferences: Identity.Preferences
|
let preferences: Identity.Preferences
|
||||||
|
|
|
@ -12,7 +12,7 @@ class IdentityRepository {
|
||||||
private let observationErrorsInput = PassthroughSubject<Error, Never>()
|
private let observationErrorsInput = PassthroughSubject<Error, Never>()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
init(identityID: String, appEnvironment: AppEnvironment) throws {
|
init(identityID: UUID, appEnvironment: AppEnvironment) throws {
|
||||||
self.appEnvironment = appEnvironment
|
self.appEnvironment = appEnvironment
|
||||||
observationErrors = observationErrorsInput.eraseToAnyPublisher()
|
observationErrors = observationErrorsInput.eraseToAnyPublisher()
|
||||||
networkClient = MastodonClient(configuration: appEnvironment.URLSessionConfiguration)
|
networkClient = MastodonClient(configuration: appEnvironment.URLSessionConfiguration)
|
||||||
|
|
|
@ -28,24 +28,24 @@ extension Secrets {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Secrets {
|
extension Secrets {
|
||||||
func set(_ data: SecretsStorable, forItem item: Item, forIdentityID identityID: String) throws {
|
func set(_ data: SecretsStorable, forItem item: Item, forIdentityID identityID: UUID) throws {
|
||||||
try keychain.set(data: data.dataStoredInSecrets, forKey: Self.key(item: item, identityID: identityID))
|
try keychain.set(data: data.dataStoredInSecrets, forKey: Self.key(item: item, identityID: identityID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func item<T: SecretsStorable>(_ item: Item, forIdentityID identityID: String) throws -> T? {
|
func item<T: SecretsStorable>(_ item: Item, forIdentityID identityID: UUID) throws -> T? {
|
||||||
guard let data = try keychain.getData(key: Self.key(item: item, identityID: identityID)) else { return nil }
|
guard let data = try keychain.getData(key: Self.key(item: item, identityID: identityID)) else { return nil }
|
||||||
|
|
||||||
return try T.fromDataStoredInSecrets(data)
|
return try T.fromDataStoredInSecrets(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func delete(_ item: Item, forIdentityID identityID: String) throws {
|
func delete(_ item: Item, forIdentityID identityID: UUID) throws {
|
||||||
try keychain.deleteData(key: Self.key(item: item, identityID: identityID))
|
try keychain.deleteData(key: Self.key(item: item, identityID: identityID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension Secrets {
|
private extension Secrets {
|
||||||
static func key(item: Item, identityID: String) -> String {
|
static func key(item: Item, identityID: UUID) -> String {
|
||||||
identityID + "." + item.rawValue
|
identityID.uuidString + "." + item.rawValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,12 @@ class AddIdentityViewModel: ObservableObject {
|
||||||
@Published var urlFieldText = ""
|
@Published var urlFieldText = ""
|
||||||
@Published var alertItem: AlertItem?
|
@Published var alertItem: AlertItem?
|
||||||
@Published private(set) var loading = false
|
@Published private(set) var loading = false
|
||||||
let addedIdentityID: AnyPublisher<String, Never>
|
let addedIdentityID: AnyPublisher<UUID, Never>
|
||||||
|
|
||||||
private let environment: AppEnvironment
|
private let environment: AppEnvironment
|
||||||
private let networkClient: MastodonClient
|
private let networkClient: MastodonClient
|
||||||
private let webAuthSessionContextProvider = WebAuthSessionContextProvider()
|
private let webAuthSessionContextProvider = WebAuthSessionContextProvider()
|
||||||
private let addedIdentityIDInput = PassthroughSubject<String, Never>()
|
private let addedIdentityIDInput = PassthroughSubject<UUID, Never>()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
init(environment: AppEnvironment) {
|
init(environment: AppEnvironment) {
|
||||||
|
@ -22,13 +22,13 @@ class AddIdentityViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func goTapped() {
|
func goTapped() {
|
||||||
let identityID = UUID().uuidString
|
let identityID = UUID()
|
||||||
let instanceURL: URL
|
let instanceURL: URL
|
||||||
let redirectURL: URL
|
let redirectURL: URL
|
||||||
|
|
||||||
do {
|
do {
|
||||||
instanceURL = try urlFieldText.url()
|
instanceURL = try urlFieldText.url()
|
||||||
redirectURL = try identityID.url(scheme: MastodonAPI.OAuth.callbackURLScheme)
|
redirectURL = try identityID.uuidString.url(scheme: MastodonAPI.OAuth.callbackURLScheme)
|
||||||
} catch {
|
} catch {
|
||||||
alertItem = AlertItem(error: error)
|
alertItem = AlertItem(error: error)
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class AddIdentityViewModel: ObservableObject {
|
||||||
|
|
||||||
private extension AddIdentityViewModel {
|
private extension AddIdentityViewModel {
|
||||||
private func authorizeApp(
|
private func authorizeApp(
|
||||||
identityID: String,
|
identityID: UUID,
|
||||||
instanceURL: URL,
|
instanceURL: URL,
|
||||||
redirectURL: URL,
|
redirectURL: URL,
|
||||||
secrets: Secrets) -> AnyPublisher<AppAuthorization, Error> {
|
secrets: Secrets) -> AnyPublisher<AppAuthorization, Error> {
|
||||||
|
@ -152,7 +152,7 @@ private extension Publisher where Output == (AppAuthorization, URL) {
|
||||||
private extension Publisher where Output == (AppAuthorization, String), Failure == Error {
|
private extension Publisher where Output == (AppAuthorization, String), Failure == Error {
|
||||||
func requestAccessToken(
|
func requestAccessToken(
|
||||||
networkClient: HTTPClient,
|
networkClient: HTTPClient,
|
||||||
identityID: String,
|
identityID: UUID,
|
||||||
instanceURL: URL,
|
instanceURL: URL,
|
||||||
redirectURL: URL) -> AnyPublisher<AccessToken, Error> {
|
redirectURL: URL) -> AnyPublisher<AccessToken, Error> {
|
||||||
flatMap { appAuthorization, code -> AnyPublisher<AccessToken, Error> in
|
flatMap { appAuthorization, code -> AnyPublisher<AccessToken, Error> in
|
||||||
|
@ -172,8 +172,8 @@ private extension Publisher where Output == (AppAuthorization, String), Failure
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension Publisher where Output == AccessToken {
|
private extension Publisher where Output == AccessToken {
|
||||||
func createIdentity(id: String, instanceURL: URL, environment: AppEnvironment) -> AnyPublisher<String, Error> {
|
func createIdentity(id: UUID, instanceURL: URL, environment: AppEnvironment) -> AnyPublisher<UUID, Error> {
|
||||||
tryMap { accessToken -> (String, URL) in
|
tryMap { accessToken -> (UUID, URL) in
|
||||||
try environment.secrets.set(accessToken.accessToken, forItem: .accessToken, forIdentityID: id)
|
try environment.secrets.set(accessToken.accessToken, forItem: .accessToken, forIdentityID: id)
|
||||||
|
|
||||||
return (id, instanceURL)
|
return (id, instanceURL)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
class RootViewModel: ObservableObject {
|
class RootViewModel: ObservableObject {
|
||||||
@Published private(set) var identityID: String?
|
@Published private(set) var identityID: UUID?
|
||||||
private let environment: AppEnvironment
|
private let environment: AppEnvironment
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class RootViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RootViewModel {
|
extension RootViewModel {
|
||||||
func newIdentitySelected(id: String) {
|
func newIdentitySelected(id: UUID) {
|
||||||
identityID = id
|
identityID = id
|
||||||
|
|
||||||
environment.identityDatabase
|
environment.identityDatabase
|
||||||
|
@ -28,7 +28,7 @@ extension RootViewModel {
|
||||||
AddIdentityViewModel(environment: environment)
|
AddIdentityViewModel(environment: environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mainNavigationViewModel(identityID: String) -> MainNavigationViewModel? {
|
func mainNavigationViewModel(identityID: UUID) -> MainNavigationViewModel? {
|
||||||
let identityRepository: IdentityRepository
|
let identityRepository: IdentityRepository
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
Loading…
Reference in New Issue