Use UUID instead of string for identity id

This commit is contained in:
Justin Mazzocchi 2020-08-07 16:19:13 -07:00
parent a92d95d229
commit c8b4e86019
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
7 changed files with 31 additions and 31 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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
} }
} }

View file

@ -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)

View file

@ -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 {