From cc34a620f1f2bf2fe89a6c4492626e443c09fe05 Mon Sep 17 00:00:00 2001 From: Pavel Gnedov Date: Mon, 14 Nov 2022 19:19:59 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BE=D1=82=D1=87=D1=91=D1=82=D0=B0=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B4=D0=B5=D0=B9=D0=BB=D0=B8=20=D0=BF=D0=BE=20=D1=80?= =?UTF-8?q?=D0=B0=D1=81=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configs/eccm-config.jsonc.dist | 6 ++- package-lock.json | 76 +++++++++++++++++++++++++++ package.json | 2 + src/app.module.ts | 4 ++ src/models/eccm-config.model.ts | 4 ++ src/reports/daily-eccm.report.task.ts | 67 +++++++++++++++++++++++ 6 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/reports/daily-eccm.report.task.ts diff --git a/configs/eccm-config.jsonc.dist b/configs/eccm-config.jsonc.dist index 3975be1..729d9f0 100644 --- a/configs/eccm-config.jsonc.dist +++ b/configs/eccm-config.jsonc.dist @@ -7,5 +7,9 @@ "name": "", "people": [""] } - ] + ], + "dailyTime": { + "hour": 9, + "minute": 0 + } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6e0d453..63fd4b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@nestjs/core": "^8.0.0", "@nestjs/platform-express": "^8.0.0", "@nestjs/platform-socket.io": "^8.4.4", + "@nestjs/schedule": "^2.1.0", "@nestjs/serve-static": "^2.2.2", "@nestjs/websockets": "^8.4.4", "axios": "^0.27.2", @@ -35,6 +36,7 @@ "@nestjs/schematics": "^8.0.0", "@nestjs/testing": "^8.0.0", "@types/cache-manager": "^4.0.1", + "@types/cron": "^2.0.0", "@types/express": "^4.17.13", "@types/jest": "27.4.0", "@types/luxon": "^3.1.0", @@ -1630,6 +1632,20 @@ "rxjs": "^7.1.0" } }, + "node_modules/@nestjs/schedule": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-2.1.0.tgz", + "integrity": "sha512-4Xaw56WiW3VsxEPPnj/iDtfjcO+sUZyYAeRxD0gnF5havncxjAnv52Iw7UH3DuzzUA784xPGgGje3Fq0Gu925g==", + "dependencies": { + "cron": "2.0.0", + "uuid": "8.3.2" + }, + "peerDependencies": { + "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0", + "@nestjs/core": "^7.0.0 || ^8.0.0 || ^9.0.0", + "reflect-metadata": "^0.1.12" + } + }, "node_modules/@nestjs/schematics": { "version": "8.0.11", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-8.0.11.tgz", @@ -1986,6 +2002,16 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" }, + "node_modules/@types/cron": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/cron/-/cron-2.0.0.tgz", + "integrity": "sha512-xZM08fqvwIXgghtPVkSPKNgC+JoMQ2OHazEvyTKnNf7aWu1aB6/4lBbQFrb03Td2cUGG7ITzMv3mFYnMu6xRaQ==", + "dev": true, + "dependencies": { + "@types/luxon": "*", + "@types/node": "*" + } + }, "node_modules/@types/eslint": { "version": "8.4.5", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz", @@ -3640,6 +3666,22 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cron": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cron/-/cron-2.0.0.tgz", + "integrity": "sha512-RPeRunBCFr/WEo7WLp8Jnm45F/ziGJiHVvVQEBSDTSGu6uHW49b2FOP2O14DcXlGJRLhwE7TIoDzHHK4KmlL6g==", + "dependencies": { + "luxon": "^1.23.x" + } + }, + "node_modules/cron/node_modules/luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", + "engines": { + "node": "*" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -11534,6 +11576,15 @@ "tslib": "2.4.0" } }, + "@nestjs/schedule": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-2.1.0.tgz", + "integrity": "sha512-4Xaw56WiW3VsxEPPnj/iDtfjcO+sUZyYAeRxD0gnF5havncxjAnv52Iw7UH3DuzzUA784xPGgGje3Fq0Gu925g==", + "requires": { + "cron": "2.0.0", + "uuid": "8.3.2" + } + }, "@nestjs/schematics": { "version": "8.0.11", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-8.0.11.tgz", @@ -11813,6 +11864,16 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" }, + "@types/cron": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/cron/-/cron-2.0.0.tgz", + "integrity": "sha512-xZM08fqvwIXgghtPVkSPKNgC+JoMQ2OHazEvyTKnNf7aWu1aB6/4lBbQFrb03Td2cUGG7ITzMv3mFYnMu6xRaQ==", + "dev": true, + "requires": { + "@types/luxon": "*", + "@types/node": "*" + } + }, "@types/eslint": { "version": "8.4.5", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz", @@ -13124,6 +13185,21 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cron": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cron/-/cron-2.0.0.tgz", + "integrity": "sha512-RPeRunBCFr/WEo7WLp8Jnm45F/ziGJiHVvVQEBSDTSGu6uHW49b2FOP2O14DcXlGJRLhwE7TIoDzHHK4KmlL6g==", + "requires": { + "luxon": "^1.23.x" + }, + "dependencies": { + "luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" + } + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/package.json b/package.json index 54839ed..c2455af 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@nestjs/core": "^8.0.0", "@nestjs/platform-express": "^8.0.0", "@nestjs/platform-socket.io": "^8.4.4", + "@nestjs/schedule": "^2.1.0", "@nestjs/serve-static": "^2.2.2", "@nestjs/websockets": "^8.4.4", "axios": "^0.27.2", @@ -47,6 +48,7 @@ "@nestjs/schematics": "^8.0.0", "@nestjs/testing": "^8.0.0", "@types/cache-manager": "^4.0.1", + "@types/cron": "^2.0.0", "@types/express": "^4.17.13", "@types/jest": "27.4.0", "@types/luxon": "^3.1.0", diff --git a/src/app.module.ts b/src/app.module.ts index d962a37..34a48ae 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -30,6 +30,8 @@ import { DailyEccmReportController } from './reports/daily-eccm.report.controlle import { DailyEccmReportService } from './reports/daily-eccm.report.service'; import { ChangesService } from './changes/changes.service'; import { DailyEccmReportsDatasource } from './couchdb-datasources/daily-eccm-reports.datasource'; +import { ScheduleModule } from '@nestjs/schedule'; +import { DailyEccmReportTask } from './reports/daily-eccm.report.task'; @Module({ imports: [ @@ -40,6 +42,7 @@ import { DailyEccmReportsDatasource } from './couchdb-datasources/daily-eccm-rep CacheModule.register({ isGlobal: true, }), + ScheduleModule.forRoot(), ], controllers: [ AppController, @@ -66,6 +69,7 @@ import { DailyEccmReportsDatasource } from './couchdb-datasources/daily-eccm-rep DailyEccmReportService, ChangesService, DailyEccmReportsDatasource, + DailyEccmReportTask, ], }) export class AppModule implements OnModuleInit { diff --git a/src/models/eccm-config.model.ts b/src/models/eccm-config.model.ts index 37317b7..74b3ab9 100644 --- a/src/models/eccm-config.model.ts +++ b/src/models/eccm-config.model.ts @@ -10,5 +10,9 @@ export namespace EccmConfig { projectName: string; currentIssuesStatuses: string[]; groups: UserGroup[]; + dailyTime: { + hour: number; + minute: number; + }; }; } diff --git a/src/reports/daily-eccm.report.task.ts b/src/reports/daily-eccm.report.task.ts new file mode 100644 index 0000000..b986936 --- /dev/null +++ b/src/reports/daily-eccm.report.task.ts @@ -0,0 +1,67 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { Cron } from '@nestjs/schedule'; +import { DailyEccmReportService } from './daily-eccm.report.service'; +import { DateTime, Duration } from 'luxon'; +import { ConfigService } from '@nestjs/config'; + +// eslint-disable-next-line @typescript-eslint/no-namespace +namespace Models { + export type Time = { + hour: number; + minute: number; + }; +} + +@Injectable() +export class DailyEccmReportTask { + private logger = new Logger(DailyEccmReportTask.name); + private eccmDailyTime: Models.Time; + + constructor( + private dailyEccmReportService: DailyEccmReportService, + private configService: ConfigService, + ) { + this.eccmDailyTime = this.configService.get( + 'redmineEccm.dailyTime', + ); + } + + @Cron('25 9,10 1-5 * *') + async generateReport(): Promise { + this.logger.log(`Generate daily eccm report by cron task started`); + const now = DateTime.now(); + const toDate = DateTime.local( + now.year, + now.month, + now.day, + this.eccmDailyTime.hour, + this.eccmDailyTime.minute, + ); + let duration: Duration; + if (now.weekday == 1) { + duration = Duration.fromObject({ days: -3 }); + } else { + duration = Duration.fromObject({ days: -1 }); + } + const fromDate = toDate.plus(duration); + const name = now.toFormat('yyyy-MM-dd'); + const params = this.dailyEccmReportService.generateParams( + fromDate.toJSDate().toISOString(), + toDate.toJSDate().toISOString(), + name, + ); + + const reportData = await this.dailyEccmReportService.generateReport(params); + const saveResult = await this.dailyEccmReportService.saveReport( + reportData, + true, + ); + this.logger.log( + `Generate daily eccm report by cron task ` + + `finished with params = ${JSON.stringify(params)} ` + + `and result = ${saveResult}`, + ); + + return; + } +}