Добавлен сервис для работы с дашбордами
This commit is contained in:
parent
b8c15c0dd0
commit
0e6b64fb27
7 changed files with 171 additions and 4 deletions
|
|
@ -4,7 +4,8 @@
|
||||||
"changes": "",
|
"changes": "",
|
||||||
"userMetaInfo": "",
|
"userMetaInfo": "",
|
||||||
"eccmDailyReports": "",
|
"eccmDailyReports": "",
|
||||||
"eccmDailyReportsUserComments": ""
|
"eccmDailyReportsUserComments": "",
|
||||||
|
"dashboards": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"telegramBotToken": "",
|
"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',
|
provide: 'CALENDAR_SERVICE',
|
||||||
useFactory: (calendarEnhancer: CalendarEnhancer, issuesService: IssuesService): CalendarService => {
|
useFactory: (
|
||||||
|
calendarEnhancer: CalendarEnhancer,
|
||||||
|
issuesService: IssuesService,
|
||||||
|
): CalendarService => {
|
||||||
const calendarEventsKey = calendarEnhancer.calendarEventsKey;
|
const calendarEventsKey = calendarEnhancer.calendarEventsKey;
|
||||||
return new CalendarService(calendarEventsKey, issuesService);
|
return new CalendarService(calendarEventsKey, issuesService);
|
||||||
},
|
},
|
||||||
inject: ['CALENDAR_ENHANCER', IssuesService]
|
inject: ['CALENDAR_ENHANCER', IssuesService],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
|
|
@ -129,7 +132,12 @@ export class EventEmitterModule implements OnModuleInit {
|
||||||
useExisting: 'CALENDAR_SERVICE',
|
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: {
|
dbs: {
|
||||||
users: string;
|
users: string;
|
||||||
issues: string;
|
issues: string;
|
||||||
|
dashboards: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
webhooks: WebhookConfigItemModel[];
|
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