From 4e760c50a773df1d5289c83a1ab649e714f88ed8 Mon Sep 17 00:00:00 2001 From: Alex Tran Date: Mon, 7 Aug 2023 21:40:50 -0500 Subject: [PATCH] feat(server): audit log --- .../database-subscriber/asset.subscriber.ts | 21 +++++++++++ server/src/infra/database.config.ts | 1 + server/src/infra/entities/audit.entity.ts | 35 +++++++++++++++++++ server/src/infra/entities/index.ts | 3 ++ .../migrations/1691462205943-AddAuditTable.ts | 14 ++++++++ 5 files changed, 74 insertions(+) create mode 100644 server/src/domain/database-subscriber/asset.subscriber.ts create mode 100644 server/src/infra/entities/audit.entity.ts create mode 100644 server/src/infra/migrations/1691462205943-AddAuditTable.ts diff --git a/server/src/domain/database-subscriber/asset.subscriber.ts b/server/src/domain/database-subscriber/asset.subscriber.ts new file mode 100644 index 000000000..9b674e8b5 --- /dev/null +++ b/server/src/domain/database-subscriber/asset.subscriber.ts @@ -0,0 +1,21 @@ +import { AssetEntity } from '@app/infra/entities'; +import { EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, UpdateEvent } from 'typeorm'; + +@EventSubscriber() +export class AssetAudit implements EntitySubscriberInterface { + listenTo() { + return AssetEntity; + } + + afterInsert(event: InsertEvent): void | Promise { + console.log('AFTER ENTITY INSERTED: ', event.entity); + } + + afterRemove(event: RemoveEvent): void | Promise { + console.log('AFTER ENTITY WITH ID ' + event.entityId + ' REMOVED: ', event.entity); + } + + afterUpdate(event: UpdateEvent): void | Promise { + console.log('AFTER ENTITY UPDATED: ', event.entity); + } +} diff --git a/server/src/infra/database.config.ts b/server/src/infra/database.config.ts index 8df877705..9c028056d 100644 --- a/server/src/infra/database.config.ts +++ b/server/src/infra/database.config.ts @@ -17,6 +17,7 @@ export const databaseConfig: PostgresConnectionOptions = { entities: [__dirname + '/entities/*.entity.{js,ts}'], synchronize: false, migrations: [__dirname + '/migrations/*.{js,ts}'], + subscribers: [__dirname + '/../domain/database-subscriber/*.{js,ts}'], migrationsRun: true, connectTimeoutMS: 10000, // 10 seconds ...urlOrParts, diff --git a/server/src/infra/entities/audit.entity.ts b/server/src/infra/entities/audit.entity.ts new file mode 100644 index 000000000..84f5d6888 --- /dev/null +++ b/server/src/infra/entities/audit.entity.ts @@ -0,0 +1,35 @@ +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm'; + +export enum DatabaseAction { + CREATE = 'CREATE', + UPDATE = 'UPDATE', + DELETE = 'DELETE', +} + +export enum EntityType { + ASSET = 'ASSET', +} + +@Entity('audit') +export class AuditEntity { + @PrimaryGeneratedColumn('increment') + id!: string; + + @Column() + entityType!: EntityType; + + @Column() + entityId!: string; + + @Column() + action!: DatabaseAction; + + @Column() + onwerId!: string; + + @Column() + userId!: string; + + @CreateDateColumn({ type: 'timestamptz' }) + createdAt!: Date; +} diff --git a/server/src/infra/entities/index.ts b/server/src/infra/entities/index.ts index 6864a3f73..632a8d6b4 100644 --- a/server/src/infra/entities/index.ts +++ b/server/src/infra/entities/index.ts @@ -2,6 +2,7 @@ import { AlbumEntity } from './album.entity'; import { APIKeyEntity } from './api-key.entity'; import { AssetFaceEntity } from './asset-face.entity'; import { AssetEntity } from './asset.entity'; +import { AuditEntity } from './audit.entity'; import { PartnerEntity } from './partner.entity'; import { PersonEntity } from './person.entity'; import { SharedLinkEntity } from './shared-link.entity'; @@ -15,6 +16,7 @@ export * from './album.entity'; export * from './api-key.entity'; export * from './asset-face.entity'; export * from './asset.entity'; +export * from './audit.entity'; export * from './exif.entity'; export * from './partner.entity'; export * from './person.entity'; @@ -30,6 +32,7 @@ export const databaseEntities = [ APIKeyEntity, AssetEntity, AssetFaceEntity, + AuditEntity, PartnerEntity, PersonEntity, SharedLinkEntity, diff --git a/server/src/infra/migrations/1691462205943-AddAuditTable.ts b/server/src/infra/migrations/1691462205943-AddAuditTable.ts new file mode 100644 index 000000000..7b6e76490 --- /dev/null +++ b/server/src/infra/migrations/1691462205943-AddAuditTable.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddAuditTable1691462205943 implements MigrationInterface { + name = 'AddAuditTable1691462205943' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "audit" ("id" SERIAL NOT NULL, "entityType" character varying NOT NULL, "entityId" character varying NOT NULL, "action" character varying NOT NULL, "onwerId" character varying NOT NULL, "userId" character varying NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), CONSTRAINT "PK_1d3d120ddaf7bc9b1ed68ed463a" PRIMARY KEY ("id"))`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "audit"`); + } + +}