From 4b2a07085114d02454daf010bc42e89362671fb3 Mon Sep 17 00:00:00 2001 From: Pavel Gnedov Date: Mon, 3 Oct 2022 08:59:54 +0700 Subject: [PATCH] =?UTF-8?q?=D0=9E=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BE=D1=82=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=BF=D0=BE?= =?UTF-8?q?=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D1=83=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D1=81=D0=BE=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 14 ++++- ...issue-and-personal-parsed-message.model.ts | 7 +++ .../personal-notification.adapter.service.ts | 55 +++++++++++++++++++ .../personal-notifications.service.ts | 16 ++++-- src/telegram-bot/telegram-bot.service.ts | 9 ++- 5 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 src/models/issue-and-personal-parsed-message.model.ts create mode 100644 src/notifications/adapters/personal-notification.adapter/personal-notification.adapter.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index fe45d01..bde342a 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -21,6 +21,7 @@ import { Users } from '@app/event-emitter/couchdb-datasources/users'; import { TelegramBotService } from './telegram-bot/telegram-bot.service'; import { UserMetaInfoService } from './user-meta-info/user-meta-info.service'; import { UserMetaInfo } from './couchdb-datasources/user-meta-info'; +import { PersonalNotificationAdapterService } from './notifications/adapters/personal-notification.adapter/personal-notification.adapter.service'; @Module({ imports: [ @@ -45,6 +46,7 @@ import { UserMetaInfo } from './couchdb-datasources/user-meta-info'; TelegramBotService, UserMetaInfoService, UserMetaInfo, + PersonalNotificationAdapterService, ], }) export class AppModule implements OnModuleInit { @@ -60,6 +62,7 @@ export class AppModule implements OnModuleInit { private statusChangeNotificationsService: StatusChangeNotificationsService, private changesCacheWriterService: ChangesCacheWriterService, private telegramBotService: TelegramBotService, + private personalNotificationAdapterService: PersonalNotificationAdapterService, ) {} onModuleInit() { @@ -74,13 +77,14 @@ export class AppModule implements OnModuleInit { this.currentUserEnhancer, ]); - this.personalNotificationsService.$messages.subscribe((message) => { + this.personalNotificationsService.$messages.subscribe((resp) => { this.logger.log( `Get personal message ` + - JSON.stringify(message.message) + + JSON.stringify(resp.personalParsedMessage.message) + ` for recipients ` + - JSON.stringify(message.recipients), + JSON.stringify(resp.personalParsedMessage.recipients), ); + this.personalNotificationAdapterService.send(resp); }); this.statusChangeNotificationsService.$changes.subscribe((change) => { this.logger.log( @@ -125,6 +129,10 @@ export class AppModule implements OnModuleInit { this.logger.debug('Save changes in couchdb successed'); return args; }), + switchMap(async (args) => { + this.logger.debug(``); + return args; + }), ) .subscribe(async (args) => { this.logger.debug( diff --git a/src/models/issue-and-personal-parsed-message.model.ts b/src/models/issue-and-personal-parsed-message.model.ts new file mode 100644 index 0000000..cc57758 --- /dev/null +++ b/src/models/issue-and-personal-parsed-message.model.ts @@ -0,0 +1,7 @@ +import { RedmineTypes } from '@app/event-emitter/models/redmine-types'; +import { PersonalParsedMessage } from './personal-parsed-message.model'; + +export type IssueAndPersonalParsedMessageModel = { + issue: RedmineTypes.Issue; + personalParsedMessage: PersonalParsedMessage; +}; diff --git a/src/notifications/adapters/personal-notification.adapter/personal-notification.adapter.service.ts b/src/notifications/adapters/personal-notification.adapter/personal-notification.adapter.service.ts new file mode 100644 index 0000000..b9bc214 --- /dev/null +++ b/src/notifications/adapters/personal-notification.adapter/personal-notification.adapter.service.ts @@ -0,0 +1,55 @@ +import { UsersService } from '@app/event-emitter/users/users.service'; +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { IssueAndPersonalParsedMessageModel } from 'src/models/issue-and-personal-parsed-message.model'; +import { TelegramBotService } from 'src/telegram-bot/telegram-bot.service'; +import Handlebars from 'handlebars'; + +@Injectable() +export class PersonalNotificationAdapterService { + private personalMessageTemplate: HandlebarsTemplateDelegate; + private redminePublicUrlPrefix: string; + + constructor( + private telegramBotService: TelegramBotService, + private configService: ConfigService, + private usersService: UsersService, + ) { + const template = this.configService.get('personalMessageTemplate'); + this.personalMessageTemplate = Handlebars.compile(template); + this.redminePublicUrlPrefix = + this.configService.get('redmineUrlPublic'); + } + + async send( + issueAndMessages: IssueAndPersonalParsedMessageModel, + ): Promise { + const promises = issueAndMessages.personalParsedMessage.recipients.map( + async (recipient) => { + const redmineId = recipient; + const issueUrl = `${this.redminePublicUrlPrefix}/issues/${issueAndMessages.issue.id}`; + const issue = issueAndMessages.issue; + const issueUrlHtml = `${issue.tracker.name} #${issue.id}`; + const sender = await this.usersService.getUser( + issueAndMessages.personalParsedMessage.sender, + ); + const data = { + data: { + issue: issueAndMessages.issue, + messages: issueAndMessages.personalParsedMessage, + }, + issue_url: issueUrlHtml, + sender_name: sender.name, + message: issueAndMessages.personalParsedMessage.message, + }; + const message = this.personalMessageTemplate(data); + return await this.telegramBotService.sendMessageByRedmineId( + redmineId, + message, + { parse_mode: 'HTML' }, + ); + }, + ); + await Promise.all(promises); + } +} diff --git a/src/notifications/personal-notifications.service.ts b/src/notifications/personal-notifications.service.ts index 2642aac..beeac60 100644 --- a/src/notifications/personal-notifications.service.ts +++ b/src/notifications/personal-notifications.service.ts @@ -3,6 +3,7 @@ import { SaveResponse } from '@app/event-emitter/models/save-response'; import { UsersService } from '@app/event-emitter/users/users.service'; import { Injectable, Logger } from '@nestjs/common'; import { Subject } from 'rxjs'; +import { IssueAndPersonalParsedMessageModel } from 'src/models/issue-and-personal-parsed-message.model'; import { PersonalParsedMessage } from 'src/models/personal-parsed-message.model'; @Injectable() @@ -10,11 +11,13 @@ export class PersonalNotificationsService { private userNameRe = /@([\wА-Яа-яЁё]+) ([\wА-Яа-яЁё]+)@/g; private logger = new Logger(PersonalNotificationsService.name); - $messages = new Subject(); + $messages = new Subject(); constructor(private usersService: UsersService) {} - async analize(data: SaveResponse): Promise { + async analize( + data: SaveResponse, + ): Promise { this.logger.debug( `Analize personal messages for issue ` + `#${data.current.id} (${data.current.subject}) start`, @@ -29,11 +32,16 @@ export class PersonalNotificationsService { `from sender ${message.sender} ` + `for recipients ${JSON.stringify(message.recipients)}`, ); - this.$messages.next(message); + this.$messages.next({ + issue: data.current, + personalParsedMessage: message, + }); } return message; }); - const res = (await Promise.all(pMessages)).filter((m) => Boolean(m)); + const res = (await Promise.all(pMessages)) + .filter((m) => Boolean(m)) + .map((m) => ({ issue: data.current, personalParsedMessage: m })); this.logger.debug( `Analize personal messages for issue ` + `#${data.current.id} (${data.current.subject}) finished`, diff --git a/src/telegram-bot/telegram-bot.service.ts b/src/telegram-bot/telegram-bot.service.ts index 44d741b..659f0da 100644 --- a/src/telegram-bot/telegram-bot.service.ts +++ b/src/telegram-bot/telegram-bot.service.ts @@ -74,17 +74,19 @@ export class TelegramBotService { async sendMessageByRedmineId( redmineId: number, msg: string, + options?: TelegramBot.SendMessageOptions, ): Promise { const userMetaInfo = await this.userMetaInfoService.findByRedmineId( redmineId, ); if (!userMetaInfo) return false; const chatId = userMetaInfo.telegram_chat_id; - await this.bot.sendMessage(chatId, msg); + await this.bot.sendMessage(chatId, msg, options); this.logger.debug( `Sent message for redmineUserId = ${redmineId}, ` + `telegramChatId = ${chatId}, ` + - `message = ${msg}`, + `message = ${msg}, ` + + `options = ${JSON.stringify(options)}`, ); return true; } @@ -93,10 +95,11 @@ export class TelegramBotService { firstname: string, lastname: string, msg: string, + options?: TelegramBot.SendMessageOptions, ): Promise { const user = await this.usersService.findUserByName(firstname, lastname); if (!user) return false; - return await this.sendMessageByRedmineId(user.id, msg); + return await this.sendMessageByRedmineId(user.id, msg, options); } private async register(