Создан контроллер для CRUD операций с дашбордами
This commit is contained in:
parent
0e6b64fb27
commit
c8e71d3926
8 changed files with 117 additions and 31 deletions
|
|
@ -43,7 +43,8 @@
|
||||||
"url": "",
|
"url": "",
|
||||||
"dbs": {
|
"dbs": {
|
||||||
"users": "",
|
"users": "",
|
||||||
"issues": ""
|
"issues": "",
|
||||||
|
"dashboards": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
"changes": "",
|
"changes": "",
|
||||||
"userMetaInfo": "",
|
"userMetaInfo": "",
|
||||||
"eccmDailyReports": "",
|
"eccmDailyReports": "",
|
||||||
"eccmDailyReportsUserComments": "",
|
"eccmDailyReportsUserComments": ""
|
||||||
"dashboards": ""
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"telegramBotToken": "",
|
"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 { 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 nano from 'nano';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
import { Result, fail, getOrThrow, success } from '../utils/result';
|
import { createAppError } from '../utils/result';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DashboardsService {
|
export class DashboardsService {
|
||||||
|
private logger = new Logger(DashboardsService.name);
|
||||||
|
|
||||||
constructor(private db: DashboardsDb) {}
|
constructor(private db: DashboardsDb) {}
|
||||||
|
|
||||||
async create(name?: string): Promise<Result<DashboardModel, string>> {
|
async create(name?: string): Promise<DashboardModel> {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
name = randomUUID();
|
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 ds = await this.db.getDatasource();
|
||||||
const doc: nano.MaybeDocument & DashboardModel = {
|
const doc: nano.MaybeDocument & DashboardModel = {
|
||||||
|
|
@ -22,15 +31,23 @@ export class DashboardsService {
|
||||||
data: null,
|
data: null,
|
||||||
};
|
};
|
||||||
await ds.insert(doc);
|
await ds.insert(doc);
|
||||||
return success(await ds.get(name));
|
return await ds.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(
|
async loadRawData(
|
||||||
name: string,
|
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();
|
const ds = await this.db.getDatasource();
|
||||||
if (!(await this.isExists(name))) return fail('NOT_EXISTS');
|
if (!(await this.isExists(name))) throw createAppError('NOT_EXISTS');
|
||||||
return success(await ds.get(name));
|
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> {
|
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 ds = await this.db.getDatasource();
|
||||||
const loadRes = await this.load(name);
|
const prevValue = await this.loadRawData(name);
|
||||||
if (loadRes.error) return fail(loadRes.error);
|
|
||||||
|
|
||||||
const prevValue = getOrThrow(loadRes);
|
const newValue = {
|
||||||
const newValue = { ...prevValue, data: data };
|
_id: prevValue._id,
|
||||||
|
_rev: prevValue._rev,
|
||||||
|
id: prevValue.id,
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
await ds.insert(newValue);
|
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 { CalendarEnhancer } from './issue-enhancers/calendar-enhancer';
|
||||||
import { CalendarService } from './calendar/calendar.service';
|
import { CalendarService } from './calendar/calendar.service';
|
||||||
import { CalendarController } from './calendar/calendar.controller';
|
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({})
|
@Module({})
|
||||||
export class EventEmitterModule implements OnModuleInit {
|
export class EventEmitterModule implements OnModuleInit {
|
||||||
|
|
@ -48,6 +51,7 @@ export class EventEmitterModule implements OnModuleInit {
|
||||||
CouchDb,
|
CouchDb,
|
||||||
Users,
|
Users,
|
||||||
Issues,
|
Issues,
|
||||||
|
DashboardsDs,
|
||||||
RedmineUserCacheWriterService,
|
RedmineUserCacheWriterService,
|
||||||
UsersService,
|
UsersService,
|
||||||
IssuesService,
|
IssuesService,
|
||||||
|
|
@ -96,6 +100,7 @@ export class EventEmitterModule implements OnModuleInit {
|
||||||
},
|
},
|
||||||
inject: ['CALENDAR_ENHANCER', IssuesService],
|
inject: ['CALENDAR_ENHANCER', IssuesService],
|
||||||
},
|
},
|
||||||
|
DashboardsService,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
EventEmitterService,
|
EventEmitterService,
|
||||||
|
|
@ -105,6 +110,7 @@ export class EventEmitterModule implements OnModuleInit {
|
||||||
CouchDb,
|
CouchDb,
|
||||||
Users,
|
Users,
|
||||||
Issues,
|
Issues,
|
||||||
|
DashboardsDs,
|
||||||
RedmineUserCacheWriterService,
|
RedmineUserCacheWriterService,
|
||||||
UsersService,
|
UsersService,
|
||||||
IssuesService,
|
IssuesService,
|
||||||
|
|
@ -131,12 +137,14 @@ export class EventEmitterModule implements OnModuleInit {
|
||||||
provide: 'CALENDAR_SERVICE',
|
provide: 'CALENDAR_SERVICE',
|
||||||
useExisting: 'CALENDAR_SERVICE',
|
useExisting: 'CALENDAR_SERVICE',
|
||||||
},
|
},
|
||||||
|
DashboardsService,
|
||||||
],
|
],
|
||||||
controllers: [
|
controllers: [
|
||||||
MainController,
|
MainController,
|
||||||
UsersController,
|
UsersController,
|
||||||
IssuesController,
|
IssuesController,
|
||||||
CalendarController,
|
CalendarController,
|
||||||
|
DashboardController,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
export type Data = Record<string, any> | null;
|
||||||
|
|
||||||
export type Dashboard = {
|
export type Dashboard = {
|
||||||
id: string;
|
id: string;
|
||||||
data: any;
|
data: Data;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { BadRequestException } from '@nestjs/common';
|
||||||
|
|
||||||
export type Result<T, E> = {
|
export type Result<T, E> = {
|
||||||
result?: T;
|
result?: T;
|
||||||
error?: E;
|
error?: E;
|
||||||
|
|
@ -39,23 +41,34 @@ export type AppError = Error & {
|
||||||
app: true;
|
app: true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createAppError(msg: string): AppError {
|
export function createAppError(msg: string | Error): AppError {
|
||||||
const err = new Error(msg);
|
let err: any;
|
||||||
const app: AppError = { ...err, app: true };
|
if (typeof msg === 'string') {
|
||||||
return app;
|
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>(
|
export async function getOrAppErrorOrThrow<T>(
|
||||||
fn: () => Promise<T>,
|
fn: () => Promise<T>,
|
||||||
onError: (err: AppError) => Promise<void>,
|
onAppError?: (err: Error) => Error,
|
||||||
): Promise<T | AppError> {
|
onOtherError?: (err: Error) => Error,
|
||||||
|
): Promise<T> {
|
||||||
try {
|
try {
|
||||||
return await fn();
|
return await fn();
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (ex && ex.app) {
|
if (ex && ex.name === 'ApplicationError') {
|
||||||
onError(ex);
|
throw onAppError ? onAppError(ex) : ex;
|
||||||
return 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 { TagsManagerController } from './tags-manager/tags-manager.controller';
|
||||||
import { CreateTagManagerServiceProvider } from './tags-manager/tags-manager.service';
|
import { CreateTagManagerServiceProvider } from './tags-manager/tags-manager.service';
|
||||||
import { CalendarEnhancer } from '@app/event-emitter/issue-enhancers/calendar-enhancer';
|
import { CalendarEnhancer } from '@app/event-emitter/issue-enhancers/calendar-enhancer';
|
||||||
|
import { Dashboards as DashboardsDs } from '@app/event-emitter/couchdb-datasources/dashboards';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
|
@ -145,6 +146,7 @@ export class AppModule implements OnModuleInit {
|
||||||
UserMetaInfo.getDatasource();
|
UserMetaInfo.getDatasource();
|
||||||
DailyEccmReportsDatasource.getDatasource();
|
DailyEccmReportsDatasource.getDatasource();
|
||||||
DailyEccmReportsUserCommentsDatasource.getDatasource();
|
DailyEccmReportsUserCommentsDatasource.getDatasource();
|
||||||
|
DashboardsDs.getDatasource();
|
||||||
|
|
||||||
this.enhancerService.addEnhancer([
|
this.enhancerService.addEnhancer([
|
||||||
this.timestampEnhancer,
|
this.timestampEnhancer,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue