From f810ca074e31d9092e56241391a5d530692ef5d3 Mon Sep 17 00:00:00 2001 From: alexeh Date: Sun, 15 Sep 2024 08:12:28 +0200 Subject: [PATCH] events + api events scaffold --- api/package.json | 1 + .../services/password-recovery.service.ts | 2 -- .../events/api-events/api-events.entity.ts | 28 +++++++++++++++++++ .../events/api-events/api-events.module.ts | 11 ++++++++ .../events/api-events/api-events.service.ts | 24 ++++++++++++++++ api/src/modules/events/events.enum.ts | 8 ++++++ api/src/modules/events/events.module.ts | 7 +++++ pnpm-lock.yaml | 19 +++++++++++++ 8 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 api/src/modules/events/api-events/api-events.entity.ts create mode 100644 api/src/modules/events/api-events/api-events.module.ts create mode 100644 api/src/modules/events/api-events/api-events.service.ts create mode 100644 api/src/modules/events/events.enum.ts create mode 100644 api/src/modules/events/events.module.ts diff --git a/api/package.json b/api/package.json index 222a5370..1ad96dc5 100644 --- a/api/package.json +++ b/api/package.json @@ -20,6 +20,7 @@ "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.2.3", "@nestjs/core": "^10.0.0", + "@nestjs/cqrs": "^10.2.7", "@nestjs/jwt": "^10.2.0", "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", diff --git a/api/src/modules/auth/services/password-recovery.service.ts b/api/src/modules/auth/services/password-recovery.service.ts index 572ff490..0a84275c 100644 --- a/api/src/modules/auth/services/password-recovery.service.ts +++ b/api/src/modules/auth/services/password-recovery.service.ts @@ -15,8 +15,6 @@ export class PasswordRecoveryService { async recoverPassword(email: string, origin: string): Promise { const user = await this.users.findByEmail(email); if (!user) { - // TODO: We don't want to expose this info back, but we probably want to log and save this event internally, plus - // maybe sent an email to admin this.logger.warn( `Email ${email} not found when trying to recover password`, ); diff --git a/api/src/modules/events/api-events/api-events.entity.ts b/api/src/modules/events/api-events/api-events.entity.ts new file mode 100644 index 00000000..87930e99 --- /dev/null +++ b/api/src/modules/events/api-events/api-events.entity.ts @@ -0,0 +1,28 @@ +import { + Column, + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, +} from 'typeorm'; +import { API_EVENT_TYPES } from '@api/modules/events/events.enum'; + +@Entity('api_events') +export class ApiEventsEntity { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ + type: 'enum', + enum: API_EVENT_TYPES, + }) + eventType: API_EVENT_TYPES; + + @Column({ type: 'uuid', nullable: true, name: 'resource_id' }) + resourceId: string | null; + + @Column('jsonb') + payload: any; + + @CreateDateColumn({ name: 'created_at' }) + createdAt: Date; +} diff --git a/api/src/modules/events/api-events/api-events.module.ts b/api/src/modules/events/api-events/api-events.module.ts new file mode 100644 index 00000000..b8082fda --- /dev/null +++ b/api/src/modules/events/api-events/api-events.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ApiEventsEntity } from '@api/modules/events/api-events/api-events.entity'; +import { ApiEventsService } from '@api/modules/events/api-events/api-events.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([ApiEventsEntity])], + providers: [ApiEventsService], + exports: [ApiEventsService], +}) +export class ApiEventsModule {} diff --git a/api/src/modules/events/api-events/api-events.service.ts b/api/src/modules/events/api-events/api-events.service.ts new file mode 100644 index 00000000..ccfc5f5b --- /dev/null +++ b/api/src/modules/events/api-events/api-events.service.ts @@ -0,0 +1,24 @@ +// src/api-events/api-events.service.ts +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { ApiEventsEntity } from './api-events.entity'; +import { API_EVENT_TYPES } from '@api/modules/events/events.enum'; + +type CreateApiEvent = { + eventType: API_EVENT_TYPES; + resourceId?: string; + payload?: any; +}; + +@Injectable() +export class ApiEventsService { + constructor( + @InjectRepository(ApiEventsEntity) + private readonly apiEventsRepository: Repository, + ) {} + + async create(createEventDto: CreateApiEvent): Promise { + await this.apiEventsRepository.insert(createEventDto); + } +} diff --git a/api/src/modules/events/events.enum.ts b/api/src/modules/events/events.enum.ts new file mode 100644 index 00000000..4b176cfe --- /dev/null +++ b/api/src/modules/events/events.enum.ts @@ -0,0 +1,8 @@ +export enum API_EVENT_TYPES { + USER_SIGNED_UP = 'user.signed_up', + USER_PASSWORD_RECOVERY_REQUESTED = 'user.password_recovery_requested', + USER_PASSWORD_RECOVERY_REQUESTED_NON_EXISTENT = 'user.password_recovery_requested_non_existent', + // More events to come.... +} + +// More enums non related to events that we want to register in DB diff --git a/api/src/modules/events/events.module.ts b/api/src/modules/events/events.module.ts new file mode 100644 index 00000000..ad3efe57 --- /dev/null +++ b/api/src/modules/events/events.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; +import { ApiEventsModule } from './api-events/api-events.module'; + +@Module({ + imports: [ApiEventsModule], +}) +export class EventsModule {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6eb18cb..90e584d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,6 +40,9 @@ importers: '@nestjs/core': specifier: ^10.0.0 version: 10.4.1(@nestjs/common@10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/cqrs': + specifier: ^10.2.7 + version: 10.2.7(@nestjs/common@10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.1(@nestjs/common@10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/jwt': specifier: ^10.2.0 version: 10.2.0(@nestjs/common@10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)) @@ -734,6 +737,14 @@ packages: '@nestjs/websockets': optional: true + '@nestjs/cqrs@10.2.7': + resolution: {integrity: sha512-RXhgQOfuT+KzvkueR4S++SB6+6333PL71pOtCzbJAAU/DY3KY56yTCncWRsIdorKfDX5AEwTiQHHJi69XJWdkA==} + peerDependencies: + '@nestjs/common': ^9.0.0 || ^10.0.0 + '@nestjs/core': ^9.0.0 || ^10.0.0 + reflect-metadata: ^0.1.13 || ^0.2.0 + rxjs: ^7.2.0 + '@nestjs/jwt@10.2.0': resolution: {integrity: sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==} peerDependencies: @@ -5330,6 +5341,14 @@ snapshots: transitivePeerDependencies: - encoding + '@nestjs/cqrs@10.2.7(@nestjs/common@10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.1(@nestjs/common@10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.1(@nestjs/common@10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + reflect-metadata: 0.2.2 + rxjs: 7.8.1 + uuid: 9.0.1 + '@nestjs/jwt@10.2.0(@nestjs/common@10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))': dependencies: '@nestjs/common': 10.4.1(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)