refactor: break up vault services (#2364)
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { GetVaultUsers } from './GetVaultUsers'
|
||||
import { TrustedContactInterface } from '@standardnotes/models'
|
||||
import { isNotUndefined } from '@standardnotes/utils'
|
||||
import { FindContact } from '../../Contacts/UseCase/FindContact'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export class GetVaultContacts implements UseCaseInterface<TrustedContactInterface[]> {
|
||||
constructor(private findContact: FindContact, private getVaultUsers: GetVaultUsers) {}
|
||||
|
||||
async execute(sharedVaultUuid: string): Promise<Result<TrustedContactInterface[]>> {
|
||||
const users = await this.getVaultUsers.execute({ sharedVaultUuid })
|
||||
if (!users) {
|
||||
return Result.fail('Failed to get vault users')
|
||||
}
|
||||
|
||||
const contacts = users
|
||||
.map((user) => this.findContact.execute({ userUuid: user.user_uuid }))
|
||||
.map((result) => (result.isFailed() ? undefined : result.getValue()))
|
||||
.filter(isNotUndefined)
|
||||
|
||||
return Result.ok(contacts)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { SharedVaultUserServerHash, isErrorResponse } from '@standardnotes/responses'
|
||||
import { SharedVaultUsersServerInterface } from '@standardnotes/api'
|
||||
|
||||
export class GetVaultUsers {
|
||||
constructor(private vaultUsersServer: SharedVaultUsersServerInterface) {}
|
||||
|
||||
async execute(params: { sharedVaultUuid: string }): Promise<SharedVaultUserServerHash[] | undefined> {
|
||||
const response = await this.vaultUsersServer.getSharedVaultUsers({ sharedVaultUuid: params.sharedVaultUuid })
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return response.data.users
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { SharedVaultListingInterface } from '@standardnotes/models'
|
||||
|
||||
export class IsVaultAdmin implements SyncUseCaseInterface<boolean> {
|
||||
execute(dto: { sharedVault: SharedVaultListingInterface; userUuid: string }): Result<boolean> {
|
||||
if (!dto.sharedVault.sharing.ownerUserUuid) {
|
||||
throw new Error(`Shared vault ${dto.sharedVault.sharing.sharedVaultUuid} does not have an owner user uuid`)
|
||||
}
|
||||
|
||||
return Result.ok(dto.sharedVault.sharing.ownerUserUuid === dto.userUuid)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses'
|
||||
import { SharedVaultUsersServerInterface } from '@standardnotes/api'
|
||||
import { DeleteThirdPartyVault } from '../../SharedVaults/UseCase/DeleteExternalSharedVault'
|
||||
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
||||
import { SharedVaultListingInterface } from '@standardnotes/models'
|
||||
|
||||
export class LeaveVault {
|
||||
constructor(
|
||||
private vaultUserServer: SharedVaultUsersServerInterface,
|
||||
private items: ItemManagerInterface,
|
||||
private deleteThirdPartyVault: DeleteThirdPartyVault,
|
||||
) {}
|
||||
|
||||
async execute(params: {
|
||||
sharedVault: SharedVaultListingInterface
|
||||
userUuid: string
|
||||
}): Promise<ClientDisplayableError | void> {
|
||||
const latestVaultListing = this.items.findItem<SharedVaultListingInterface>(params.sharedVault.uuid)
|
||||
if (!latestVaultListing) {
|
||||
throw new Error(`LeaveVaultUseCase: Could not find vault ${params.sharedVault.uuid}`)
|
||||
}
|
||||
|
||||
const response = await this.vaultUserServer.deleteSharedVaultUser({
|
||||
sharedVaultUuid: latestVaultListing.sharing.sharedVaultUuid,
|
||||
userUuid: params.userUuid,
|
||||
})
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return ClientDisplayableError.FromString(`Failed to leave vault ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
await this.deleteThirdPartyVault.execute(latestVaultListing)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { getErrorFromErrorResponse, isErrorResponse } from '@standardnotes/responses'
|
||||
import { SharedVaultUsersServerInterface } from '@standardnotes/api'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export class RemoveVaultMember implements UseCaseInterface<void> {
|
||||
constructor(private vaultUserServer: SharedVaultUsersServerInterface) {}
|
||||
|
||||
async execute(params: { sharedVaultUuid: string; userUuid: string }): Promise<Result<void>> {
|
||||
const response = await this.vaultUserServer.deleteSharedVaultUser({
|
||||
sharedVaultUuid: params.sharedVaultUuid,
|
||||
userUuid: params.userUuid,
|
||||
})
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return Result.fail(getErrorFromErrorResponse(response).message)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
103
packages/services/src/Domain/VaultUser/VaultUserService.ts
Normal file
103
packages/services/src/Domain/VaultUser/VaultUserService.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { LeaveVault } from './UseCase/LeaveSharedVault'
|
||||
import { GetVault } from './../Vaults/UseCase/GetVault'
|
||||
import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface'
|
||||
import { RemoveVaultMember } from './UseCase/RemoveSharedVaultMember'
|
||||
import { VaultServiceInterface } from './../Vaults/VaultServiceInterface'
|
||||
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
|
||||
import { GetVaultUsers } from './UseCase/GetVaultUsers'
|
||||
import { SharedVaultListingInterface } from '@standardnotes/models'
|
||||
import { VaultUserServiceInterface } from './VaultUserServiceInterface'
|
||||
import { ClientDisplayableError, SharedVaultUserServerHash, isClientDisplayableError } from '@standardnotes/responses'
|
||||
import { AbstractService } from './../Service/AbstractService'
|
||||
import { VaultUserServiceEvent } from './VaultUserServiceEvent'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
import { IsVaultAdmin } from './UseCase/IsVaultAdmin'
|
||||
|
||||
export class VaultUserService extends AbstractService<VaultUserServiceEvent> implements VaultUserServiceInterface {
|
||||
constructor(
|
||||
private session: SessionsClientInterface,
|
||||
private vaults: VaultServiceInterface,
|
||||
private _getVaultUsers: GetVaultUsers,
|
||||
private _removeVaultMember: RemoveVaultMember,
|
||||
private _isVaultAdmin: IsVaultAdmin,
|
||||
private _getVault: GetVault,
|
||||
private _leaveVault: LeaveVault,
|
||||
eventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(eventBus)
|
||||
}
|
||||
|
||||
override deinit(): void {
|
||||
super.deinit()
|
||||
;(this.session as unknown) = undefined
|
||||
;(this.vaults as unknown) = undefined
|
||||
;(this._getVaultUsers as unknown) = undefined
|
||||
;(this._removeVaultMember as unknown) = undefined
|
||||
;(this._isVaultAdmin as unknown) = undefined
|
||||
;(this._getVault as unknown) = undefined
|
||||
;(this._leaveVault as unknown) = undefined
|
||||
}
|
||||
|
||||
public async getSharedVaultUsers(
|
||||
sharedVault: SharedVaultListingInterface,
|
||||
): Promise<SharedVaultUserServerHash[] | undefined> {
|
||||
return this._getVaultUsers.execute({ sharedVaultUuid: sharedVault.sharing.sharedVaultUuid })
|
||||
}
|
||||
|
||||
public isCurrentUserSharedVaultAdmin(sharedVault: SharedVaultListingInterface): boolean {
|
||||
return this._isVaultAdmin
|
||||
.execute({
|
||||
sharedVault,
|
||||
userUuid: this.session.userUuid,
|
||||
})
|
||||
.getValue()
|
||||
}
|
||||
|
||||
async removeUserFromSharedVault(sharedVault: SharedVaultListingInterface, userUuid: string): Promise<Result<void>> {
|
||||
if (!this.isCurrentUserSharedVaultAdmin(sharedVault)) {
|
||||
throw new Error('Only vault admins can remove users')
|
||||
}
|
||||
|
||||
if (this.vaults.isVaultLocked(sharedVault)) {
|
||||
throw new Error('Cannot remove user from locked vault')
|
||||
}
|
||||
|
||||
const result = await this._removeVaultMember.execute({
|
||||
sharedVaultUuid: sharedVault.sharing.sharedVaultUuid,
|
||||
userUuid,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
return result
|
||||
}
|
||||
|
||||
void this.notifyEvent(VaultUserServiceEvent.UsersChanged)
|
||||
|
||||
await this.vaults.rotateVaultRootKey(sharedVault)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
public isVaultUserOwner(user: SharedVaultUserServerHash): boolean {
|
||||
const result = this._getVault.execute<SharedVaultListingInterface>({ sharedVaultUuid: user.shared_vault_uuid })
|
||||
if (result.isFailed()) {
|
||||
return false
|
||||
}
|
||||
|
||||
const vault = result.getValue()
|
||||
return vault != undefined && vault.sharing.ownerUserUuid === user.user_uuid
|
||||
}
|
||||
|
||||
async leaveSharedVault(sharedVault: SharedVaultListingInterface): Promise<ClientDisplayableError | void> {
|
||||
const result = await this._leaveVault.execute({
|
||||
sharedVault: sharedVault,
|
||||
userUuid: this.session.getSureUser().uuid,
|
||||
})
|
||||
|
||||
if (isClientDisplayableError(result)) {
|
||||
return result
|
||||
}
|
||||
|
||||
void this.notifyEvent(VaultUserServiceEvent.UsersChanged)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum VaultUserServiceEvent {
|
||||
UsersChanged = 'VaultUserServiceEvent.UsersChanged',
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ApplicationServiceInterface } from './../Service/ApplicationServiceInterface'
|
||||
import { SharedVaultListingInterface } from '@standardnotes/models'
|
||||
import { ClientDisplayableError, SharedVaultUserServerHash } from '@standardnotes/responses'
|
||||
import { VaultUserServiceEvent } from './VaultUserServiceEvent'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
export interface VaultUserServiceInterface extends ApplicationServiceInterface<VaultUserServiceEvent, unknown> {
|
||||
getSharedVaultUsers(sharedVault: SharedVaultListingInterface): Promise<SharedVaultUserServerHash[] | undefined>
|
||||
isCurrentUserSharedVaultAdmin(sharedVault: SharedVaultListingInterface): boolean
|
||||
removeUserFromSharedVault(sharedVault: SharedVaultListingInterface, userUuid: string): Promise<Result<void>>
|
||||
leaveSharedVault(sharedVault: SharedVaultListingInterface): Promise<ClientDisplayableError | void>
|
||||
isVaultUserOwner(user: SharedVaultUserServerHash): boolean
|
||||
}
|
||||
Reference in New Issue
Block a user