Compare commits

...

4 Commits

40 changed files with 352 additions and 107 deletions
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.26.18](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.17...@standardnotes/analytics@2.26.18) (2023-09-20)
**Note:** Version bump only for package @standardnotes/analytics
## [2.26.17](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.16...@standardnotes/analytics@2.26.17) (2023-09-19)
**Note:** Version bump only for package @standardnotes/analytics
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "2.26.17",
"version": "2.26.18",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.74.16](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.15...@standardnotes/api-gateway@1.74.16) (2023-09-20)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.74.15](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.14...@standardnotes/api-gateway@1.74.15) (2023-09-19)
**Note:** Version bump only for package @standardnotes/api-gateway
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.74.15",
"version": "1.74.16",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.143.8](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.143.7...@standardnotes/auth-server@1.143.8) (2023-09-20)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.143.7](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.143.6...@standardnotes/auth-server@1.143.7) (2023-09-19)
**Note:** Version bump only for package @standardnotes/auth-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.143.7",
"version": "1.143.8",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.31.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.30.1...@standardnotes/domain-core@1.31.0) (2023-09-20)
### Features
* **syncing-server:** add notification for user upon declined shared vault invitation ([#837](https://github.com/standardnotes/server/issues/837)) ([31e7aaf](https://github.com/standardnotes/server/commit/31e7aaf253029a951d8b943d6cffd655cd5ca765))
## [1.30.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.30.0...@standardnotes/domain-core@1.30.1) (2023-09-19)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-core",
"version": "1.30.1",
"version": "1.31.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -7,6 +7,7 @@ export class NotificationType extends ValueObject<NotificationTypeProps> {
SharedVaultItemRemoved: 'shared_vault_item_removed',
RemovedFromSharedVault: 'removed_from_shared_vault',
UserAddedToSharedVault: 'user_added_to_shared_vault',
SharedVaultInviteDeclined: 'shared_vault_invite_declined',
SharedVaultFileUploaded: 'shared_vault_file_uploaded',
SharedVaultFileRemoved: 'shared_vault_file_removed',
}
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.11.46](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.45...@standardnotes/event-store@1.11.46) (2023-09-20)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.45](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.44...@standardnotes/event-store@1.11.45) (2023-09-19)
**Note:** Version bump only for package @standardnotes/event-store
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/event-store",
"version": "1.11.45",
"version": "1.11.46",
"description": "Event Store Service",
"private": true,
"main": "dist/src/index.js",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.25](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.24...@standardnotes/files-server@1.22.25) (2023-09-20)
**Note:** Version bump only for package @standardnotes/files-server
## [1.22.24](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.23...@standardnotes/files-server@1.22.24) (2023-09-19)
**Note:** Version bump only for package @standardnotes/files-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files-server",
"version": "1.22.24",
"version": "1.22.25",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.15.70](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.69...@standardnotes/home-server@1.15.70) (2023-09-20)
**Note:** Version bump only for package @standardnotes/home-server
## [1.15.69](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.68...@standardnotes/home-server@1.15.69) (2023-09-20)
**Note:** Version bump only for package @standardnotes/home-server
## [1.15.68](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.67...@standardnotes/home-server@1.15.68) (2023-09-19)
**Note:** Version bump only for package @standardnotes/home-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/home-server",
"version": "1.15.68",
"version": "1.15.70",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.35.8](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.35.7...@standardnotes/revisions-server@1.35.8) (2023-09-20)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.35.7](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.35.6...@standardnotes/revisions-server@1.35.7) (2023-09-19)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/revisions-server",
"version": "1.35.7",
"version": "1.35.8",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.20.50](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.49...@standardnotes/scheduler-server@1.20.50) (2023-09-20)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.20.49](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.48...@standardnotes/scheduler-server@1.20.49) (2023-09-19)
**Note:** Version bump only for package @standardnotes/scheduler-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/scheduler-server",
"version": "1.20.49",
"version": "1.20.50",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.35](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.34...@standardnotes/settings@1.21.35) (2023-09-20)
**Note:** Version bump only for package @standardnotes/settings
## [1.21.34](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.33...@standardnotes/settings@1.21.34) (2023-09-19)
**Note:** Version bump only for package @standardnotes/settings
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/settings",
"version": "1.21.34",
"version": "1.21.35",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.100.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.99.0...@standardnotes/syncing-server@1.100.0) (2023-09-20)
### Features
* **syncing-server:** remove owned shared vaults upon account deletion ([#838](https://github.com/standardnotes/syncing-server-js/issues/838)) ([22a8cc9](https://github.com/standardnotes/syncing-server-js/commit/22a8cc90f1232fd5f5646f613c80bd7c60186670))
# [1.99.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.98.6...@standardnotes/syncing-server@1.99.0) (2023-09-20)
### Features
* **syncing-server:** add notification for user upon declined shared vault invitation ([#837](https://github.com/standardnotes/syncing-server-js/issues/837)) ([31e7aaf](https://github.com/standardnotes/syncing-server-js/commit/31e7aaf253029a951d8b943d6cffd655cd5ca765))
## [1.98.6](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.98.5...@standardnotes/syncing-server@1.98.6) (2023-09-19)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/syncing-server",
"version": "1.98.6",
"version": "1.100.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -165,6 +165,7 @@ import { SQLItemPersistenceMapper } from '../Mapping/Persistence/SQLItemPersiste
import { SQLItemRepository } from '../Infra/TypeORM/SQLItemRepository'
import { SendEventToClient } from '../Domain/UseCase/Syncing/SendEventToClient/SendEventToClient'
import { TransitionRequestedEventHandler } from '../Domain/Handler/TransitionRequestedEventHandler'
import { DeleteSharedVaults } from '../Domain/UseCase/SharedVaults/DeleteSharedVaults/DeleteSharedVaults'
export class ContainerConfigLoader {
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
@@ -723,7 +724,12 @@ export class ContainerConfigLoader {
)
container
.bind<DeclineInviteToSharedVault>(TYPES.Sync_DeclineInviteToSharedVault)
.toConstantValue(new DeclineInviteToSharedVault(container.get(TYPES.Sync_SharedVaultInviteRepository)))
.toConstantValue(
new DeclineInviteToSharedVault(
container.get<SharedVaultInviteRepositoryInterface>(TYPES.Sync_SharedVaultInviteRepository),
container.get<AddNotificationForUser>(TYPES.Sync_AddNotificationForUser),
),
)
container
.bind<DeleteSharedVaultInvitesToUser>(TYPES.Sync_DeleteSharedVaultInvitesToUser)
.toConstantValue(
@@ -775,10 +781,19 @@ export class ContainerConfigLoader {
.bind<DeleteSharedVault>(TYPES.Sync_DeleteSharedVault)
.toConstantValue(
new DeleteSharedVault(
container.get(TYPES.Sync_SharedVaultRepository),
container.get(TYPES.Sync_SharedVaultUserRepository),
container.get(TYPES.Sync_SharedVaultInviteRepository),
container.get(TYPES.Sync_RemoveSharedVaultUser),
container.get<SharedVaultRepositoryInterface>(TYPES.Sync_SharedVaultRepository),
container.get<SharedVaultUserRepositoryInterface>(TYPES.Sync_SharedVaultUserRepository),
container.get<SharedVaultInviteRepositoryInterface>(TYPES.Sync_SharedVaultInviteRepository),
container.get<RemoveUserFromSharedVault>(TYPES.Sync_RemoveSharedVaultUser),
container.get<DeclineInviteToSharedVault>(TYPES.Sync_DeclineInviteToSharedVault),
),
)
container
.bind<DeleteSharedVaults>(TYPES.Sync_DeleteSharedVaults)
.toConstantValue(
new DeleteSharedVaults(
container.get<SharedVaultRepositoryInterface>(TYPES.Sync_SharedVaultRepository),
container.get<DeleteSharedVault>(TYPES.Sync_DeleteSharedVault),
),
)
container
@@ -897,6 +912,7 @@ export class ContainerConfigLoader {
.toConstantValue(
new AccountDeletionRequestedEventHandler(
container.get<ItemRepositoryResolverInterface>(TYPES.Sync_ItemRepositoryResolver),
container.get<DeleteSharedVaults>(TYPES.Sync_DeleteSharedVaults),
container.get<Logger>(TYPES.Sync_Logger),
),
)
@@ -54,6 +54,7 @@ const TYPES = {
Sync_GetSharedVaults: Symbol.for('Sync_GetSharedVaults'),
Sync_CreateSharedVault: Symbol.for('Sync_CreateSharedVault'),
Sync_DeleteSharedVault: Symbol.for('Sync_DeleteSharedVault'),
Sync_DeleteSharedVaults: Symbol.for('Sync_DeleteSharedVaults'),
Sync_CreateSharedVaultFileValetToken: Symbol.for('Sync_CreateSharedVaultFileValetToken'),
Sync_GetSharedVaultUsers: Symbol.for('Sync_GetSharedVaultUsers'),
Sync_AddUserToSharedVault: Symbol.for('Sync_AddUserToSharedVault'),
@@ -1,71 +0,0 @@
import 'reflect-metadata'
import { AccountDeletionRequestedEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { Item } from '../Item/Item'
import { ItemRepositoryInterface } from '../Item/ItemRepositoryInterface'
import { AccountDeletionRequestedEventHandler } from './AccountDeletionRequestedEventHandler'
import { Uuid, ContentType, Dates, Timestamps, UniqueEntityId } from '@standardnotes/domain-core'
import { ItemRepositoryResolverInterface } from '../Item/ItemRepositoryResolverInterface'
describe('AccountDeletionRequestedEventHandler', () => {
let itemRepositoryResolver: ItemRepositoryResolverInterface
let itemRepository: ItemRepositoryInterface
let logger: Logger
let event: AccountDeletionRequestedEvent
let item: Item
const createHandler = () => new AccountDeletionRequestedEventHandler(itemRepositoryResolver, logger)
beforeEach(() => {
item = Item.create(
{
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
updatedWithSession: null,
content: 'foobar',
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
encItemKey: null,
authHash: null,
itemsKeyId: null,
duplicateOf: null,
deleted: false,
dates: Dates.create(new Date(1616164633241311), new Date(1616164633241311)).getValue(),
timestamps: Timestamps.create(1616164633241311, 1616164633241311).getValue(),
},
new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
).getValue()
itemRepository = {} as jest.Mocked<ItemRepositoryInterface>
itemRepository.findAll = jest.fn().mockReturnValue([item])
itemRepository.deleteByUserUuid = jest.fn()
itemRepositoryResolver = {} as jest.Mocked<ItemRepositoryResolverInterface>
itemRepositoryResolver.resolve = jest.fn().mockReturnValue(itemRepository)
logger = {} as jest.Mocked<Logger>
logger.info = jest.fn()
event = {} as jest.Mocked<AccountDeletionRequestedEvent>
event.createdAt = new Date(1)
event.payload = {
userUuid: '2-3-4',
userCreatedAtTimestamp: 1,
regularSubscriptionUuid: '1-2-3',
roleNames: ['CORE_USER'],
}
})
it('should remove all items for a user', async () => {
await createHandler().handle(event)
expect(itemRepository.deleteByUserUuid).toHaveBeenCalledWith('2-3-4')
})
it('should do nothing if role names are not valid', async () => {
event.payload.roleNames = ['INVALID_ROLE_NAME']
await createHandler().handle(event)
expect(itemRepository.deleteByUserUuid).not.toHaveBeenCalled()
})
})
@@ -3,10 +3,12 @@ import { RoleNameCollection } from '@standardnotes/domain-core'
import { Logger } from 'winston'
import { ItemRepositoryResolverInterface } from '../Item/ItemRepositoryResolverInterface'
import { DeleteSharedVaults } from '../UseCase/SharedVaults/DeleteSharedVaults/DeleteSharedVaults'
export class AccountDeletionRequestedEventHandler implements DomainEventHandlerInterface {
constructor(
private itemRepositoryResolver: ItemRepositoryResolverInterface,
private deleteSharedVaults: DeleteSharedVaults,
private logger: Logger,
) {}
@@ -21,6 +23,15 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
await itemRepository.deleteByUserUuid(event.payload.userUuid)
const result = await this.deleteSharedVaults.execute({
ownerUuid: event.payload.userUuid,
})
if (result.isFailed()) {
this.logger.error(`Failed to delete shared vaults for user: ${event.payload.userUuid}: ${result.getError()}`)
return
}
this.logger.info(`Finished account cleanup for user: ${event.payload.userUuid}`)
}
}
@@ -3,6 +3,7 @@ import { SharedVault } from './SharedVault'
export interface SharedVaultRepositoryInterface {
findByUuid(uuid: Uuid): Promise<SharedVault | null>
findByUserUuid(userUuid: Uuid): Promise<SharedVault[]>
countByUserUuid(userUuid: Uuid): Promise<number>
findByUuids(uuids: Uuid[], lastSyncTime?: number): Promise<SharedVault[]>
save(sharedVault: SharedVault): Promise<void>
@@ -6,7 +6,7 @@ export interface SharedVaultInviteRepositoryInterface {
findByUuid(sharedVaultInviteUuid: Uuid): Promise<SharedVaultInvite | null>
save(sharedVaultInvite: SharedVaultInvite): Promise<void>
remove(sharedVaultInvite: SharedVaultInvite): Promise<void>
removeBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<void>
findBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<SharedVaultInvite[]>
findByUserUuid(userUuid: Uuid): Promise<SharedVaultInvite[]>
findByUserUuidUpdatedAfter(userUuid: Uuid, updatedAtTimestamp: number): Promise<SharedVaultInvite[]>
findBySenderUuid(senderUuid: Uuid): Promise<SharedVaultInvite[]>
@@ -1,13 +1,15 @@
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { NotificationPayload, Result, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { DeclineInviteToSharedVault } from './DeclineInviteToSharedVault'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { AddNotificationForUser } from '../../Messaging/AddNotificationForUser/AddNotificationForUser'
describe('DeclineInviteToSharedVault', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
let invite: SharedVaultInvite
let addNotificationForUser: AddNotificationForUser
const createUseCase = () => new DeclineInviteToSharedVault(sharedVaultInviteRepository)
const createUseCase = () => new DeclineInviteToSharedVault(sharedVaultInviteRepository, addNotificationForUser)
beforeEach(() => {
invite = SharedVaultInvite.create({
@@ -22,6 +24,9 @@ describe('DeclineInviteToSharedVault', () => {
sharedVaultInviteRepository = {} as jest.Mocked<SharedVaultInviteRepositoryInterface>
sharedVaultInviteRepository.findByUuid = jest.fn().mockResolvedValue(invite)
sharedVaultInviteRepository.remove = jest.fn()
addNotificationForUser = {} as jest.Mocked<AddNotificationForUser>
addNotificationForUser.execute = jest.fn().mockReturnValue(Result.ok())
})
it('should fail if invite uuid is invalid', async () => {
@@ -36,6 +41,37 @@ describe('DeclineInviteToSharedVault', () => {
expect(result.getError()).toBe('Given value is not a valid uuid: invalid')
})
it('should fail if adding a notification for user fails', async () => {
addNotificationForUser.execute = jest.fn().mockReturnValue(Result.fail('Error'))
const useCase = createUseCase()
const result = await useCase.execute({
inviteUuid: '00000000-0000-0000-0000-000000000000',
userUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Error')
})
it('should return error if notification payload could not be created', async () => {
const mock = jest.spyOn(NotificationPayload, 'create')
mock.mockReturnValue(Result.fail('Oops'))
const useCase = createUseCase()
const result = await useCase.execute({
inviteUuid: '00000000-0000-0000-0000-000000000000',
userUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Oops')
mock.mockRestore()
})
it('should fail if originator uuid is invalid', async () => {
const useCase = createUseCase()
@@ -1,9 +1,14 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { NotificationPayload, NotificationType, Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { DeclineInviteToSharedVaultDTO } from './DeclineInviteToSharedVaultDTO'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { AddNotificationForUser } from '../../Messaging/AddNotificationForUser/AddNotificationForUser'
export class DeclineInviteToSharedVault implements UseCaseInterface<void> {
constructor(private sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface) {}
constructor(
private sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface,
private addNotificationForUser: AddNotificationForUser,
) {}
async execute(dto: DeclineInviteToSharedVaultDTO): Promise<Result<void>> {
const inviteUuidOrError = Uuid.create(dto.inviteUuid)
@@ -29,6 +34,26 @@ export class DeclineInviteToSharedVault implements UseCaseInterface<void> {
await this.sharedVaultInviteRepository.remove(invite)
const notificationPayloadOrError = NotificationPayload.create({
sharedVaultUuid: invite.props.sharedVaultUuid,
type: NotificationType.create(NotificationType.TYPES.SharedVaultInviteDeclined).getValue(),
version: '1.0',
})
if (notificationPayloadOrError.isFailed()) {
return Result.fail(notificationPayloadOrError.getError())
}
const notificationPayload = notificationPayloadOrError.getValue()
const result = await this.addNotificationForUser.execute({
userUuid: invite.props.userUuid.value,
type: NotificationType.TYPES.SharedVaultInviteDeclined,
payload: notificationPayload,
version: '1.0',
})
if (result.isFailed()) {
return Result.fail(result.getError())
}
return Result.ok()
}
}
@@ -6,14 +6,18 @@ import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/Sh
import { DeleteSharedVault } from './DeleteSharedVault'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
describe('DeleteSharedVault', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
let removeUserFromSharedVault: RemoveUserFromSharedVault
let declineInviteToSharedVault: DeclineInviteToSharedVault
let sharedVault: SharedVault
let sharedVaultUser: SharedVaultUser
let sharedVaultInvite: SharedVaultInvite
const createUseCase = () =>
new DeleteSharedVault(
@@ -21,6 +25,7 @@ describe('DeleteSharedVault', () => {
sharedVaultUserRepository,
sharedVaultInviteRepository,
removeUserFromSharedVault,
declineInviteToSharedVault,
)
beforeEach(() => {
@@ -42,8 +47,19 @@ describe('DeleteSharedVault', () => {
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
sharedVaultUserRepository.findBySharedVaultUuid = jest.fn().mockResolvedValue([sharedVaultUser])
sharedVaultInvite = SharedVaultInvite.create({
encryptedMessage: 'test',
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
senderUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
sharedVaultInviteRepository = {} as jest.Mocked<SharedVaultInviteRepositoryInterface>
sharedVaultInviteRepository.removeBySharedVaultUuid = jest.fn()
sharedVaultInviteRepository.findBySharedVaultUuid = jest.fn().mockReturnValue([sharedVaultInvite])
declineInviteToSharedVault = {} as jest.Mocked<DeclineInviteToSharedVault>
declineInviteToSharedVault.execute = jest.fn().mockReturnValue(Result.ok())
removeUserFromSharedVault = {} as jest.Mocked<RemoveUserFromSharedVault>
removeUserFromSharedVault.execute = jest.fn().mockReturnValue(Result.ok())
@@ -59,7 +75,7 @@ describe('DeleteSharedVault', () => {
expect(result.isFailed()).toBeFalsy()
expect(sharedVaultRepository.remove).toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).toHaveBeenCalled()
expect(declineInviteToSharedVault.execute).toHaveBeenCalled()
expect(removeUserFromSharedVault.execute).toHaveBeenCalled()
})
@@ -74,7 +90,7 @@ describe('DeleteSharedVault', () => {
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.remove).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(declineInviteToSharedVault.execute).not.toHaveBeenCalled()
expect(removeUserFromSharedVault.execute).not.toHaveBeenCalled()
})
@@ -88,7 +104,7 @@ describe('DeleteSharedVault', () => {
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.remove).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(declineInviteToSharedVault.execute).not.toHaveBeenCalled()
expect(removeUserFromSharedVault.execute).not.toHaveBeenCalled()
})
@@ -102,7 +118,7 @@ describe('DeleteSharedVault', () => {
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.remove).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(declineInviteToSharedVault.execute).not.toHaveBeenCalled()
expect(removeUserFromSharedVault.execute).not.toHaveBeenCalled()
})
@@ -122,7 +138,7 @@ describe('DeleteSharedVault', () => {
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.remove).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(declineInviteToSharedVault.execute).not.toHaveBeenCalled()
expect(removeUserFromSharedVault.execute).not.toHaveBeenCalled()
})
@@ -137,7 +153,22 @@ describe('DeleteSharedVault', () => {
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.remove).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(declineInviteToSharedVault.execute).not.toHaveBeenCalled()
expect(removeUserFromSharedVault.execute).toHaveBeenCalled()
})
it('should return error if declining invite to shared vault fails', async () => {
declineInviteToSharedVault.execute = jest.fn().mockReturnValue(Result.fail('failed'))
const useCase = createUseCase()
const result = await useCase.execute({
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
originatorUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.remove).not.toHaveBeenCalled()
expect(declineInviteToSharedVault.execute).toHaveBeenCalled()
expect(removeUserFromSharedVault.execute).toHaveBeenCalled()
})
})
@@ -5,6 +5,7 @@ import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVault
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
export class DeleteSharedVault implements UseCaseInterface<void> {
constructor(
@@ -12,6 +13,7 @@ export class DeleteSharedVault implements UseCaseInterface<void> {
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
private sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface,
private removeUserFromSharedVault: RemoveUserFromSharedVault,
private declineInviteToSharedVault: DeclineInviteToSharedVault,
) {}
async execute(dto: DeleteSharedVaultDTO): Promise<Result<void>> {
@@ -50,7 +52,17 @@ export class DeleteSharedVault implements UseCaseInterface<void> {
}
}
await this.sharedVaultInviteRepository.removeBySharedVaultUuid(sharedVaultUuid)
const sharedVaultInvites = await this.sharedVaultInviteRepository.findBySharedVaultUuid(sharedVaultUuid)
for (const sharedVaultInvite of sharedVaultInvites) {
const result = await this.declineInviteToSharedVault.execute({
inviteUuid: sharedVaultInvite.id.toString(),
userUuid: sharedVaultInvite.props.userUuid.value,
})
if (result.isFailed()) {
return Result.fail(result.getError())
}
}
await this.sharedVaultRepository.remove(sharedVault)
@@ -0,0 +1,72 @@
import { Result, Timestamps, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { DeleteSharedVault } from '../DeleteSharedVault/DeleteSharedVault'
import { DeleteSharedVaults } from './DeleteSharedVaults'
describe('DeleteSharedVaults', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface
let deleteSharedVaultUseCase: DeleteSharedVault
let sharedVault: SharedVault
const createUseCase = () => new DeleteSharedVaults(sharedVaultRepository, deleteSharedVaultUseCase)
beforeEach(() => {
sharedVault = SharedVault.create(
{
fileUploadBytesUsed: 2,
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
},
new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
).getValue()
sharedVaultRepository = {} as jest.Mocked<SharedVaultRepositoryInterface>
sharedVaultRepository.findByUserUuid = jest.fn().mockResolvedValue([sharedVault])
deleteSharedVaultUseCase = {} as jest.Mocked<DeleteSharedVault>
deleteSharedVaultUseCase.execute = jest.fn().mockResolvedValue(Result.ok())
})
it('should delete all shared vaults for a user', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
ownerUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(false)
expect(sharedVaultRepository.findByUserUuid).toHaveBeenCalled()
expect(deleteSharedVaultUseCase.execute).toHaveBeenCalledWith({
originatorUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
})
})
it('should return error if delete shared vault fails', async () => {
deleteSharedVaultUseCase.execute = jest.fn().mockResolvedValue(Result.fail('error'))
const useCase = createUseCase()
const result = await useCase.execute({
ownerUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(true)
expect(sharedVaultRepository.findByUserUuid).toHaveBeenCalled()
expect(deleteSharedVaultUseCase.execute).toHaveBeenCalledWith({
originatorUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
})
})
it('should return error if owner uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
ownerUuid: 'invalid',
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.findByUserUuid).not.toHaveBeenCalled()
expect(deleteSharedVaultUseCase.execute).not.toHaveBeenCalled()
})
})
@@ -0,0 +1,34 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { DeleteSharedVaultsDTO } from './DeleteSharedVaultsDTO'
import { DeleteSharedVault } from '../DeleteSharedVault/DeleteSharedVault'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
export class DeleteSharedVaults implements UseCaseInterface<void> {
constructor(
private sharedVaultRepository: SharedVaultRepositoryInterface,
private deleteSharedVaultUseCase: DeleteSharedVault,
) {}
async execute(dto: DeleteSharedVaultsDTO): Promise<Result<void>> {
const ownerUuidOrError = Uuid.create(dto.ownerUuid)
if (ownerUuidOrError.isFailed()) {
return Result.fail(ownerUuidOrError.getError())
}
const ownerUuid = ownerUuidOrError.getValue()
const sharedVaults = await this.sharedVaultRepository.findByUserUuid(ownerUuid)
for (const sharedVault of sharedVaults) {
const result = await this.deleteSharedVaultUseCase.execute({
originatorUuid: ownerUuid.value,
sharedVaultUuid: sharedVault.id.toString(),
})
if (result.isFailed()) {
return Result.fail(result.getError())
}
}
return Result.ok()
}
}
@@ -0,0 +1,3 @@
export interface DeleteSharedVaultsDTO {
ownerUuid: string
}
@@ -64,13 +64,13 @@ export class TypeORMSharedVaultInviteRepository implements SharedVaultInviteRepo
return persistence.map((p) => this.mapper.toDomain(p))
}
async removeBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<void> {
await this.ormRepository
async findBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<SharedVaultInvite[]> {
const persistence = await this.ormRepository
.createQueryBuilder('shared_vault_invite')
.delete()
.from('shared_vault_invites')
.where('shared_vault_uuid = :sharedVaultUuid', { sharedVaultUuid: sharedVaultUuid.value })
.execute()
.where('shared_vault_invite.shared_vault_uuid = :sharedVaultUuid', { sharedVaultUuid: sharedVaultUuid.value })
.getMany()
return persistence.map((p) => this.mapper.toDomain(p))
}
async findByUserUuidAndSharedVaultUuid(dto: {
@@ -11,6 +11,17 @@ export class TypeORMSharedVaultRepository implements SharedVaultRepositoryInterf
private mapper: MapperInterface<SharedVault, TypeORMSharedVault>,
) {}
async findByUserUuid(userUuid: Uuid): Promise<SharedVault[]> {
const persistence = await this.ormRepository
.createQueryBuilder('shared_vault')
.where('shared_vault.user_uuid = :userUuid', {
userUuid: userUuid.value,
})
.getMany()
return persistence.map((p) => this.mapper.toDomain(p))
}
async countByUserUuid(userUuid: Uuid): Promise<number> {
const count = await this.ormRepository
.createQueryBuilder('shared_vault')
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.10.47](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.46...@standardnotes/websockets-server@1.10.47) (2023-09-20)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.10.46](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.45...@standardnotes/websockets-server@1.10.46) (2023-09-19)
**Note:** Version bump only for package @standardnotes/websockets-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/websockets-server",
"version": "1.10.46",
"version": "1.10.47",
"engines": {
"node": ">=18.0.0 <21.0.0"
},