Compare commits

...

10 Commits

Author SHA1 Message Date
standardci
c970b1ea68 chore(release): publish new version
- @standardnotes/home-server@1.11.38
 - @standardnotes/syncing-server@1.62.1
2023-07-11 15:22:11 +00:00
Karol Sójko
4d1e2dec26 fix: unify use case usage (#654) 2023-07-11 17:05:45 +02:00
standardci
108408a944 chore(release): publish new version
- @standardnotes/home-server@1.11.37
 - @standardnotes/syncing-server@1.62.0
2023-07-10 12:37:48 +00:00
Karol Sójko
18d07d431f feat: messages controller. (#653)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-10 14:21:59 +02:00
standardci
cbc024f67a chore(release): publish new version
- @standardnotes/home-server@1.11.36
 - @standardnotes/syncing-server@1.61.0
2023-07-10 11:54:54 +00:00
Karol Sójko
55ec5970da feat: message operations use cases. (#652)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-10 13:38:07 +02:00
standardci
58bdca6659 chore(release): publish new version
- @standardnotes/home-server@1.11.35
 - @standardnotes/syncing-server@1.60.0
2023-07-10 11:25:21 +00:00
Karol Sójko
ef49b0d3f8 feat: sending messages. (#651)
* feat: sending messages.

Co-authored-by: Mo <mo@standardnotes.com>

* fix: messages repository.

Co-authored-by: Mo <mo@standardnotes.com>

---------

Co-authored-by: Mo <mo@standardnotes.com>
2023-07-10 13:10:31 +02:00
standardci
9cb691e5ad chore(release): publish new version
- @standardnotes/home-server@1.11.34
 - @standardnotes/syncing-server@1.59.1
2023-07-10 10:58:38 +00:00
Karol Sójko
04d09582d4 fix: restructure use cases (#650) 2023-07-10 12:43:20 +02:00
107 changed files with 1254 additions and 472 deletions

View File

@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.11.38](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.37...@standardnotes/home-server@1.11.38) (2023-07-11)
**Note:** Version bump only for package @standardnotes/home-server
## [1.11.37](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.36...@standardnotes/home-server@1.11.37) (2023-07-10)
**Note:** Version bump only for package @standardnotes/home-server
## [1.11.36](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.35...@standardnotes/home-server@1.11.36) (2023-07-10)
**Note:** Version bump only for package @standardnotes/home-server
## [1.11.35](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.34...@standardnotes/home-server@1.11.35) (2023-07-10)
**Note:** Version bump only for package @standardnotes/home-server
## [1.11.34](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.33...@standardnotes/home-server@1.11.34) (2023-07-10)
**Note:** Version bump only for package @standardnotes/home-server
## [1.11.33](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.32...@standardnotes/home-server@1.11.33) (2023-07-10)
**Note:** Version bump only for package @standardnotes/home-server

View File

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

View File

@@ -3,6 +3,36 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.62.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.62.0...@standardnotes/syncing-server@1.62.1) (2023-07-11)
### Bug Fixes
* unify use case usage ([#654](https://github.com/standardnotes/syncing-server-js/issues/654)) ([4d1e2de](https://github.com/standardnotes/syncing-server-js/commit/4d1e2dec264b156a4cfb4980ca3b486433ce64b7))
# [1.62.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.61.0...@standardnotes/syncing-server@1.62.0) (2023-07-10)
### Features
* messages controller. ([#653](https://github.com/standardnotes/syncing-server-js/issues/653)) ([18d07d4](https://github.com/standardnotes/syncing-server-js/commit/18d07d431f08dc17a276f84c0724935d9014a4fd))
# [1.61.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.60.0...@standardnotes/syncing-server@1.61.0) (2023-07-10)
### Features
* message operations use cases. ([#652](https://github.com/standardnotes/syncing-server-js/issues/652)) ([55ec597](https://github.com/standardnotes/syncing-server-js/commit/55ec5970daff9ef51f59e23eca17b312d392542a))
# [1.60.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.59.1...@standardnotes/syncing-server@1.60.0) (2023-07-10)
### Features
* sending messages. ([#651](https://github.com/standardnotes/syncing-server-js/issues/651)) ([ef49b0d](https://github.com/standardnotes/syncing-server-js/commit/ef49b0d3f8ab76dfa63a4c691feb9f35ad65c46f))
## [1.59.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.59.0...@standardnotes/syncing-server@1.59.1) (2023-07-10)
### Bug Fixes
* restructure use cases ([#650](https://github.com/standardnotes/syncing-server-js/issues/650)) ([04d0958](https://github.com/standardnotes/syncing-server-js/commit/04d09582d4c90706a7c7a4601ce011edf6cbc9c2))
# [1.59.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.58.1...@standardnotes/syncing-server@1.59.0) (2023-07-10)
### Features

View File

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

View File

@@ -41,9 +41,9 @@ import { SyncResponseFactory20161215 } from '../Domain/Item/SyncResponse/SyncRes
import { SyncResponseFactory20200115 } from '../Domain/Item/SyncResponse/SyncResponseFactory20200115'
import { SyncResponseFactoryResolver } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolver'
import { SyncResponseFactoryResolverInterface } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface'
import { CheckIntegrity } from '../Domain/UseCase/CheckIntegrity/CheckIntegrity'
import { GetItem } from '../Domain/UseCase/GetItem/GetItem'
import { SyncItems } from '../Domain/UseCase/SyncItems'
import { CheckIntegrity } from '../Domain/UseCase/Syncing/CheckIntegrity/CheckIntegrity'
import { GetItem } from '../Domain/UseCase/Syncing/GetItem/GetItem'
import { SyncItems } from '../Domain/UseCase/Syncing/SyncItems/SyncItems'
import { InversifyExpressAuthMiddleware } from '../Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware'
import { ItemConflictProjection } from '../Projection/ItemConflictProjection'
import { ItemConflictProjector } from '../Projection/ItemConflictProjector'

View File

@@ -52,7 +52,11 @@ const TYPES = {
Sync_DeleteSharedVaultInvitesSentByUser: Symbol.for('Sync_DeleteSharedVaultInvitesSentByUser'),
Sync_GetSharedVaultInvitesSentByUser: Symbol.for('Sync_GetSharedVaultInvitesSentByUser'),
Sync_GetSharedVaultInvitesSentToUser: Symbol.for('Sync_GetSharedVaultInvitesSentToUser'),
Sync_SharedVaultInviteHttpMapper: Symbol.for('Sync_SharedVaultInviteHttpMapper'),
Sync_GetMessagesSentToUser: Symbol.for('Sync_GetMessagesSentToUser'),
Sync_GetMessagesSentByUser: Symbol.for('Sync_GetMessagesSentByUser'),
Sync_SendMessageToUser: Symbol.for('Sync_SendMessageToUser'),
Sync_DeleteAllMessagesSentToUser: Symbol.for('Sync_DeleteAllMessagesSentToUser'),
Sync_DeleteMessage: Symbol.for('Sync_DeleteMessage'),
// Handlers
Sync_AccountDeletionRequestedEventHandler: Symbol.for('Sync_AccountDeletionRequestedEventHandler'),
Sync_DuplicateItemSyncedEventHandler: Symbol.for('Sync_DuplicateItemSyncedEventHandler'),
@@ -86,6 +90,8 @@ const TYPES = {
// Mapping
Sync_SharedVaultHttpMapper: Symbol.for('Sync_SharedVaultHttpMapper'),
Sync_SharedVaultUserHttpMapper: Symbol.for('Sync_SharedVaultUserHttpMapper'),
Sync_SharedVaultInviteHttpMapper: Symbol.for('Sync_SharedVaultInviteHttpMapper'),
Sync_MessageHttpMapper: Symbol.for('Sync_MessageHttpMapper'),
}
export default TYPES

View File

@@ -1,12 +1,13 @@
import { ConflictType } from '@standardnotes/responses'
import { ProjectorInterface } from '../../../Projection/ProjectorInterface'
import { SyncItemsResponse } from '../../UseCase/SyncItemsResponse'
import { Item } from '../Item'
import { ItemConflict } from '../ItemConflict'
import { ItemHash } from '../ItemHash'
import { ItemProjection } from '../../../Projection/ItemProjection'
import { SyncResponse20161215 } from './SyncResponse20161215'
import { SyncResponseFactoryInterface } from './SyncResponseFactoryInterface'
import { ConflictType } from '@standardnotes/responses'
import { SyncItemsResponse } from '../../UseCase/Syncing/SyncItems/SyncItemsResponse'
export class SyncResponseFactory20161215 implements SyncResponseFactoryInterface {
private readonly LEGACY_MIN_CONFLICT_INTERVAL = 20_000_000

View File

@@ -1,5 +1,4 @@
import { ProjectorInterface } from '../../../Projection/ProjectorInterface'
import { SyncItemsResponse } from '../../UseCase/SyncItemsResponse'
import { Item } from '../Item'
import { ItemConflict } from '../ItemConflict'
import { ItemConflictProjection } from '../../../Projection/ItemConflictProjection'
@@ -7,6 +6,7 @@ import { ItemProjection } from '../../../Projection/ItemProjection'
import { SyncResponse20200115 } from './SyncResponse20200115'
import { SyncResponseFactoryInterface } from './SyncResponseFactoryInterface'
import { SavedItemProjection } from '../../../Projection/SavedItemProjection'
import { SyncItemsResponse } from '../../UseCase/Syncing/SyncItems/SyncItemsResponse'
export class SyncResponseFactory20200115 implements SyncResponseFactoryInterface {
constructor(

View File

@@ -1,4 +1,4 @@
import { SyncItemsResponse } from '../../UseCase/SyncItemsResponse'
import { SyncItemsResponse } from '../../UseCase/Syncing/SyncItems/SyncItemsResponse'
import { SyncResponse20161215 } from './SyncResponse20161215'
import { SyncResponse20200115 } from './SyncResponse20200115'

View File

@@ -0,0 +1,18 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { Message } from './Message'
describe('Message', () => {
it('should create an entity', () => {
const entityOrError = Message.create({
timestamps: Timestamps.create(123456789, 123456789).getValue(),
recipientUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
senderUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
encryptedMessage: 'encryptedMessage',
replaceabilityIdentifier: 'replaceabilityIdentifier',
})
expect(entityOrError.isFailed()).toBeFalsy()
expect(entityOrError.getValue().id).not.toBeNull()
})
})

View File

@@ -4,6 +4,12 @@ import { Message } from './Message'
export interface MessageRepositoryInterface {
findByUuid: (uuid: Uuid) => Promise<Message | null>
findByRecipientUuid: (uuid: Uuid) => Promise<Message[]>
findBySenderUuid: (uuid: Uuid) => Promise<Message[]>
findByRecipientUuidAndReplaceabilityIdentifier: (dto: {
recipientUuid: Uuid
replaceabilityIdentifier: string
}) => Promise<Message | null>
save(message: Message): Promise<void>
remove(message: Message): Promise<void>
}

View File

@@ -1,136 +0,0 @@
import 'reflect-metadata'
import { ItemRepositoryInterface } from '../../Item/ItemRepositoryInterface'
import { CheckIntegrity } from './CheckIntegrity'
import { ContentType } from '@standardnotes/common'
describe('CheckIntegrity', () => {
let itemRepository: ItemRepositoryInterface
const createUseCase = () => new CheckIntegrity(itemRepository)
beforeEach(() => {
itemRepository = {} as jest.Mocked<ItemRepositoryInterface>
itemRepository.findItemsForComputingIntegrityPayloads = jest.fn().mockReturnValue([
{
uuid: '1-2-3',
updated_at_timestamp: 1,
content_type: ContentType.Note,
},
{
uuid: '2-3-4',
updated_at_timestamp: 2,
content_type: ContentType.Note,
},
{
uuid: '3-4-5',
updated_at_timestamp: 3,
content_type: ContentType.Note,
},
{
uuid: '4-5-6',
updated_at_timestamp: 4,
content_type: ContentType.ItemsKey,
},
{
uuid: '5-6-7',
updated_at_timestamp: 5,
content_type: ContentType.File,
},
])
})
it('should return an empty result if there are no integrity mismatches', async () => {
expect(
await createUseCase().execute({
userUuid: '1-2-3',
freeUser: false,
integrityPayloads: [
{
uuid: '1-2-3',
updated_at_timestamp: 1,
},
{
uuid: '2-3-4',
updated_at_timestamp: 2,
},
{
uuid: '3-4-5',
updated_at_timestamp: 3,
},
{
uuid: '5-6-7',
updated_at_timestamp: 5,
},
],
}),
).toEqual({
mismatches: [],
})
})
it('should return a mismatch item that has a different update at timemstap', async () => {
expect(
await createUseCase().execute({
userUuid: '1-2-3',
freeUser: false,
integrityPayloads: [
{
uuid: '1-2-3',
updated_at_timestamp: 1,
},
{
uuid: '2-3-4',
updated_at_timestamp: 1,
},
{
uuid: '3-4-5',
updated_at_timestamp: 3,
},
{
uuid: '5-6-7',
updated_at_timestamp: 5,
},
],
}),
).toEqual({
mismatches: [
{
uuid: '2-3-4',
updated_at_timestamp: 2,
},
],
})
})
it('should return a mismatch item that is missing on the client side', async () => {
expect(
await createUseCase().execute({
userUuid: '1-2-3',
freeUser: false,
integrityPayloads: [
{
uuid: '1-2-3',
updated_at_timestamp: 1,
},
{
uuid: '2-3-4',
updated_at_timestamp: 2,
},
{
uuid: '5-6-7',
updated_at_timestamp: 5,
},
],
}),
).toEqual({
mismatches: [
{
uuid: '3-4-5',
updated_at_timestamp: 3,
},
],
})
})
})

View File

@@ -1,5 +0,0 @@
import { IntegrityPayload } from '@standardnotes/responses'
export type CheckIntegrityResponse = {
mismatches: IntegrityPayload[]
}

View File

@@ -1,7 +0,0 @@
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
export interface CreateSharedVaultResult {
sharedVaultUser: SharedVaultUser
sharedVault: SharedVault
}

View File

@@ -1,24 +0,0 @@
import { ItemRepositoryInterface } from '../../Item/ItemRepositoryInterface'
import { UseCaseInterface } from '../UseCaseInterface'
import { GetItemDTO } from './GetItemDTO'
import { GetItemResponse } from './GetItemResponse'
export class GetItem implements UseCaseInterface {
constructor(private itemRepository: ItemRepositoryInterface) {}
async execute(dto: GetItemDTO): Promise<GetItemResponse> {
const item = await this.itemRepository.findByUuidAndUserUuid(dto.itemUuid, dto.userUuid)
if (item === null) {
return {
success: false,
message: `Could not find item with uuid ${dto.itemUuid}`,
}
}
return {
success: true,
item,
}
}
}

View File

@@ -1,11 +0,0 @@
import { Item } from '../../Item/Item'
export type GetItemResponse =
| {
success: true
item: Item
}
| {
success: false
message: string
}

View File

@@ -1,10 +1,10 @@
import { TimerInterface } from '@standardnotes/time'
import { Result } from '@standardnotes/domain-core'
import { NotificationRepositoryInterface } from '../../Notifications/NotificationRepositoryInterface'
import { Notification } from '../../Notifications/Notification'
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
import { Notification } from '../../../Notifications/Notification'
import { AddNotificationForUser } from './AddNotificationForUser'
import { NotificationType } from '../../Notifications/NotificationType'
import { NotificationType } from '../../../Notifications/NotificationType'
describe('AddNotificationForUser', () => {
let notificationRepository: NotificationRepositoryInterface

View File

@@ -2,9 +2,9 @@ import { Result, Timestamps, UseCaseInterface, Uuid, Validator } from '@standard
import { TimerInterface } from '@standardnotes/time'
import { AddNotificationForUserDTO } from './AddNotificationForUserDTO'
import { NotificationRepositoryInterface } from '../../Notifications/NotificationRepositoryInterface'
import { Notification } from '../../Notifications/Notification'
import { NotificationType } from '../../Notifications/NotificationType'
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
import { Notification } from '../../../Notifications/Notification'
import { NotificationType } from '../../../Notifications/NotificationType'
export class AddNotificationForUser implements UseCaseInterface<Notification> {
constructor(private notificationRepository: NotificationRepositoryInterface, private timer: TimerInterface) {}

View File

@@ -0,0 +1,60 @@
import { Result, Timestamps, Uuid } from '@standardnotes/domain-core'
import { Message } from '../../../Message/Message'
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { DeleteMessage } from '../DeleteMessage/DeleteMessage'
import { DeleteAllMessagesSentToUser } from './DeleteAllMessagesSentToUser'
describe('DeleteAllMessagesSentToUser', () => {
let messageRepository: MessageRepositoryInterface
let deleteMessageUseCase: DeleteMessage
let message: Message
const createUseCase = () => new DeleteAllMessagesSentToUser(messageRepository, deleteMessageUseCase)
beforeEach(() => {
message = Message.create({
senderUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
recipientUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
encryptedMessage: 'encryptedMessage',
replaceabilityIdentifier: 'replaceabilityIdentifier',
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
messageRepository = {} as jest.Mocked<MessageRepositoryInterface>
messageRepository.findByRecipientUuid = jest.fn().mockReturnValue([message])
deleteMessageUseCase = {} as jest.Mocked<DeleteMessage>
deleteMessageUseCase.execute = jest.fn().mockReturnValue(Result.ok())
})
it('should delete all messages sent to user', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeFalsy()
})
it('should return error when recipient uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: 'invalid',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Given value is not a valid uuid: invalid')
})
it('should return error when delete message use case fails', async () => {
const useCase = createUseCase()
deleteMessageUseCase.execute = jest.fn().mockReturnValue(Result.fail('error'))
const result = await useCase.execute({
recipientUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('error')
})
})

View File

@@ -0,0 +1,30 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { DeleteAllMessagesSentToUserDTO } from './DeleteAllMessagesSentToUserDTO'
import { DeleteMessage } from '../DeleteMessage/DeleteMessage'
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
export class DeleteAllMessagesSentToUser implements UseCaseInterface<void> {
constructor(private messageRepository: MessageRepositoryInterface, private deleteMessageUseCase: DeleteMessage) {}
async execute(dto: DeleteAllMessagesSentToUserDTO): Promise<Result<void>> {
const recipientUuidOrError = Uuid.create(dto.recipientUuid)
if (recipientUuidOrError.isFailed()) {
return Result.fail(recipientUuidOrError.getError())
}
const recipientUuid = recipientUuidOrError.getValue()
const messages = await this.messageRepository.findByRecipientUuid(recipientUuid)
for (const message of messages) {
const result = await this.deleteMessageUseCase.execute({
originatorUuid: recipientUuid.value,
messageUuid: message.id.toString(),
})
if (result.isFailed()) {
return Result.fail(result.getError())
}
}
return Result.ok()
}
}

View File

@@ -0,0 +1,3 @@
export interface DeleteAllMessagesSentToUserDTO {
recipientUuid: string
}

View File

@@ -0,0 +1,77 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { Message } from '../../../Message/Message'
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { DeleteMessage } from './DeleteMessage'
describe('DeleteMessage', () => {
let messageRepository: MessageRepositoryInterface
let message: Message
const createUseCase = () => new DeleteMessage(messageRepository)
beforeEach(() => {
message = Message.create({
senderUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
recipientUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
encryptedMessage: 'encryptedMessage',
replaceabilityIdentifier: 'replaceabilityIdentifier',
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
messageRepository = {} as jest.Mocked<MessageRepositoryInterface>
messageRepository.remove = jest.fn()
messageRepository.findByUuid = jest.fn().mockReturnValue(message)
})
it('should remove message', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
messageUuid: '00000000-0000-0000-0000-000000000000',
originatorUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeFalsy()
})
it('should return error when message is not found', async () => {
messageRepository.findByUuid = jest.fn().mockReturnValue(null)
const useCase = createUseCase()
const result = await useCase.execute({
messageUuid: '00000000-0000-0000-0000-000000000000',
originatorUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
})
it('should return error if originator is neither the sender nor the recipient', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
messageUuid: '00000000-0000-0000-0000-000000000000',
originatorUuid: '11111111-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
})
it('should return error when message uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
messageUuid: 'invalid',
originatorUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
})
it('should return error when originator uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
messageUuid: '00000000-0000-0000-0000-000000000000',
originatorUuid: 'invalid',
})
expect(result.isFailed()).toBeTruthy()
})
})

View File

@@ -0,0 +1,38 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { DeleteMessageDTO } from './DeleteMessageDTO'
export class DeleteMessage implements UseCaseInterface<void> {
constructor(private messageRepository: MessageRepositoryInterface) {}
async execute(dto: DeleteMessageDTO): Promise<Result<void>> {
const originatorUuidOrError = Uuid.create(dto.originatorUuid)
if (originatorUuidOrError.isFailed()) {
return Result.fail(originatorUuidOrError.getError())
}
const originatorUuid = originatorUuidOrError.getValue()
const messageUuidOrError = Uuid.create(dto.messageUuid)
if (messageUuidOrError.isFailed()) {
return Result.fail(messageUuidOrError.getError())
}
const messageUuid = messageUuidOrError.getValue()
const message = await this.messageRepository.findByUuid(messageUuid)
if (!message) {
return Result.fail('Message not found')
}
const isSentByOriginator = message.props.senderUuid.equals(originatorUuid)
const isSentToOriginator = message.props.recipientUuid.equals(originatorUuid)
if (!isSentByOriginator && !isSentToOriginator) {
return Result.fail('Not authorized to delete this message')
}
await this.messageRepository.remove(message)
return Result.ok()
}
}

View File

@@ -0,0 +1,4 @@
export interface DeleteMessageDTO {
originatorUuid: string
messageUuid: string
}

View File

@@ -0,0 +1,32 @@
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { GetMessagesSentByUser } from './GetMessagesSentByUser'
describe('GetMessagesSentByUser', () => {
let messageRepository: MessageRepositoryInterface
const createUseCase = () => new GetMessagesSentByUser(messageRepository)
beforeEach(() => {
messageRepository = {} as jest.Mocked<MessageRepositoryInterface>
messageRepository.findBySenderUuid = jest.fn().mockReturnValue([])
})
it('should return messages sent by user', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
senderUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.getValue()).toEqual([])
})
it('should return error when sender uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
senderUuid: 'invalid',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Given value is not a valid uuid: invalid')
})
})

View File

@@ -0,0 +1,21 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { Message } from '../../../Message/Message'
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { GetMessagesSentByUserDTO } from './GetMessagesSentByUserDTO'
export class GetMessagesSentByUser implements UseCaseInterface<Message[]> {
constructor(private messageRepository: MessageRepositoryInterface) {}
async execute(dto: GetMessagesSentByUserDTO): Promise<Result<Message[]>> {
const senderUuidOrError = Uuid.create(dto.senderUuid)
if (senderUuidOrError.isFailed()) {
return Result.fail(senderUuidOrError.getError())
}
const senderUuid = senderUuidOrError.getValue()
const messages = await this.messageRepository.findBySenderUuid(senderUuid)
return Result.ok(messages)
}
}

View File

@@ -0,0 +1,3 @@
export interface GetMessagesSentByUserDTO {
senderUuid: string
}

View File

@@ -0,0 +1,32 @@
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { GetMessagesSentToUser } from './GetMessagesSentToUser'
describe('GetMessagesSentToUser', () => {
let messageRepository: MessageRepositoryInterface
const createUseCase = () => new GetMessagesSentToUser(messageRepository)
beforeEach(() => {
messageRepository = {} as jest.Mocked<MessageRepositoryInterface>
messageRepository.findByRecipientUuid = jest.fn().mockReturnValue([])
})
it('should return messages sent to user', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.getValue()).toEqual([])
})
it('should return error when recipient uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: 'invalid',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Given value is not a valid uuid: invalid')
})
})

View File

@@ -0,0 +1,21 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { Message } from '../../../Message/Message'
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { GetMessagesSentToUserDTO } from './GetMessagesSentToUserDTO'
export class GetMessagesSentToUser implements UseCaseInterface<Message[]> {
constructor(private messageRepository: MessageRepositoryInterface) {}
async execute(dto: GetMessagesSentToUserDTO): Promise<Result<Message[]>> {
const recipientUuidOrError = Uuid.create(dto.recipientUuid)
if (recipientUuidOrError.isFailed()) {
return Result.fail(recipientUuidOrError.getError())
}
const recipientUuid = recipientUuidOrError.getValue()
const messages = await this.messageRepository.findByRecipientUuid(recipientUuid)
return Result.ok(messages)
}
}

View File

@@ -0,0 +1,3 @@
export interface GetMessagesSentToUserDTO {
recipientUuid: string
}

View File

@@ -0,0 +1,107 @@
import { TimerInterface } from '@standardnotes/time'
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { SendMessageToUser } from './SendMessageToUser'
import { Message } from '../../../Message/Message'
import { Result } from '@standardnotes/domain-core'
describe('SendMessageToUser', () => {
let messageRepository: MessageRepositoryInterface
let timer: TimerInterface
let existingMessage: Message
const createUseCase = () => new SendMessageToUser(messageRepository, timer)
beforeEach(() => {
existingMessage = {} as jest.Mocked<Message>
messageRepository = {} as jest.Mocked<MessageRepositoryInterface>
messageRepository.findByRecipientUuidAndReplaceabilityIdentifier = jest.fn().mockReturnValue(null)
messageRepository.remove = jest.fn()
messageRepository.save = jest.fn()
timer = {} as jest.Mocked<TimerInterface>
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123456789)
})
it('saves a new message', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: '00000000-0000-0000-0000-000000000000',
senderUuid: '00000000-0000-0000-0000-000000000000',
encryptedMessage: 'encrypted-message',
})
expect(result.isFailed()).toBeFalsy()
})
it('removes existing message with the same replaceability identifier', async () => {
messageRepository.findByRecipientUuidAndReplaceabilityIdentifier = jest.fn().mockReturnValue(existingMessage)
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: '00000000-0000-0000-0000-000000000000',
senderUuid: '00000000-0000-0000-0000-000000000000',
encryptedMessage: 'encrypted-message',
replaceabilityIdentifier: 'replaceability-identifier',
})
expect(result.isFailed()).toBeFalsy()
expect(messageRepository.remove).toHaveBeenCalledWith(existingMessage)
})
it('returns error when recipient uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: 'invalid-uuid',
senderUuid: '00000000-0000-0000-0000-000000000000',
encryptedMessage: 'encrypted-message',
})
expect(result.isFailed()).toBeTruthy()
})
it('returns error when sender uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: '00000000-0000-0000-0000-000000000000',
senderUuid: 'invalid-uuid',
encryptedMessage: 'encrypted-message',
})
expect(result.isFailed()).toBeTruthy()
})
it('returns error when message is empty', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: '00000000-0000-0000-0000-000000000000',
senderUuid: '00000000-0000-0000-0000-000000000000',
encryptedMessage: '',
})
expect(result.isFailed()).toBeTruthy()
})
it('returns error when message fails to create', async () => {
const mock = jest.spyOn(Message, 'create')
mock.mockImplementation(() => {
return Result.fail('Oops')
})
const useCase = createUseCase()
const result = await useCase.execute({
recipientUuid: '00000000-0000-0000-0000-000000000000',
senderUuid: '00000000-0000-0000-0000-000000000000',
encryptedMessage: 'encrypted-message',
})
expect(result.isFailed()).toBeTruthy()
mock.mockRestore()
})
})

View File

@@ -0,0 +1,59 @@
import { Result, Timestamps, UseCaseInterface, Uuid, Validator } from '@standardnotes/domain-core'
import { TimerInterface } from '@standardnotes/time'
import { SendMessageToUserDTO } from './SendMessageToUserDTO'
import { MessageRepositoryInterface } from '../../../Message/MessageRepositoryInterface'
import { Message } from '../../../Message/Message'
export class SendMessageToUser implements UseCaseInterface<Message> {
constructor(private messageRepository: MessageRepositoryInterface, private timer: TimerInterface) {}
async execute(dto: SendMessageToUserDTO): Promise<Result<Message>> {
const recipientUuidOrError = Uuid.create(dto.recipientUuid)
if (recipientUuidOrError.isFailed()) {
return Result.fail(recipientUuidOrError.getError())
}
const recipientUuid = recipientUuidOrError.getValue()
const senderUuidOrError = Uuid.create(dto.senderUuid)
if (senderUuidOrError.isFailed()) {
return Result.fail(senderUuidOrError.getError())
}
const senderUuid = senderUuidOrError.getValue()
const validateNotEmptyMessage = Validator.isNotEmpty(dto.encryptedMessage)
if (validateNotEmptyMessage.isFailed()) {
return Result.fail(validateNotEmptyMessage.getError())
}
if (dto.replaceabilityIdentifier) {
const existingMessage = await this.messageRepository.findByRecipientUuidAndReplaceabilityIdentifier({
recipientUuid,
replaceabilityIdentifier: dto.replaceabilityIdentifier,
})
if (existingMessage) {
await this.messageRepository.remove(existingMessage)
}
}
const messageOrError = Message.create({
recipientUuid,
senderUuid,
encryptedMessage: dto.encryptedMessage,
timestamps: Timestamps.create(
this.timer.getTimestampInMicroseconds(),
this.timer.getTimestampInMicroseconds(),
).getValue(),
replaceabilityIdentifier: dto.replaceabilityIdentifier ?? null,
})
if (messageOrError.isFailed()) {
return Result.fail(messageOrError.getError())
}
const message = messageOrError.getValue()
await this.messageRepository.save(message)
return Result.ok(message)
}
}

View File

@@ -0,0 +1,6 @@
export interface SendMessageToUserDTO {
recipientUuid: string
senderUuid: string
encryptedMessage: string
replaceabilityIdentifier?: string
}

View File

@@ -1,9 +0,0 @@
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { RemoveUserEventsDTO } from './RemoveUserEventsDTO'
export class RemoveUserEvents implements UseCaseInterface<void> {
async execute(_dto: RemoveUserEventsDTO): Promise<Result<void>> {
throw new Error('Method not implemented.')
}
}

View File

@@ -1,4 +0,0 @@
export interface RemoveUserEventsDTO {
sharedVaultUuid: string
userUuid: string
}

View File

@@ -1,9 +1,9 @@
import { Result, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { AddUserToSharedVault } from '../AddUserToSharedVault/AddUserToSharedVault'
import { AcceptInviteToSharedVault } from './AcceptInviteToSharedVault'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('AcceptInviteToSharedVault', () => {
let addUserToSharedVault: AddUserToSharedVault

View File

@@ -1,6 +1,6 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { AcceptInviteToSharedVaultDTO } from './AcceptInviteToSharedVaultDTO'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { AddUserToSharedVault } from '../AddUserToSharedVault/AddUserToSharedVault'
export class AcceptInviteToSharedVault implements UseCaseInterface<void> {

View File

@@ -1,14 +1,12 @@
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { RemoveUserEvents } from '../RemoveUserEvents/RemoveUserEvents'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { AddUserToSharedVault } from './AddUserToSharedVault'
import { Result } from '@standardnotes/domain-core'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
describe('AddUserToSharedVault', () => {
let removeUserEvents: RemoveUserEvents
let sharedVaultRepository: SharedVaultRepositoryInterface
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
let timer: TimerInterface
@@ -16,13 +14,9 @@ describe('AddUserToSharedVault', () => {
const validUuid = '00000000-0000-0000-0000-000000000000'
const createUseCase = () =>
new AddUserToSharedVault(removeUserEvents, sharedVaultRepository, sharedVaultUserRepository, timer)
const createUseCase = () => new AddUserToSharedVault(sharedVaultRepository, sharedVaultUserRepository, timer)
beforeEach(() => {
removeUserEvents = {} as jest.Mocked<RemoveUserEvents>
removeUserEvents.execute = jest.fn().mockResolvedValue(Result.ok())
sharedVault = {} as jest.Mocked<SharedVault>
sharedVaultRepository = {} as jest.Mocked<SharedVaultRepositoryInterface>
@@ -89,21 +83,6 @@ describe('AddUserToSharedVault', () => {
expect(result.getError()).toBe('Attempting to add a shared vault user to a non-existent shared vault')
})
it('should return a failure result if removing user events fails', async () => {
const useCase = createUseCase()
removeUserEvents.execute = jest.fn().mockResolvedValueOnce(Result.fail('test'))
const result = await useCase.execute({
sharedVaultUuid: validUuid,
userUuid: validUuid,
permission: 'read',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('test')
})
it('should return a failure result if creating the shared vault user fails', async () => {
const useCase = createUseCase()

View File

@@ -2,15 +2,13 @@ import { Result, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domai
import { TimerInterface } from '@standardnotes/time'
import { AddUserToSharedVaultDTO } from './AddUserToSharedVaultDTO'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { RemoveUserEvents } from '../RemoveUserEvents/RemoveUserEvents'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
export class AddUserToSharedVault implements UseCaseInterface<SharedVaultUser> {
constructor(
private removeUserEvents: RemoveUserEvents,
private sharedVaultRepository: SharedVaultRepositoryInterface,
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
private timer: TimerInterface,
@@ -40,14 +38,6 @@ export class AddUserToSharedVault implements UseCaseInterface<SharedVaultUser> {
}
const permission = permissionOrError.getValue()
const removingEventsResult = await this.removeUserEvents.execute({
sharedVaultUuid: sharedVaultUuid.value,
userUuid: userUuid.value,
})
if (removingEventsResult.isFailed()) {
return Result.fail(removingEventsResult.getError())
}
const timestamps = Timestamps.create(
this.timer.getTimestampInMicroseconds(),
this.timer.getTimestampInMicroseconds(),

View File

@@ -1,10 +1,10 @@
import { TimerInterface } from '@standardnotes/time'
import { Result } from '@standardnotes/domain-core'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { AddUserToSharedVault } from '../AddUserToSharedVault/AddUserToSharedVault'
import { CreateSharedVault } from './CreateSharedVault'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVault } from '../../../SharedVault/SharedVault'
describe('CreateSharedVault', () => {
let addUserToSharedVault: AddUserToSharedVault

View File

@@ -2,9 +2,9 @@ import { Result, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domai
import { CreateSharedVaultResult } from './CreateSharedVaultResult'
import { CreateSharedVaultDTO } from './CreateSharedVaultDTO'
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { AddUserToSharedVault } from '../AddUserToSharedVault/AddUserToSharedVault'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVault } from '../../../SharedVault/SharedVault'
export class CreateSharedVault implements UseCaseInterface<CreateSharedVaultResult> {
private readonly FILE_UPLOAD_BYTES_LIMIT = 1_000_000

View File

@@ -0,0 +1,7 @@
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
export interface CreateSharedVaultResult {
sharedVaultUser: SharedVaultUser
sharedVault: SharedVault
}

View File

@@ -1,10 +1,10 @@
import { SharedVaultValetTokenData, TokenEncoderInterface, ValetTokenOperation } from '@standardnotes/security'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { CreateSharedVaultFileValetToken } from './CreateSharedVaultFileValetToken'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { Timestamps, Uuid } from '@standardnotes/domain-core'
describe('CreateSharedVaultFileValetToken', () => {

View File

@@ -1,10 +1,10 @@
import { SharedVaultValetTokenData, TokenEncoderInterface, ValetTokenOperation } from '@standardnotes/security'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { CreateSharedVaultFileValetTokenDTO } from './CreateSharedVaultFileValetTokenDTO'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
export class CreateSharedVaultFileValetToken implements UseCaseInterface<string> {
constructor(

View File

@@ -1,8 +1,8 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { DeclineInviteToSharedVault } from './DeclineInviteToSharedVault'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('DeclineInviteToSharedVault', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface

View File

@@ -1,6 +1,6 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { DeclineInviteToSharedVaultDTO } from './DeclineInviteToSharedVaultDTO'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
export class DeclineInviteToSharedVault implements UseCaseInterface<void> {
constructor(private sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface) {}

View File

@@ -1,12 +1,12 @@
import { Uuid, Timestamps, Result } from '@standardnotes/domain-core'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { DeleteSharedVault } from './DeleteSharedVault'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
describe('DeleteSharedVault', () => {

View File

@@ -1,9 +1,9 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { DeleteSharedVaultDTO } from './DeleteSharedVaultDTO'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
export class DeleteSharedVault implements UseCaseInterface<void> {

View File

@@ -1,9 +1,9 @@
import { Result, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { DeleteSharedVaultInvitesSentByUser } from './DeleteSharedVaultInvitesSentByUser'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('DeleteSharedVaultInvitesSentByUser', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface

View File

@@ -1,7 +1,7 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { DeleteSharedVaultInvitesSentByUserDTO } from './DeleteSharedVaultInvitesSentByUserDTO'
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
export class DeleteSharedVaultInvitesSentByUser implements UseCaseInterface<void> {
constructor(

View File

@@ -1,9 +1,9 @@
import { Result, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { DeleteSharedVaultInvitesToUser } from './DeleteSharedVaultInvitesToUser'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('DeleteSharedVaultInvitesToUser', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface

View File

@@ -1,7 +1,7 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { DeleteSharedVaultInvitesToUserDTO } from './DeleteSharedVaultInvitesToUserDTO'
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
export class DeleteSharedVaultInvitesToUser implements UseCaseInterface<void> {
constructor(

View File

@@ -1,8 +1,8 @@
import { Uuid, Timestamps } from '@standardnotes/domain-core'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { GetSharedVaultInvitesSentByUser } from './GetSharedVaultInvitesSentByUser'
describe('GetSharedVaultInvitesSentByUser', () => {

View File

@@ -1,7 +1,7 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { GetSharedVaultInvitesSentByUserDTO } from './GetSharedVaultInvitesSentByUserDTO'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
export class GetSharedVaultInvitesSentByUser implements UseCaseInterface<SharedVaultInvite[]> {
constructor(private sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface) {}

View File

@@ -1,8 +1,8 @@
import { Uuid, Timestamps } from '@standardnotes/domain-core'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { GetSharedVaultInvitesSentToUser } from './GetSharedVaultInvitesSentToUser'
describe('GetSharedVaultInvitesSentToUser', () => {

View File

@@ -1,7 +1,7 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { GetSharedVaultInvitesSentToUserDTO } from './GetSharedVaultInvitesSentToUserDTO'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
export class GetSharedVaultInvitesSentToUser implements UseCaseInterface<SharedVaultInvite[]> {
constructor(private sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface) {}

View File

@@ -1,9 +1,9 @@
import { Uuid, Timestamps } 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 { 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 { GetSharedVaultUsers } from './GetSharedVaultUsers'
describe('GetSharedVaultUsers', () => {

View File

@@ -1,8 +1,8 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { GetSharedVaultUsersDTO } from './GetSharedVaultUsersDTO'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
export class GetSharedVaultUsers implements UseCaseInterface<SharedVaultUser[]> {
constructor(

View File

@@ -1,9 +1,9 @@
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 { 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', () => {

View File

@@ -1,9 +1,9 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { GetSharedVaultsDTO } from './GetSharedVaultsDTO'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
export class GetSharedVaults implements UseCaseInterface<SharedVault[]> {
constructor(

View File

@@ -1,11 +1,11 @@
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { InviteUserToSharedVault } from './InviteUserToSharedVault'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { Uuid, Timestamps, Result } from '@standardnotes/domain-core'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('InviteUserToSharedVault', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface

View File

@@ -1,10 +1,10 @@
import { Result, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { InviteUserToSharedVaultDTO } from './InviteUserToSharedVaultDTO'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvite> {
constructor(

View File

@@ -1,12 +1,12 @@
import { Uuid, Timestamps, Result } 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 { 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 { RemoveUserFromSharedVault } from './RemoveUserFromSharedVault'
import { AddNotificationForUser } from '../AddNotificationForUser/AddNotificationForUser'
import { AddNotificationForUser } from '../../Messaging/AddNotificationForUser/AddNotificationForUser'
describe('RemoveUserFromSharedVault', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface

View File

@@ -1,10 +1,10 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { RemoveUserFromSharedVaultDTO } from './RemoveUserFromSharedVaultDTO'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { AddNotificationForUser } from '../AddNotificationForUser/AddNotificationForUser'
import { NotificationType } from '../../Notifications/NotificationType'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { NotificationType } from '../../../Notifications/NotificationType'
import { AddNotificationForUser } from '../../Messaging/AddNotificationForUser/AddNotificationForUser'
export class RemoveUserFromSharedVault implements UseCaseInterface<void> {
constructor(

View File

@@ -1,9 +1,9 @@
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { UpdateSharedVaultInvite } from './UpdateSharedVaultInvite'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('UpdateSharedVaultInvite', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface

View File

@@ -1,10 +1,10 @@
import { Result, Timestamps, UseCaseInterface, Uuid, Validator } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { UpdateSharedVaultInviteDTO } from './UpdateSharedVaultInviteDTO'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
export class UpdateSharedVaultInvite implements UseCaseInterface<SharedVaultInvite> {
constructor(

View File

@@ -0,0 +1,127 @@
import 'reflect-metadata'
import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface'
import { CheckIntegrity } from './CheckIntegrity'
import { ContentType } from '@standardnotes/common'
describe('CheckIntegrity', () => {
let itemRepository: ItemRepositoryInterface
const createUseCase = () => new CheckIntegrity(itemRepository)
beforeEach(() => {
itemRepository = {} as jest.Mocked<ItemRepositoryInterface>
itemRepository.findItemsForComputingIntegrityPayloads = jest.fn().mockReturnValue([
{
uuid: '1-2-3',
updated_at_timestamp: 1,
content_type: ContentType.Note,
},
{
uuid: '2-3-4',
updated_at_timestamp: 2,
content_type: ContentType.Note,
},
{
uuid: '3-4-5',
updated_at_timestamp: 3,
content_type: ContentType.Note,
},
{
uuid: '4-5-6',
updated_at_timestamp: 4,
content_type: ContentType.ItemsKey,
},
{
uuid: '5-6-7',
updated_at_timestamp: 5,
content_type: ContentType.File,
},
])
})
it('should return an empty result if there are no integrity mismatches', async () => {
const result = await createUseCase().execute({
userUuid: '1-2-3',
freeUser: false,
integrityPayloads: [
{
uuid: '1-2-3',
updated_at_timestamp: 1,
},
{
uuid: '2-3-4',
updated_at_timestamp: 2,
},
{
uuid: '3-4-5',
updated_at_timestamp: 3,
},
{
uuid: '5-6-7',
updated_at_timestamp: 5,
},
],
})
expect(result.getValue()).toEqual([])
})
it('should return a mismatch item that has a different update at timemstap', async () => {
const result = await createUseCase().execute({
userUuid: '1-2-3',
freeUser: false,
integrityPayloads: [
{
uuid: '1-2-3',
updated_at_timestamp: 1,
},
{
uuid: '2-3-4',
updated_at_timestamp: 1,
},
{
uuid: '3-4-5',
updated_at_timestamp: 3,
},
{
uuid: '5-6-7',
updated_at_timestamp: 5,
},
],
})
expect(result.getValue()).toEqual([
{
uuid: '2-3-4',
updated_at_timestamp: 2,
},
])
})
it('should return a mismatch item that is missing on the client side', async () => {
const result = await createUseCase().execute({
userUuid: '1-2-3',
freeUser: false,
integrityPayloads: [
{
uuid: '1-2-3',
updated_at_timestamp: 1,
},
{
uuid: '2-3-4',
updated_at_timestamp: 2,
},
{
uuid: '5-6-7',
updated_at_timestamp: 5,
},
],
})
expect(result.getValue()).toEqual([
{
uuid: '3-4-5',
updated_at_timestamp: 3,
},
])
})
})

View File

@@ -1,16 +1,15 @@
import { IntegrityPayload } from '@standardnotes/responses'
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { ContentType } from '@standardnotes/common'
import { ItemRepositoryInterface } from '../../Item/ItemRepositoryInterface'
import { UseCaseInterface } from '../UseCaseInterface'
import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface'
import { CheckIntegrityDTO } from './CheckIntegrityDTO'
import { CheckIntegrityResponse } from './CheckIntegrityResponse'
import { ExtendedIntegrityPayload } from '../../Item/ExtendedIntegrityPayload'
import { ExtendedIntegrityPayload } from '../../../Item/ExtendedIntegrityPayload'
export class CheckIntegrity implements UseCaseInterface {
export class CheckIntegrity implements UseCaseInterface<IntegrityPayload[]> {
constructor(private itemRepository: ItemRepositoryInterface) {}
async execute(dto: CheckIntegrityDTO): Promise<CheckIntegrityResponse> {
async execute(dto: CheckIntegrityDTO): Promise<Result<IntegrityPayload[]>> {
const serverItemIntegrityPayloads = await this.itemRepository.findItemsForComputingIntegrityPayloads(dto.userUuid)
const serverItemIntegrityPayloadsMap = new Map<string, ExtendedIntegrityPayload>()
@@ -59,8 +58,6 @@ export class CheckIntegrity implements UseCaseInterface {
}
}
return {
mismatches,
}
return Result.ok(mismatches)
}
}

View File

@@ -1,6 +1,6 @@
import 'reflect-metadata'
import { Item } from '../../Item/Item'
import { ItemRepositoryInterface } from '../../Item/ItemRepositoryInterface'
import { Item } from '../../../Item/Item'
import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface'
import { GetItem } from './GetItem'
@@ -15,23 +15,23 @@ describe('GetItem', () => {
})
it('should fail if item is not found', async () => {
expect(
await createUseCase().execute({
userUuid: '1-2-3',
itemUuid: '2-3-4',
}),
).toEqual({ success: false, message: 'Could not find item with uuid 2-3-4' })
const result = await createUseCase().execute({
userUuid: '1-2-3',
itemUuid: '2-3-4',
})
expect(result.isFailed()).toBeTruthy()
expect(result.getError()).toEqual('Could not find item with uuid 2-3-4')
})
it('should succeed if item is found', async () => {
const item = {} as jest.Mocked<Item>
itemRepository.findByUuidAndUserUuid = jest.fn().mockReturnValue(item)
expect(
await createUseCase().execute({
userUuid: '1-2-3',
itemUuid: '2-3-4',
}),
).toEqual({ success: true, item })
const result = await createUseCase().execute({
userUuid: '1-2-3',
itemUuid: '2-3-4',
})
expect(result.getValue()).toEqual(item)
})
})

View File

@@ -0,0 +1,19 @@
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface'
import { GetItemDTO } from './GetItemDTO'
import { Item } from '../../../Item/Item'
export class GetItem implements UseCaseInterface<Item> {
constructor(private itemRepository: ItemRepositoryInterface) {}
async execute(dto: GetItemDTO): Promise<Result<Item>> {
const item = await this.itemRepository.findByUuidAndUserUuid(dto.itemUuid, dto.userUuid)
if (item === null) {
return Result.fail(`Could not find item with uuid ${dto.itemUuid}`)
}
return Result.ok(item)
}
}

View File

@@ -2,10 +2,10 @@ import 'reflect-metadata'
import { ContentType } from '@standardnotes/common'
import { ApiVersion } from '../Api/ApiVersion'
import { Item } from '../Item/Item'
import { ItemHash } from '../Item/ItemHash'
import { ItemServiceInterface } from '../Item/ItemServiceInterface'
import { ApiVersion } from '../../../Api/ApiVersion'
import { Item } from '../../../Item/Item'
import { ItemHash } from '../../../Item/ItemHash'
import { ItemServiceInterface } from '../../../Item/ItemServiceInterface'
import { SyncItems } from './SyncItems'
@@ -54,20 +54,20 @@ describe('SyncItems', () => {
})
it('should sync items', async () => {
expect(
await createUseCase().execute({
userUuid: '1-2-3',
itemHashes: [itemHash],
computeIntegrityHash: false,
syncToken: 'foo',
cursorToken: 'bar',
limit: 10,
readOnlyAccess: false,
contentType: 'Note',
apiVersion: ApiVersion.v20200115,
sessionUuid: null,
}),
).toEqual({
const result = await createUseCase().execute({
userUuid: '1-2-3',
itemHashes: [itemHash],
computeIntegrityHash: false,
syncToken: 'foo',
cursorToken: 'bar',
limit: 10,
readOnlyAccess: false,
contentType: 'Note',
apiVersion: ApiVersion.v20200115,
sessionUuid: null,
snjsVersion: '1.2.3',
})
expect(result.getValue()).toEqual({
conflicts: [],
cursorToken: 'asdzxc',
retrievedItems: [item1],
@@ -93,18 +93,18 @@ describe('SyncItems', () => {
})
it('should sync items and return items keys on top for first sync', async () => {
expect(
await createUseCase().execute({
userUuid: '1-2-3',
itemHashes: [itemHash],
computeIntegrityHash: false,
limit: 10,
readOnlyAccess: false,
sessionUuid: '2-3-4',
contentType: 'Note',
apiVersion: ApiVersion.v20200115,
}),
).toEqual({
const result = await createUseCase().execute({
userUuid: '1-2-3',
itemHashes: [itemHash],
computeIntegrityHash: false,
limit: 10,
readOnlyAccess: false,
sessionUuid: '2-3-4',
contentType: 'Note',
apiVersion: ApiVersion.v20200115,
snjsVersion: '1.2.3',
})
expect(result.getValue()).toEqual({
conflicts: [],
cursorToken: 'asdzxc',
retrievedItems: [item3, item1],
@@ -134,20 +134,21 @@ describe('SyncItems', () => {
syncToken: 'qwerty',
})
expect(
await createUseCase().execute({
userUuid: '1-2-3',
itemHashes: [itemHash],
computeIntegrityHash: false,
syncToken: 'foo',
readOnlyAccess: false,
sessionUuid: '2-3-4',
cursorToken: 'bar',
limit: 10,
contentType: 'Note',
apiVersion: ApiVersion.v20200115,
}),
).toEqual({
const result = await createUseCase().execute({
userUuid: '1-2-3',
itemHashes: [itemHash],
computeIntegrityHash: false,
syncToken: 'foo',
readOnlyAccess: false,
sessionUuid: '2-3-4',
cursorToken: 'bar',
limit: 10,
contentType: 'Note',
apiVersion: ApiVersion.v20200115,
snjsVersion: '1.2.3',
})
expect(result.getValue()).toEqual({
conflicts: [
{
serverItem: item2,

View File

@@ -1,14 +1,14 @@
import { Item } from '../Item/Item'
import { ItemConflict } from '../Item/ItemConflict'
import { ItemServiceInterface } from '../Item/ItemServiceInterface'
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { Item } from '../../../Item/Item'
import { ItemConflict } from '../../../Item/ItemConflict'
import { ItemServiceInterface } from '../../../Item/ItemServiceInterface'
import { SyncItemsDTO } from './SyncItemsDTO'
import { SyncItemsResponse } from './SyncItemsResponse'
import { UseCaseInterface } from './UseCaseInterface'
export class SyncItems implements UseCaseInterface {
export class SyncItems implements UseCaseInterface<SyncItemsResponse> {
constructor(private itemService: ItemServiceInterface) {}
async execute(dto: SyncItemsDTO): Promise<SyncItemsResponse> {
async execute(dto: SyncItemsDTO): Promise<Result<SyncItemsResponse>> {
const getItemsResult = await this.itemService.getItems({
userUuid: dto.userUuid,
syncToken: dto.syncToken,
@@ -38,7 +38,7 @@ export class SyncItems implements UseCaseInterface {
cursorToken: getItemsResult.cursorToken,
}
return syncResponse
return Result.ok(syncResponse)
}
private isFirstSync(dto: SyncItemsDTO): boolean {

View File

@@ -1,14 +1,16 @@
import { ItemHash } from '../Item/ItemHash'
import { ItemHash } from '../../../Item/ItemHash'
export type SyncItemsDTO = {
userUuid: string
itemHashes: Array<ItemHash>
computeIntegrityHash: boolean
limit: number
sharedVaultUuids?: string[] | null
syncToken?: string | null
cursorToken?: string | null
contentType?: string
apiVersion: string
snjsVersion: string
readOnlyAccess: boolean
sessionUuid: string | null
}

View File

@@ -1,5 +1,5 @@
import { Item } from '../Item/Item'
import { ItemConflict } from '../Item/ItemConflict'
import { Item } from '../../../Item/Item'
import { ItemConflict } from '../../../Item/ItemConflict'
export type SyncItemsResponse = {
retrievedItems: Array<Item>

View File

@@ -1,3 +0,0 @@
export interface UseCaseInterface {
execute(...args: any[]): Promise<Record<string, unknown>>
}

View File

@@ -4,12 +4,13 @@ import { Request, Response } from 'express'
import { Item } from '../../../Domain/Item/Item'
import { SyncResponseFactoryResolverInterface } from '../../../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface'
import { CheckIntegrity } from '../../../Domain/UseCase/CheckIntegrity/CheckIntegrity'
import { GetItem } from '../../../Domain/UseCase/GetItem/GetItem'
import { SyncItems } from '../../../Domain/UseCase/SyncItems'
import { CheckIntegrity } from '../../../Domain/UseCase/Syncing/CheckIntegrity/CheckIntegrity'
import { GetItem } from '../../../Domain/UseCase/Syncing/GetItem/GetItem'
import { ItemProjection } from '../../../Projection/ItemProjection'
import { ProjectorInterface } from '../../../Projection/ProjectorInterface'
import { ApiVersion } from '../../../Domain/Api/ApiVersion'
import { SyncItems } from '../../../Domain/UseCase/Syncing/SyncItems/SyncItems'
import { HttpStatusCode } from '@standardnotes/responses'
export class HomeServerItemsController extends BaseHttpController {
constructor(
@@ -41,16 +42,21 @@ export class HomeServerItemsController extends BaseHttpController {
computeIntegrityHash: request.body.compute_integrity === true,
syncToken: request.body.sync_token,
cursorToken: request.body.cursor_token,
sharedVaultUuids: request.body.shared_vault_uuids,
limit: request.body.limit,
contentType: request.body.content_type,
apiVersion: request.body.api ?? ApiVersion.v20161215,
snjsVersion: <string>request.headers['x-snjs-version'],
readOnlyAccess: response.locals.readOnlyAccess,
sessionUuid: response.locals.session ? response.locals.session.uuid : null,
})
if (syncResult.isFailed()) {
return this.json({ error: { message: syncResult.getError() } }, HttpStatusCode.BadRequest)
}
const syncResponse = await this.syncResponseFactoryResolver
.resolveSyncResponseFactoryVersion(request.body.api)
.createResponse(syncResult)
.createResponse(syncResult.getValue())
return this.json(syncResponse)
}
@@ -67,19 +73,25 @@ export class HomeServerItemsController extends BaseHttpController {
freeUser: response.locals.freeUser,
})
return this.json(result)
if (result.isFailed()) {
return this.json({ error: { message: result.getError() } }, HttpStatusCode.BadRequest)
}
return this.json({
mismatches: result.getValue(),
})
}
async getSingleItem(request: Request, response: Response): Promise<results.NotFoundResult | results.JsonResult> {
async getSingleItem(request: Request, response: Response): Promise<results.JsonResult> {
const result = await this.getItem.execute({
userUuid: response.locals.user.uuid,
itemUuid: request.params.uuid,
})
if (!result.success) {
return this.notFound()
if (result.isFailed()) {
return this.json({ error: { message: result.getError() } }, 404)
}
return this.json({ item: await this.itemProjector.projectFull(result.item) })
return this.json({ item: await this.itemProjector.projectFull(result.getValue()) })
}
}

View File

@@ -0,0 +1,138 @@
import { Request, Response } from 'express'
import { BaseHttpController, results } from 'inversify-express-utils'
import { HttpStatusCode } from '@standardnotes/responses'
import { ControllerContainerInterface, MapperInterface } from '@standardnotes/domain-core'
import { GetMessagesSentToUser } from '../../../Domain/UseCase/Messaging/GetMessagesSentToUser/GetMessagesSentToUser'
import { MessageHttpRepresentation } from '../../../Mapping/Http/MessageHttpRepresentation'
import { Message } from '../../../Domain/Message/Message'
import { SendMessageToUser } from '../../../Domain/UseCase/Messaging/SendMessageToUser/SendMessageToUser'
import { DeleteAllMessagesSentToUser } from '../../../Domain/UseCase/Messaging/DeleteAllMessagesSentToUser/DeleteAllMessagesSentToUser'
import { DeleteMessage } from '../../../Domain/UseCase/Messaging/DeleteMessage/DeleteMessage'
import { GetMessagesSentByUser } from '../../../Domain/UseCase/Messaging/GetMessagesSentByUser/GetMessagesSentByUser'
export class HomeServerMessagesController extends BaseHttpController {
constructor(
protected getMessageSentToUserUseCase: GetMessagesSentToUser,
protected getMessagesSentByUserUseCase: GetMessagesSentByUser,
protected sendMessageToUserUseCase: SendMessageToUser,
protected deleteMessagesSentToUserUseCase: DeleteAllMessagesSentToUser,
protected deleteMessageUseCase: DeleteMessage,
protected messageHttpMapper: MapperInterface<Message, MessageHttpRepresentation>,
private controllerContainer?: ControllerContainerInterface,
) {
super()
if (this.controllerContainer !== undefined) {
this.controllerContainer.register('sync.messages.get-received', this.getMessages.bind(this))
this.controllerContainer.register('sync.messages.get-sent', this.getMessagesSent.bind(this))
this.controllerContainer.register('sync.messages.send', this.sendMessage.bind(this))
this.controllerContainer.register('sync.messages.delete-all', this.deleteMessagesSentToUser.bind(this))
this.controllerContainer.register('sync.messages.delete', this.deleteMessage.bind(this))
}
}
async getMessages(_request: Request, response: Response): Promise<results.JsonResult> {
const result = await this.getMessageSentToUserUseCase.execute({
recipientUuid: response.locals.user.uuid,
})
if (result.isFailed()) {
return this.json(
{
error: {
message: result.getError(),
},
},
HttpStatusCode.BadRequest,
)
}
return this.json({
messages: result.getValue().map((message) => this.messageHttpMapper.toProjection(message)),
})
}
async getMessagesSent(_request: Request, response: Response): Promise<results.JsonResult> {
const result = await this.getMessagesSentByUserUseCase.execute({
senderUuid: response.locals.user.uuid,
})
if (result.isFailed()) {
return this.json(
{
error: {
message: result.getError(),
},
},
HttpStatusCode.BadRequest,
)
}
return this.json({
messages: result.getValue().map((message) => this.messageHttpMapper.toProjection(message)),
})
}
async sendMessage(request: Request, response: Response): Promise<results.JsonResult> {
const result = await this.sendMessageToUserUseCase.execute({
senderUuid: response.locals.user.uuid,
recipientUuid: request.body.recipient_uuid,
encryptedMessage: request.body.encrypted_message,
replaceabilityIdentifier: request.body.replaceability_identifier,
})
if (result.isFailed()) {
return this.json(
{
error: {
message: result.getError(),
},
},
HttpStatusCode.BadRequest,
)
}
return this.json({
message: this.messageHttpMapper.toProjection(result.getValue()),
})
}
async deleteMessagesSentToUser(_request: Request, response: Response): Promise<results.JsonResult> {
const result = await this.deleteMessagesSentToUserUseCase.execute({
recipientUuid: response.locals.user.uuid,
})
if (result.isFailed()) {
return this.json(
{
error: {
message: result.getError(),
},
},
HttpStatusCode.BadRequest,
)
}
return this.json({ success: true })
}
async deleteMessage(request: Request, response: Response): Promise<results.JsonResult> {
const result = await this.deleteMessageUseCase.execute({
messageUuid: request.params.messageUuid,
originatorUuid: response.locals.user.uuid,
})
if (result.isFailed()) {
return this.json(
{
error: {
message: result.getError(),
},
},
HttpStatusCode.BadRequest,
)
}
return this.json({ success: true })
}
}

View File

@@ -3,16 +3,16 @@ import { BaseHttpController, results } from 'inversify-express-utils'
import { HttpStatusCode } from '@standardnotes/responses'
import { ControllerContainerInterface, MapperInterface } from '@standardnotes/domain-core'
import { InviteUserToSharedVault } from '../../../Domain/UseCase/InviteUserToSharedVault/InviteUserToSharedVault'
import { InviteUserToSharedVault } from '../../../Domain/UseCase/SharedVaults/InviteUserToSharedVault/InviteUserToSharedVault'
import { SharedVaultInvite } from '../../../Domain/SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInviteHttpRepresentation } from '../../../Mapping/Http/SharedVaultInviteHttpRepresentation'
import { UpdateSharedVaultInvite } from '../../../Domain/UseCase/UpdateSharedVaultInvite/UpdateSharedVaultInvite'
import { AcceptInviteToSharedVault } from '../../../Domain/UseCase/AcceptInviteToSharedVault/AcceptInviteToSharedVault'
import { DeclineInviteToSharedVault } from '../../../Domain/UseCase/DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { DeleteSharedVaultInvitesToUser } from '../../../Domain/UseCase/DeleteSharedVaultInvitesToUser/DeleteSharedVaultInvitesToUser'
import { GetSharedVaultInvitesSentByUser } from '../../../Domain/UseCase/GetSharedVaultInvitesSentByUser/GetSharedVaultInvitesSentByUser'
import { DeleteSharedVaultInvitesSentByUser } from '../../../Domain/UseCase/DeleteSharedVaultInvitesSentByUser/DeleteSharedVaultInvitesSentByUser'
import { GetSharedVaultInvitesSentToUser } from '../../../Domain/UseCase/GetSharedVaultInvitesSentToUser/GetSharedVaultInvitesSentToUser'
import { UpdateSharedVaultInvite } from '../../../Domain/UseCase/SharedVaults/UpdateSharedVaultInvite/UpdateSharedVaultInvite'
import { AcceptInviteToSharedVault } from '../../../Domain/UseCase/SharedVaults/AcceptInviteToSharedVault/AcceptInviteToSharedVault'
import { DeclineInviteToSharedVault } from '../../../Domain/UseCase/SharedVaults/DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { DeleteSharedVaultInvitesToUser } from '../../../Domain/UseCase/SharedVaults/DeleteSharedVaultInvitesToUser/DeleteSharedVaultInvitesToUser'
import { GetSharedVaultInvitesSentByUser } from '../../../Domain/UseCase/SharedVaults/GetSharedVaultInvitesSentByUser/GetSharedVaultInvitesSentByUser'
import { DeleteSharedVaultInvitesSentByUser } from '../../../Domain/UseCase/SharedVaults/DeleteSharedVaultInvitesSentByUser/DeleteSharedVaultInvitesSentByUser'
import { GetSharedVaultInvitesSentToUser } from '../../../Domain/UseCase/SharedVaults/GetSharedVaultInvitesSentToUser/GetSharedVaultInvitesSentToUser'
export class HomeServerSharedVaultInvitesController extends BaseHttpController {
constructor(

View File

@@ -5,8 +5,8 @@ import { ControllerContainerInterface, MapperInterface } from '@standardnotes/do
import { SharedVaultUser } from '../../../Domain/SharedVault/User/SharedVaultUser'
import { SharedVaultUserHttpRepresentation } from '../../../Mapping/Http/SharedVaultUserHttpRepresentation'
import { GetSharedVaultUsers } from '../../../Domain/UseCase/GetSharedVaultUsers/GetSharedVaultUsers'
import { RemoveUserFromSharedVault } from '../../../Domain/UseCase/RemoveUserFromSharedVault/RemoveUserFromSharedVault'
import { GetSharedVaultUsers } from '../../../Domain/UseCase/SharedVaults/GetSharedVaultUsers/GetSharedVaultUsers'
import { RemoveUserFromSharedVault } from '../../../Domain/UseCase/SharedVaults/RemoveUserFromSharedVault/RemoveUserFromSharedVault'
export class HomeServerSharedVaultUsersController extends BaseHttpController {
constructor(

View File

@@ -3,14 +3,14 @@ import { BaseHttpController, results } from 'inversify-express-utils'
import { HttpStatusCode } from '@standardnotes/responses'
import { ControllerContainerInterface, MapperInterface } from '@standardnotes/domain-core'
import { GetSharedVaults } from '../../../Domain/UseCase/GetSharedVaults/GetSharedVaults'
import { GetSharedVaults } from '../../../Domain/UseCase/SharedVaults/GetSharedVaults/GetSharedVaults'
import { SharedVault } from '../../../Domain/SharedVault/SharedVault'
import { SharedVaultHttpRepresentation } from '../../../Mapping/Http/SharedVaultHttpRepresentation'
import { CreateSharedVault } from '../../../Domain/UseCase/CreateSharedVault/CreateSharedVault'
import { CreateSharedVault } from '../../../Domain/UseCase/SharedVaults/CreateSharedVault/CreateSharedVault'
import { SharedVaultUser } from '../../../Domain/SharedVault/User/SharedVaultUser'
import { SharedVaultUserHttpRepresentation } from '../../../Mapping/Http/SharedVaultUserHttpRepresentation'
import { DeleteSharedVault } from '../../../Domain/UseCase/DeleteSharedVault/DeleteSharedVault'
import { CreateSharedVaultFileValetToken } from '../../../Domain/UseCase/CreateSharedVaultFileValetToken/CreateSharedVaultFileValetToken'
import { DeleteSharedVault } from '../../../Domain/UseCase/SharedVaults/DeleteSharedVault/DeleteSharedVault'
import { CreateSharedVaultFileValetToken } from '../../../Domain/UseCase/SharedVaults/CreateSharedVaultFileValetToken/CreateSharedVaultFileValetToken'
export class HomeServerSharedVaultsController extends BaseHttpController {
constructor(

View File

@@ -2,9 +2,10 @@ import 'reflect-metadata'
import * as express from 'express'
import { ContentType } from '@standardnotes/common'
import { Result } from '@standardnotes/domain-core'
import { results } from 'inversify-express-utils'
import { InversifyExpressItemsController } from './InversifyExpressItemsController'
import { results } from 'inversify-express-utils'
import { Item } from '../../Domain/Item/Item'
import { ItemProjection } from '../../Projection/ItemProjection'
import { ProjectorInterface } from '../../Projection/ProjectorInterface'
@@ -12,9 +13,9 @@ import { ApiVersion } from '../../Domain/Api/ApiVersion'
import { SyncResponse20200115 } from '../../Domain/Item/SyncResponse/SyncResponse20200115'
import { SyncResponseFactoryInterface } from '../../Domain/Item/SyncResponse/SyncResponseFactoryInterface'
import { SyncResponseFactoryResolverInterface } from '../../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface'
import { CheckIntegrity } from '../../Domain/UseCase/CheckIntegrity/CheckIntegrity'
import { GetItem } from '../../Domain/UseCase/GetItem/GetItem'
import { SyncItems } from '../../Domain/UseCase/SyncItems'
import { CheckIntegrity } from '../../Domain/UseCase/Syncing/CheckIntegrity/CheckIntegrity'
import { GetItem } from '../../Domain/UseCase/Syncing/GetItem/GetItem'
import { SyncItems } from '../../Domain/UseCase/Syncing/SyncItems/SyncItems'
describe('InversifyExpressItemsController', () => {
let syncItems: SyncItems
@@ -35,13 +36,13 @@ describe('InversifyExpressItemsController', () => {
itemProjector.projectFull = jest.fn().mockReturnValue({ foo: 'bar' })
syncItems = {} as jest.Mocked<SyncItems>
syncItems.execute = jest.fn().mockReturnValue({ foo: 'bar' })
syncItems.execute = jest.fn().mockReturnValue(Result.ok({ foo: 'bar' }))
checkIntegrity = {} as jest.Mocked<CheckIntegrity>
checkIntegrity.execute = jest.fn().mockReturnValue({ mismatches: [{ uuid: '1-2-3', updated_at_timestamp: 2 }] })
checkIntegrity.execute = jest.fn().mockReturnValue(Result.ok([{ uuid: '1-2-3', updated_at_timestamp: 2 }]))
getItem = {} as jest.Mocked<GetItem>
getItem.execute = jest.fn().mockReturnValue({ success: true, item: {} as jest.Mocked<Item> })
getItem.execute = jest.fn().mockReturnValue(Result.ok({} as jest.Mocked<Item>))
request = {
headers: {},
@@ -100,7 +101,7 @@ describe('InversifyExpressItemsController', () => {
it('should return 404 on a missing single item', async () => {
request.params.uuid = '1-2-3'
getItem.execute = jest.fn().mockReturnValue({ success: false })
getItem.execute = jest.fn().mockReturnValue(Result.fail('Oops'))
const httpResponse = <results.NotFoundResult>await createController().getSingleItem(request, response)
const result = await httpResponse.executeAsync()

View File

@@ -5,9 +5,9 @@ import { controller, httpGet, httpPost, results } from 'inversify-express-utils'
import TYPES from '../../Bootstrap/Types'
import { Item } from '../../Domain/Item/Item'
import { SyncResponseFactoryResolverInterface } from '../../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface'
import { CheckIntegrity } from '../../Domain/UseCase/CheckIntegrity/CheckIntegrity'
import { GetItem } from '../../Domain/UseCase/GetItem/GetItem'
import { SyncItems } from '../../Domain/UseCase/SyncItems'
import { CheckIntegrity } from '../../Domain/UseCase/Syncing/CheckIntegrity/CheckIntegrity'
import { GetItem } from '../../Domain/UseCase/Syncing/GetItem/GetItem'
import { SyncItems } from '../../Domain/UseCase/Syncing/SyncItems/SyncItems'
import { ItemProjection } from '../../Projection/ItemProjection'
import { ProjectorInterface } from '../../Projection/ProjectorInterface'
import { HomeServerItemsController } from './HomeServer/HomeServerItemsController'
@@ -36,10 +36,7 @@ export class InversifyExpressItemsController extends HomeServerItemsController {
}
@httpGet('/:uuid')
override async getSingleItem(
request: Request,
response: Response,
): Promise<results.NotFoundResult | results.JsonResult> {
override async getSingleItem(request: Request, response: Response): Promise<results.JsonResult> {
return super.getSingleItem(request, response)
}
}

Some files were not shown because too many files have changed in this diff Show More