Отправка отформатированных по шаблону персональных сообщений

This commit is contained in:
Pavel Gnedov 2022-10-03 08:59:54 +07:00
parent b5a90b357b
commit 4b2a070851
5 changed files with 91 additions and 10 deletions

View file

@ -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(

View file

@ -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;
};

View file

@ -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<string>('personalMessageTemplate');
this.personalMessageTemplate = Handlebars.compile(template);
this.redminePublicUrlPrefix =
this.configService.get<string>('redmineUrlPublic');
}
async send(
issueAndMessages: IssueAndPersonalParsedMessageModel,
): Promise<void> {
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 = `<a href="${issueUrl}">${issue.tracker.name} #${issue.id}</a>`;
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);
}
}

View file

@ -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<PersonalParsedMessage>();
$messages = new Subject<IssueAndPersonalParsedMessageModel>();
constructor(private usersService: UsersService) {}
async analize(data: SaveResponse): Promise<PersonalParsedMessage[]> {
async analize(
data: SaveResponse,
): Promise<IssueAndPersonalParsedMessageModel[]> {
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`,

View file

@ -74,17 +74,19 @@ export class TelegramBotService {
async sendMessageByRedmineId(
redmineId: number,
msg: string,
options?: TelegramBot.SendMessageOptions,
): Promise<boolean> {
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<boolean> {
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(