mirror of
https://github.com/standardnotes/server
synced 2026-10-12 15:13:39 -04:00
feat: remove user from all shared vaults upon account deletion (#843)
This commit is contained in:
+79
@@ -0,0 +1,79 @@
|
||||
import { Result, SharedVaultUser, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
||||
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
|
||||
import { RemoveUserFromSharedVaults } from './RemoveUserFromSharedVaults'
|
||||
|
||||
describe('RemoveUserFromSharedVaults', () => {
|
||||
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
|
||||
let sharedVaultUser: SharedVaultUser
|
||||
let removeUserFromSharedVault: RemoveUserFromSharedVault
|
||||
let logger: Logger
|
||||
|
||||
const createUseCase = () =>
|
||||
new RemoveUserFromSharedVaults(sharedVaultUserRepository, removeUserFromSharedVault, logger)
|
||||
|
||||
beforeEach(() => {
|
||||
sharedVaultUser = SharedVaultUser.create({
|
||||
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
|
||||
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
timestamps: Timestamps.create(123, 123).getValue(),
|
||||
isDesignatedSurvivor: false,
|
||||
}).getValue()
|
||||
|
||||
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
|
||||
sharedVaultUserRepository.findByUserUuid = jest.fn().mockResolvedValue([sharedVaultUser])
|
||||
|
||||
removeUserFromSharedVault = {} as jest.Mocked<RemoveUserFromSharedVault>
|
||||
removeUserFromSharedVault.execute = jest.fn().mockResolvedValue(Result.ok())
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.error = jest.fn()
|
||||
})
|
||||
|
||||
it('should remove user from shared vaults', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(removeUserFromSharedVault.execute).toHaveBeenCalledTimes(1)
|
||||
expect(removeUserFromSharedVault.execute).toHaveBeenCalledWith({
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
originatorUuid: '00000000-0000-0000-0000-000000000000',
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
forceRemoveOwner: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('should log error if removing user from shared vault fails', async () => {
|
||||
removeUserFromSharedVault.execute = jest.fn().mockResolvedValue(Result.fail('error'))
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(logger.error).toHaveBeenCalledTimes(1)
|
||||
expect(logger.error).toHaveBeenCalledWith(
|
||||
'Failed to remove user: 00000000-0000-0000-0000-000000000000 from shared vault: 00000000-0000-0000-0000-000000000000: error',
|
||||
)
|
||||
})
|
||||
|
||||
it('should fail if the user uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: 'invalid',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(removeUserFromSharedVault.execute).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
||||
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
|
||||
import { Logger } from 'winston'
|
||||
import { RemoveUserFromSharedVaultsDTO } from './RemoveUserFromSharedVaultsDTO'
|
||||
|
||||
export class RemoveUserFromSharedVaults implements UseCaseInterface<void> {
|
||||
constructor(
|
||||
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
|
||||
private removeUserFromSharedVault: RemoveUserFromSharedVault,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async execute(dto: RemoveUserFromSharedVaultsDTO): Promise<Result<void>> {
|
||||
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return Result.fail(userUuidOrError.getError())
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const sharedVaultUsers = await this.sharedVaultUserRepository.findByUserUuid(userUuid)
|
||||
for (const sharedVaultUser of sharedVaultUsers) {
|
||||
const result = await this.removeUserFromSharedVault.execute({
|
||||
sharedVaultUuid: sharedVaultUser.props.sharedVaultUuid.value,
|
||||
originatorUuid: userUuid.value,
|
||||
userUuid: userUuid.value,
|
||||
forceRemoveOwner: true,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(
|
||||
`Failed to remove user: ${userUuid.value} from shared vault: ${
|
||||
sharedVaultUser.props.sharedVaultUuid.value
|
||||
}: ${result.getError()}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export interface RemoveUserFromSharedVaultsDTO {
|
||||
userUuid: string
|
||||
}
|
||||
Reference in New Issue
Block a user