From 3bef47c27e66ab06770b020f2bc774d3d07bd458 Mon Sep 17 00:00:00 2001 From: Fanch Date: Mon, 13 May 2024 17:23:15 +0200 Subject: [PATCH 1/6] feat(pause ad): add first basic ad pause service --- src/app.constants.ts | 2 + src/modules/ad/ad.mapper.ts | 3 ++ src/modules/ad/ad.module.ts | 4 ++ .../commands/create-ad/create-ad.command.ts | 2 + .../commands/pause-ad/pause-ad.command.ts | 7 +++ .../commands/pause-ad/pause-ad.service.ts | 19 ++++++++ ...-when-ad-is-paused.domain-event-handler.ts | 19 ++++++++ .../application/ports/ad.repository.port.ts | 5 +++ src/modules/ad/core/domain/ad.entity.ts | 20 ++++++++- src/modules/ad/core/domain/ad.types.ts | 1 + .../domain/events/ad-created.domain-event.ts | 2 + .../domain/events/ad-paused.domain-event.ts | 7 +++ .../ad/infrastructure/ad.repository.ts | 1 + .../ad/interface/dtos/ad.response.dto.ts | 1 + .../dtos/create-ad.request.dto.ts | 4 ++ .../dtos/pause-ad.request.dto.ts | 7 +++ .../pause-ad.grpc.controller.ts | 45 +++++++++++++++++++ 17 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/modules/ad/core/application/commands/pause-ad/pause-ad.command.ts create mode 100644 src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts create mode 100644 src/modules/ad/core/application/event-handlers/publish-message-when-ad-is-paused.domain-event-handler.ts create mode 100644 src/modules/ad/core/domain/events/ad-paused.domain-event.ts create mode 100644 src/modules/ad/interface/grpc-controllers/dtos/pause-ad.request.dto.ts create mode 100644 src/modules/ad/interface/grpc-controllers/pause-ad.grpc.controller.ts diff --git a/src/app.constants.ts b/src/app.constants.ts index 7f2ec77..ec3f2ab 100644 --- a/src/app.constants.ts +++ b/src/app.constants.ts @@ -9,6 +9,8 @@ export const GRPC_SERVICE_NAME = 'AdService'; export const AD_CREATED_ROUTING_KEY = 'ad.created'; export const AD_UPDATED_ROUTING_KEY = 'ad.updated'; export const AD_DELETED_ROUTING_KEY = 'ad.deleted'; +// messaging output +export const AD_PAUSED_ROUTING_KEY = 'ad.paused'; // messaging input export const MATCHER_AD_CREATED_MESSAGE_HANDLER = 'matcherAdCreated'; diff --git a/src/modules/ad/ad.mapper.ts b/src/modules/ad/ad.mapper.ts index 839ced6..acdb6df 100644 --- a/src/modules/ad/ad.mapper.ts +++ b/src/modules/ad/ad.mapper.ts @@ -49,6 +49,7 @@ export class AdMapper seatsRequested: copy.seatsRequested as number, strict: copy.strict as boolean, waypoints: this.toWaypointWriteModel(copy.waypoints, update), + pause: copy.pause, comment: copy.comment, }; return record; @@ -160,6 +161,7 @@ export class AdMapper }, }, })), + pause: record.pause, comment: record.comment, }, }); @@ -227,6 +229,7 @@ export class AdMapper lon: waypoint.address.coordinates.lon, lat: waypoint.address.coordinates.lat, })); + response.pause = props.pause; response.comment = props.comment; return response; }; diff --git a/src/modules/ad/ad.module.ts b/src/modules/ad/ad.module.ts index 286670a..df2694d 100644 --- a/src/modules/ad/ad.module.ts +++ b/src/modules/ad/ad.module.ts @@ -12,6 +12,7 @@ import { import { AdMapper } from './ad.mapper'; import { CreateAdService } from './core/application/commands/create-ad/create-ad.service'; import { DeleteAdService } from './core/application/commands/delete-ad/delete-ad.service'; +import { PauseAdService } from './core/application/commands/pause-ad/pause-ad.service'; import { DeleteUserAdsService } from './core/application/commands/delete-user-ads/delete-user-ads.service'; import { InvalidateAdService } from './core/application/commands/invalidate-ad/invalidate-ad.service'; import { UpdateAdService } from './core/application/commands/update-ad/update-ad.service'; @@ -30,6 +31,7 @@ import { TimeConverter } from './infrastructure/time-converter'; import { TimezoneFinder } from './infrastructure/timezone-finder'; import { CreateAdGrpcController } from './interface/grpc-controllers/create-ad.grpc.controller'; import { DeleteAdGrpcController } from './interface/grpc-controllers/delete-ad.grpc.controller'; +import { PauseAdGrpcController } from './interface/grpc-controllers/pause-ad.grpc.controller'; import { FindAdByIdGrpcController } from './interface/grpc-controllers/find-ad-by-id.grpc.controller'; import { FindAdsByIdsGrpcController } from './interface/grpc-controllers/find-ads-by-ids.grpc.controller'; import { FindAdsByUserIdGrpcController } from './interface/grpc-controllers/find-ads-by-user-id.grpc.controller'; @@ -42,6 +44,7 @@ const grpcControllers = [ CreateAdGrpcController, UpdateAdGrpcController, DeleteAdGrpcController, + PauseAdGrpcController, FindAdByIdGrpcController, FindAdsByIdsGrpcController, FindAdsByUserIdGrpcController, @@ -63,6 +66,7 @@ const commandHandlers: Provider[] = [ CreateAdService, UpdateAdService, DeleteAdService, + PauseAdService, DeleteUserAdsService, ValidateAdService, InvalidateAdService, diff --git a/src/modules/ad/core/application/commands/create-ad/create-ad.command.ts b/src/modules/ad/core/application/commands/create-ad/create-ad.command.ts index fefe004..96dc243 100644 --- a/src/modules/ad/core/application/commands/create-ad/create-ad.command.ts +++ b/src/modules/ad/core/application/commands/create-ad/create-ad.command.ts @@ -15,6 +15,7 @@ export class CreateAdCommand extends Command { readonly seatsRequested?: number; readonly strict: boolean; readonly waypoints: Waypoint[]; + readonly pause: boolean; readonly comment?: string; constructor(props: CommandProps) { @@ -30,6 +31,7 @@ export class CreateAdCommand extends Command { this.seatsRequested = props.seatsRequested; this.strict = props.strict; this.waypoints = props.waypoints; + this.pause = props.pause; this.comment = props.comment; } } diff --git a/src/modules/ad/core/application/commands/pause-ad/pause-ad.command.ts b/src/modules/ad/core/application/commands/pause-ad/pause-ad.command.ts new file mode 100644 index 0000000..2c910b1 --- /dev/null +++ b/src/modules/ad/core/application/commands/pause-ad/pause-ad.command.ts @@ -0,0 +1,7 @@ +import { Command, CommandProps } from '@mobicoop/ddd-library'; + +export class PauseAdCommand extends Command { + constructor(props: CommandProps) { + super(props); + } +} diff --git a/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts b/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts new file mode 100644 index 0000000..fecfe01 --- /dev/null +++ b/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts @@ -0,0 +1,19 @@ +import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens'; +import { Inject } from '@nestjs/common'; +import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; +import { AdRepositoryPort } from '../../ports/ad.repository.port'; +import { PauseAdCommand } from './pause-ad.command'; + +@CommandHandler(PauseAdCommand) +export class PauseAdService implements ICommandHandler { + constructor( + @Inject(AD_REPOSITORY) + private readonly adRepository: AdRepositoryPort, + ) {} + + async execute(command: PauseAdCommand): Promise { + const ad = await this.adRepository.findOneById(command.id); + ad.pause(); + await this.adRepository.update(ad.id, ad); + } +} diff --git a/src/modules/ad/core/application/event-handlers/publish-message-when-ad-is-paused.domain-event-handler.ts b/src/modules/ad/core/application/event-handlers/publish-message-when-ad-is-paused.domain-event-handler.ts new file mode 100644 index 0000000..58193b0 --- /dev/null +++ b/src/modules/ad/core/application/event-handlers/publish-message-when-ad-is-paused.domain-event-handler.ts @@ -0,0 +1,19 @@ +import { MessagePublisherPort } from '@mobicoop/ddd-library'; +import { AD_MESSAGE_PUBLISHER } from '@modules/ad/ad.di-tokens'; +import { Inject, Injectable } from '@nestjs/common'; +import { OnEvent } from '@nestjs/event-emitter'; +import { AD_PAUSED_ROUTING_KEY } from '@src/app.constants'; +import { AdPausedDomainEvent } from '../../domain/events/ad-paused.domain-event'; + +@Injectable() +export class PublishMessageWhenAdIsPausedDomainEventHandler { + constructor( + @Inject(AD_MESSAGE_PUBLISHER) + private readonly messagePublisher: MessagePublisherPort, + ) {} + + @OnEvent(AdPausedDomainEvent.name, { async: true, promisify: true }) + async handle(event: AdPausedDomainEvent): Promise { + this.messagePublisher.publish(AD_PAUSED_ROUTING_KEY, JSON.stringify(event)); + } +} diff --git a/src/modules/ad/core/application/ports/ad.repository.port.ts b/src/modules/ad/core/application/ports/ad.repository.port.ts index 5b9fe49..748c9cf 100644 --- a/src/modules/ad/core/application/ports/ad.repository.port.ts +++ b/src/modules/ad/core/application/ports/ad.repository.port.ts @@ -2,3 +2,8 @@ import { RepositoryPort } from '@mobicoop/ddd-library'; import { AdEntity } from '../../domain/ad.entity'; export type AdRepositoryPort = RepositoryPort; +/* + & { + pause(entity: AdEntity, identifier?: string): Promise; +}; +*/ diff --git a/src/modules/ad/core/domain/ad.entity.ts b/src/modules/ad/core/domain/ad.entity.ts index 00ea1eb..60149f5 100644 --- a/src/modules/ad/core/domain/ad.entity.ts +++ b/src/modules/ad/core/domain/ad.entity.ts @@ -3,6 +3,7 @@ import { v4 } from 'uuid'; import { AdProps, CreateAdProps, Status } from './ad.types'; import { AdCreatedDomainEvent } from './events/ad-created.domain-event'; import { AdDeletedDomainEvent } from './events/ad-delete.domain-event'; +import { AdPausedDomainEvent } from './events/ad-paused.domain-event'; import { AdInvalidatedDomainEvent } from './events/ad-invalidated.domain-event'; import { AdSuspendedDomainEvent } from './events/ad-suspended.domain-event'; import { AdValidatedDomainEvent } from './events/ad-validated.domain-event'; @@ -48,6 +49,7 @@ export class AdEntity extends AggregateRoot { lon: waypoint.address.coordinates.lon, lat: waypoint.address.coordinates.lat, })), + pause: props.pause, comment: props.comment, }), ); @@ -114,6 +116,10 @@ export class AdEntity extends AggregateRoot { return this; }; + validate(): void { + // entity business rules validation to protect it's invariant before saving entity to a database + } + delete(): void { this.addEvent( new AdDeletedDomainEvent({ @@ -122,7 +128,17 @@ export class AdEntity extends AggregateRoot { ); } - validate(): void { - // entity business rules validation to protect it's invariant before saving entity to a database + pause(): AdEntity { + this.props.pause = !this.props.pause; + this.addEvent( + new AdPausedDomainEvent({ + metadata: { + correlationId: this.id, + timestamp: Date.now(), + }, + aggregateId: this.id, + }), + ); + return this; } } diff --git a/src/modules/ad/core/domain/ad.types.ts b/src/modules/ad/core/domain/ad.types.ts index d42115a..83e3a1a 100644 --- a/src/modules/ad/core/domain/ad.types.ts +++ b/src/modules/ad/core/domain/ad.types.ts @@ -14,6 +14,7 @@ export interface CreateAdProps { seatsRequested: number; strict: boolean; waypoints: WaypointProps[]; + pause: boolean; comment?: string; } diff --git a/src/modules/ad/core/domain/events/ad-created.domain-event.ts b/src/modules/ad/core/domain/events/ad-created.domain-event.ts index 12c45cf..2fe16d5 100644 --- a/src/modules/ad/core/domain/events/ad-created.domain-event.ts +++ b/src/modules/ad/core/domain/events/ad-created.domain-event.ts @@ -13,6 +13,7 @@ export class AdCreatedDomainEvent extends DomainEvent { readonly seatsRequested: number; readonly strict: boolean; readonly waypoints: Waypoint[]; + readonly pause?: boolean; readonly comment?: string; constructor(props: DomainEventProps) { @@ -28,6 +29,7 @@ export class AdCreatedDomainEvent extends DomainEvent { this.seatsRequested = props.seatsRequested; this.strict = props.strict; this.waypoints = props.waypoints; + this.pause = props.pause; this.comment = props.comment; } } diff --git a/src/modules/ad/core/domain/events/ad-paused.domain-event.ts b/src/modules/ad/core/domain/events/ad-paused.domain-event.ts new file mode 100644 index 0000000..7737564 --- /dev/null +++ b/src/modules/ad/core/domain/events/ad-paused.domain-event.ts @@ -0,0 +1,7 @@ +import { DomainEvent, DomainEventProps } from '@mobicoop/ddd-library'; + +export class AdPausedDomainEvent extends DomainEvent { + constructor(props: DomainEventProps) { + super(props); + } +} diff --git a/src/modules/ad/infrastructure/ad.repository.ts b/src/modules/ad/infrastructure/ad.repository.ts index fa06d0a..ecc63cb 100644 --- a/src/modules/ad/infrastructure/ad.repository.ts +++ b/src/modules/ad/infrastructure/ad.repository.ts @@ -24,6 +24,7 @@ export type AdBaseModel = { seatsProposed: number; seatsRequested: number; strict: boolean; + pause: boolean; comment?: string; }; diff --git a/src/modules/ad/interface/dtos/ad.response.dto.ts b/src/modules/ad/interface/dtos/ad.response.dto.ts index 60a301f..c6b0a41 100644 --- a/src/modules/ad/interface/dtos/ad.response.dto.ts +++ b/src/modules/ad/interface/dtos/ad.response.dto.ts @@ -28,5 +28,6 @@ export class AdResponseDto extends ResponseBase { lon: number; lat: number; }[]; + pause: boolean; comment?: string; } diff --git a/src/modules/ad/interface/grpc-controllers/dtos/create-ad.request.dto.ts b/src/modules/ad/interface/grpc-controllers/dtos/create-ad.request.dto.ts index 14122d0..aa08e32 100644 --- a/src/modules/ad/interface/grpc-controllers/dtos/create-ad.request.dto.ts +++ b/src/modules/ad/interface/grpc-controllers/dtos/create-ad.request.dto.ts @@ -81,6 +81,10 @@ export class CreateAdRequestDto { @ValidateNested({ each: true }) waypoints: WaypointDto[]; + @IsBoolean() + @IsOptional() + pause: boolean; + @Length(0, 2000) @IsString() @IsOptional() diff --git a/src/modules/ad/interface/grpc-controllers/dtos/pause-ad.request.dto.ts b/src/modules/ad/interface/grpc-controllers/dtos/pause-ad.request.dto.ts new file mode 100644 index 0000000..0e6726d --- /dev/null +++ b/src/modules/ad/interface/grpc-controllers/dtos/pause-ad.request.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from 'class-validator'; + +export class PauseAdRequestDto { + @IsString() + @IsNotEmpty() + id: string; +} diff --git a/src/modules/ad/interface/grpc-controllers/pause-ad.grpc.controller.ts b/src/modules/ad/interface/grpc-controllers/pause-ad.grpc.controller.ts new file mode 100644 index 0000000..78cd230 --- /dev/null +++ b/src/modules/ad/interface/grpc-controllers/pause-ad.grpc.controller.ts @@ -0,0 +1,45 @@ +import { + DatabaseErrorException, + NotFoundException, + RpcExceptionCode, + RpcValidationPipe, +} from '@mobicoop/ddd-library'; +import { PauseAdCommand } from '@modules/ad/core/application/commands/pause-ad/pause-ad.command'; +import { Controller, UsePipes } from '@nestjs/common'; +import { CommandBus } from '@nestjs/cqrs'; +import { GrpcMethod, RpcException } from '@nestjs/microservices'; +import { GRPC_SERVICE_NAME } from '@src/app.constants'; +import { PauseAdRequestDto } from './dtos/pause-ad.request.dto'; + +@UsePipes( + new RpcValidationPipe({ + whitelist: false, + forbidUnknownValues: false, + }), +) +@Controller() +export class PauseAdGrpcController { + constructor(private readonly commandBus: CommandBus) {} + + @GrpcMethod(GRPC_SERVICE_NAME, 'Pause') + async pause(data: PauseAdRequestDto): Promise { + try { + await this.commandBus.execute(new PauseAdCommand(data)); + } catch (error: any) { + if (error instanceof NotFoundException) + throw new RpcException({ + code: RpcExceptionCode.NOT_FOUND, + message: error.message, + }); + if (error instanceof DatabaseErrorException) + throw new RpcException({ + code: RpcExceptionCode.INTERNAL, + message: error.message, + }); + throw new RpcException({ + code: RpcExceptionCode.UNKNOWN, + message: error.message, + }); + } + } +} From 3b8ab49396e75efe09abb432227f9d9acb0e6dad Mon Sep 17 00:00:00 2001 From: Fanch Date: Tue, 14 May 2024 15:30:44 +0200 Subject: [PATCH 2/6] feat(pause ad): add pause as rpc route in proto --- src/modules/ad/interface/grpc-controllers/ad.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/ad/interface/grpc-controllers/ad.proto b/src/modules/ad/interface/grpc-controllers/ad.proto index da93584..684ce08 100644 --- a/src/modules/ad/interface/grpc-controllers/ad.proto +++ b/src/modules/ad/interface/grpc-controllers/ad.proto @@ -9,6 +9,7 @@ service AdService { rpc Create(Ad) returns (AdById); rpc Update(Ad) returns (Empty); rpc Delete(AdById) returns (Empty); + rpc Pause(AdById) returns (Empty); } message AdById { @@ -37,6 +38,7 @@ message Ad { bool strict = 11; repeated Waypoint waypoints = 12; optional string comment = 13; + optional bool pause = 14; } message ScheduleItem { From 54d1dab461fb7d1391ac9b3f00861397613df292 Mon Sep 17 00:00:00 2001 From: Fanch Date: Tue, 14 May 2024 15:31:14 +0200 Subject: [PATCH 3/6] feat(pause ad): add pause in db with prisma --- prisma/migrations/20240514132712_pause/migration.sql | 2 ++ prisma/schema.prisma | 1 + 2 files changed, 3 insertions(+) create mode 100644 prisma/migrations/20240514132712_pause/migration.sql diff --git a/prisma/migrations/20240514132712_pause/migration.sql b/prisma/migrations/20240514132712_pause/migration.sql new file mode 100644 index 0000000..0fcd0e3 --- /dev/null +++ b/prisma/migrations/20240514132712_pause/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "ad" ADD COLUMN "pause" BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c7d36f3..179925c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -27,6 +27,7 @@ model Ad { createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt waypoints Waypoint[] + pause Boolean @default(false) comment String? @@map("ad") From be2a2badcf6f3d02d20e9035580cab6541be9630 Mon Sep 17 00:00:00 2001 From: Fanch Date: Wed, 15 May 2024 14:23:05 +0200 Subject: [PATCH 4/6] test(pause ad): adapt current test after adding pause flag in ad --- tests/integration/ad/ad.repository.spec.ts | 2 ++ tests/unit/ad/ad.mapper.spec.ts | 2 ++ tests/unit/ad/core/ad.entity.spec.ts | 6 ++++++ tests/unit/ad/core/ad.fixtures.ts | 1 + tests/unit/ad/core/create-ad.service.spec.ts | 1 + tests/unit/ad/core/find-ads-by-ids.query-handler.spec.ts | 1 + .../unit/ad/core/find-ads-by-user-id.query-handler.spec.ts | 1 + tests/unit/ad/core/invalidate-ad.service.spec.ts | 1 + tests/unit/ad/core/validate-ad.service.spec.ts | 1 + 9 files changed, 16 insertions(+) diff --git a/tests/integration/ad/ad.repository.spec.ts b/tests/integration/ad/ad.repository.spec.ts index 8bcfb9d..228450b 100644 --- a/tests/integration/ad/ad.repository.spec.ts +++ b/tests/integration/ad/ad.repository.spec.ts @@ -225,6 +225,7 @@ describe('Ad Repository', () => { }, }, ], + pause: false, }; const adToCreate: AdEntity = AdEntity.create(createAdProps); @@ -301,6 +302,7 @@ describe('Ad Repository', () => { }, }, ], + pause: false, }; const adToCreate: AdEntity = AdEntity.create(createAdProps); diff --git a/tests/unit/ad/ad.mapper.spec.ts b/tests/unit/ad/ad.mapper.spec.ts index dd71928..5e53507 100644 --- a/tests/unit/ad/ad.mapper.spec.ts +++ b/tests/unit/ad/ad.mapper.spec.ts @@ -59,6 +59,7 @@ const adEntity: AdEntity = new AdEntity({ strict: false, seatsProposed: 3, seatsRequested: 1, + pause: false, }, createdAt: now, updatedAt: now, @@ -112,6 +113,7 @@ const adReadModel: AdReadModel = { seatsProposed: 3, seatsRequested: 1, comment: '', + pause: false, createdAt: now, updatedAt: now, }; diff --git a/tests/unit/ad/core/ad.entity.spec.ts b/tests/unit/ad/core/ad.entity.spec.ts index 72bafb7..abf46c2 100644 --- a/tests/unit/ad/core/ad.entity.spec.ts +++ b/tests/unit/ad/core/ad.entity.spec.ts @@ -90,36 +90,42 @@ const punctualPassengerCreateAdProps: CreateAdProps = { ...punctualCreateAdProps, driver: false, passenger: true, + pause: false, }; const recurrentPassengerCreateAdProps: CreateAdProps = { ...baseCreateAdProps, ...recurrentCreateAdProps, driver: false, passenger: true, + pause: false, }; const punctualDriverCreateAdProps: CreateAdProps = { ...baseCreateAdProps, ...punctualCreateAdProps, driver: true, passenger: false, + pause: false, }; const recurrentDriverCreateAdProps: CreateAdProps = { ...baseCreateAdProps, ...recurrentCreateAdProps, driver: true, passenger: false, + pause: false, }; const punctualDriverPassengerCreateAdProps: CreateAdProps = { ...baseCreateAdProps, ...punctualCreateAdProps, driver: true, passenger: true, + pause: false, }; const recurrentDriverPassengerCreateAdProps: CreateAdProps = { ...baseCreateAdProps, ...recurrentCreateAdProps, driver: true, passenger: true, + pause: false, }; describe('Ad entity create', () => { diff --git a/tests/unit/ad/core/ad.fixtures.ts b/tests/unit/ad/core/ad.fixtures.ts index 3e2663c..4505f1b 100644 --- a/tests/unit/ad/core/ad.fixtures.ts +++ b/tests/unit/ad/core/ad.fixtures.ts @@ -53,5 +53,6 @@ export function punctualPassengerCreateAdProps(): CreateAdProps { ...punctualCreateAdProps, driver: false, passenger: true, + pause: false, }; } diff --git a/tests/unit/ad/core/create-ad.service.spec.ts b/tests/unit/ad/core/create-ad.service.spec.ts index 89ac262..61c4479 100644 --- a/tests/unit/ad/core/create-ad.service.spec.ts +++ b/tests/unit/ad/core/create-ad.service.spec.ts @@ -49,6 +49,7 @@ const punctualCreateAdRequest: CreateAdRequestDto = { strict: false, frequency: Frequency.PUNCTUAL, waypoints: [originWaypoint, destinationWaypoint], + pause: false, }; const mockAdRepository = { diff --git a/tests/unit/ad/core/find-ads-by-ids.query-handler.spec.ts b/tests/unit/ad/core/find-ads-by-ids.query-handler.spec.ts index 0f7e05d..d3ac40e 100644 --- a/tests/unit/ad/core/find-ads-by-ids.query-handler.spec.ts +++ b/tests/unit/ad/core/find-ads-by-ids.query-handler.spec.ts @@ -56,6 +56,7 @@ const punctualPassengerCreateAdProps: CreateAdProps = { ...punctualCreateAdProps, driver: false, passenger: true, + pause: false, }; const ads: AdEntity[] = [ diff --git a/tests/unit/ad/core/find-ads-by-user-id.query-handler.spec.ts b/tests/unit/ad/core/find-ads-by-user-id.query-handler.spec.ts index 4f7751a..c6748ce 100644 --- a/tests/unit/ad/core/find-ads-by-user-id.query-handler.spec.ts +++ b/tests/unit/ad/core/find-ads-by-user-id.query-handler.spec.ts @@ -56,6 +56,7 @@ const punctualPassengerCreateAdProps: CreateAdProps = { ...punctualCreateAdProps, driver: false, passenger: true, + pause: false, }; const ads: AdEntity[] = [ diff --git a/tests/unit/ad/core/invalidate-ad.service.spec.ts b/tests/unit/ad/core/invalidate-ad.service.spec.ts index 8bd1568..8d89466 100644 --- a/tests/unit/ad/core/invalidate-ad.service.spec.ts +++ b/tests/unit/ad/core/invalidate-ad.service.spec.ts @@ -57,6 +57,7 @@ const punctualPassengerCreateAdProps: CreateAdProps = { ...punctualCreateAdProps, driver: false, passenger: true, + pause: false, }; const ad: AdEntity = AdEntity.create(punctualPassengerCreateAdProps); diff --git a/tests/unit/ad/core/validate-ad.service.spec.ts b/tests/unit/ad/core/validate-ad.service.spec.ts index 1ccd147..b33fca4 100644 --- a/tests/unit/ad/core/validate-ad.service.spec.ts +++ b/tests/unit/ad/core/validate-ad.service.spec.ts @@ -57,6 +57,7 @@ const punctualPassengerCreateAdProps: CreateAdProps = { ...punctualCreateAdProps, driver: false, passenger: true, + pause: false, }; const ad: AdEntity = AdEntity.create(punctualPassengerCreateAdProps); From 2ce64cd1c48f9e4f0666dcaff9b81e79f17f3957 Mon Sep 17 00:00:00 2001 From: Fanch Date: Thu, 16 May 2024 11:24:14 +0200 Subject: [PATCH 5/6] fix(ad pause): fix code after merge of update ad --- .../ad/core/application/commands/create-ad/create-ad.service.ts | 1 + tests/unit/ad/interface/ad.fixtures.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/modules/ad/core/application/commands/create-ad/create-ad.service.ts b/src/modules/ad/core/application/commands/create-ad/create-ad.service.ts index 98a95dc..8ed52c7 100644 --- a/src/modules/ad/core/application/commands/create-ad/create-ad.service.ts +++ b/src/modules/ad/core/application/commands/create-ad/create-ad.service.ts @@ -75,6 +75,7 @@ export function createPropsFromCommand( seatsProposed: command.seatsProposed ?? 0, seatsRequested: command.seatsRequested ?? 0, strict: command.strict, + pause: command.pause, waypoints: command.waypoints.map((waypoint: Waypoint) => ({ position: waypoint.position, address: { diff --git a/tests/unit/ad/interface/ad.fixtures.ts b/tests/unit/ad/interface/ad.fixtures.ts index 6e19747..05328e8 100644 --- a/tests/unit/ad/interface/ad.fixtures.ts +++ b/tests/unit/ad/interface/ad.fixtures.ts @@ -37,6 +37,7 @@ export function punctualCreateAdRequest(): CreateAdRequestDto { seatsRequested: 1, seatsProposed: 3, strict: false, + pause: false, frequency: Frequency.PUNCTUAL, waypoints: [originWaypoint, destinationWaypoint], }; From eeddd54139852cea9a0655db280572bb803fd954 Mon Sep 17 00:00:00 2001 From: Fanch Date: Thu, 16 May 2024 15:40:03 +0200 Subject: [PATCH 6/6] feat(pause ad): emit update event after pause ad --- .../commands/pause-ad/pause-ad.service.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts b/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts index fecfe01..356f66d 100644 --- a/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts +++ b/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts @@ -1,19 +1,30 @@ import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens'; import { Inject } from '@nestjs/common'; import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; +import { EventEmitter2 } from '@nestjs/event-emitter'; import { AdRepositoryPort } from '../../ports/ad.repository.port'; import { PauseAdCommand } from './pause-ad.command'; +import { AdUpdatedDomainEvent } from '@modules/ad/core/domain/events/ad.domain-event'; @CommandHandler(PauseAdCommand) export class PauseAdService implements ICommandHandler { constructor( @Inject(AD_REPOSITORY) private readonly adRepository: AdRepositoryPort, + private readonly eventEmitter: EventEmitter2, ) {} async execute(command: PauseAdCommand): Promise { - const ad = await this.adRepository.findOneById(command.id); + const ad = await this.adRepository.findOneById(command.id, { + // TODO: waypoints and schedule needed for event, should be optional if no modif on them ... + waypoints: true, + schedule: true, + }); ad.pause(); await this.adRepository.update(ad.id, ad); + this.eventEmitter.emitAsync( + AdUpdatedDomainEvent.name, + new AdUpdatedDomainEvent(ad), + ); } }