From 0a9c8a416a6e65b3fad84056c35d181422e9745c Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Tue, 26 Sep 2023 14:55:26 -0400 Subject: [PATCH] Define account service observable responsibilities --- .../src/auth/abstractions/account.service.ts | 14 +++- .../src/auth/services/account.service.ts | 33 +++++++++ .../src/services/account/account.service.ts | 73 +++++++++++++++++++ libs/common/src/types/guid.d.ts | 5 ++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 libs/common/src/services/account/account.service.ts create mode 100644 libs/common/src/types/guid.d.ts diff --git a/libs/common/src/auth/abstractions/account.service.ts b/libs/common/src/auth/abstractions/account.service.ts index 26c260eb6d5..d943e906459 100644 --- a/libs/common/src/auth/abstractions/account.service.ts +++ b/libs/common/src/auth/abstractions/account.service.ts @@ -1,4 +1,16 @@ -export abstract class AccountService {} +import { Observable } from "rxjs"; + +import { UserId } from "../../types/guid"; +import { AuthenticationStatus } from "../enums/authentication-status"; + +export abstract class AccountService { + accounts$: Observable>; + activeAccount$: Observable<{ id: UserId | undefined; status: AuthenticationStatus | undefined }>; + accountLock$: Observable; + accountLogout$: Observable; + abstract setAccountStatus(userId: UserId, status: AuthenticationStatus): void; + abstract switchAccount(userId: UserId): void; +} export abstract class InternalAccountService extends AccountService { abstract delete(): void; diff --git a/libs/common/src/auth/services/account.service.ts b/libs/common/src/auth/services/account.service.ts index 02c12050952..8079b16e2d9 100644 --- a/libs/common/src/auth/services/account.service.ts +++ b/libs/common/src/auth/services/account.service.ts @@ -1,10 +1,43 @@ +import { BehaviorSubject, Subject } from "rxjs"; + import { InternalAccountService } from "../../auth/abstractions/account.service"; import { LogService } from "../../platform/abstractions/log.service"; import { MessagingService } from "../../platform/abstractions/messaging.service"; +import { UserId } from "../../types/guid"; +import { AuthenticationStatus } from "../enums/authentication-status"; export class AccountServiceImplementation implements InternalAccountService { + private accounts = new BehaviorSubject>({}); + private activeAccount = new BehaviorSubject<{ + id: UserId | undefined; + status: AuthenticationStatus | undefined; + }>({ id: undefined, status: undefined }); + private lock = new Subject(); + private logout = new Subject(); + + accounts$ = this.accounts.asObservable(); + activeAccount$ = this.activeAccount.asObservable(); + accountLock$ = this.lock.asObservable(); + accountLogout$ = this.logout.asObservable(); constructor(private messagingService: MessagingService, private logService: LogService) {} + setAccountStatus(userId: UserId, status: AuthenticationStatus): void { + this.accounts.value[userId] = status; + this.accounts.next(this.accounts.value); + if (status === AuthenticationStatus.LoggedOut) { + this.logout.next(userId); + } else if (status === AuthenticationStatus.Locked) { + this.lock.next(userId); + } + } + + switchAccount(userId: UserId) { + if (this.accounts.value[userId] != null) { + throw new Error("Account does not exist"); + } + } + + // TODO: update to use our own account status settings. async delete(): Promise { try { this.messagingService.send("logout"); diff --git a/libs/common/src/services/account/account.service.ts b/libs/common/src/services/account/account.service.ts new file mode 100644 index 00000000000..d56bdb3b31b --- /dev/null +++ b/libs/common/src/services/account/account.service.ts @@ -0,0 +1,73 @@ +import { BehaviorSubject, filter, Subject } from "rxjs"; + +import { InternalAccountService } from "../../abstractions/account/account.service"; +import { LogService } from "../../abstractions/log.service"; +import { MessagingService } from "../../abstractions/messaging.service"; +import { AuthenticationStatus } from "../../enums/authenticationStatus"; + +export class AccountServiceImplementation implements InternalAccountService { + private accounts = new BehaviorSubject>(new Map()); + private activeAccount = new BehaviorSubject<{ + id: string | undefined; + status: AuthenticationStatus | undefined; + }>({ id: undefined, status: undefined }); + private lock = new Subject(); + private logout = new Subject(); + private unlock = new Subject(); + + accounts$ = this.accounts.asObservable(); + activeAccount$ = this.activeAccount.asObservable(); + accountLocked$ = this.lock.asObservable(); + accountLogout$ = this.logout.asObservable(); + accountUnlocked$ = this.unlock.asObservable(); + + activeAccountLocked$ = this.accountLocked$.pipe( + filter((userId) => userId === this.activeAccount.value.id) + ); + activeAccountUnlocked$ = this.accountUnlocked$.pipe( + filter((userId) => userId === this.activeAccount.value.id) + ); + activeAccountLogout$ = this.accountLogout$.pipe( + filter((userId) => userId === this.activeAccount.value.id) + ); + + constructor(private messagingService: MessagingService, private logService: LogService) {} + + setAccountStatus(userId: string, status: AuthenticationStatus) { + this.accounts.value.set(userId, status); + this.accounts.next(this.accounts.value); + if (status === AuthenticationStatus.LoggedOut) { + this.logout.next(userId); + } else if (status === AuthenticationStatus.Locked) { + this.lock.next(userId); + } else if (status === AuthenticationStatus.Unlocked) { + this.unlock.next(userId); + } + } + + switchAccount(userId: string) { + if (!this.accounts.value.has(userId)) { + throw new Error("Account does not exist"); + } + this.activeAccount.next({ id: userId, status: this.accounts.value.get(userId) }); + } + + delete(): void { + try { + this.logout.next(this.activeAccount.value.id); + this.accounts.value.delete(this.activeAccount.value.id); + this.accounts.next(this.accounts.value); + this.messagingService.send("logout"); + } catch (e) { + this.logService.error(e); + throw e; + } + } + + complete() { + this.accounts.complete(); + this.activeAccount.complete(); + this.lock.complete(); + this.logout.complete(); + } +} diff --git a/libs/common/src/types/guid.d.ts b/libs/common/src/types/guid.d.ts new file mode 100644 index 00000000000..f77655a95f3 --- /dev/null +++ b/libs/common/src/types/guid.d.ts @@ -0,0 +1,5 @@ +import { Opaque } from "type-fest"; + +type Guid = Opaque; + +type UserId = Opaque;