Создан контроллер для CRUD операций с дашбордами
This commit is contained in:
parent
0e6b64fb27
commit
c8e71d3926
8 changed files with 117 additions and 31 deletions
|
|
@ -43,7 +43,8 @@
|
|||
"url": "",
|
||||
"dbs": {
|
||||
"users": "",
|
||||
"issues": ""
|
||||
"issues": "",
|
||||
"dashboards": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,7 @@
|
|||
"changes": "",
|
||||
"userMetaInfo": "",
|
||||
"eccmDailyReports": "",
|
||||
"eccmDailyReportsUserComments": "",
|
||||
"dashboards": ""
|
||||
"eccmDailyReportsUserComments": ""
|
||||
}
|
||||
},
|
||||
"telegramBotToken": "",
|
||||
|
|
|
|||
38
libs/event-emitter/src/dashboards/dashboard.controller.ts
Normal file
38
libs/event-emitter/src/dashboards/dashboard.controller.ts
Normal file
|
|
@ -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<string> {
|
||||
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<any> {
|
||||
const res = await getOrAppErrorOrThrow(
|
||||
() => this.dashboardsService.load(name),
|
||||
BadRequestErrorHandler,
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Put(':name')
|
||||
async save(@Param('name') name: string, @Body() data: any): Promise<void> {
|
||||
const res = await getOrAppErrorOrThrow(
|
||||
() => this.dashboardsService.save(name, data),
|
||||
BadRequestErrorHandler,
|
||||
);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Result<DashboardModel, string>> {
|
||||
async create(name?: string): Promise<DashboardModel> {
|
||||
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<Result<DashboardModel & nano.MaybeDocument, string>> {
|
||||
): Promise<DashboardModel & nano.MaybeDocument> {
|
||||
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<DashboardData> {
|
||||
this.logger.debug(`Load dashboard name - ${name}`);
|
||||
const rawData = await this.loadRawData(name);
|
||||
return rawData.data;
|
||||
}
|
||||
|
||||
async isExists(name: string): Promise<boolean> {
|
||||
|
|
@ -43,14 +60,20 @@ export class DashboardsService {
|
|||
}
|
||||
}
|
||||
|
||||
async save(name: string, data: any): Promise<Result<any, string>> {
|
||||
async save(name: string, data: any): Promise<void> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
export type Data = Record<string, any> | null;
|
||||
|
||||
export type Dashboard = {
|
||||
id: string;
|
||||
data: any;
|
||||
data: Data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
export type Result<T, E> = {
|
||||
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<T>(
|
||||
fn: () => Promise<T>,
|
||||
onError: (err: AppError) => Promise<void>,
|
||||
): Promise<T | AppError> {
|
||||
onAppError?: (err: Error) => Error,
|
||||
onOtherError?: (err: Error) => Error,
|
||||
): Promise<T> {
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue