Улучшена групповая отправка уведомлений

* Отправка только последнего уведомления пользователю по задаче
* Предотвращены отправки сообщений самому себе
This commit is contained in:
Pavel Gnedov 2022-11-11 09:23:37 +07:00
parent 5140e5a442
commit d9cfb523b9
3 changed files with 70 additions and 14 deletions

View file

@ -104,20 +104,8 @@ export class AppModule implements OnModuleInit {
); );
this.personalNotificationAdapterService.send(resp); this.personalNotificationAdapterService.send(resp);
}); });
this.statusChangeNotificationsService.$changes.subscribe((change) => { this.statusChangeNotificationsService.$batchChanges.subscribe((changes) => {
const messages = change.messages this.statusChangeAdapterService.batchSend(changes);
.map((m) => m.change_message)
.filter((m) => !!m);
const notifications = change.messages
.map((m) => m.notification_message)
.filter((m) => !!m);
this.logger.log(
`Get status changes messages for ` +
`issue_id = ${change.issue_id}, ` +
`messages = ${JSON.stringify(messages)}, ` +
`notifications = ${JSON.stringify(notifications)}`,
);
this.statusChangeAdapterService.send(change);
}); });
this.redmineIssuesCacheWriterService.subject this.redmineIssuesCacheWriterService.subject

View file

@ -1,7 +1,20 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import TelegramBot from 'node-telegram-bot-api';
import { Change } from 'src/models/change.model'; import { Change } from 'src/models/change.model';
import { TelegramBotService } from 'src/telegram-bot/telegram-bot.service'; import { TelegramBotService } from 'src/telegram-bot/telegram-bot.service';
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace StatusChangeAdapter {
export type MsgFromBatch = {
initiatorId: number;
recipientId: number;
issueId: number;
createdAt: number;
msg: string;
options?: TelegramBot.SendMessageOptions;
};
}
@Injectable() @Injectable()
export class StatusChangeAdapterService { export class StatusChangeAdapterService {
constructor(private telegramBotService: TelegramBotService) {} constructor(private telegramBotService: TelegramBotService) {}
@ -19,4 +32,57 @@ export class StatusChangeAdapterService {
}); });
return await Promise.all(promises); return await Promise.all(promises);
} }
async batchSend(changes: Change[]): Promise<void> {
const messages = this.getMessages(changes).map((item) => {
item.options = { parse_mode: 'HTML' };
return item;
});
for (let i = 0; i < messages.length; i++) {
const message = messages[i];
await this.telegramBotService.sendMessageByRedmineId(
message.recipientId,
message.msg,
message.options,
);
}
}
private getMessages(changes: Change[]): StatusChangeAdapter.MsgFromBatch[] {
const res: StatusChangeAdapter.MsgFromBatch[] = [];
const store: Record<string, StatusChangeAdapter.MsgFromBatch> = {};
for (let i = 0; i < changes.length; i++) {
const change = changes[i];
for (let j = 0; j < change.messages.length; j++) {
const message = change.messages[j];
if (!message.change_message) continue;
if (change.initiator.id == message.recipient.id) continue;
const item: StatusChangeAdapter.MsgFromBatch = {
initiatorId: change.initiator.id,
recipientId: message.recipient.id,
createdAt: change.created_on_timestamp,
issueId: change.issue_id,
msg: message.change_message,
};
const key = this.keyForMsgFromBatch(item);
if (
!store[key] ||
(store[key] && store[key].createdAt < item.createdAt)
) {
store[key] = item;
}
}
}
for (const key in store) {
if (Object.prototype.hasOwnProperty.call(store, key)) {
const item = store[key];
res.push(item);
}
}
return res;
}
private keyForMsgFromBatch(item: StatusChangeAdapter.MsgFromBatch): string {
return `${item.issueId}-${item.recipientId}`;
}
} }

View file

@ -19,6 +19,7 @@ export class StatusChangeNotificationsService {
private statusChanges: StatusChangesConfig.Config; private statusChanges: StatusChangesConfig.Config;
$changes = new Subject<Change>(); $changes = new Subject<Change>();
$batchChanges = new Subject<Change[]>();
constructor( constructor(
private usersService: UsersService, private usersService: UsersService,
@ -68,6 +69,7 @@ export class StatusChangeNotificationsService {
); );
changes.forEach((c) => this.$changes.next(c)); changes.forEach((c) => this.$changes.next(c));
this.$batchChanges.next(changes);
return changes; return changes;
} }