Добавлен обработчик получения комментария для дейли

This commit is contained in:
Pavel Gnedov 2022-12-08 13:17:13 +07:00
parent addff66c8c
commit e71491b637
9 changed files with 244 additions and 3 deletions

View file

@ -3,7 +3,8 @@
"dbs": {
"changes": "",
"userMetaInfo": "",
"eccmDailyReports": ""
"eccmDailyReports": "",
"eccmDailyReportsUserComments": ""
}
},
"telegramBotToken": "",

View file

@ -32,6 +32,9 @@ import { ChangesService } from './changes/changes.service';
import { DailyEccmReportsDatasource } from './couchdb-datasources/daily-eccm-reports.datasource';
import { ScheduleModule } from '@nestjs/schedule';
import { DailyEccmReportTask } from './reports/daily-eccm.report.task';
import { DailyEccmReportsUserCommentsDatasource } from './couchdb-datasources/daily-eccm-reports-user-comments.datasource';
import { DailyEccmUserCommentsService } from './reports/daily-eccm-user-comments.service';
import { SetDailyEccmUserCommentBotHandlerService } from './telegram-bot/handlers/set-daily-eccm-user-comment.bot-handler.service';
@Module({
imports: [
@ -70,6 +73,9 @@ import { DailyEccmReportTask } from './reports/daily-eccm.report.task';
ChangesService,
DailyEccmReportsDatasource,
DailyEccmReportTask,
DailyEccmReportsUserCommentsDatasource,
DailyEccmUserCommentsService,
SetDailyEccmUserCommentBotHandlerService,
],
})
export class AppModule implements OnModuleInit {
@ -95,6 +101,7 @@ export class AppModule implements OnModuleInit {
Changes.getDatasource();
UserMetaInfo.getDatasource();
DailyEccmReportsDatasource.getDatasource();
DailyEccmReportsUserCommentsDatasource.getDatasource();
this.enhancerService.addEnhancer([
this.timestampEnhancer,

View file

@ -0,0 +1 @@
export const ISO_DATE_FORMAT = 'yyyy-MM-dd';

View file

@ -0,0 +1,43 @@
import { CouchDb } from '@app/event-emitter/couchdb-datasources/couchdb';
import nano from 'nano';
import { Injectable, Logger } from '@nestjs/common';
import configuration from '../configs/app';
import { DailyEccmUserComments } from 'src/reports/daily-eccm-user-comments.service';
const config = configuration();
@Injectable()
export class DailyEccmReportsUserCommentsDatasource {
private static logger = new Logger(
DailyEccmReportsUserCommentsDatasource.name,
);
private static db = null;
private static initilized = false;
static async getDatasource(): Promise<
nano.DocumentScope<DailyEccmUserComments.Models.Item>
> {
if (DailyEccmReportsUserCommentsDatasource.initilized) {
return DailyEccmReportsUserCommentsDatasource.db;
}
DailyEccmReportsUserCommentsDatasource.initilized = true;
const n = CouchDb.getCouchDb();
const dbName = config.couchDb.dbs.eccmDailyReportsUserComments;
const dbs = await n.db.list();
if (!dbs.includes(dbName)) {
await n.db.create(dbName);
}
DailyEccmReportsUserCommentsDatasource.db = await n.db.use(dbName);
DailyEccmReportsUserCommentsDatasource.initilized = true;
DailyEccmReportsUserCommentsDatasource.logger.log(
`Connected to eccm_daily_reports_user_comments db - ${dbName}`,
);
return DailyEccmReportsUserCommentsDatasource.db;
}
async getDatasource(): Promise<
nano.DocumentScope<DailyEccmUserComments.Models.Item>
> {
return await DailyEccmReportsUserCommentsDatasource.getDatasource();
}
}

View file

@ -14,6 +14,7 @@ export type AppConfig = {
changes: string;
userMetaInfo: string;
eccmDailyReports: string;
eccmDailyReportsUserComments: string;
};
};
telegramBotToken: string;

View file

@ -0,0 +1,93 @@
/* eslint-disable @typescript-eslint/no-namespace */
import { UNLIMITED } from '@app/event-emitter/consts/consts';
import { Timestamped } from '@app/event-emitter/models/timestamped';
import { TimestampNowFill } from '@app/event-emitter/utils/timestamp-now-fill';
import { Injectable } from '@nestjs/common';
import nano from 'nano';
import { DailyEccmReportsUserCommentsDatasource } from 'src/couchdb-datasources/daily-eccm-reports-user-comments.datasource';
export namespace DailyEccmUserComments {
export namespace Models {
export type Item = {
userId: number;
date: string;
comment: string;
};
export type CouchDbItem = Item & Timestamped & nano.DocumentGetResponse;
}
}
@Injectable()
export class DailyEccmUserCommentsService {
constructor(private datasource: DailyEccmReportsUserCommentsDatasource) {}
async setComment(
userId: number,
date: string,
comment: string,
): Promise<void> {
const key = this.getKey(userId, date);
const ds = await this.datasource.getDatasource();
let existsItem: any;
try {
existsItem = await ds.get(key);
} catch (ex) {
existsItem = null;
}
const item: DailyEccmUserComments.Models.CouchDbItem = TimestampNowFill({
userId: userId,
date: date,
comment: comment,
_id: key,
_rev: existsItem?._rev,
});
await ds.insert(item);
}
async loadComment(userId: number, date: string): Promise<string | null> {
const key = this.getKey(userId, date);
const ds = await this.datasource.getDatasource();
try {
const res: any = await ds.get(key);
return res.comment;
} catch (ex) {
return null;
}
}
async loadComments(
userIds: number[],
date: string,
): Promise<Record<number, string>> {
const query: nano.MangoQuery = {
limit: UNLIMITED,
selector: {
userId: {
$in: userIds,
},
date: {
$eq: date,
},
},
};
const ds = await this.datasource.getDatasource();
const resp = await ds.find(query);
if (!resp || !resp.docs || resp.docs.length <= 0) {
return [];
}
const items = resp.docs;
const res: Record<number, string> = {};
for (const key in items) {
if (Object.prototype.hasOwnProperty.call(items, key)) {
const item = items[key];
res[item.userId] = item.comment;
}
}
return res;
}
private getKey(userId: number, date: string): string {
return `${date} - ${userId}`;
}
}

View file

@ -14,6 +14,7 @@ import { DailyEccmReportsDatasource } from 'src/couchdb-datasources/daily-eccm-r
import { Timestamped } from '@app/event-emitter/models/timestamped';
import { TimestampNowFill } from '@app/event-emitter/utils/timestamp-now-fill';
import { DateTime } from 'luxon';
import { ISO_DATE_FORMAT } from 'src/consts/date-time.consts';
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace DailyEccmReport {
@ -413,7 +414,7 @@ export class DailyEccmReportService {
if (!toDate.isValid) throw new Error('to is invalid date');
let nameValue: string | null = name || null;
if (!nameValue) {
nameValue = DateTime.now().toFormat('yyyy-MM-dd');
nameValue = DateTime.now().toFormat(ISO_DATE_FORMAT);
}
return {
from: fromDate.toISO(),

View file

@ -0,0 +1,88 @@
/* eslint-disable @typescript-eslint/no-namespace */
import { TelegramBotService } from '../telegram-bot.service';
import { TelegramBotHandlerInterface } from '../telegram.bot-handler.interface';
import TelegramBot from 'node-telegram-bot-api';
import { Injectable, Logger } from '@nestjs/common';
import { UserMetaInfoService } from 'src/user-meta-info/user-meta-info.service';
import { Subject } from 'rxjs';
import { DateTime } from 'luxon';
import { ISO_DATE_FORMAT } from 'src/consts/date-time.consts';
export namespace SetDailyEccmUserCommentBotHandler {
export namespace Models {
export type SetDailyEccmUserComment = {
userId: number;
date: string;
comment: string;
};
}
}
@Injectable()
export class SetDailyEccmUserCommentBotHandlerService
implements TelegramBotHandlerInterface
{
private service: TelegramBotService;
private regexp = /\/set_daily_eccm_user_comment (.+)/;
private logger = new Logger(SetDailyEccmUserCommentBotHandlerService.name);
private dateParamRegexp = /^date=([\d\-]+) (.+)$/;
$messages =
new Subject<SetDailyEccmUserCommentBotHandler.Models.SetDailyEccmUserComment>();
constructor(private userMetaInfoService: UserMetaInfoService) {
return;
}
async init(service: TelegramBotService, bot: TelegramBot): Promise<void> {
if (!this.service) {
this.service = service;
}
bot.onText(this.regexp, async (msg) => {
const userMetaInfo = await this.userMetaInfoService.findByTelegramId(
msg.chat.id,
);
const redmineUserId = userMetaInfo.user_id;
const data = this.parseDate(msg.text);
this.logger.debug(
`Setting user comment for daily eccm ` +
`by redmineUserId = ${redmineUserId}, ` +
`full text - ${msg.text}, ` +
`parsed data - ${JSON.stringify(data)}`,
);
this.$messages.next({
userId: redmineUserId,
date: data.date,
comment: data.msg,
});
return;
});
}
getHelpMsg(): string {
return (
`/set_daily_eccm_user_comment ` +
`[дата=yyyy-MM-dd] <комментарий> ` +
`- дополнительный комментарий для дейли`
);
}
private parseDate(src: string): { date: string; msg: string } | null {
let msgWithoutCommand: any = src.match(this.regexp);
if (!msgWithoutCommand || !msgWithoutCommand[1]) {
return null;
}
msgWithoutCommand = msgWithoutCommand[1];
const msgWithDate: any = msgWithoutCommand.match(this.dateParamRegexp);
let date: any = '';
if (msgWithDate && msgWithDate[1] && msgWithDate[2]) {
date = msgWithDate[1];
if (DateTime.fromFormat(date, ISO_DATE_FORMAT).isValid) {
msgWithoutCommand = msgWithDate[2];
} else {
date = '';
}
}
return { date: date, msg: msgWithoutCommand };
}
}

View file

@ -7,6 +7,7 @@ import axios from 'axios';
import { UserMetaInfoModel } from 'src/models/user-meta-info.model';
import { CurrentIssuesEccmBotHandlerService } from './handlers/current-issues-eccm.bot-handler.service';
import { TelegramBotHandlerInterface } from './telegram.bot-handler.interface';
import { SetDailyEccmUserCommentBotHandlerService } from './handlers/set-daily-eccm-user-comment.bot-handler.service';
@Injectable()
export class TelegramBotService {
@ -24,12 +25,14 @@ export class TelegramBotService {
private usersService: UsersService,
private configService: ConfigService,
private currentIssuesBotHandlerService: CurrentIssuesEccmBotHandlerService,
private setDailyEccmUserCommentBotHandlerService: SetDailyEccmUserCommentBotHandlerService,
) {
this.telegramBotToken = this.configService.get<string>('telegramBotToken');
this.redminePublicUrlPrefix =
this.configService.get<string>('redmineUrlPublic');
this.initTelegramBot();
this.handlers.push(this.currentIssuesBotHandlerService);
this.handlers.push(this.setDailyEccmUserCommentBotHandlerService);
}
private async initTelegramBot(): Promise<void> {
@ -47,7 +50,10 @@ export class TelegramBotService {
this.bot.onText(/\/leave/, async (msg) => {
await this.leave(msg);
});
this.currentIssuesBotHandlerService.init(this, this.bot);
for (let i = 0; i < this.handlers.length; i++) {
const handler = this.handlers[i];
await handler.init(this, this.bot);
}
}
private async showHelpMessage(msg: TelegramBot.Message): Promise<void> {