Compare commits

...

4 Commits

51 changed files with 509 additions and 19 deletions

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.24.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.5...@standardnotes/analytics@2.24.6) (2023-07-05)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.4...@standardnotes/analytics@2.24.5) (2023-06-30)
**Note:** Version bump only for package @standardnotes/analytics

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "2.24.5",
"version": "2.24.6",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

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.65.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.2...@standardnotes/api-gateway@1.65.3) (2023-07-05)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.65.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.1...@standardnotes/api-gateway@1.65.2) (2023-06-30)
**Note:** Version bump only for package @standardnotes/api-gateway

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.65.2",
"version": "1.65.3",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

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.122.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.121.0...@standardnotes/auth-server@1.122.0) (2023-07-05)
### Features
* deleting shared vaults. ([#640](https://github.com/standardnotes/server/issues/640)) ([f3161c2](https://github.com/standardnotes/server/commit/f3161c271296159331639814b2dbb2e566cc54c9))
# [1.121.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.120.2...@standardnotes/auth-server@1.121.0) (2023-07-05)
### Features

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.121.0",
"version": "1.122.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -1,7 +1,6 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { NotificationType, Timestamps, Uuid } from '@standardnotes/domain-core'
import { Notification } from './Notification'
import { NotificationType } from './NotificationType'
describe('Notification', () => {
it('should create an entity', () => {

View File

@@ -1,5 +1,4 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { NotificationType } from './NotificationType'
import { NotificationType, Timestamps, Uuid } from '@standardnotes/domain-core'
export interface NotificationProps {
userUuid: Uuid

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.20.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.19.0...@standardnotes/domain-core@1.20.0) (2023-07-05)
### Features
* deleting shared vaults. ([#640](https://github.com/standardnotes/server/issues/640)) ([f3161c2](https://github.com/standardnotes/server/commit/f3161c271296159331639814b2dbb2e566cc54c9))
# [1.19.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.18.0...@standardnotes/domain-core@1.19.0) (2023-06-30)
### Features

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-core",
"version": "1.19.0",
"version": "1.20.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -1,4 +1,5 @@
import { Result, ValueObject } from '@standardnotes/domain-core'
import { Result } from '../Core/Result'
import { ValueObject } from '../Core/ValueObject'
import { NotificationTypeProps } from './NotificationTypeProps'

View File

@@ -43,6 +43,9 @@ export * from './Env/AbstractEnv'
export * from './Mapping/MapperInterface'
export * from './Notification/NotificationType'
export * from './Notification/NotificationTypeProps'
export * from './Service/ServiceConfiguration'
export * from './Service/ServiceContainer'
export * from './Service/ServiceContainerInterface'

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.12.8](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.7...@standardnotes/domain-events-infra@1.12.8) (2023-07-05)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.12.7](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.6...@standardnotes/domain-events-infra@1.12.7) (2023-06-30)
**Note:** Version bump only for package @standardnotes/domain-events-infra

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events-infra",
"version": "1.12.7",
"version": "1.12.8",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

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.
# [2.113.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.112.1...@standardnotes/domain-events@2.113.0) (2023-07-05)
### Features
* deleting shared vaults. ([#640](https://github.com/standardnotes/server/issues/640)) ([f3161c2](https://github.com/standardnotes/server/commit/f3161c271296159331639814b2dbb2e566cc54c9))
## [2.112.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.112.0...@standardnotes/domain-events@2.112.1) (2023-06-30)
**Note:** Version bump only for package @standardnotes/domain-events

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events",
"version": "2.112.1",
"version": "2.113.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -0,0 +1,7 @@
import { DomainEventInterface } from './DomainEventInterface'
import { NotificationRequestedEventPayload } from './NotificationRequestedEventPayload'
export interface NotificationRequestedEvent extends DomainEventInterface {
type: 'NOTIFICATION_REQUESTED'
payload: NotificationRequestedEventPayload
}

View File

@@ -0,0 +1,5 @@
export interface NotificationRequestedEventPayload {
userUuid: string
type: string
payload: string
}

View File

@@ -42,6 +42,8 @@ export * from './Event/ListedAccountRequestedEvent'
export * from './Event/ListedAccountRequestedEventPayload'
export * from './Event/MuteEmailsSettingChangedEvent'
export * from './Event/MuteEmailsSettingChangedEventPayload'
export * from './Event/NotificationRequestedEvent'
export * from './Event/NotificationRequestedEventPayload'
export * from './Event/PaymentFailedEvent'
export * from './Event/PaymentFailedEventPayload'
export * from './Event/PaymentSuccessEvent'

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.3](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.2...@standardnotes/event-store@1.11.3) (2023-07-05)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.2](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.1...@standardnotes/event-store@1.11.2) (2023-06-30)
**Note:** Version bump only for package @standardnotes/event-store

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/event-store",
"version": "1.11.2",
"version": "1.11.3",
"description": "Event Store Service",
"private": true,
"main": "dist/src/index.js",

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.19.3](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.2...@standardnotes/files-server@1.19.3) (2023-07-05)
**Note:** Version bump only for package @standardnotes/files-server
## [1.19.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.1...@standardnotes/files-server@1.19.2) (2023-06-30)
**Note:** Version bump only for package @standardnotes/files-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files-server",
"version": "1.19.2",
"version": "1.19.3",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

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.11.25](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.24...@standardnotes/home-server@1.11.25) (2023-07-05)
**Note:** Version bump only for package @standardnotes/home-server
## [1.11.24](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.23...@standardnotes/home-server@1.11.24) (2023-07-05)
**Note:** Version bump only for package @standardnotes/home-server
## [1.11.23](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.22...@standardnotes/home-server@1.11.23) (2023-07-05)
**Note:** Version bump only for package @standardnotes/home-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/home-server",
"version": "1.11.23",
"version": "1.11.25",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

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.23.7](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.23.6...@standardnotes/revisions-server@1.23.7) (2023-07-05)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.23.6](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.23.5...@standardnotes/revisions-server@1.23.6) (2023-06-30)
**Note:** Version bump only for package @standardnotes/revisions-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/revisions-server",
"version": "1.23.6",
"version": "1.23.7",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

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.5](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.4...@standardnotes/scheduler-server@1.20.5) (2023-07-05)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.20.4](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.3...@standardnotes/scheduler-server@1.20.4) (2023-06-30)
**Note:** Version bump only for package @standardnotes/scheduler-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/scheduler-server",
"version": "1.20.4",
"version": "1.20.5",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

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.10](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.9...@standardnotes/settings@1.21.10) (2023-07-05)
**Note:** Version bump only for package @standardnotes/settings
## [1.21.9](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.8...@standardnotes/settings@1.21.9) (2023-06-30)
**Note:** Version bump only for package @standardnotes/settings

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/settings",
"version": "1.21.9",
"version": "1.21.10",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

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.52.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.51.0...@standardnotes/syncing-server@1.52.0) (2023-07-05)
### Features
* deleting shared vaults. ([#640](https://github.com/standardnotes/syncing-server-js/issues/640)) ([f3161c2](https://github.com/standardnotes/syncing-server-js/commit/f3161c271296159331639814b2dbb2e566cc54c9))
# [1.51.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.50.0...@standardnotes/syncing-server@1.51.0) (2023-07-05)
### Features
* add getting shared vaults for a user ([#639](https://github.com/standardnotes/syncing-server-js/issues/639)) ([d2b2c33](https://github.com/standardnotes/syncing-server-js/commit/d2b2c339f2089ea5d538ee40118af083983be5ef))
# [1.50.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.49.0...@standardnotes/syncing-server@1.50.0) (2023-07-03)
### Features

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/syncing-server",
"version": "1.50.0",
"version": "1.52.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -5,6 +5,7 @@ import {
EmailRequestedEvent,
ItemDumpedEvent,
ItemRevisionCreationRequestedEvent,
NotificationRequestedEvent,
RevisionsCopyRequestedEvent,
} from '@standardnotes/domain-events'
import { TimerInterface } from '@standardnotes/time'
@@ -13,6 +14,25 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
export class DomainEventFactory implements DomainEventFactoryInterface {
constructor(private timer: TimerInterface) {}
createNotificationRequestedEvent(dto: {
userUuid: string
type: string
payload: string
}): NotificationRequestedEvent {
return {
type: 'NOTIFICATION_REQUESTED',
createdAt: this.timer.getUTCDate(),
meta: {
correlation: {
userIdentifier: dto.userUuid,
userIdentifierType: 'uuid',
},
origin: DomainEventService.SyncingServer,
},
payload: dto,
}
}
createRevisionsCopyRequestedEvent(
userUuid: string,
dto: {

View File

@@ -3,10 +3,12 @@ import {
EmailRequestedEvent,
ItemDumpedEvent,
ItemRevisionCreationRequestedEvent,
NotificationRequestedEvent,
RevisionsCopyRequestedEvent,
} from '@standardnotes/domain-events'
export interface DomainEventFactoryInterface {
createNotificationRequestedEvent(dto: { userUuid: string; type: string; payload: string }): NotificationRequestedEvent
createEmailRequestedEvent(dto: {
userEmail: string
messageIdentifier: string

View File

@@ -3,6 +3,7 @@ import { SharedVault } from './SharedVault'
export interface SharedVaultRepositoryInterface {
findByUuid(uuid: Uuid): Promise<SharedVault | null>
findByUuids(uuids: Uuid[], lastSyncTime?: number): Promise<SharedVault[]>
save(sharedVault: SharedVault): Promise<void>
remove(sharedVault: SharedVault): Promise<void>
}

View File

@@ -6,5 +6,6 @@ export interface SharedVaultInviteRepositoryInterface {
findByUuid(sharedVaultInviteUuid: Uuid): Promise<SharedVaultInvite | null>
save(sharedVaultInvite: SharedVaultInvite): Promise<void>
remove(sharedVaultInvite: SharedVaultInvite): Promise<void>
removeBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<void>
findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultInvite | null>
}

View File

@@ -4,7 +4,10 @@ import { SharedVaultUser } from './SharedVaultUser'
export interface SharedVaultUserRepositoryInterface {
findByUuid(sharedVaultUserUuid: Uuid): Promise<SharedVaultUser | null>
findByUserUuid(userUuid: Uuid): Promise<SharedVaultUser[]>
findBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<SharedVaultUser[]>
save(sharedVaultUser: SharedVaultUser): Promise<void>
remove(sharedVault: SharedVaultUser): Promise<void>
removeBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<void>
findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultUser | null>
}

View File

@@ -0,0 +1,146 @@
import { DomainEventPublisherInterface, NotificationRequestedEvent } from '@standardnotes/domain-events'
import { Uuid, Timestamps } from '@standardnotes/domain-core'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { DeleteSharedVault } from './DeleteSharedVault'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
describe('DeleteSharedVault', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
let domainEventPublisher: DomainEventPublisherInterface
let domainEventFactory: DomainEventFactoryInterface
let sharedVault: SharedVault
let sharedVaultUser: SharedVaultUser
const createUseCase = () =>
new DeleteSharedVault(
sharedVaultRepository,
sharedVaultUserRepository,
sharedVaultInviteRepository,
domainEventPublisher,
domainEventFactory,
)
beforeEach(() => {
sharedVault = SharedVault.create({
fileUploadBytesLimit: 100,
fileUploadBytesUsed: 2,
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
sharedVaultRepository = {} as jest.Mocked<SharedVaultRepositoryInterface>
sharedVaultRepository.findByUuid = jest.fn().mockResolvedValue(sharedVault)
sharedVaultRepository.remove = jest.fn()
sharedVaultUser = SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).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(),
}).getValue()
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
sharedVaultUserRepository.findBySharedVaultUuid = jest.fn().mockResolvedValue([sharedVaultUser])
sharedVaultUserRepository.removeBySharedVaultUuid = jest.fn()
sharedVaultInviteRepository = {} as jest.Mocked<SharedVaultInviteRepositoryInterface>
sharedVaultInviteRepository.removeBySharedVaultUuid = jest.fn()
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
domainEventPublisher.publish = jest.fn()
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
domainEventFactory.createNotificationRequestedEvent = jest
.fn()
.mockReturnValue({} as jest.Mocked<NotificationRequestedEvent>)
})
it('should remove shared vault', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
originatorUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeFalsy()
expect(sharedVaultRepository.remove).toHaveBeenCalled()
expect(sharedVaultUserRepository.removeBySharedVaultUuid).toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).toHaveBeenCalled()
expect(domainEventPublisher.publish).toHaveBeenCalled()
})
it('should return error when shared vault does not exist', async () => {
sharedVaultRepository.findByUuid = jest.fn().mockResolvedValue(null)
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(sharedVaultUserRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
})
it('should return error when shared vault uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
sharedVaultUuid: 'invalid',
originatorUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.remove).not.toHaveBeenCalled()
expect(sharedVaultUserRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
})
it('should return error when originator uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
originatorUuid: 'invalid',
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultRepository.remove).not.toHaveBeenCalled()
expect(sharedVaultUserRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
})
it('should return error when originator of the delete request is not the owner of the shared vault', async () => {
sharedVault = SharedVault.create({
fileUploadBytesLimit: 100,
fileUploadBytesUsed: 2,
userUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
sharedVaultRepository.findByUuid = jest.fn().mockResolvedValue(sharedVault)
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(sharedVaultUserRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(sharedVaultInviteRepository.removeBySharedVaultUuid).not.toHaveBeenCalled()
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
})
})

View File

@@ -0,0 +1,62 @@
import { NotificationType, Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { DeleteSharedVaultDTO } from './DeleteSharedVaultDTO'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
export class DeleteSharedVault implements UseCaseInterface<void> {
constructor(
private sharedVaultRepository: SharedVaultRepositoryInterface,
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
private sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface,
private domainEventPublisher: DomainEventPublisherInterface,
private domainEventFactory: DomainEventFactoryInterface,
) {}
async execute(dto: DeleteSharedVaultDTO): Promise<Result<void>> {
const originatorUuidOrError = Uuid.create(dto.originatorUuid)
if (originatorUuidOrError.isFailed()) {
return Result.fail(originatorUuidOrError.getError())
}
const originatorUuid = originatorUuidOrError.getValue()
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
if (sharedVaultUuidOrError.isFailed()) {
return Result.fail(sharedVaultUuidOrError.getError())
}
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
const sharedVault = await this.sharedVaultRepository.findByUuid(sharedVaultUuid)
if (!sharedVault) {
return Result.fail('Shared vault not found')
}
if (sharedVault.props.userUuid.value !== originatorUuid.value) {
return Result.fail('Shared vault does not belong to the user')
}
const sharedVaultUsers = await this.sharedVaultUserRepository.findBySharedVaultUuid(sharedVaultUuid)
for (const sharedVaultUser of sharedVaultUsers) {
await this.domainEventPublisher.publish(
this.domainEventFactory.createNotificationRequestedEvent({
payload: JSON.stringify({
sharedVaultUuid: sharedVault.id.toString(),
version: '1.0',
}),
userUuid: sharedVaultUser.props.userUuid.value,
type: NotificationType.TYPES.RemovedFromSharedVault,
}),
)
}
await this.sharedVaultInviteRepository.removeBySharedVaultUuid(sharedVaultUuid)
await this.sharedVaultUserRepository.removeBySharedVaultUuid(sharedVaultUuid)
await this.sharedVaultRepository.remove(sharedVault)
return Result.ok()
}
}

View File

@@ -0,0 +1,4 @@
export interface DeleteSharedVaultDTO {
originatorUuid: string
sharedVaultUuid: string
}

View File

@@ -0,0 +1,68 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { GetSharedVaults } from './GetSharedVaults'
describe('GetSharedVaults', () => {
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
let sharedVaultRepository: SharedVaultRepositoryInterface
let sharedVault: SharedVault
let sharedVaultUser: SharedVaultUser
const createUseCase = () => new GetSharedVaults(sharedVaultUserRepository, sharedVaultRepository)
beforeEach(() => {
sharedVaultUser = SharedVaultUser.create({
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Admin).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
sharedVaultUserRepository.findByUserUuid = jest.fn().mockResolvedValue([sharedVaultUser])
sharedVault = SharedVault.create({
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
fileUploadBytesLimit: 123,
fileUploadBytesUsed: 123,
}).getValue()
sharedVaultRepository = {} as jest.Mocked<SharedVaultRepositoryInterface>
sharedVaultRepository.findByUuids = jest.fn().mockResolvedValue([sharedVault])
})
it('returns shared vaults', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.getValue()).toEqual([sharedVault])
})
it('returns empty array if no shared vaults found', async () => {
sharedVaultUserRepository.findByUserUuid = jest.fn().mockResolvedValue([])
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.getValue()).toEqual([])
})
it('returns error if user uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: 'invalid',
})
expect(result.isFailed()).toBeTruthy()
})
})

View File

@@ -0,0 +1,35 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVault } from '../../SharedVault/SharedVault'
import { GetSharedVaultsDTO } from './GetSharedVaultsDTO'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
export class GetSharedVaults implements UseCaseInterface<SharedVault[]> {
constructor(
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
private sharedVaultRepository: SharedVaultRepositoryInterface,
) {}
async execute(dto: GetSharedVaultsDTO): Promise<Result<SharedVault[]>> {
const userUuidOrError = Uuid.create(dto.userUuid)
if (userUuidOrError.isFailed()) {
return Result.fail(userUuidOrError.getError())
}
const userUuid = userUuidOrError.getValue()
const ownedSharedVaultsAssociations = await this.sharedVaultUserRepository.findByUserUuid(userUuid)
const sharedVaultUuids = ownedSharedVaultsAssociations.map(
(sharedVaultUser) => sharedVaultUser.props.sharedVaultUuid,
)
if (sharedVaultUuids.length === 0) {
return Result.ok([])
}
const sharedVaults = await this.sharedVaultRepository.findByUuids(sharedVaultUuids, dto.lastSyncTime)
return Result.ok(sharedVaults)
}
}

View File

@@ -0,0 +1,4 @@
export interface GetSharedVaultsDTO {
userUuid: string
lastSyncTime?: number
}

View File

@@ -11,6 +11,15 @@ export class TypeORMSharedVaultInviteRepository implements SharedVaultInviteRepo
private mapper: MapperInterface<SharedVaultInvite, TypeORMSharedVaultInvite>,
) {}
async removeBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<void> {
await this.ormRepository
.createQueryBuilder('shared_vault_invite')
.delete()
.from('shared_vault_invites')
.where('shared_vault_uuid = :sharedVaultUuid', { sharedVaultUuid: sharedVaultUuid.value })
.execute()
}
async findByUserUuidAndSharedVaultUuid(dto: {
userUuid: Uuid
sharedVaultUuid: Uuid

View File

@@ -11,6 +11,20 @@ export class TypeORMSharedVaultRepository implements SharedVaultRepositoryInterf
private mapper: MapperInterface<SharedVault, TypeORMSharedVault>,
) {}
async findByUuids(uuids: Uuid[], lastSyncTime?: number | undefined): Promise<SharedVault[]> {
const queryBuilder = await this.ormRepository
.createQueryBuilder('shared_vault')
.where('shared_vault.uuid IN (:...sharedVaultUuids)', { sharedVaultUuids: uuids.map((uuid) => uuid.value) })
if (lastSyncTime !== undefined) {
queryBuilder.andWhere('shared_vault.updated_at_timestamp > :lastSyncTime', { lastSyncTime })
}
const persistence = await queryBuilder.getMany()
return persistence.map((p) => this.mapper.toDomain(p))
}
async save(sharedVault: SharedVault): Promise<void> {
const persistence = this.mapper.toProjection(sharedVault)

View File

@@ -11,6 +11,37 @@ export class TypeORMSharedVaultUserRepository implements SharedVaultUserReposito
private mapper: MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>,
) {}
async removeBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<void> {
await this.ormRepository
.createQueryBuilder('shared_vault_user')
.delete()
.from('shared_vault_users')
.where('shared_vault_uuid = :sharedVaultUuid', { sharedVaultUuid: sharedVaultUuid.value })
.execute()
}
async findBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<SharedVaultUser[]> {
const persistence = await this.ormRepository
.createQueryBuilder('shared_vault_user')
.where('shared_vault_user.shared_vault_uuid = :sharedVaultUuid', {
sharedVaultUuid: sharedVaultUuid.value,
})
.getMany()
return persistence.map((p) => this.mapper.toDomain(p))
}
async findByUserUuid(userUuid: Uuid): Promise<SharedVaultUser[]> {
const persistence = await this.ormRepository
.createQueryBuilder('shared_vault_user')
.where('shared_vault_user.user_uuid = :userUuid', {
userUuid: userUuid.value,
})
.getMany()
return persistence.map((p) => this.mapper.toDomain(p))
}
async findByUserUuidAndSharedVaultUuid(dto: {
userUuid: Uuid
sharedVaultUuid: Uuid

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.9.6](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.9.5...@standardnotes/websockets-server@1.9.6) (2023-07-05)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.9.5](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.9.4...@standardnotes/websockets-server@1.9.5) (2023-06-30)
**Note:** Version bump only for package @standardnotes/websockets-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/websockets-server",
"version": "1.9.5",
"version": "1.9.6",
"engines": {
"node": ">=18.0.0 <21.0.0"
},