From c8e71d3926de3c58fd562d017eb3e1d5e659a163 Mon Sep 17 00:00:00 2001 From: Pavel Gnedov Date: Wed, 20 Sep 2023 10:12:45 +0700 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20CRUD=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B9=20=D1=81=20=D0=B4=D0=B0=D1=88=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=B4=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configs/issue-event-emitter-config.jsonc.dist | 3 +- configs/main-config.jsonc.dist | 3 +- .../src/dashboards/dashboard.controller.ts | 38 +++++++++++++ .../src/dashboards/dashboards.service.ts | 57 +++++++++++++------ .../event-emitter/src/event-emitter.module.ts | 8 +++ libs/event-emitter/src/models/dashboard.ts | 4 +- libs/event-emitter/src/utils/result.ts | 33 +++++++---- src/app.module.ts | 2 + 8 files changed, 117 insertions(+), 31 deletions(-) create mode 100644 libs/event-emitter/src/dashboards/dashboard.controller.ts diff --git a/configs/issue-event-emitter-config.jsonc.dist b/configs/issue-event-emitter-config.jsonc.dist index d147a5b..3129594 100644 --- a/configs/issue-event-emitter-config.jsonc.dist +++ b/configs/issue-event-emitter-config.jsonc.dist @@ -43,7 +43,8 @@ "url": "", "dbs": { "users": "", - "issues": "" + "issues": "", + "dashboards": "" } } } \ No newline at end of file diff --git a/configs/main-config.jsonc.dist b/configs/main-config.jsonc.dist index 6114f24..e51d60d 100644 --- a/configs/main-config.jsonc.dist +++ b/configs/main-config.jsonc.dist @@ -4,8 +4,7 @@ "changes": "", "userMetaInfo": "", "eccmDailyReports": "", - "eccmDailyReportsUserComments": "", - "dashboards": "" + "eccmDailyReportsUserComments": "" } }, "telegramBotToken": "", diff --git a/libs/event-emitter/src/dashboards/dashboard.controller.ts b/libs/event-emitter/src/dashboards/dashboard.controller.ts new file mode 100644 index 0000000..b631554 --- /dev/null +++ b/libs/event-emitter/src/dashboards/dashboard.controller.ts @@ -0,0 +1,38 @@ +import { Body, Controller, Get, Param, Post, Put } from '@nestjs/common'; +import { DashboardsService } from './dashboards.service'; +import { BadRequestErrorHandler, getOrAppErrorOrThrow } from '../utils/result'; + +@Controller('dashboard') +export class DashboardController { + constructor(private dashboardsService: DashboardsService) {} + + @Post(':name') + async create(@Param('name') name: string): Promise { + if (name === 'anonymous') { + name = null; + } + const res = await getOrAppErrorOrThrow( + () => this.dashboardsService.create(name), + BadRequestErrorHandler, + ); + return res.id; + } + + @Get(':name') + async load(@Param('name') name: string): Promise { + const res = await getOrAppErrorOrThrow( + () => this.dashboardsService.load(name), + BadRequestErrorHandler, + ); + return res; + } + + @Put(':name') + async save(@Param('name') name: string, @Body() data: any): Promise { + const res = await getOrAppErrorOrThrow( + () => this.dashboardsService.save(name, data), + BadRequestErrorHandler, + ); + return res; + } +} diff --git a/libs/event-emitter/src/dashboards/dashboards.service.ts b/libs/event-emitter/src/dashboards/dashboards.service.ts index 98efd9e..797be20 100644 --- a/libs/event-emitter/src/dashboards/dashboards.service.ts +++ b/libs/event-emitter/src/dashboards/dashboards.service.ts @@ -1,19 +1,28 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { Dashboards as DashboardsDb } from '../couchdb-datasources/dashboards'; -import { Dashboard as DashboardModel } from '../models/dashboard'; +import { + Dashboard as DashboardModel, + Data as DashboardData, +} from '../models/dashboard'; import nano from 'nano'; import { randomUUID } from 'crypto'; -import { Result, fail, getOrThrow, success } from '../utils/result'; +import { createAppError } from '../utils/result'; @Injectable() export class DashboardsService { + private logger = new Logger(DashboardsService.name); + constructor(private db: DashboardsDb) {} - async create(name?: string): Promise> { + async create(name?: string): Promise { if (!name) { name = randomUUID(); - } else if (await this.isExists(name)) { - return fail('ALREADY_EXISTS'); + } + this.logger.debug(`Create new dashboard with name - ${name}`); + if (await this.isExists(name)) { + const err = createAppError('ALREADY_EXISTS'); + this.logger.error(`Error - ${JSON.stringify(err)}`); + throw err; } const ds = await this.db.getDatasource(); const doc: nano.MaybeDocument & DashboardModel = { @@ -22,15 +31,23 @@ export class DashboardsService { data: null, }; await ds.insert(doc); - return success(await ds.get(name)); + return await ds.get(name); } - async load( + async loadRawData( name: string, - ): Promise> { + ): Promise { + this.logger.debug(`Load raw data, dashboard name - ${name}`); const ds = await this.db.getDatasource(); - if (!(await this.isExists(name))) return fail('NOT_EXISTS'); - return success(await ds.get(name)); + if (!(await this.isExists(name))) throw createAppError('NOT_EXISTS'); + const res = await ds.get(name); + return res; + } + + async load(name: string): Promise { + this.logger.debug(`Load dashboard name - ${name}`); + const rawData = await this.loadRawData(name); + return rawData.data; } async isExists(name: string): Promise { @@ -43,14 +60,20 @@ export class DashboardsService { } } - async save(name: string, data: any): Promise> { + async save(name: string, data: any): Promise { + this.logger.debug( + `Save dashboard name - ${name}, data - ${JSON.stringify(data)}`, + ); const ds = await this.db.getDatasource(); - const loadRes = await this.load(name); - if (loadRes.error) return fail(loadRes.error); + const prevValue = await this.loadRawData(name); - const prevValue = getOrThrow(loadRes); - const newValue = { ...prevValue, data: data }; + const newValue = { + _id: prevValue._id, + _rev: prevValue._rev, + id: prevValue.id, + data: data, + }; await ds.insert(newValue); - return success(newValue); + return; } } diff --git a/libs/event-emitter/src/event-emitter.module.ts b/libs/event-emitter/src/event-emitter.module.ts index 03ebfca..f1c9607 100644 --- a/libs/event-emitter/src/event-emitter.module.ts +++ b/libs/event-emitter/src/event-emitter.module.ts @@ -31,6 +31,9 @@ import { IssuesUpdaterService } from './issues-updater/issues-updater.service'; import { CalendarEnhancer } from './issue-enhancers/calendar-enhancer'; import { CalendarService } from './calendar/calendar.service'; import { CalendarController } from './calendar/calendar.controller'; +import { Dashboards as DashboardsDs } from './couchdb-datasources/dashboards'; +import { DashboardController } from './dashboards/dashboard.controller'; +import { DashboardsService } from './dashboards/dashboards.service'; @Module({}) export class EventEmitterModule implements OnModuleInit { @@ -48,6 +51,7 @@ export class EventEmitterModule implements OnModuleInit { CouchDb, Users, Issues, + DashboardsDs, RedmineUserCacheWriterService, UsersService, IssuesService, @@ -96,6 +100,7 @@ export class EventEmitterModule implements OnModuleInit { }, inject: ['CALENDAR_ENHANCER', IssuesService], }, + DashboardsService, ], exports: [ EventEmitterService, @@ -105,6 +110,7 @@ export class EventEmitterModule implements OnModuleInit { CouchDb, Users, Issues, + DashboardsDs, RedmineUserCacheWriterService, UsersService, IssuesService, @@ -131,12 +137,14 @@ export class EventEmitterModule implements OnModuleInit { provide: 'CALENDAR_SERVICE', useExisting: 'CALENDAR_SERVICE', }, + DashboardsService, ], controllers: [ MainController, UsersController, IssuesController, CalendarController, + DashboardController, ], }; } diff --git a/libs/event-emitter/src/models/dashboard.ts b/libs/event-emitter/src/models/dashboard.ts index ef4a812..8c19d37 100644 --- a/libs/event-emitter/src/models/dashboard.ts +++ b/libs/event-emitter/src/models/dashboard.ts @@ -1,4 +1,6 @@ +export type Data = Record | null; + export type Dashboard = { id: string; - data: any; + data: Data; }; diff --git a/libs/event-emitter/src/utils/result.ts b/libs/event-emitter/src/utils/result.ts index 945d2eb..fef53a4 100644 --- a/libs/event-emitter/src/utils/result.ts +++ b/libs/event-emitter/src/utils/result.ts @@ -1,3 +1,5 @@ +import { BadRequestException } from '@nestjs/common'; + export type Result = { result?: T; error?: E; @@ -39,23 +41,34 @@ export type AppError = Error & { app: true; }; -export function createAppError(msg: string): AppError { - const err = new Error(msg); - const app: AppError = { ...err, app: true }; - return app; +export function createAppError(msg: string | Error): AppError { + let err: any; + if (typeof msg === 'string') { + err = new Error(msg); + } else if (typeof msg === 'object') { + err = msg; + } else { + err = new Error('UNKNOWN_APP_ERROR'); + } + err.name = 'ApplicationError'; + return err; } export async function getOrAppErrorOrThrow( fn: () => Promise, - onError: (err: AppError) => Promise, -): Promise { + onAppError?: (err: Error) => Error, + onOtherError?: (err: Error) => Error, +): Promise { try { return await fn(); } catch (ex) { - if (ex && ex.app) { - onError(ex); - return ex; + if (ex && ex.name === 'ApplicationError') { + throw onAppError ? onAppError(ex) : ex; } - throw ex; + throw onOtherError ? onOtherError(ex) : ex; } } + +export function BadRequestErrorHandler(err: Error): Error { + return new BadRequestException(err.message); +} diff --git a/src/app.module.ts b/src/app.module.ts index 2afa718..221d5e8 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -51,6 +51,7 @@ import { SimpleIssuesListController } from './dashboards/simple-issues-list.cont import { TagsManagerController } from './tags-manager/tags-manager.controller'; import { CreateTagManagerServiceProvider } from './tags-manager/tags-manager.service'; import { CalendarEnhancer } from '@app/event-emitter/issue-enhancers/calendar-enhancer'; +import { Dashboards as DashboardsDs } from '@app/event-emitter/couchdb-datasources/dashboards'; @Module({ imports: [ @@ -145,6 +146,7 @@ export class AppModule implements OnModuleInit { UserMetaInfo.getDatasource(); DailyEccmReportsDatasource.getDatasource(); DailyEccmReportsUserCommentsDatasource.getDatasource(); + DashboardsDs.getDatasource(); this.enhancerService.addEnhancer([ this.timestampEnhancer,