From 39fe3c7a7952812e647444ace2d874fe307a63f9 Mon Sep 17 00:00:00 2001 From: Pavel Gnedov Date: Mon, 8 Aug 2022 13:02:41 +0700 Subject: [PATCH] =?UTF-8?q?=D0=93=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=BE=D0=B2=D1=8B=D1=85=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B4=D0=B0=D1=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 44 +++++++++++++ src/models/status-changes-config.model.ts | 1 + .../status-change-notifications.service.ts | 61 +++++++++++++++++-- 3 files changed, 100 insertions(+), 6 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index 02f2906..ea50e85 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -5,6 +5,7 @@ import { TimestampEnhancer } from '@app/event-emitter/issue-enhancers/timestamps import { MainController } from '@app/event-emitter/main/main.controller'; import { Logger, Module, OnModuleInit } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; +import { switchMap } from 'rxjs'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import configuration from './configs/app'; @@ -43,6 +44,7 @@ export class AppModule implements OnModuleInit { private timestampEnhancer: TimestampEnhancer, private customFieldsEnhancer: CustomFieldsEnhancer, private currentUserEnhancer: CurrentUserEnhancer, + private statusChangeNotificationsService: StatusChangeNotificationsService, ) {} onModuleInit() { @@ -51,14 +53,56 @@ export class AppModule implements OnModuleInit { this.customFieldsEnhancer, this.currentUserEnhancer, ]); + this.personalNotificationsService.$messages.subscribe((message) => { // eslint-disable-next-line prettier/prettier this.logger.log(`Get personal message ${JSON.stringify(message.message)} for recipients ${JSON.stringify(message.recipients)}`); }); + this.statusChangeNotificationsService.$changes.subscribe((change) => { + this.logger.log( + `Get status changes messages for ` + + `issue_id = ${change.issue_id}, ` + + `messages = ${JSON.stringify( + change.messages.map((m) => m.change_message).filter((m) => !!m), + )}`, + ); + }); + this.redmineIssuesCacheWriterService.subject.subscribe( async (saveResult) => { await this.personalNotificationsService.analize(saveResult); }, ); + + this.redmineIssuesCacheWriterService.subject + .pipe( + switchMap(async (saveResult) => { + this.logger.debug( + `Save result process started, issue_id = ${saveResult.current.id}`, + ); + return saveResult; + }), + ) + .pipe( + switchMap(async (saveResult) => { + this.logger.debug(`personalNotificationsService.analize started`); + await this.personalNotificationsService.analize(saveResult); + this.logger.debug('personalNotificationsService.analize successed'); + return saveResult; + }), + switchMap(async (saveResult) => { + // eslint-disable-next-line prettier/prettier + this.logger.debug(`statusChangeNotificationsService.getChanges started`); + await this.statusChangeNotificationsService.getChanges(saveResult); + // eslint-disable-next-line prettier/prettier + this.logger.debug(`statusChangeNotificationsService.getChanges successed`); + return saveResult; + }), + ) + .subscribe(async (saveResult) => { + this.logger.debug( + `Save result process success finished, issue_id = ${saveResult.current.id}`, + ); + }); } } diff --git a/src/models/status-changes-config.model.ts b/src/models/status-changes-config.model.ts index 43369f8..251833a 100644 --- a/src/models/status-changes-config.model.ts +++ b/src/models/status-changes-config.model.ts @@ -8,6 +8,7 @@ export namespace StatusChangesConfig { export type Item = { default: boolean; + new_issue?: boolean; from: string; to: string; messages: Message[]; diff --git a/src/notifications/status-change-notifications.service.ts b/src/notifications/status-change-notifications.service.ts index 51d517f..23063ea 100644 --- a/src/notifications/status-change-notifications.service.ts +++ b/src/notifications/status-change-notifications.service.ts @@ -10,6 +10,7 @@ import { StatusChangesConfig } from 'src/models/status-changes-config.model'; import { StatusesConfig } from 'src/models/statuses-config.model'; import Handlebars from 'handlebars'; import { ChangeMessage } from 'src/models/change-message.model'; +import { Subject } from 'rxjs'; @Injectable() export class StatusChangeNotificationsService { @@ -17,6 +18,8 @@ export class StatusChangeNotificationsService { private statuses: StatusesConfig.Config; private statusChanges: StatusChangesConfig.Config; + $changes = new Subject(); + constructor( private usersService: UsersService, private config: ConfigService, @@ -29,7 +32,10 @@ export class StatusChangeNotificationsService { this.logger.debug( `StatusChangeNotificationsService created, ` + `statuses = ${JSON.stringify(this.statuses.map((s) => s.name))}, ` + - `statusChanges.length = ${this.statusChanges.length}`, + `statusChanges.length = ${this.statusChanges.length}, ` + + `statusChanges = ` + + // eslint-disable-next-line prettier/prettier + `${JSON.stringify(this.statusChanges.map((c) => `${c.from} -> ${c.to}`))}`, ); } @@ -43,6 +49,11 @@ export class StatusChangeNotificationsService { const issue = saveResponse.current; + if (!saveResponse.prev) { + const newChange = await this.getMessagesForNewIssue(issue); + changes.push(newChange); + } + for (let i = 0; i < saveResponse.journalsDiff.length; i++) { const journal = saveResponse.journalsDiff[i]; const change = await this.getMessagesForChangeStatus(issue, journal); @@ -55,6 +66,9 @@ export class StatusChangeNotificationsService { `Analize change statuses for issue #${saveResponse.current.id} ` + `(${saveResponse.current.subject}) for journalsDiff.length = ${saveResponse.journalsDiff.length} finished`, ); + + changes.forEach((c) => this.$changes.next(c)); + return changes; } @@ -71,8 +85,8 @@ export class StatusChangeNotificationsService { } private async getMessagesForChangeStatus( - issue: any, - journal: any, + issue: RedmineTypes.Issue & Record, + journal: RedmineTypes.Journal, ): Promise { const statusChangeDetails = this.getStatusChangeDetails(journal); if (!statusChangeDetails) return null; @@ -101,8 +115,43 @@ export class StatusChangeNotificationsService { return change; } + private async getMessagesForNewIssue( + issue: RedmineTypes.Issue & Record, + ): Promise { + const changeParams = this.statusChanges.find((p) => p.new_issue); + const change: Change = { + initiator: await this.usersService.getUser(issue.author.id), + dev: await this.usersService.getUser(issue?.dev?.id), + qa: await this.usersService.getUser(issue?.qa?.id), + cr: await this.usersService.getUser(issue?.cr?.id), + current_user: await this.usersService.getUser(issue?.current_user?.id), + author: await this.usersService.getUser(issue?.author?.id), + old_status: this.findStatusById(issue.status.id), + new_status: this.findStatusById(issue.status.id), + issue_id: issue.id, + issue_url: this.redminePublicUrlConverter.convert(issue.id), + issue_tracker: issue.tracker?.name || '', + issue_subject: issue.subject || '', + created_on: issue.created_on, + created_on_timestamp: TimestampConverter.toTimestamp(issue.created_on), + journal_note: '', + messages: [], + }; + const filledMessages = await Promise.all( + changeParams.messages.map(async (messageParams: any) => { + return await this.generateMessage(messageParams, change); + }), + ); + change.messages = filledMessages.filter((m) => Boolean(m)); + return change; + } + private findStatusById(id: number | string): StatusesConfig.Item | null { - if (typeof id === 'string' && !Number.isNaN(id) && Number.isFinite(id)) { + if ( + typeof id === 'string' && + !Number.isNaN(id) && + Number.isFinite(Number(id)) + ) { id = Number(id); } return this.statuses.find((s) => s.id === id) || null; @@ -111,7 +160,7 @@ export class StatusChangeNotificationsService { private async generateMessages( detail: RedmineTypes.JournalDetail, change: Change, - ): Promise { + ): Promise { const oldStatus = this.findStatusById(detail.old_value); const newStatus = this.findStatusById(detail.new_value); if (!oldStatus || !newStatus) return null; @@ -122,7 +171,7 @@ export class StatusChangeNotificationsService { return await this.generateMessage(messageParams, change); }), ); - return filledMessages.filter((m) => m); + return filledMessages.filter((m) => Boolean(m)); } private findChangeParams(