Добавлен сервис для работы с дашбордами
This commit is contained in:
parent
b8c15c0dd0
commit
0e6b64fb27
7 changed files with 171 additions and 4 deletions
|
|
@ -4,7 +4,8 @@
|
|||
"changes": "",
|
||||
"userMetaInfo": "",
|
||||
"eccmDailyReports": "",
|
||||
"eccmDailyReportsUserComments": ""
|
||||
"eccmDailyReportsUserComments": "",
|
||||
"dashboards": ""
|
||||
}
|
||||
},
|
||||
"telegramBotToken": "",
|
||||
|
|
|
|||
36
libs/event-emitter/src/couchdb-datasources/dashboards.ts
Normal file
36
libs/event-emitter/src/couchdb-datasources/dashboards.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import nano from 'nano';
|
||||
import * as DashboardModel from '../models/dashboard';
|
||||
import { CouchDb } from './couchdb';
|
||||
import configuration from '../configs/main-config';
|
||||
|
||||
const config = configuration();
|
||||
|
||||
@Injectable()
|
||||
export class Dashboards {
|
||||
private static logger = new Logger(Dashboards.name);
|
||||
private static dashboardsDb = null;
|
||||
private static initialized = false;
|
||||
|
||||
static async getDatasource(): Promise<
|
||||
nano.DocumentScope<DashboardModel.Dashboard>
|
||||
> {
|
||||
if (Dashboards.initialized) {
|
||||
return Dashboards.dashboardsDb;
|
||||
}
|
||||
Dashboards.initialized = true;
|
||||
const n = CouchDb.getCouchDb();
|
||||
const dashboardsDbName = config.couchDb?.dbs?.dashboards;
|
||||
const dbs = await n.db.list();
|
||||
if (!dbs.includes(dashboardsDbName)) {
|
||||
await n.db.create(dashboardsDbName);
|
||||
}
|
||||
Dashboards.dashboardsDb = await n.db.use(dashboardsDbName);
|
||||
Dashboards.logger.log(`Connected to dashboards db - ${dashboardsDbName}`);
|
||||
return Dashboards.dashboardsDb;
|
||||
}
|
||||
|
||||
async getDatasource(): Promise<nano.DocumentScope<DashboardModel.Dashboard>> {
|
||||
return await Dashboards.getDatasource();
|
||||
}
|
||||
}
|
||||
56
libs/event-emitter/src/dashboards/dashboards.service.ts
Normal file
56
libs/event-emitter/src/dashboards/dashboards.service.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Dashboards as DashboardsDb } from '../couchdb-datasources/dashboards';
|
||||
import { Dashboard as DashboardModel } from '../models/dashboard';
|
||||
import nano from 'nano';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { Result, fail, getOrThrow, success } from '../utils/result';
|
||||
|
||||
@Injectable()
|
||||
export class DashboardsService {
|
||||
constructor(private db: DashboardsDb) {}
|
||||
|
||||
async create(name?: string): Promise<Result<DashboardModel, string>> {
|
||||
if (!name) {
|
||||
name = randomUUID();
|
||||
} else if (await this.isExists(name)) {
|
||||
return fail('ALREADY_EXISTS');
|
||||
}
|
||||
const ds = await this.db.getDatasource();
|
||||
const doc: nano.MaybeDocument & DashboardModel = {
|
||||
_id: name,
|
||||
id: name,
|
||||
data: null,
|
||||
};
|
||||
await ds.insert(doc);
|
||||
return success(await ds.get(name));
|
||||
}
|
||||
|
||||
async load(
|
||||
name: string,
|
||||
): Promise<Result<DashboardModel & nano.MaybeDocument, string>> {
|
||||
const ds = await this.db.getDatasource();
|
||||
if (!(await this.isExists(name))) return fail('NOT_EXISTS');
|
||||
return success(await ds.get(name));
|
||||
}
|
||||
|
||||
async isExists(name: string): Promise<boolean> {
|
||||
const ds = await this.db.getDatasource();
|
||||
try {
|
||||
await ds.get(name);
|
||||
return true;
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async save(name: string, data: any): Promise<Result<any, string>> {
|
||||
const ds = await this.db.getDatasource();
|
||||
const loadRes = await this.load(name);
|
||||
if (loadRes.error) return fail(loadRes.error);
|
||||
|
||||
const prevValue = getOrThrow(loadRes);
|
||||
const newValue = { ...prevValue, data: data };
|
||||
await ds.insert(newValue);
|
||||
return success(newValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -87,11 +87,14 @@ export class EventEmitterModule implements OnModuleInit {
|
|||
},
|
||||
{
|
||||
provide: 'CALENDAR_SERVICE',
|
||||
useFactory: (calendarEnhancer: CalendarEnhancer, issuesService: IssuesService): CalendarService => {
|
||||
useFactory: (
|
||||
calendarEnhancer: CalendarEnhancer,
|
||||
issuesService: IssuesService,
|
||||
): CalendarService => {
|
||||
const calendarEventsKey = calendarEnhancer.calendarEventsKey;
|
||||
return new CalendarService(calendarEventsKey, issuesService);
|
||||
},
|
||||
inject: ['CALENDAR_ENHANCER', IssuesService]
|
||||
inject: ['CALENDAR_ENHANCER', IssuesService],
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
|
|
@ -129,7 +132,12 @@ export class EventEmitterModule implements OnModuleInit {
|
|||
useExisting: 'CALENDAR_SERVICE',
|
||||
},
|
||||
],
|
||||
controllers: [MainController, UsersController, IssuesController, CalendarController],
|
||||
controllers: [
|
||||
MainController,
|
||||
UsersController,
|
||||
IssuesController,
|
||||
CalendarController,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
4
libs/event-emitter/src/models/dashboard.ts
Normal file
4
libs/event-emitter/src/models/dashboard.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export type Dashboard = {
|
||||
id: string;
|
||||
data: any;
|
||||
};
|
||||
|
|
@ -16,6 +16,7 @@ export type MainConfigModel = {
|
|||
dbs: {
|
||||
users: string;
|
||||
issues: string;
|
||||
dashboards: string;
|
||||
};
|
||||
};
|
||||
webhooks: WebhookConfigItemModel[];
|
||||
|
|
|
|||
61
libs/event-emitter/src/utils/result.ts
Normal file
61
libs/event-emitter/src/utils/result.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
export type Result<T, E> = {
|
||||
result?: T;
|
||||
error?: E;
|
||||
};
|
||||
|
||||
export function success<T, E>(res: T): Result<T, E> {
|
||||
return {
|
||||
result: res,
|
||||
};
|
||||
}
|
||||
|
||||
export function fail<T, E>(error: E): Result<T, E> {
|
||||
return {
|
||||
error: error,
|
||||
};
|
||||
}
|
||||
|
||||
export function getOrThrow<T, E>(res: Result<T, E>): T {
|
||||
if (res.result) return res.result;
|
||||
throw res.error ? res.error : 'UNKNOWN_ERROR';
|
||||
}
|
||||
|
||||
export async function successOrError<T, E>(
|
||||
cb: () => Promise<T>,
|
||||
): Promise<Result<T, E>> {
|
||||
try {
|
||||
const res = await cb();
|
||||
return {
|
||||
result: res,
|
||||
};
|
||||
} catch (ex) {
|
||||
return {
|
||||
error: ex,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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 async function getOrAppErrorOrThrow<T>(
|
||||
fn: () => Promise<T>,
|
||||
onError: (err: AppError) => Promise<void>,
|
||||
): Promise<T | AppError> {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (ex) {
|
||||
if (ex && ex.app) {
|
||||
onError(ex);
|
||||
return ex;
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue