From 9056b6093710484837f9cf3df2750d5706a06e4b Mon Sep 17 00:00:00 2001 From: Aswin Ashar Abdullah Date: Tue, 16 Jul 2024 13:17:06 +0700 Subject: [PATCH 1/5] feat(SPG-448) REST API CUD Berita --- src/app.module.ts | 4 + .../strings/constants/module.constants.ts | 1 + src/core/strings/constants/table.constants.ts | 1 + src/database/migrations/1721109817371-news.ts | 19 ++++ src/modules/web-information/news/constants.ts | 0 .../news/data/models/news.model.ts | 22 ++++ .../news/data/services/news-data.service.ts | 17 +++ .../event/news-change-status.event.ts | 5 + .../entities/event/news-created.event.ts | 5 + .../entities/event/news-deleted.event.ts | 5 + .../entities/event/news-updated.event.ts | 5 + .../news/domain/entities/news.entity.ts | 8 ++ .../usecases/managers/active-news.manager.ts | 45 ++++++++ .../managers/batch-active-news.manager.ts | 45 ++++++++ .../managers/batch-confirm-news.manager.ts | 45 ++++++++ .../managers/batch-delete-news.manager.ts | 45 ++++++++ .../managers/batch-inactive-news.manager.ts | 45 ++++++++ .../usecases/managers/confirm-news.manager.ts | 45 ++++++++ .../usecases/managers/create-news.manager.ts | 42 +++++++ .../usecases/managers/delete-news.manager.ts | 45 ++++++++ .../managers/inactive-news.manager.ts | 45 ++++++++ .../usecases/managers/update-news.manager.ts | 46 ++++++++ .../domain/usecases/news-data.orchestrator.ts | 106 ++++++++++++++++++ src/modules/web-information/news/index.ts | 0 .../news/infrastructure/dto/news.dto.ts | 33 ++++++ .../infrastructure/news-data.controller.ts | 78 +++++++++++++ .../web-information/news/news.module.ts | 54 +++++++++ 27 files changed, 811 insertions(+) create mode 100644 src/database/migrations/1721109817371-news.ts create mode 100644 src/modules/web-information/news/constants.ts create mode 100644 src/modules/web-information/news/data/models/news.model.ts create mode 100644 src/modules/web-information/news/data/services/news-data.service.ts create mode 100644 src/modules/web-information/news/domain/entities/event/news-change-status.event.ts create mode 100644 src/modules/web-information/news/domain/entities/event/news-created.event.ts create mode 100644 src/modules/web-information/news/domain/entities/event/news-deleted.event.ts create mode 100644 src/modules/web-information/news/domain/entities/event/news-updated.event.ts create mode 100644 src/modules/web-information/news/domain/entities/news.entity.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/active-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/batch-active-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/batch-confirm-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/batch-delete-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/batch-inactive-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/confirm-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/create-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/delete-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/inactive-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/update-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/news-data.orchestrator.ts create mode 100644 src/modules/web-information/news/index.ts create mode 100644 src/modules/web-information/news/infrastructure/dto/news.dto.ts create mode 100644 src/modules/web-information/news/infrastructure/news-data.controller.ts create mode 100644 src/modules/web-information/news/news.module.ts diff --git a/src/app.module.ts b/src/app.module.ts index 40bb073..d7e62db 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -64,6 +64,8 @@ import { TermConditionModel } from './modules/web-information/term-condition/dat import { FaqModel } from './modules/web-information/faq/data/models/faq.model'; import { FaqModule } from './modules/web-information/faq/faq.module'; import { UploadModule } from './modules/configuration/upload/upload.module'; +import { NewsModule } from './modules/web-information/news/news.module'; +import { NewsModel } from './modules/web-information/news/data/models/news.model'; @Module({ imports: [ @@ -88,6 +90,7 @@ import { UploadModule } from './modules/configuration/upload/upload.module'; ItemCategoryModel, ItemRateModel, LogModel, + NewsModel, PaymentMethodModel, RefundModel, RefundItemModel, @@ -148,6 +151,7 @@ import { UploadModule } from './modules/configuration/upload/upload.module'; // web information FaqModule, GateModule, + NewsModule, TermConditionModule, // report diff --git a/src/core/strings/constants/module.constants.ts b/src/core/strings/constants/module.constants.ts index 6549a5a..a26cada 100644 --- a/src/core/strings/constants/module.constants.ts +++ b/src/core/strings/constants/module.constants.ts @@ -4,6 +4,7 @@ export enum MODULE_NAME { ITEM = 'items', ITEM_CATEGORY = 'item-categories', ITEM_RATE = 'item-rates', + NEWS = 'news', PAYMENT_METHOD = 'payment-methods', RECONCILIATION = 'reconciliations', REFUND = 'refunds', diff --git a/src/core/strings/constants/table.constants.ts b/src/core/strings/constants/table.constants.ts index 862d2d5..e757c1f 100644 --- a/src/core/strings/constants/table.constants.ts +++ b/src/core/strings/constants/table.constants.ts @@ -6,6 +6,7 @@ export enum TABLE_NAME { ITEM_RATE = 'item_rates', GATE = 'gates', LOG = 'logs', + NEWS = 'news', PAYMENT_METHOD = 'payment_methods', PRICE_FORMULA = 'price_formulas', REFUND = 'refunds', diff --git a/src/database/migrations/1721109817371-news.ts b/src/database/migrations/1721109817371-news.ts new file mode 100644 index 0000000..cfabc56 --- /dev/null +++ b/src/database/migrations/1721109817371-news.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class News1721109817371 implements MigrationInterface { + name = 'News1721109817371'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE "public"."news_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`, + ); + await queryRunner.query( + `CREATE TABLE "news" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "creator_id" character varying(36), "creator_name" character varying(125), "editor_id" character varying(36), "editor_name" character varying(125), "created_at" bigint NOT NULL, "updated_at" bigint NOT NULL, "status" "public"."news_status_enum" NOT NULL DEFAULT 'draft', "image_url" character varying, "title" character varying, "teaser" character varying, "description" character varying, CONSTRAINT "PK_39a43dfcb6007180f04aff2357e" PRIMARY KEY ("id"))`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "news"`); + await queryRunner.query(`DROP TYPE "public"."news_status_enum"`); + } +} diff --git a/src/modules/web-information/news/constants.ts b/src/modules/web-information/news/constants.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/web-information/news/data/models/news.model.ts b/src/modules/web-information/news/data/models/news.model.ts new file mode 100644 index 0000000..b74b247 --- /dev/null +++ b/src/modules/web-information/news/data/models/news.model.ts @@ -0,0 +1,22 @@ +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { NewsEntity } from '../../domain/entities/news.entity'; +import { Column, Entity } from 'typeorm'; +import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; + +@Entity(TABLE_NAME.NEWS) +export class NewsModel + extends BaseStatusModel + implements NewsEntity +{ + @Column('varchar', { name: 'image_url', nullable: true }) + image_url: string; + + @Column('varchar', { name: 'title', nullable: true }) + title: string; + + @Column('varchar', { name: 'teaser', nullable: true }) + teaser: string; + + @Column('varchar', { name: 'description', nullable: true }) + description: string; +} diff --git a/src/modules/web-information/news/data/services/news-data.service.ts b/src/modules/web-information/news/data/services/news-data.service.ts new file mode 100644 index 0000000..6e2846d --- /dev/null +++ b/src/modules/web-information/news/data/services/news-data.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; +import { NewsEntity } from '../../domain/entities/news.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { NewsModel } from '../models/news.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; + +@Injectable() +export class NewsDataService extends BaseDataService { + constructor( + @InjectRepository(NewsModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/web-information/news/domain/entities/event/news-change-status.event.ts b/src/modules/web-information/news/domain/entities/event/news-change-status.event.ts new file mode 100644 index 0000000..e45723f --- /dev/null +++ b/src/modules/web-information/news/domain/entities/event/news-change-status.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class NewsChangeStatusEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/news/domain/entities/event/news-created.event.ts b/src/modules/web-information/news/domain/entities/event/news-created.event.ts new file mode 100644 index 0000000..8e0f2ec --- /dev/null +++ b/src/modules/web-information/news/domain/entities/event/news-created.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class NewsCreatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/news/domain/entities/event/news-deleted.event.ts b/src/modules/web-information/news/domain/entities/event/news-deleted.event.ts new file mode 100644 index 0000000..ee1d268 --- /dev/null +++ b/src/modules/web-information/news/domain/entities/event/news-deleted.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class NewsDeletedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/news/domain/entities/event/news-updated.event.ts b/src/modules/web-information/news/domain/entities/event/news-updated.event.ts new file mode 100644 index 0000000..6d30473 --- /dev/null +++ b/src/modules/web-information/news/domain/entities/event/news-updated.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class NewsUpdatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/news/domain/entities/news.entity.ts b/src/modules/web-information/news/domain/entities/news.entity.ts new file mode 100644 index 0000000..f71ec1a --- /dev/null +++ b/src/modules/web-information/news/domain/entities/news.entity.ts @@ -0,0 +1,8 @@ +import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.entity'; + +export interface NewsEntity extends BaseStatusEntity { + image_url: string; + title: string; + teaser: string; + description: string; +} diff --git a/src/modules/web-information/news/domain/usecases/managers/active-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/active-news.manager.ts new file mode 100644 index 0000000..934230c --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/active-news.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsChangeStatusEvent } from '../../entities/event/news-change-status.event'; + +@Injectable() +export class ActiveNewsManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.title}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/batch-active-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/batch-active-news.manager.ts new file mode 100644 index 0000000..3bfb58d --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/batch-active-news.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsChangeStatusEvent } from '../../entities/event/news-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchActiveNewsManager extends BaseBatchUpdateStatusManager { + validateData(data: NewsEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/batch-confirm-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/batch-confirm-news.manager.ts new file mode 100644 index 0000000..171e091 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/batch-confirm-news.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsChangeStatusEvent } from '../../entities/event/news-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchConfirmNewsManager extends BaseBatchUpdateStatusManager { + validateData(data: NewsEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/batch-delete-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/batch-delete-news.manager.ts new file mode 100644 index 0000000..9a88df9 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/batch-delete-news.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsDeletedEvent } from '../../entities/event/news-deleted.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchDeleteNewsManager extends BaseBatchDeleteManager { + async beforeProcess(): Promise { + return; + } + + async validateData(data: NewsEntity): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsDeletedEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/batch-inactive-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/batch-inactive-news.manager.ts new file mode 100644 index 0000000..e683418 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/batch-inactive-news.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsChangeStatusEvent } from '../../entities/event/news-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchInactiveNewsManager extends BaseBatchUpdateStatusManager { + validateData(data: NewsEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/confirm-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/confirm-news.manager.ts new file mode 100644 index 0000000..50a20c8 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/confirm-news.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsChangeStatusEvent } from '../../entities/event/news-change-status.event'; + +@Injectable() +export class ConfirmNewsManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.title}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/create-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/create-news.manager.ts new file mode 100644 index 0000000..b806003 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/create-news.manager.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@nestjs/common'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsEntity } from '../../entities/news.entity'; +import { NewsModel } from '../../../data/models/news.model'; +import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager'; +import { NewsCreatedEvent } from '../../entities/event/news-created.event'; + +@Injectable() +export class CreateNewsManager extends BaseCreateManager { + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsCreatedEvent, + data: this.data, + }, + ]; + } + + get entityTarget(): any { + return NewsModel; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/delete-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/delete-news.manager.ts new file mode 100644 index 0000000..f8890b1 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/delete-news.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsDeletedEvent } from '../../entities/event/news-deleted.event'; + +@Injectable() +export class DeleteNewsManager extends BaseDeleteManager { + getResult(): string { + return `Success`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsDeletedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/inactive-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/inactive-news.manager.ts new file mode 100644 index 0000000..fb1ee1a --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/inactive-news.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsChangeStatusEvent } from '../../entities/event/news-change-status.event'; + +@Injectable() +export class InactiveNewsManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success inactive data ${this.result.title}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/update-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/update-news.manager.ts new file mode 100644 index 0000000..695d0d5 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/update-news.manager.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { NewsModel } from '../../../data/models/news.model'; +import { NewsUpdatedEvent } from '../../entities/event/news-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; + +@Injectable() +export class UpdateNewsManager extends BaseUpdateManager { + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get entityTarget(): any { + return NewsModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: NewsUpdatedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/news/domain/usecases/news-data.orchestrator.ts b/src/modules/web-information/news/domain/usecases/news-data.orchestrator.ts new file mode 100644 index 0000000..e428a13 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/news-data.orchestrator.ts @@ -0,0 +1,106 @@ +import { Injectable } from '@nestjs/common'; +import { CreateNewsManager } from './managers/create-news.manager'; +import { NewsDataService } from '../../data/services/news-data.service'; +import { NewsEntity } from '../entities/news.entity'; +import { DeleteNewsManager } from './managers/delete-news.manager'; +import { UpdateNewsManager } from './managers/update-news.manager'; +import { BaseDataTransactionOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-data-transaction.orchestrator'; +import { ActiveNewsManager } from './managers/active-news.manager'; +import { InactiveNewsManager } from './managers/inactive-news.manager'; +import { ConfirmNewsManager } from './managers/confirm-news.manager'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchConfirmNewsManager } from './managers/batch-confirm-news.manager'; +import { BatchInactiveNewsManager } from './managers/batch-inactive-news.manager'; +import { BatchActiveNewsManager } from './managers/batch-active-news.manager'; +import { BatchDeleteNewsManager } from './managers/batch-delete-news.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class NewsDataOrchestrator extends BaseDataTransactionOrchestrator { + constructor( + private createManager: CreateNewsManager, + private updateManager: UpdateNewsManager, + private deleteManager: DeleteNewsManager, + private activeManager: ActiveNewsManager, + private confirmManager: ConfirmNewsManager, + private inactiveManager: InactiveNewsManager, + private batchDeleteManager: BatchDeleteNewsManager, + private batchActiveManager: BatchActiveNewsManager, + private batchConfirmManager: BatchConfirmNewsManager, + private batchInactiveManager: BatchInactiveNewsManager, + private serviceData: NewsDataService, + ) { + super(); + } + + async create(data): Promise { + this.createManager.setData(data); + this.createManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.createManager.execute(); + return this.createManager.getResult(); + } + + async update(dataId, data): Promise { + this.updateManager.setData(dataId, data); + this.updateManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.updateManager.execute(); + return this.updateManager.getResult(); + } + + async delete(dataId): Promise { + this.deleteManager.setData(dataId); + this.deleteManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.deleteManager.execute(); + return this.deleteManager.getResult(); + } + + async batchDelete(dataIds: string[]): Promise { + this.batchDeleteManager.setData(dataIds); + this.batchDeleteManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.batchDeleteManager.execute(); + return this.batchDeleteManager.getResult(); + } + + async active(dataId): Promise { + this.activeManager.setData(dataId, STATUS.ACTIVE); + this.activeManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.activeManager.execute(); + return this.activeManager.getResult(); + } + + async batchActive(dataIds: string[]): Promise { + this.batchActiveManager.setData(dataIds, STATUS.ACTIVE); + this.batchActiveManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.batchActiveManager.execute(); + return this.batchActiveManager.getResult(); + } + + async confirm(dataId): Promise { + this.confirmManager.setData(dataId, STATUS.ACTIVE); + this.confirmManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.confirmManager.execute(); + return this.confirmManager.getResult(); + } + + async batchConfirm(dataIds: string[]): Promise { + this.batchConfirmManager.setData(dataIds, STATUS.ACTIVE); + this.batchConfirmManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.batchConfirmManager.execute(); + return this.batchConfirmManager.getResult(); + } + + async inactive(dataId): Promise { + this.inactiveManager.setData(dataId, STATUS.INACTIVE); + this.inactiveManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.inactiveManager.execute(); + return this.inactiveManager.getResult(); + } + + async batchInactive(dataIds: string[]): Promise { + this.batchInactiveManager.setData(dataIds, STATUS.INACTIVE); + this.batchInactiveManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.batchInactiveManager.execute(); + return this.batchInactiveManager.getResult(); + } +} diff --git a/src/modules/web-information/news/index.ts b/src/modules/web-information/news/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/web-information/news/infrastructure/dto/news.dto.ts b/src/modules/web-information/news/infrastructure/dto/news.dto.ts new file mode 100644 index 0000000..20d5c70 --- /dev/null +++ b/src/modules/web-information/news/infrastructure/dto/news.dto.ts @@ -0,0 +1,33 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { NewsEntity } from '../../domain/entities/news.entity'; +import { ApiProperty } from '@nestjs/swagger'; + +export class NewsDto extends BaseStatusDto implements NewsEntity { + @ApiProperty({ + type: String, + required: false, + example: 'https://...', + }) + image_url: string; + + @ApiProperty({ + type: String, + required: true, + example: 'The Flash Speed Force', + }) + title: string; + + @ApiProperty({ + type: String, + required: false, + example: 'Get ready to take on the first ride-within-a-ride experience', + }) + teaser: string; + + @ApiProperty({ + type: String, + required: false, + example: 'description', + }) + description: string; +} diff --git a/src/modules/web-information/news/infrastructure/news-data.controller.ts b/src/modules/web-information/news/infrastructure/news-data.controller.ts new file mode 100644 index 0000000..61b8b1e --- /dev/null +++ b/src/modules/web-information/news/infrastructure/news-data.controller.ts @@ -0,0 +1,78 @@ +import { + Body, + Controller, + Delete, + Param, + Patch, + Post, + Put, +} from '@nestjs/common'; +import { NewsDataOrchestrator } from '../domain/usecases/news-data.orchestrator'; +import { NewsDto } from './dto/news.dto'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { NewsEntity } from '../domain/entities/news.entity'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; +import { Public } from 'src/core/guards'; + +@ApiTags(`${MODULE_NAME.NEWS.split('-').join(' ')} - data`) +@Controller(`v1/${MODULE_NAME.NEWS}`) +@Public(false) +@ApiBearerAuth('JWT') +export class NewsDataController { + constructor(private orchestrator: NewsDataOrchestrator) {} + + @Post() + async create(@Body() data: NewsDto): Promise { + return await this.orchestrator.create(data); + } + + @Put('/batch-delete') + async batchDeleted(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchDelete(body.ids); + } + + @Patch(':id/active') + async active(@Param('id') dataId: string): Promise { + return await this.orchestrator.active(dataId); + } + + @Put('/batch-active') + async batchActive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchActive(body.ids); + } + + @Patch(':id/confirm') + async confirm(@Param('id') dataId: string): Promise { + return await this.orchestrator.confirm(dataId); + } + + @Put('/batch-confirm') + async batchConfirm(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchConfirm(body.ids); + } + + @Patch(':id/inactive') + async inactive(@Param('id') dataId: string): Promise { + return await this.orchestrator.inactive(dataId); + } + + @Put('/batch-inactive') + async batchInactive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchInactive(body.ids); + } + + @Put(':id') + async update( + @Param('id') dataId: string, + @Body() data: NewsDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Delete(':id') + async delete(@Param('id') dataId: string): Promise { + return await this.orchestrator.delete(dataId); + } +} diff --git a/src/modules/web-information/news/news.module.ts b/src/modules/web-information/news/news.module.ts new file mode 100644 index 0000000..0e9e522 --- /dev/null +++ b/src/modules/web-information/news/news.module.ts @@ -0,0 +1,54 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { NewsDataService } from './data/services/news-data.service'; +import { NewsReadService } from './data/services/news-read.service'; +import { NewsReadController } from './infrastructure/news-read.controller'; +import { NewsReadOrchestrator } from './domain/usecases/news-read.orchestrator'; +import { NewsDataController } from './infrastructure/news-data.controller'; +import { NewsDataOrchestrator } from './domain/usecases/news-data.orchestrator'; +import { CreateNewsManager } from './domain/usecases/managers/create-news.manager'; +import { CqrsModule } from '@nestjs/cqrs'; +import { IndexNewsManager } from './domain/usecases/managers/index-news.manager'; +import { DeleteNewsManager } from './domain/usecases/managers/delete-news.manager'; +import { UpdateNewsManager } from './domain/usecases/managers/update-news.manager'; +import { ActiveNewsManager } from './domain/usecases/managers/active-news.manager'; +import { ConfirmNewsManager } from './domain/usecases/managers/confirm-news.manager'; +import { InactiveNewsManager } from './domain/usecases/managers/inactive-news.manager'; +import { DetailNewsManager } from './domain/usecases/managers/detail-news.manager'; +import { BatchDeleteNewsManager } from './domain/usecases/managers/batch-delete-news.manager'; +import { BatchActiveNewsManager } from './domain/usecases/managers/batch-active-news.manager'; +import { BatchConfirmNewsManager } from './domain/usecases/managers/batch-confirm-news.manager'; +import { BatchInactiveNewsManager } from './domain/usecases/managers/batch-inactive-news.manager'; +import { NewsModel } from './data/models/news.model'; + +@Module({ + imports: [ + ConfigModule.forRoot(), + TypeOrmModule.forFeature([NewsModel], CONNECTION_NAME.DEFAULT), + CqrsModule, + ], + controllers: [NewsDataController, NewsReadController], + providers: [ + IndexNewsManager, + DetailNewsManager, + CreateNewsManager, + DeleteNewsManager, + UpdateNewsManager, + ActiveNewsManager, + ConfirmNewsManager, + InactiveNewsManager, + BatchDeleteNewsManager, + BatchActiveNewsManager, + BatchConfirmNewsManager, + BatchInactiveNewsManager, + + NewsDataService, + NewsReadService, + + NewsDataOrchestrator, + NewsReadOrchestrator, + ], +}) +export class NewsModule {} From 7a74711834ca6c5dcd7615f6a026209afb406b4e Mon Sep 17 00:00:00 2001 From: Aswin Ashar Abdullah Date: Tue, 16 Jul 2024 13:17:41 +0700 Subject: [PATCH 2/5] feat(SPG-451) REST API Read berita --- .../news/data/services/news-read.service.ts | 17 +++++ .../domain/entities/filter-news.entity.ts | 5 ++ .../usecases/managers/detail-news.manager.ts | 54 +++++++++++++++ .../usecases/managers/index-news.manager.ts | 67 +++++++++++++++++++ .../domain/usecases/news-read.orchestrator.ts | 33 +++++++++ .../infrastructure/dto/filter-news.dto.ts | 12 ++++ .../infrastructure/news-read.controller.ts | 30 +++++++++ 7 files changed, 218 insertions(+) create mode 100644 src/modules/web-information/news/data/services/news-read.service.ts create mode 100644 src/modules/web-information/news/domain/entities/filter-news.entity.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/detail-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/managers/index-news.manager.ts create mode 100644 src/modules/web-information/news/domain/usecases/news-read.orchestrator.ts create mode 100644 src/modules/web-information/news/infrastructure/dto/filter-news.dto.ts create mode 100644 src/modules/web-information/news/infrastructure/news-read.controller.ts diff --git a/src/modules/web-information/news/data/services/news-read.service.ts b/src/modules/web-information/news/data/services/news-read.service.ts new file mode 100644 index 0000000..e9ed46b --- /dev/null +++ b/src/modules/web-information/news/data/services/news-read.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { NewsEntity } from '../../domain/entities/news.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { NewsModel } from '../models/news.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; +import { BaseReadService } from 'src/core/modules/data/service/base-read.service'; + +@Injectable() +export class NewsReadService extends BaseReadService { + constructor( + @InjectRepository(NewsModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/web-information/news/domain/entities/filter-news.entity.ts b/src/modules/web-information/news/domain/entities/filter-news.entity.ts new file mode 100644 index 0000000..20f1802 --- /dev/null +++ b/src/modules/web-information/news/domain/entities/filter-news.entity.ts @@ -0,0 +1,5 @@ +import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; + +export interface FilterNewsEntity extends BaseFilterEntity { + titles: string[]; +} diff --git a/src/modules/web-information/news/domain/usecases/managers/detail-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/detail-news.manager.ts new file mode 100644 index 0000000..092c785 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/detail-news.manager.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { RelationParam } from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class DetailNewsManager extends BaseDetailManager { + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + // relation only join (for query purpose) + joinRelations: [], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.created_at`, + `${this.tableName}.creator_name`, + `${this.tableName}.updated_at`, + `${this.tableName}.editor_name`, + + `${this.tableName}.status`, + `${this.tableName}.image_url`, + `${this.tableName}.title`, + `${this.tableName}.teaser`, + `${this.tableName}.description`, + ]; + } + + get setFindProperties(): any { + return { + id: this.dataId, + }; + } +} diff --git a/src/modules/web-information/news/domain/usecases/managers/index-news.manager.ts b/src/modules/web-information/news/domain/usecases/managers/index-news.manager.ts new file mode 100644 index 0000000..d779b5f --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/managers/index-news.manager.ts @@ -0,0 +1,67 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { NewsEntity } from '../../entities/news.entity'; +import { SelectQueryBuilder } from 'typeorm'; +import { + Param, + RelationParam, +} from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class IndexNewsManager extends BaseIndexManager { + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + // relation only join (for query purpose) + joinRelations: [], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.created_at`, + `${this.tableName}.creator_name`, + `${this.tableName}.updated_at`, + `${this.tableName}.editor_name`, + + `${this.tableName}.status`, + `${this.tableName}.image_url`, + `${this.tableName}.title`, + `${this.tableName}.teaser`, + `${this.tableName}.description`, + ]; + } + + get specificFilter(): Param[] { + return [ + { + cols: `${this.tableName}.title`, + data: this.filterParam.titles, + }, + ]; + } + + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + return queryBuilder; + } +} diff --git a/src/modules/web-information/news/domain/usecases/news-read.orchestrator.ts b/src/modules/web-information/news/domain/usecases/news-read.orchestrator.ts new file mode 100644 index 0000000..15df4c5 --- /dev/null +++ b/src/modules/web-information/news/domain/usecases/news-read.orchestrator.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { IndexNewsManager } from './managers/index-news.manager'; +import { NewsReadService } from '../../data/services/news-read.service'; +import { NewsEntity } from '../entities/news.entity'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; +import { DetailNewsManager } from './managers/detail-news.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class NewsReadOrchestrator extends BaseReadOrchestrator { + constructor( + private indexManager: IndexNewsManager, + private detailManager: DetailNewsManager, + private serviceData: NewsReadService, + ) { + super(); + } + + async index(params): Promise> { + this.indexManager.setFilterParam(params); + this.indexManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.indexManager.execute(); + return this.indexManager.getResult(); + } + + async detail(dataId: string): Promise { + this.detailManager.setData(dataId); + this.detailManager.setService(this.serviceData, TABLE_NAME.NEWS); + await this.detailManager.execute(); + return this.detailManager.getResult(); + } +} diff --git a/src/modules/web-information/news/infrastructure/dto/filter-news.dto.ts b/src/modules/web-information/news/infrastructure/dto/filter-news.dto.ts new file mode 100644 index 0000000..294c305 --- /dev/null +++ b/src/modules/web-information/news/infrastructure/dto/filter-news.dto.ts @@ -0,0 +1,12 @@ +import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto'; +import { FilterNewsEntity } from '../../domain/entities/filter-news.entity'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class FilterNewsDto extends BaseFilterDto implements FilterNewsEntity { + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + titles: string[]; +} diff --git a/src/modules/web-information/news/infrastructure/news-read.controller.ts b/src/modules/web-information/news/infrastructure/news-read.controller.ts new file mode 100644 index 0000000..1e31953 --- /dev/null +++ b/src/modules/web-information/news/infrastructure/news-read.controller.ts @@ -0,0 +1,30 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { FilterNewsDto } from './dto/filter-news.dto'; +import { Pagination } from 'src/core/response'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { NewsEntity } from '../domain/entities/news.entity'; +import { NewsReadOrchestrator } from '../domain/usecases/news-read.orchestrator'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { Public } from 'src/core/guards'; + +@ApiTags(`${MODULE_NAME.NEWS.split('-').join(' ')} - read`) +@Controller(`v1/${MODULE_NAME.NEWS}`) +@Public(false) +@ApiBearerAuth('JWT') +export class NewsReadController { + constructor(private orchestrator: NewsReadOrchestrator) {} + + @Get() + @Pagination() + async index( + @Query() params: FilterNewsDto, + ): Promise> { + return await this.orchestrator.index(params); + } + + @Get(':id') + async detail(@Param('id') id: string): Promise { + return await this.orchestrator.detail(id); + } +} From bfa8d6d5248055b44d7e25aca8a2bcb2ecee96b6 Mon Sep 17 00:00:00 2001 From: Aswin Ashar Abdullah Date: Tue, 16 Jul 2024 13:17:58 +0700 Subject: [PATCH 3/5] fix(filter) perbaikan filter search --- .../faq/domain/entities/filter-faq.entity.ts | 4 +++- .../faq/domain/usecases/managers/index-faq.manager.ts | 4 ++-- .../faq/infrastructure/dto/filter-faq.dto.ts | 10 +++++++++- .../domain/entities/filter-term-condition.entity.ts | 4 +++- .../usecases/managers/index-term-condition.manager.ts | 4 ++-- .../infrastructure/dto/filter-term-condition.dto.ts | 11 ++++++++++- 6 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/modules/web-information/faq/domain/entities/filter-faq.entity.ts b/src/modules/web-information/faq/domain/entities/filter-faq.entity.ts index 9488909..d0589ac 100644 --- a/src/modules/web-information/faq/domain/entities/filter-faq.entity.ts +++ b/src/modules/web-information/faq/domain/entities/filter-faq.entity.ts @@ -1,3 +1,5 @@ import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; -export interface FilterFaqEntity extends BaseFilterEntity {} +export interface FilterFaqEntity extends BaseFilterEntity { + titles: string[]; +} diff --git a/src/modules/web-information/faq/domain/usecases/managers/index-faq.manager.ts b/src/modules/web-information/faq/domain/usecases/managers/index-faq.manager.ts index a1508eb..418c42b 100644 --- a/src/modules/web-information/faq/domain/usecases/managers/index-faq.manager.ts +++ b/src/modules/web-information/faq/domain/usecases/managers/index-faq.manager.ts @@ -50,8 +50,8 @@ export class IndexFaqManager extends BaseIndexManager { get specificFilter(): Param[] { return [ { - cols: `${this.tableName}.name`, - data: this.filterParam.names, + cols: `${this.tableName}.title`, + data: this.filterParam.titles, }, ]; } diff --git a/src/modules/web-information/faq/infrastructure/dto/filter-faq.dto.ts b/src/modules/web-information/faq/infrastructure/dto/filter-faq.dto.ts index ce6a148..028b7a1 100644 --- a/src/modules/web-information/faq/infrastructure/dto/filter-faq.dto.ts +++ b/src/modules/web-information/faq/infrastructure/dto/filter-faq.dto.ts @@ -1,4 +1,12 @@ import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto'; import { FilterFaqEntity } from '../../domain/entities/filter-faq.entity'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; -export class FilterFaqDto extends BaseFilterDto implements FilterFaqEntity {} +export class FilterFaqDto extends BaseFilterDto implements FilterFaqEntity { + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + titles: string[]; +} diff --git a/src/modules/web-information/term-condition/domain/entities/filter-term-condition.entity.ts b/src/modules/web-information/term-condition/domain/entities/filter-term-condition.entity.ts index 66cee61..903ed96 100644 --- a/src/modules/web-information/term-condition/domain/entities/filter-term-condition.entity.ts +++ b/src/modules/web-information/term-condition/domain/entities/filter-term-condition.entity.ts @@ -1,3 +1,5 @@ import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; -export interface FilterTermConditionEntity extends BaseFilterEntity {} +export interface FilterTermConditionEntity extends BaseFilterEntity { + titles: string[]; +} diff --git a/src/modules/web-information/term-condition/domain/usecases/managers/index-term-condition.manager.ts b/src/modules/web-information/term-condition/domain/usecases/managers/index-term-condition.manager.ts index 7897eca..dd58ac6 100644 --- a/src/modules/web-information/term-condition/domain/usecases/managers/index-term-condition.manager.ts +++ b/src/modules/web-information/term-condition/domain/usecases/managers/index-term-condition.manager.ts @@ -50,8 +50,8 @@ export class IndexTermConditionManager extends BaseIndexManager { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + titles: string[]; +} From 4178b72af91178753caaf130a00206da347de3ed Mon Sep 17 00:00:00 2001 From: Aswin Ashar Abdullah Date: Tue, 16 Jul 2024 13:30:17 +0700 Subject: [PATCH 4/5] feat(SPG-457) REST API CUD Banner --- src/app.module.ts | 4 + .../strings/constants/module.constants.ts | 1 + src/core/strings/constants/table.constants.ts | 1 + .../migrations/1721111093665-banner.ts | 19 ++++ .../web-information/banner/banner.module.ts | 54 +++++++++ .../web-information/banner/constants.ts | 0 .../banner/data/models/banner.model.ts | 19 ++++ .../data/services/banner-data.service.ts | 17 +++ .../banner/domain/entities/banner.entity.ts | 7 ++ .../event/banner-change-status.event.ts | 5 + .../entities/event/banner-created.event.ts | 5 + .../entities/event/banner-deleted.event.ts | 5 + .../entities/event/banner-updated.event.ts | 5 + .../usecases/banner-data.orchestrator.ts | 106 ++++++++++++++++++ .../managers/active-banner.manager.ts | 45 ++++++++ .../managers/batch-active-banner.manager.ts | 45 ++++++++ .../managers/batch-confirm-banner.manager.ts | 45 ++++++++ .../managers/batch-delete-banner.manager.ts | 45 ++++++++ .../managers/batch-inactive-banner.manager.ts | 45 ++++++++ .../managers/confirm-banner.manager.ts | 45 ++++++++ .../managers/create-banner.manager.ts | 42 +++++++ .../managers/delete-banner.manager.ts | 45 ++++++++ .../managers/inactive-banner.manager.ts | 45 ++++++++ .../managers/update-banner.manager.ts | 46 ++++++++ src/modules/web-information/banner/index.ts | 0 .../infrastructure/banner-data.controller.ts | 78 +++++++++++++ .../banner/infrastructure/dto/banner.dto.ts | 26 +++++ 27 files changed, 800 insertions(+) create mode 100644 src/database/migrations/1721111093665-banner.ts create mode 100644 src/modules/web-information/banner/banner.module.ts create mode 100644 src/modules/web-information/banner/constants.ts create mode 100644 src/modules/web-information/banner/data/models/banner.model.ts create mode 100644 src/modules/web-information/banner/data/services/banner-data.service.ts create mode 100644 src/modules/web-information/banner/domain/entities/banner.entity.ts create mode 100644 src/modules/web-information/banner/domain/entities/event/banner-change-status.event.ts create mode 100644 src/modules/web-information/banner/domain/entities/event/banner-created.event.ts create mode 100644 src/modules/web-information/banner/domain/entities/event/banner-deleted.event.ts create mode 100644 src/modules/web-information/banner/domain/entities/event/banner-updated.event.ts create mode 100644 src/modules/web-information/banner/domain/usecases/banner-data.orchestrator.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/active-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/batch-active-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/batch-confirm-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/batch-delete-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/batch-inactive-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/confirm-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/create-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/delete-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/inactive-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/update-banner.manager.ts create mode 100644 src/modules/web-information/banner/index.ts create mode 100644 src/modules/web-information/banner/infrastructure/banner-data.controller.ts create mode 100644 src/modules/web-information/banner/infrastructure/dto/banner.dto.ts diff --git a/src/app.module.ts b/src/app.module.ts index d7e62db..36258c3 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -66,6 +66,8 @@ import { FaqModule } from './modules/web-information/faq/faq.module'; import { UploadModule } from './modules/configuration/upload/upload.module'; import { NewsModule } from './modules/web-information/news/news.module'; import { NewsModel } from './modules/web-information/news/data/models/news.model'; +import { BannerModule } from './modules/web-information/banner/banner.module'; +import { BannerModel } from './modules/web-information/banner/data/models/banner.model'; @Module({ imports: [ @@ -83,6 +85,7 @@ import { NewsModel } from './modules/web-information/news/data/models/news.model database: process.env.DEFAULT_DB_NAME, entities: [ ...UserPrivilegeModels, + BannerModel, ErrorLogModel, FaqModel, GateModel, @@ -149,6 +152,7 @@ import { NewsModel } from './modules/web-information/news/data/models/news.model SeasonPeriodModule, // web information + BannerModule, FaqModule, GateModule, NewsModule, diff --git a/src/core/strings/constants/module.constants.ts b/src/core/strings/constants/module.constants.ts index a26cada..92913b4 100644 --- a/src/core/strings/constants/module.constants.ts +++ b/src/core/strings/constants/module.constants.ts @@ -1,4 +1,5 @@ export enum MODULE_NAME { + BANNER = 'banners', FAQ = 'faqs', GATE = 'gates', ITEM = 'items', diff --git a/src/core/strings/constants/table.constants.ts b/src/core/strings/constants/table.constants.ts index e757c1f..8c14c7d 100644 --- a/src/core/strings/constants/table.constants.ts +++ b/src/core/strings/constants/table.constants.ts @@ -1,4 +1,5 @@ export enum TABLE_NAME { + BANNER = 'banners', ERROR_LOG = 'log_errors', FAQ = 'faqs', ITEM = 'items', diff --git a/src/database/migrations/1721111093665-banner.ts b/src/database/migrations/1721111093665-banner.ts new file mode 100644 index 0000000..c983c33 --- /dev/null +++ b/src/database/migrations/1721111093665-banner.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class Banner1721111093665 implements MigrationInterface { + name = 'Banner1721111093665'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE "public"."banners_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`, + ); + await queryRunner.query( + `CREATE TABLE "banners" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "creator_id" character varying(36), "creator_name" character varying(125), "editor_id" character varying(36), "editor_name" character varying(125), "created_at" bigint NOT NULL, "updated_at" bigint NOT NULL, "status" "public"."banners_status_enum" NOT NULL DEFAULT 'draft', "image_url" character varying, "title" character varying, "link" character varying, CONSTRAINT "PK_e9b186b959296fcb940790d31c3" PRIMARY KEY ("id"))`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "banners"`); + await queryRunner.query(`DROP TYPE "public"."banners_status_enum"`); + } +} diff --git a/src/modules/web-information/banner/banner.module.ts b/src/modules/web-information/banner/banner.module.ts new file mode 100644 index 0000000..61e54d8 --- /dev/null +++ b/src/modules/web-information/banner/banner.module.ts @@ -0,0 +1,54 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { BannerDataService } from './data/services/banner-data.service'; +import { BannerReadService } from './data/services/banner-read.service'; +import { BannerReadController } from './infrastructure/banner-read.controller'; +import { BannerReadOrchestrator } from './domain/usecases/banner-read.orchestrator'; +import { BannerDataController } from './infrastructure/banner-data.controller'; +import { BannerDataOrchestrator } from './domain/usecases/banner-data.orchestrator'; +import { CreateBannerManager } from './domain/usecases/managers/create-banner.manager'; +import { CqrsModule } from '@nestjs/cqrs'; +import { IndexBannerManager } from './domain/usecases/managers/index-banner.manager'; +import { DeleteBannerManager } from './domain/usecases/managers/delete-banner.manager'; +import { UpdateBannerManager } from './domain/usecases/managers/update-banner.manager'; +import { ActiveBannerManager } from './domain/usecases/managers/active-banner.manager'; +import { ConfirmBannerManager } from './domain/usecases/managers/confirm-banner.manager'; +import { InactiveBannerManager } from './domain/usecases/managers/inactive-banner.manager'; +import { DetailBannerManager } from './domain/usecases/managers/detail-banner.manager'; +import { BatchDeleteBannerManager } from './domain/usecases/managers/batch-delete-banner.manager'; +import { BatchActiveBannerManager } from './domain/usecases/managers/batch-active-banner.manager'; +import { BatchConfirmBannerManager } from './domain/usecases/managers/batch-confirm-banner.manager'; +import { BatchInactiveBannerManager } from './domain/usecases/managers/batch-inactive-banner.manager'; +import { BannerModel } from './data/models/banner.model'; + +@Module({ + imports: [ + ConfigModule.forRoot(), + TypeOrmModule.forFeature([BannerModel], CONNECTION_NAME.DEFAULT), + CqrsModule, + ], + controllers: [BannerDataController, BannerReadController], + providers: [ + IndexBannerManager, + DetailBannerManager, + CreateBannerManager, + DeleteBannerManager, + UpdateBannerManager, + ActiveBannerManager, + ConfirmBannerManager, + InactiveBannerManager, + BatchDeleteBannerManager, + BatchActiveBannerManager, + BatchConfirmBannerManager, + BatchInactiveBannerManager, + + BannerDataService, + BannerReadService, + + BannerDataOrchestrator, + BannerReadOrchestrator, + ], +}) +export class BannerModule {} diff --git a/src/modules/web-information/banner/constants.ts b/src/modules/web-information/banner/constants.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/web-information/banner/data/models/banner.model.ts b/src/modules/web-information/banner/data/models/banner.model.ts new file mode 100644 index 0000000..f434b59 --- /dev/null +++ b/src/modules/web-information/banner/data/models/banner.model.ts @@ -0,0 +1,19 @@ +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { BannerEntity } from '../../domain/entities/banner.entity'; +import { Column, Entity } from 'typeorm'; +import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; + +@Entity(TABLE_NAME.BANNER) +export class BannerModel + extends BaseStatusModel + implements BannerEntity +{ + @Column('varchar', { name: 'image_url', nullable: true }) + image_url: string; + + @Column('varchar', { name: 'title', nullable: true }) + title: string; + + @Column('varchar', { name: 'link', nullable: true }) + link: string; +} diff --git a/src/modules/web-information/banner/data/services/banner-data.service.ts b/src/modules/web-information/banner/data/services/banner-data.service.ts new file mode 100644 index 0000000..b42e3ae --- /dev/null +++ b/src/modules/web-information/banner/data/services/banner-data.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; +import { BannerEntity } from '../../domain/entities/banner.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { BannerModel } from '../models/banner.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; + +@Injectable() +export class BannerDataService extends BaseDataService { + constructor( + @InjectRepository(BannerModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/web-information/banner/domain/entities/banner.entity.ts b/src/modules/web-information/banner/domain/entities/banner.entity.ts new file mode 100644 index 0000000..fe2f1a7 --- /dev/null +++ b/src/modules/web-information/banner/domain/entities/banner.entity.ts @@ -0,0 +1,7 @@ +import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.entity'; + +export interface BannerEntity extends BaseStatusEntity { + image_url: string; + title: string; + link: string; +} diff --git a/src/modules/web-information/banner/domain/entities/event/banner-change-status.event.ts b/src/modules/web-information/banner/domain/entities/event/banner-change-status.event.ts new file mode 100644 index 0000000..3c0467c --- /dev/null +++ b/src/modules/web-information/banner/domain/entities/event/banner-change-status.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class BannerChangeStatusEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/banner/domain/entities/event/banner-created.event.ts b/src/modules/web-information/banner/domain/entities/event/banner-created.event.ts new file mode 100644 index 0000000..816f1f1 --- /dev/null +++ b/src/modules/web-information/banner/domain/entities/event/banner-created.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class BannerCreatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/banner/domain/entities/event/banner-deleted.event.ts b/src/modules/web-information/banner/domain/entities/event/banner-deleted.event.ts new file mode 100644 index 0000000..d8dcdd6 --- /dev/null +++ b/src/modules/web-information/banner/domain/entities/event/banner-deleted.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class BannerDeletedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/banner/domain/entities/event/banner-updated.event.ts b/src/modules/web-information/banner/domain/entities/event/banner-updated.event.ts new file mode 100644 index 0000000..fc9bf1e --- /dev/null +++ b/src/modules/web-information/banner/domain/entities/event/banner-updated.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class BannerUpdatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/banner/domain/usecases/banner-data.orchestrator.ts b/src/modules/web-information/banner/domain/usecases/banner-data.orchestrator.ts new file mode 100644 index 0000000..3116fb7 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/banner-data.orchestrator.ts @@ -0,0 +1,106 @@ +import { Injectable } from '@nestjs/common'; +import { CreateBannerManager } from './managers/create-banner.manager'; +import { BannerDataService } from '../../data/services/banner-data.service'; +import { BannerEntity } from '../entities/banner.entity'; +import { DeleteBannerManager } from './managers/delete-banner.manager'; +import { UpdateBannerManager } from './managers/update-banner.manager'; +import { BaseDataTransactionOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-data-transaction.orchestrator'; +import { ActiveBannerManager } from './managers/active-banner.manager'; +import { InactiveBannerManager } from './managers/inactive-banner.manager'; +import { ConfirmBannerManager } from './managers/confirm-banner.manager'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchConfirmBannerManager } from './managers/batch-confirm-banner.manager'; +import { BatchInactiveBannerManager } from './managers/batch-inactive-banner.manager'; +import { BatchActiveBannerManager } from './managers/batch-active-banner.manager'; +import { BatchDeleteBannerManager } from './managers/batch-delete-banner.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class BannerDataOrchestrator extends BaseDataTransactionOrchestrator { + constructor( + private createManager: CreateBannerManager, + private updateManager: UpdateBannerManager, + private deleteManager: DeleteBannerManager, + private activeManager: ActiveBannerManager, + private confirmManager: ConfirmBannerManager, + private inactiveManager: InactiveBannerManager, + private batchDeleteManager: BatchDeleteBannerManager, + private batchActiveManager: BatchActiveBannerManager, + private batchConfirmManager: BatchConfirmBannerManager, + private batchInactiveManager: BatchInactiveBannerManager, + private serviceData: BannerDataService, + ) { + super(); + } + + async create(data): Promise { + this.createManager.setData(data); + this.createManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.createManager.execute(); + return this.createManager.getResult(); + } + + async update(dataId, data): Promise { + this.updateManager.setData(dataId, data); + this.updateManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.updateManager.execute(); + return this.updateManager.getResult(); + } + + async delete(dataId): Promise { + this.deleteManager.setData(dataId); + this.deleteManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.deleteManager.execute(); + return this.deleteManager.getResult(); + } + + async batchDelete(dataIds: string[]): Promise { + this.batchDeleteManager.setData(dataIds); + this.batchDeleteManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.batchDeleteManager.execute(); + return this.batchDeleteManager.getResult(); + } + + async active(dataId): Promise { + this.activeManager.setData(dataId, STATUS.ACTIVE); + this.activeManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.activeManager.execute(); + return this.activeManager.getResult(); + } + + async batchActive(dataIds: string[]): Promise { + this.batchActiveManager.setData(dataIds, STATUS.ACTIVE); + this.batchActiveManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.batchActiveManager.execute(); + return this.batchActiveManager.getResult(); + } + + async confirm(dataId): Promise { + this.confirmManager.setData(dataId, STATUS.ACTIVE); + this.confirmManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.confirmManager.execute(); + return this.confirmManager.getResult(); + } + + async batchConfirm(dataIds: string[]): Promise { + this.batchConfirmManager.setData(dataIds, STATUS.ACTIVE); + this.batchConfirmManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.batchConfirmManager.execute(); + return this.batchConfirmManager.getResult(); + } + + async inactive(dataId): Promise { + this.inactiveManager.setData(dataId, STATUS.INACTIVE); + this.inactiveManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.inactiveManager.execute(); + return this.inactiveManager.getResult(); + } + + async batchInactive(dataIds: string[]): Promise { + this.batchInactiveManager.setData(dataIds, STATUS.INACTIVE); + this.batchInactiveManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.batchInactiveManager.execute(); + return this.batchInactiveManager.getResult(); + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/active-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/active-banner.manager.ts new file mode 100644 index 0000000..b46bce5 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/active-banner.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerChangeStatusEvent } from '../../entities/event/banner-change-status.event'; + +@Injectable() +export class ActiveBannerManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.title}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/batch-active-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/batch-active-banner.manager.ts new file mode 100644 index 0000000..f62fa04 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/batch-active-banner.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerChangeStatusEvent } from '../../entities/event/banner-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchActiveBannerManager extends BaseBatchUpdateStatusManager { + validateData(data: BannerEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/batch-confirm-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/batch-confirm-banner.manager.ts new file mode 100644 index 0000000..c378071 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/batch-confirm-banner.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerChangeStatusEvent } from '../../entities/event/banner-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchConfirmBannerManager extends BaseBatchUpdateStatusManager { + validateData(data: BannerEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/batch-delete-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/batch-delete-banner.manager.ts new file mode 100644 index 0000000..d29870c --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/batch-delete-banner.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerDeletedEvent } from '../../entities/event/banner-deleted.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchDeleteBannerManager extends BaseBatchDeleteManager { + async beforeProcess(): Promise { + return; + } + + async validateData(data: BannerEntity): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerDeletedEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/batch-inactive-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/batch-inactive-banner.manager.ts new file mode 100644 index 0000000..3cb261b --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/batch-inactive-banner.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerChangeStatusEvent } from '../../entities/event/banner-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchInactiveBannerManager extends BaseBatchUpdateStatusManager { + validateData(data: BannerEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/confirm-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/confirm-banner.manager.ts new file mode 100644 index 0000000..5564e64 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/confirm-banner.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerChangeStatusEvent } from '../../entities/event/banner-change-status.event'; + +@Injectable() +export class ConfirmBannerManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.title}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/create-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/create-banner.manager.ts new file mode 100644 index 0000000..167bf06 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/create-banner.manager.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@nestjs/common'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerEntity } from '../../entities/banner.entity'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager'; +import { BannerCreatedEvent } from '../../entities/event/banner-created.event'; + +@Injectable() +export class CreateBannerManager extends BaseCreateManager { + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerCreatedEvent, + data: this.data, + }, + ]; + } + + get entityTarget(): any { + return BannerModel; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/delete-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/delete-banner.manager.ts new file mode 100644 index 0000000..9650928 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/delete-banner.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerDeletedEvent } from '../../entities/event/banner-deleted.event'; + +@Injectable() +export class DeleteBannerManager extends BaseDeleteManager { + getResult(): string { + return `Success`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerDeletedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/inactive-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/inactive-banner.manager.ts new file mode 100644 index 0000000..b8a886d --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/inactive-banner.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerChangeStatusEvent } from '../../entities/event/banner-change-status.event'; + +@Injectable() +export class InactiveBannerManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success inactive data ${this.result.title}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/update-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/update-banner.manager.ts new file mode 100644 index 0000000..30b0c8b --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/update-banner.manager.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { BannerModel } from '../../../data/models/banner.model'; +import { BannerUpdatedEvent } from '../../entities/event/banner-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; + +@Injectable() +export class UpdateBannerManager extends BaseUpdateManager { + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get entityTarget(): any { + return BannerModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: BannerUpdatedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/banner/index.ts b/src/modules/web-information/banner/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/web-information/banner/infrastructure/banner-data.controller.ts b/src/modules/web-information/banner/infrastructure/banner-data.controller.ts new file mode 100644 index 0000000..93b7f47 --- /dev/null +++ b/src/modules/web-information/banner/infrastructure/banner-data.controller.ts @@ -0,0 +1,78 @@ +import { + Body, + Controller, + Delete, + Param, + Patch, + Post, + Put, +} from '@nestjs/common'; +import { BannerDataOrchestrator } from '../domain/usecases/banner-data.orchestrator'; +import { BannerDto } from './dto/banner.dto'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { BannerEntity } from '../domain/entities/banner.entity'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; +import { Public } from 'src/core/guards'; + +@ApiTags(`${MODULE_NAME.BANNER.split('-').join(' ')} - data`) +@Controller(`v1/${MODULE_NAME.BANNER}`) +@Public(false) +@ApiBearerAuth('JWT') +export class BannerDataController { + constructor(private orchestrator: BannerDataOrchestrator) {} + + @Post() + async create(@Body() data: BannerDto): Promise { + return await this.orchestrator.create(data); + } + + @Put('/batch-delete') + async batchDeleted(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchDelete(body.ids); + } + + @Patch(':id/active') + async active(@Param('id') dataId: string): Promise { + return await this.orchestrator.active(dataId); + } + + @Put('/batch-active') + async batchActive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchActive(body.ids); + } + + @Patch(':id/confirm') + async confirm(@Param('id') dataId: string): Promise { + return await this.orchestrator.confirm(dataId); + } + + @Put('/batch-confirm') + async batchConfirm(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchConfirm(body.ids); + } + + @Patch(':id/inactive') + async inactive(@Param('id') dataId: string): Promise { + return await this.orchestrator.inactive(dataId); + } + + @Put('/batch-inactive') + async batchInactive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchInactive(body.ids); + } + + @Put(':id') + async update( + @Param('id') dataId: string, + @Body() data: BannerDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Delete(':id') + async delete(@Param('id') dataId: string): Promise { + return await this.orchestrator.delete(dataId); + } +} diff --git a/src/modules/web-information/banner/infrastructure/dto/banner.dto.ts b/src/modules/web-information/banner/infrastructure/dto/banner.dto.ts new file mode 100644 index 0000000..bb055b4 --- /dev/null +++ b/src/modules/web-information/banner/infrastructure/dto/banner.dto.ts @@ -0,0 +1,26 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { BannerEntity } from '../../domain/entities/banner.entity'; +import { ApiProperty } from '@nestjs/swagger'; + +export class BannerDto extends BaseStatusDto implements BannerEntity { + @ApiProperty({ + type: String, + required: false, + example: 'https://...', + }) + image_url: string; + + @ApiProperty({ + type: String, + required: true, + example: 'The Flash Speed Force', + }) + title: string; + + @ApiProperty({ + type: String, + required: false, + example: 'Get ready to take on the first ride-within-a-ride experience', + }) + link: string; +} From 9ac1fa9ae2a0b70360c15187babd297a727a840a Mon Sep 17 00:00:00 2001 From: Aswin Ashar Abdullah Date: Tue, 16 Jul 2024 13:30:33 +0700 Subject: [PATCH 5/5] feat(SPG-460) REST API Read Banner --- .../data/services/banner-read.service.ts | 17 +++++ .../domain/entities/filter-banner.entity.ts | 3 + .../usecases/banner-read.orchestrator.ts | 33 ++++++++++ .../managers/detail-banner.manager.ts | 53 +++++++++++++++ .../usecases/managers/index-banner.manager.ts | 66 +++++++++++++++++++ .../infrastructure/banner-read.controller.ts | 30 +++++++++ .../infrastructure/dto/filter-banner.dto.ts | 6 ++ 7 files changed, 208 insertions(+) create mode 100644 src/modules/web-information/banner/data/services/banner-read.service.ts create mode 100644 src/modules/web-information/banner/domain/entities/filter-banner.entity.ts create mode 100644 src/modules/web-information/banner/domain/usecases/banner-read.orchestrator.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/detail-banner.manager.ts create mode 100644 src/modules/web-information/banner/domain/usecases/managers/index-banner.manager.ts create mode 100644 src/modules/web-information/banner/infrastructure/banner-read.controller.ts create mode 100644 src/modules/web-information/banner/infrastructure/dto/filter-banner.dto.ts diff --git a/src/modules/web-information/banner/data/services/banner-read.service.ts b/src/modules/web-information/banner/data/services/banner-read.service.ts new file mode 100644 index 0000000..bc5e314 --- /dev/null +++ b/src/modules/web-information/banner/data/services/banner-read.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { BannerEntity } from '../../domain/entities/banner.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { BannerModel } from '../models/banner.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; +import { BaseReadService } from 'src/core/modules/data/service/base-read.service'; + +@Injectable() +export class BannerReadService extends BaseReadService { + constructor( + @InjectRepository(BannerModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/web-information/banner/domain/entities/filter-banner.entity.ts b/src/modules/web-information/banner/domain/entities/filter-banner.entity.ts new file mode 100644 index 0000000..a895e80 --- /dev/null +++ b/src/modules/web-information/banner/domain/entities/filter-banner.entity.ts @@ -0,0 +1,3 @@ +import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; + +export interface FilterBannerEntity extends BaseFilterEntity {} diff --git a/src/modules/web-information/banner/domain/usecases/banner-read.orchestrator.ts b/src/modules/web-information/banner/domain/usecases/banner-read.orchestrator.ts new file mode 100644 index 0000000..7ec3cb4 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/banner-read.orchestrator.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { IndexBannerManager } from './managers/index-banner.manager'; +import { BannerReadService } from '../../data/services/banner-read.service'; +import { BannerEntity } from '../entities/banner.entity'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; +import { DetailBannerManager } from './managers/detail-banner.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class BannerReadOrchestrator extends BaseReadOrchestrator { + constructor( + private indexManager: IndexBannerManager, + private detailManager: DetailBannerManager, + private serviceData: BannerReadService, + ) { + super(); + } + + async index(params): Promise> { + this.indexManager.setFilterParam(params); + this.indexManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.indexManager.execute(); + return this.indexManager.getResult(); + } + + async detail(dataId: string): Promise { + this.detailManager.setData(dataId); + this.detailManager.setService(this.serviceData, TABLE_NAME.BANNER); + await this.detailManager.execute(); + return this.detailManager.getResult(); + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/detail-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/detail-banner.manager.ts new file mode 100644 index 0000000..7c4e0ab --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/detail-banner.manager.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { RelationParam } from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class DetailBannerManager extends BaseDetailManager { + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + // relation only join (for query purpose) + joinRelations: [], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.created_at`, + `${this.tableName}.creator_name`, + `${this.tableName}.updated_at`, + `${this.tableName}.editor_name`, + + `${this.tableName}.status`, + `${this.tableName}.image_url`, + `${this.tableName}.title`, + `${this.tableName}.link`, + ]; + } + + get setFindProperties(): any { + return { + id: this.dataId, + }; + } +} diff --git a/src/modules/web-information/banner/domain/usecases/managers/index-banner.manager.ts b/src/modules/web-information/banner/domain/usecases/managers/index-banner.manager.ts new file mode 100644 index 0000000..8e33166 --- /dev/null +++ b/src/modules/web-information/banner/domain/usecases/managers/index-banner.manager.ts @@ -0,0 +1,66 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { BannerEntity } from '../../entities/banner.entity'; +import { SelectQueryBuilder } from 'typeorm'; +import { + Param, + RelationParam, +} from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class IndexBannerManager extends BaseIndexManager { + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + // relation only join (for query purpose) + joinRelations: [], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.created_at`, + `${this.tableName}.creator_name`, + `${this.tableName}.updated_at`, + `${this.tableName}.editor_name`, + + `${this.tableName}.status`, + `${this.tableName}.image_url`, + `${this.tableName}.title`, + `${this.tableName}.link`, + ]; + } + + get specificFilter(): Param[] { + return [ + { + cols: `${this.tableName}.name`, + data: this.filterParam.names, + }, + ]; + } + + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + return queryBuilder; + } +} diff --git a/src/modules/web-information/banner/infrastructure/banner-read.controller.ts b/src/modules/web-information/banner/infrastructure/banner-read.controller.ts new file mode 100644 index 0000000..62ae8aa --- /dev/null +++ b/src/modules/web-information/banner/infrastructure/banner-read.controller.ts @@ -0,0 +1,30 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { FilterBannerDto } from './dto/filter-banner.dto'; +import { Pagination } from 'src/core/response'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { BannerEntity } from '../domain/entities/banner.entity'; +import { BannerReadOrchestrator } from '../domain/usecases/banner-read.orchestrator'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { Public } from 'src/core/guards'; + +@ApiTags(`${MODULE_NAME.BANNER.split('-').join(' ')} - read`) +@Controller(`v1/${MODULE_NAME.BANNER}`) +@Public(false) +@ApiBearerAuth('JWT') +export class BannerReadController { + constructor(private orchestrator: BannerReadOrchestrator) {} + + @Get() + @Pagination() + async index( + @Query() params: FilterBannerDto, + ): Promise> { + return await this.orchestrator.index(params); + } + + @Get(':id') + async detail(@Param('id') id: string): Promise { + return await this.orchestrator.detail(id); + } +} diff --git a/src/modules/web-information/banner/infrastructure/dto/filter-banner.dto.ts b/src/modules/web-information/banner/infrastructure/dto/filter-banner.dto.ts new file mode 100644 index 0000000..b8fa4af --- /dev/null +++ b/src/modules/web-information/banner/infrastructure/dto/filter-banner.dto.ts @@ -0,0 +1,6 @@ +import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto'; +import { FilterBannerEntity } from '../../domain/entities/filter-banner.entity'; + +export class FilterBannerDto + extends BaseFilterDto + implements FilterBannerEntity {}