Улучшена групповая отправка уведомлений
* Отправка только последнего уведомления пользователю по задаче * Предотвращены отправки сообщений самому себе
This commit is contained in:
parent
5140e5a442
commit
d9cfb523b9
3 changed files with 70 additions and 14 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue