From 18d07d431f08dc17a276f84c0724935d9014a4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20S=C3=B3jko?= Date: Mon, 10 Jul 2023 14:21:59 +0200 Subject: [PATCH] feat: messages controller. (#653) Co-authored-by: Mo --- .../syncing-server/src/Bootstrap/Types.ts | 8 +- .../HomeServerMessagesController.ts | 138 ++++++++++++++++++ .../InversifyExpressMessagesController.ts | 62 ++++++++ .../src/Mapping/Http/MessageHttpMapper.ts | 21 +++ .../Mapping/Http/MessageHttpRepresentation.ts | 8 + 5 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 packages/syncing-server/src/Infra/InversifyExpressUtils/HomeServer/HomeServerMessagesController.ts create mode 100644 packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressMessagesController.ts create mode 100644 packages/syncing-server/src/Mapping/Http/MessageHttpMapper.ts create mode 100644 packages/syncing-server/src/Mapping/Http/MessageHttpRepresentation.ts diff --git a/packages/syncing-server/src/Bootstrap/Types.ts b/packages/syncing-server/src/Bootstrap/Types.ts index c1ce73cdf..e78f595d9 100644 --- a/packages/syncing-server/src/Bootstrap/Types.ts +++ b/packages/syncing-server/src/Bootstrap/Types.ts @@ -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 diff --git a/packages/syncing-server/src/Infra/InversifyExpressUtils/HomeServer/HomeServerMessagesController.ts b/packages/syncing-server/src/Infra/InversifyExpressUtils/HomeServer/HomeServerMessagesController.ts new file mode 100644 index 000000000..4c874b8ce --- /dev/null +++ b/packages/syncing-server/src/Infra/InversifyExpressUtils/HomeServer/HomeServerMessagesController.ts @@ -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, + 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 { + 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 { + 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 { + 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 { + 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 { + 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 }) + } +} diff --git a/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressMessagesController.ts b/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressMessagesController.ts new file mode 100644 index 000000000..13771b067 --- /dev/null +++ b/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressMessagesController.ts @@ -0,0 +1,62 @@ +import { controller, httpDelete, httpGet, httpPost, results } from 'inversify-express-utils' +import { inject } from 'inversify' +import { MapperInterface } from '@standardnotes/domain-core' +import { Request, Response } from 'express' + +import TYPES from '../../Bootstrap/Types' +import { HomeServerMessagesController } from './HomeServer/HomeServerMessagesController' +import { GetMessagesSentToUser } from '../../Domain/UseCase/Messaging/GetMessagesSentToUser/GetMessagesSentToUser' +import { DeleteAllMessagesSentToUser } from '../../Domain/UseCase/Messaging/DeleteAllMessagesSentToUser/DeleteAllMessagesSentToUser' +import { DeleteMessage } from '../../Domain/UseCase/Messaging/DeleteMessage/DeleteMessage' +import { SendMessageToUser } from '../../Domain/UseCase/Messaging/SendMessageToUser/SendMessageToUser' +import { MessageHttpRepresentation } from '../../Mapping/Http/MessageHttpRepresentation' +import { Message } from '../../Domain/Message/Message' +import { GetMessagesSentByUser } from '../../Domain/UseCase/Messaging/GetMessagesSentByUser/GetMessagesSentByUser' + +@controller('/messages', TYPES.Sync_AuthMiddleware) +export class InversifyExpressMessagesController extends HomeServerMessagesController { + constructor( + @inject(TYPES.Sync_GetMessagesSentToUser) override getMessageSentToUserUseCase: GetMessagesSentToUser, + @inject(TYPES.Sync_GetMessagesSentByUser) override getMessagesSentByUserUseCase: GetMessagesSentByUser, + @inject(TYPES.Sync_SendMessageToUser) override sendMessageToUserUseCase: SendMessageToUser, + @inject(TYPES.Sync_DeleteAllMessagesSentToUser) + override deleteMessagesSentToUserUseCase: DeleteAllMessagesSentToUser, + @inject(TYPES.Sync_DeleteMessage) override deleteMessageUseCase: DeleteMessage, + @inject(TYPES.Sync_MessageHttpMapper) + override messageHttpMapper: MapperInterface, + ) { + super( + getMessageSentToUserUseCase, + getMessagesSentByUserUseCase, + sendMessageToUserUseCase, + deleteMessagesSentToUserUseCase, + deleteMessageUseCase, + messageHttpMapper, + ) + } + + @httpGet('/') + override async getMessages(_request: Request, response: Response): Promise { + return super.getMessages(_request, response) + } + + @httpGet('/outbound') + override async getMessagesSent(_request: Request, response: Response): Promise { + return super.getMessagesSent(_request, response) + } + + @httpPost('/') + override async sendMessage(request: Request, response: Response): Promise { + return super.sendMessage(request, response) + } + + @httpDelete('/inbound') + override async deleteMessagesSentToUser(_request: Request, response: Response): Promise { + return super.deleteMessagesSentToUser(_request, response) + } + + @httpDelete('/:messageUuid') + override async deleteMessage(request: Request, response: Response): Promise { + return super.deleteMessage(request, response) + } +} diff --git a/packages/syncing-server/src/Mapping/Http/MessageHttpMapper.ts b/packages/syncing-server/src/Mapping/Http/MessageHttpMapper.ts new file mode 100644 index 000000000..21f32c0ef --- /dev/null +++ b/packages/syncing-server/src/Mapping/Http/MessageHttpMapper.ts @@ -0,0 +1,21 @@ +import { MapperInterface } from '@standardnotes/domain-core' + +import { Message } from '../../Domain/Message/Message' +import { MessageHttpRepresentation } from './MessageHttpRepresentation' + +export class MessageHttpMapper implements MapperInterface { + toDomain(_projection: MessageHttpRepresentation): Message { + throw new Error('Mapping from http representation to domain is not implemented.') + } + + toProjection(domain: Message): MessageHttpRepresentation { + return { + uuid: domain.id.toString(), + recipient_uuid: domain.props.recipientUuid.value, + sender_uuid: domain.props.senderUuid.value, + encrypted_message: domain.props.encryptedMessage, + created_at_timestamp: domain.props.timestamps.createdAt, + updated_at_timestamp: domain.props.timestamps.updatedAt, + } + } +} diff --git a/packages/syncing-server/src/Mapping/Http/MessageHttpRepresentation.ts b/packages/syncing-server/src/Mapping/Http/MessageHttpRepresentation.ts new file mode 100644 index 000000000..ccc2d9911 --- /dev/null +++ b/packages/syncing-server/src/Mapping/Http/MessageHttpRepresentation.ts @@ -0,0 +1,8 @@ +export interface MessageHttpRepresentation { + uuid: string + recipient_uuid: string + sender_uuid: string + encrypted_message: string + created_at_timestamp: number + updated_at_timestamp: number +}