From a707570e79702f4bb3a48a4c2d79f8a95a3a9a5c Mon Sep 17 00:00:00 2001 From: Peng Peng Date: Sun, 30 Mar 2025 16:00:54 +0800 Subject: [PATCH 01/58] feat: init version --- packages/api/package-lock.json | 49 ++ packages/api/package.json | 1 + packages/api/src/notification/NatsService.ts | 59 +++ packages/api/src/notification/job.service.ts | 456 ------------------ .../api/src/notification/message.service.ts | 33 -- .../notification/notification.controller.ts | 162 +------ .../src/notification/notification.module.ts | 22 +- .../src/notification/notify.policy.service.ts | 41 -- .../src/notification/notify.rule.service.ts | 37 -- .../notification/recipient.address.service.ts | 31 -- .../src/notification/recipients.service.ts | 33 -- .../api/src/notification/sender.service.ts | 65 --- .../api/src/notification/system.controller.ts | 85 ++-- .../api/src/notification/template.service.ts | 51 +- .../src/notification/termipass.controller.ts | 67 --- packages/api/src/prisma/prisma.service.ts | 208 +------- packages/api/src/prisma/seeds.ts | 135 ++---- packages/api/src/sender/application.ts | 107 ---- packages/api/src/sender/base.ts | 61 --- packages/api/src/sender/index.ts | 6 - packages/api/src/sender/instance.ts | 77 --- packages/api/src/sender/lark.ts | 54 --- packages/api/src/sender/provider.client.ts | 141 ------ packages/api/src/sender/slack.ts | 40 -- packages/api/src/sender/sms.ts | 49 -- packages/api/src/sender/smtp.ts | 68 --- packages/api/src/sender/webhook.ts | 52 -- .../20230829050304_init/migration.sql | 124 ----- .../20230831115239_v2/migration.sql | 207 -------- .../migration.sql | 20 - .../migration.sql | 20 - .../migrations/20230831141631_/migration.sql | 51 -- .../migration.sql | 12 - .../migration.sql | 10 - .../migrations/20230831164432_/migration.sql | 59 --- .../migration.sql | 21 - .../migration.sql | 9 - .../migration.sql | 13 - .../migrations/20230901105316_/migration.sql | 8 - .../migrations/20230901120721_/migration.sql | 9 - .../migrations/20230901143343_/migration.sql | 21 - .../migrations/20230902085838_/migration.sql | 2 - .../migration.sql | 15 - .../migration.sql | 27 -- .../migration.sql | 19 - .../migration.sql | 2 - .../migration.sql | 8 - .../migration.sql | 10 - .../20250323125830_init/migration.sql | 48 ++ .../migrations/20250330074927_/migration.sql | 20 + packages/database/prisma/schema.prisma | 152 +----- packages/database/src/core.ts | 303 +----------- packages/frontend/.quasar/app.js | 2 - packages/frontend/.quasar/client-entry.js | 3 - 54 files changed, 301 insertions(+), 3084 deletions(-) create mode 100644 packages/api/src/notification/NatsService.ts delete mode 100644 packages/api/src/notification/job.service.ts delete mode 100644 packages/api/src/notification/message.service.ts delete mode 100644 packages/api/src/notification/notify.policy.service.ts delete mode 100644 packages/api/src/notification/notify.rule.service.ts delete mode 100644 packages/api/src/notification/recipient.address.service.ts delete mode 100644 packages/api/src/notification/recipients.service.ts delete mode 100644 packages/api/src/notification/sender.service.ts delete mode 100644 packages/api/src/notification/termipass.controller.ts delete mode 100644 packages/api/src/sender/application.ts delete mode 100644 packages/api/src/sender/base.ts delete mode 100644 packages/api/src/sender/index.ts delete mode 100644 packages/api/src/sender/instance.ts delete mode 100644 packages/api/src/sender/lark.ts delete mode 100644 packages/api/src/sender/provider.client.ts delete mode 100644 packages/api/src/sender/slack.ts delete mode 100644 packages/api/src/sender/sms.ts delete mode 100644 packages/api/src/sender/smtp.ts delete mode 100644 packages/api/src/sender/webhook.ts delete mode 100644 packages/database/prisma/migrations/20230829050304_init/migration.sql delete mode 100644 packages/database/prisma/migrations/20230831115239_v2/migration.sql delete mode 100644 packages/database/prisma/migrations/20230831123906_update_sender_table/migration.sql delete mode 100644 packages/database/prisma/migrations/20230831135514_add_user_filed_in_notifygroup/migration.sql delete mode 100644 packages/database/prisma/migrations/20230831141631_/migration.sql delete mode 100644 packages/database/prisma/migrations/20230831141923_update_template_content/migration.sql delete mode 100644 packages/database/prisma/migrations/20230831142534_change_channel_to_notify_group/migration.sql delete mode 100644 packages/database/prisma/migrations/20230831164432_/migration.sql delete mode 100644 packages/database/prisma/migrations/20230901075538_change_recipients_address_structure/migration.sql delete mode 100644 packages/database/prisma/migrations/20230901093742_change_variables_from_json_to_string_array/migration.sql delete mode 100644 packages/database/prisma/migrations/20230901104617_change_json_type_to_string/migration.sql delete mode 100644 packages/database/prisma/migrations/20230901105316_/migration.sql delete mode 100644 packages/database/prisma/migrations/20230901120721_/migration.sql delete mode 100644 packages/database/prisma/migrations/20230901143343_/migration.sql delete mode 100644 packages/database/prisma/migrations/20230902085838_/migration.sql delete mode 100644 packages/database/prisma/migrations/20230902091146_modify_sender_type/migration.sql delete mode 100644 packages/database/prisma/migrations/20230902111509_add_local_credential_table/migration.sql delete mode 100644 packages/database/prisma/migrations/20231224122203_added_template_topic/migration.sql delete mode 100644 packages/database/prisma/migrations/20231228031153_change_notifygroup_from_id_to_name/migration.sql delete mode 100644 packages/database/prisma/migrations/20231228053704_add_index_and_add_raw_message_in_job/migration.sql delete mode 100644 packages/database/prisma/migrations/20231228054320_fix_spell_issue/migration.sql create mode 100644 packages/database/prisma/migrations/20250323125830_init/migration.sql create mode 100644 packages/database/prisma/migrations/20250330074927_/migration.sql diff --git a/packages/api/package-lock.json b/packages/api/package-lock.json index cc0b4dd..bcd0850 100644 --- a/packages/api/package-lock.json +++ b/packages/api/package-lock.json @@ -18,6 +18,7 @@ "bcrypt": "5.1.0", "bullmq": "^4.8.0", "dotenv": "16.3.1", + "nats": "^2.28.2", "nodemailer": "6.9.5", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", @@ -6539,6 +6540,17 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/nats": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/nats/-/nats-2.29.3.tgz", + "integrity": "sha512-tOQCRCwC74DgBTk4pWZ9V45sk4d7peoE2njVprMRCBXrhJ5q5cYM7i6W+Uvw2qUrcfOSnuisrX7bEx3b3Wx4QA==", + "dependencies": { + "nkeys.js": "1.1.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6559,6 +6571,17 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/nkeys.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nkeys.js/-/nkeys.js-1.1.0.tgz", + "integrity": "sha512-tB/a0shZL5UZWSwsoeyqfTszONTt4k2YS0tuQioMOD180+MbombYVgzDUYHlx+gejYK6rgf08n/2Df99WY0Sxg==", + "dependencies": { + "tweetnacl": "1.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -8370,6 +8393,11 @@ "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.6.0.tgz", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", @@ -13912,6 +13940,14 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "nats": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/nats/-/nats-2.29.3.tgz", + "integrity": "sha512-tOQCRCwC74DgBTk4pWZ9V45sk4d7peoE2njVprMRCBXrhJ5q5cYM7i6W+Uvw2qUrcfOSnuisrX7bEx3b3Wx4QA==", + "requires": { + "nkeys.js": "1.1.0" + } + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", @@ -13929,6 +13965,14 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "nkeys.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nkeys.js/-/nkeys.js-1.1.0.tgz", + "integrity": "sha512-tB/a0shZL5UZWSwsoeyqfTszONTt4k2YS0tuQioMOD180+MbombYVgzDUYHlx+gejYK6rgf08n/2Df99WY0Sxg==", + "requires": { + "tweetnacl": "1.0.3" + } + }, "node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -15307,6 +15351,11 @@ "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.6.0.tgz", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", diff --git a/packages/api/package.json b/packages/api/package.json index 8936b40..59358fa 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -35,6 +35,7 @@ "rxjs": "^7.8.1", "swagger-ui-express": "^5.0.0", "uuid": "^9.0.0", + "nats": "^2.28.2", "nodemailer": "6.9.5" }, "devDependencies": { diff --git a/packages/api/src/notification/NatsService.ts b/packages/api/src/notification/NatsService.ts new file mode 100644 index 0000000..0a14eed --- /dev/null +++ b/packages/api/src/notification/NatsService.ts @@ -0,0 +1,59 @@ +import { Injectable, OnModuleDestroy, Logger } from '@nestjs/common'; +//import { SocketService } from './pgsocket.service'; + +import { NatsConnection, StringCodec, connect } from 'nats'; +//import { get } from 'http'; + +const NATS_HOST = process.env.NATS_HOST || ''; +const NATS_PORT = process.env.NATS_PORT || 4222; +const NATS_USERNAME = process.env.NATS_USERNAME || ''; +const NATS_PASSWORD = process.env.NATS_PASSWORD || ''; +const NATS_SUBJECT = process.env.NATS_SUBJECT || ''; +const nats_url = NATS_HOST + ':' + NATS_PORT; + +export function getNATS(): boolean { + const value = process.env.NATS; + return value?.toLowerCase() !== 'false'; +} + +@Injectable() +export class NatsService implements OnModuleDestroy { + private readonly logger = new Logger(NatsService.name); + private natsClient: NatsConnection; + + async onModuleInit() { + if (!getNATS()) { + return; + } + console.log('nats username:', NATS_USERNAME); + console.log('nats password:', NATS_PASSWORD); + this.natsClient = await connect({ + servers: nats_url, + user: NATS_USERNAME, + pass: NATS_PASSWORD, + }); + const sub = this.natsClient.subscribe(NATS_SUBJECT); + + const sc = StringCodec(); + + (async () => { + for await (const m of sub) { + console.log(`[${sub.getProcessed()}]: ${sc.decode(m.data)}`); + // await this.socketService.sendMsg(sc.decode(m.data)); + } + })(); + } + + onModuleDestroy(): void { + this.natsClient.drain(); + } + + async pushTemplate( + userid: string, + templateid: string, + data: any, + ): Promise { + console.log('pushTemplate', userid, templateid, data); + return; + } +} diff --git a/packages/api/src/notification/job.service.ts b/packages/api/src/notification/job.service.ts deleted file mode 100644 index 9b601ae..0000000 --- a/packages/api/src/notification/job.service.ts +++ /dev/null @@ -1,456 +0,0 @@ -import axios from 'axios'; -import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; -import { PrismaService } from '../prisma/prisma.service'; -import { SenderService } from './sender.service'; -import { RecipientsService } from './recipients.service'; -import { RecipientAddressService } from './recipient.address.service'; -import { NotifyPolicyService } from './notify.policy.service'; -import { NotifyRuleService } from './notify.rule.service'; -import { TemplateService } from './template.service'; -import { TemplateContentService } from './template.content.service'; -import { Interval } from '@nestjs/schedule'; -import { - Job, - JobStatus, - MessageStatus, - RecipientAddress, - Sender, - Message, - RecipientType, -} from '@notifications/database'; -import { - validateRecipient, - getSenderInstance, - TerminusNotificationSender, - getNotificationRecipient, -} from '../sender'; -import { LOCAL_CREDENTIAL } from './global'; -import { - NotificationCredential, - NotificationRecipientData, -} from '@notifications/database'; -import { - Recipients, - NotifyPolicy, - NotifyRule, - Template, -} from '@notifications/database'; -import { - Result, - returnSucceed, - NotificationResultCode, - NotificationResult, - MessageBody, - MessageData, - MessageTopic, - returnError, - TerminusInfo, -} from '@bytetrade/core'; - -@Injectable() -export class JobService implements OnModuleInit { - private readonly logger = new Logger(JobService.name); - private isInSent = false; - - private pendingMessages = []; - - public terminusInfo: TerminusInfo | null = null; - - public language: string = 'en-US'; - - constructor( - private prisma: PrismaService, - private readonly senderService: SenderService, - private readonly recipientsService: RecipientsService, - private readonly recipientAddressService: RecipientAddressService, - private readonly notifyPolicyService: NotifyPolicyService, - private readonly notifyRuleService: NotifyRuleService, - private readonly templateService: TemplateService, - private readonly templateContentService: TemplateContentService, - ) {} - - public async updateTerminusInfo(): Promise { - const response: any = await axios.get( - 'http://bfl/bfl/backend/v1/terminus-info', - ); - if (response.status !== 200) { - throw new Error(response.statusText); - } - if (response.data.code != 0) { - throw new Error(response.data); - } - this.terminusInfo = response.data.data; - this.logger.log('terminusInfo'); - this.logger.log(this.terminusInfo); - return response.data.data; - } - - public async updateLanguage() { - this.logger.debug('updateLanguage'); - try { - const response: any = await axios.get( - 'http://bfl/bfl/backend/v1/config-system', - ); - this.logger.log('config_system'); - this.logger.log(response.data); - - if (response.data.code !== 0) { - throw new Error(response.data.message); - } - - this.language = response.data.data.language || 'en-US'; - console.log(this.language); - } catch (e) { - console.log(e); - } - } - - async onModuleInit() { - const m = await this.prisma.message.findMany({ - where: { status: 'Pending' }, - }); - this.logger.verbose('JobService pending job in database: ' + m.length); - for (const message of m) { - this.pendingMessages.push(message); - } - - this.logger.verbose( - 'JobService pendingJobs length: ' + this.pendingMessages.length, - ); - - await this.updateTerminusInfo(); - await this.updateLanguage(); - } - - async findAll(): Promise { - return this.prisma.job.findMany({ where: {} }); - } - - async findOne(id: number): Promise { - return this.prisma.job.findUnique({ where: { id } }); - } - - async update(id: number, data: Job): Promise { - return this.prisma.job.update({ - where: { id }, - data: data, - }); - } - - async remove(id: number): Promise { - return this.prisma.job.delete({ where: { id } }); - } - - async processOneJob(job: Partial): Promise> { - try { - const template: Template = await this.templateService.findOne( - job.templateId, - ); - if (!template) { - //throw Error('Template not found.'); - return returnError(1, 'Template not found'); - } - - const messageData: MessageBody = await this.getMessageBody(job, template); - this.logger.debug('MessageBody'); - this.logger.debug(messageData); - - let notifyPolicy: NotifyPolicy = null; - - if (job.notifyPolicyId == -1) { - if (template.notifyGroup == '') { - notifyPolicy = await this.notifyPolicyService.findDefault(); - } else { - notifyPolicy = await this.notifyPolicyService.findByName( - template.notifyGroup, - ); - } - } else { - notifyPolicy = await this.notifyPolicyService.findOne( - job.notifyPolicyId, - ); - } - if (!notifyPolicy) { - throw Error('NotifyPolicy not found.'); - } - - const notifyRules: NotifyRule[] = - await this.notifyRuleService.findByPolicyId(job.notifyPolicyId); - - const messages = []; - for (const rule of notifyRules) { - this.logger.debug('rule'); - this.logger.debug(rule); - const sender: Sender = await this.senderService.findOne(rule.sender); - if (!sender) { - throw Error('sender not found.'); - } - const recipients: Recipients = await this.recipientsService.findOne( - rule.recipients, - ); - if (!recipients) { - throw Error('recipients not found.'); - } - - if (recipients.type == RecipientType.NoNeed) { - const message = { - senderType: sender.type, - message: JSON.stringify(messageData), - sender: JSON.stringify(sender), - recipientType: recipients.type, - recipient: JSON.stringify({ type: 'NoNeed', data: {} }), - user: this.terminusInfo.terminusName, - status: MessageStatus.Pending, - statusInfo: '', - }; - messages.push(message); - } else { - const addresses: RecipientAddress[] = - await this.recipientAddressService.findByRecipientId( - rule.recipients, - ); - - this.logger.debug('addresses'); - this.logger.debug(addresses); - - for (const address of addresses) { - const message = { - senderType: sender.type, - message: JSON.stringify(messageData), - sender: JSON.stringify(sender), - recipientType: recipients.type, - recipient: JSON.stringify(address), - user: this.terminusInfo.terminusName, - status: MessageStatus.Pending, - statusInfo: '', - }; - messages.push(message); - } - } - } - - const imessage = { - data: { - templateId: job.templateId, - notifyPolicyId: job.notifyPolicyId, - language: job.language, - messageNum: messages.length, - messages: { - create: messages, - }, - rawMessage: job.rawMessage, - user: this.terminusInfo.terminusName, - status: messages.length == 0 ? JobStatus.Finished : JobStatus.Pending, - }, - }; - this.logger.log(imessage); - - const res = await this.prisma.job.create(imessage); - this.logger.log(res); - const ms = await this.prisma.message.findMany({ - where: { jobId: res.id, status: MessageStatus.Pending }, - }); - this.logger.log('message lenth: ' + ms.length); - for (const mm of ms) { - this.pendingMessages.push(mm); - } - return returnSucceed(res); - } catch (e) { - this.logger.log('error'); - this.logger.log(e.message); - return returnError(1, e.message || 'insert job failed'); - } - } - - async getMessageBody( - job: Partial, - template: Template, - ): Promise { - const raw_message: MessageData = JSON.parse(JSON.stringify(job.rawMessage)); - - const message: MessageBody = { - topic: MessageTopic.Data, - event: template.appTemplateName, //raw_message.event, - message: raw_message, - terminusName: this.terminusInfo.terminusName, - }; - - if (template.topic == MessageTopic.Data) { - } else if (template.topic == MessageTopic.CANCEL_SIGN) { - message.topic = MessageTopic.CANCEL_SIGN; - } else if ( - template.topic == MessageTopic.Notification || - template.topic == MessageTopic.SIGN - ) { - let templateContent = await this.templateContentService.findByLanguage( - template.id, - job.language, - ); - if (templateContent.length == 0) { - templateContent = await this.templateContentService.findByLanguage( - template.id, - template.defaultLanguage, - ); - } - if (templateContent.length != 1) { - throw Error('Template Content not matched.'); - } - - if (template.topic == MessageTopic.SIGN) { - message.topic = MessageTopic.SIGN; - message.app = { - id: template.appId, - title: template.appName, - icon: 'https://file.bttcdn.com/termipass/icon.png', - }; - } else { - message.topic = MessageTopic.Notification; - } - - if ( - (await this.templateService.checkTemplateMatchedVariablesWithRecord( - templateContent[0].title + ' ' + templateContent[0].body, - raw_message.vars, - )) == false - ) { - throw Error('Check Template Matched Variables Failed.'); - } - - message.notification = { - title: this.templateService.replaceTemplateWithVariables( - templateContent[0].title, - raw_message.vars, - ), - body: this.templateService.replaceTemplateWithVariables( - templateContent[0].body, - raw_message.vars, - ), - }; - } - return message; - } - - async updateMessage(m: Message) { - await this.prisma.message.update({ - where: { id: m.id }, - data: m, - }); - const job = await this.findOne(m.jobId); - if (m.status == MessageStatus.Succeed) { - job.successNum++; - } - job.sentNum++; - if (job.sentNum == job.messageNum) { - job.status = JobStatus.Finished; - } else { - job.status = JobStatus.Running; - } - await this.update(job.id, job); - } - - //@Cron('*/2 * * * * *') - @Interval(100) - async handlePendingMessage() { - if (this.isInSent || this.pendingMessages.length == 0) { - return; - } - this.isInSent = true; - - const m = this.pendingMessages.shift(); - this.logger.debug('handle message'); - this.logger.debug(m); - - try { - const recipient: RecipientAddress = JSON.parse(m.recipient); - this.logger.verbose('Recipient'); - this.logger.verbose(recipient); - if (!validateRecipient(recipient.type, recipient.data)) { - m.status = MessageStatus.Failed; - m.statusInfo = 'Invalid recipient'; - await this.updateMessage(m); - this.isInSent = false; - return; - } - - const sender: Sender = JSON.parse(m.sender); - this.logger.verbose('Sender'); - this.logger.verbose(sender); - - let credential: any; - if (LOCAL_CREDENTIAL) { - credential = await this.prisma.credential.findFirst({ - where: { id: sender.id }, - }); - } else { - // TODO: get credential from remote - } - this.logger.verbose('credential'); - this.logger.verbose(credential); - - if (!credential) { - m.status = MessageStatus.Failed; - m.statusInfo = 'Invalid credential'; - await this.updateMessage(m); - this.isInSent = false; - return; - } - - const s: TerminusNotificationSender = getSenderInstance( - m.senderType, - credential.data as NotificationCredential, - ); - - if (!s) { - m.status = MessageStatus.Failed; - m.statusInfo = 'Invalid sender'; - await this.updateMessage(m); - this.isInSent = false; - return; - } - - const notificationRecipient = getNotificationRecipient( - m.recipientType, - recipient.data as NotificationRecipientData, - ); - if (!notificationRecipient) { - m.status = MessageStatus.Failed; - m.statusInfo = 'Invalid recipient'; - await this.updateMessage(m); - this.isInSent = false; - return; - } - this.logger.verbose('notificationRecipient'); - this.logger.verbose(notificationRecipient); - - m.status = MessageStatus.Senting; - await this.prisma.message.update({ - where: { id: m.id }, - data: m, - }); - - const result: NotificationResult = await s.execute( - m.id, - notificationRecipient, - JSON.parse(m.message), - ); - - if (result.code === NotificationResultCode.Success) { - m.status = MessageStatus.Succeed; - } else { - m.status = MessageStatus.Failed; - } - if (result.message) { - m.statusInfo = result.message; - } - - await this.updateMessage(m); - } catch (e) { - this.logger.error(e); - m.status = MessageStatus.Failed; - m.statusInfo = e.message || 'Unknown error'; - await this.updateMessage(m); - } finally { - this.isInSent = false; - } - } -} diff --git a/packages/api/src/notification/message.service.ts b/packages/api/src/notification/message.service.ts deleted file mode 100644 index 50ecc44..0000000 --- a/packages/api/src/notification/message.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PrismaService } from 'src/prisma/prisma.service'; -import { Message } from '@notifications/database'; - -@Injectable() -export class MessageService { - constructor(private prisma: PrismaService) {} - - async create(data: Message): Promise { - return this.prisma.message.create({ - data, - }); - } - - async findAll(): Promise { - return this.prisma.message.findMany({ where: {} }); - } - - async findOne(id: number): Promise { - return this.prisma.message.findUnique({ where: { id } }); - } - - async update(id: number, data: Message): Promise { - return this.prisma.message.update({ - where: { id }, - data: data, - }); - } - - async remove(id: number): Promise { - return this.prisma.message.delete({ where: { id } }); - } -} diff --git a/packages/api/src/notification/notification.controller.ts b/packages/api/src/notification/notification.controller.ts index 143c2c8..1da5205 100644 --- a/packages/api/src/notification/notification.controller.ts +++ b/packages/api/src/notification/notification.controller.ts @@ -8,28 +8,12 @@ import { Logger, } from '@nestjs/common'; -import { Result, returnSucceed, ProviderRequest } from '@bytetrade/core'; -import { - Sender, - RecipientAddress, - Recipients, - NotifyPolicy, - NotifyRule, - Template, - TemplateContent, - Job, - Message, -} from '@notifications/database'; +import { Result, returnSucceed } from '@bytetrade/core'; +import { Template, TemplateContent } from '@notifications/database'; import { PrismaService } from '../prisma/prisma.service'; -import { SenderService } from './sender.service'; -import { RecipientsService } from './recipients.service'; -import { RecipientAddressService } from './recipient.address.service'; -import { NotifyPolicyService } from './notify.policy.service'; -import { NotifyRuleService } from './notify.rule.service'; + import { TemplateService } from './template.service'; import { TemplateContentService } from './template.content.service'; -import { JobService } from './job.service'; -import { NotificationCredential } from '@notifications/database'; @Controller('/notification') export class NotificationController { @@ -37,119 +21,10 @@ export class NotificationController { constructor( private readonly prisma: PrismaService, - private readonly senderService: SenderService, - private readonly recipientsService: RecipientsService, - private readonly recipientAddressService: RecipientAddressService, - private readonly notifyPolicyService: NotifyPolicyService, - private readonly notifyRuleService: NotifyRuleService, private readonly templateService: TemplateService, private readonly templateContentService: TemplateContentService, - private readonly jobService: JobService, ) {} - @Get('/sender') - async allSenders(): Promise> { - return returnSucceed(await this.senderService.findAll()); - } - - @Post('/sender') - async addSender( - @Body() - { - sender, - credential, - }: { - sender: Sender; - credential: NotificationCredential; - }, - ): Promise> { - return returnSucceed(await this.senderService.create(sender, credential)); - } - - @Get('/recipients') - async allRecipients(): Promise> { - return returnSucceed(await this.recipientsService.findAll()); - } - - @Post('/recipients') - async createRecipients( - @Body() { recipients }: { recipients: Recipients }, - ): Promise> { - return returnSucceed(await this.recipientsService.create(recipients)); - } - - @Get('/recipientAddress') - async allRecipientAddress(): Promise> { - return returnSucceed(await this.recipientAddressService.findAll()); - } - - @Post('/recipientAddress') - async createRecipientAddress( - @Body() { id, name, data }: { name: string; id: number; data: any }, - ): Promise> { - console.log(id); - const recipients: Recipients = await this.recipientsService.findOne( - Number(id), - ); - if (!recipients) { - throw new Error('Not found recipients.'); - } - - console.log(recipients); - return returnSucceed( - await this.prisma.recipientAddress.create({ - data: { - name: name, - recipientsId: recipients.id, - type: recipients.type, - data: data, - }, - }), - ); - } - - @Delete('/recipientAddress/:id') - async deleteRecipientAddress( - @Param('id') id: number, - ): Promise> { - return returnSucceed(await this.recipientAddressService.remove(id)); - } - - @Get('/notifyPolicy') - async allNotifyGroup(): Promise> { - return returnSucceed(await this.notifyPolicyService.findAll()); - } - - @Post('/notifyPolicy') - async createNotifyGroup( - @Body() { policy }: { policy: NotifyPolicy }, - ): Promise> { - return returnSucceed(await this.notifyPolicyService.create(policy)); - } - - @Get('/notifyRule/:id') - async getNotifyByPolicyID( - @Param('id') id: number, - ): Promise> { - return returnSucceed( - await this.notifyRuleService.findByPolicyId(Number(id)), - ); - } - - @Post('/notifyRule') - async createNotifyRule( - @Body() { rule }: { rule: NotifyRule }, - ): Promise> { - return returnSucceed(await this.notifyRuleService.create(rule)); - } - - @Delete('/notifyRule/:id') - async deleteNotifyByPolicyID( - @Param('id') id: number, - ): Promise> { - return returnSucceed(await this.notifyRuleService.remove(Number(id))); - } - @Get('/template') async allTemplate(): Promise> { return returnSucceed(await this.templateService.findAll()); @@ -172,35 +47,4 @@ export class NotificationController { async allTemplateContent(): Promise> { return returnSucceed(await this.templateContentService.findAll()); } - - @Get('/job') - async allJob(): Promise> { - return returnSucceed(await this.jobService.findAll()); - } - - @Post('/create_job') - async addNewJob( - @Body() - body: ProviderRequest<{ job: Job }>, - ): Promise> { - this.logger.debug(body); - return await this.jobService.processOneJob(body.data.job); - } - - @Post('/job') - async createJob( - @Body() - { job }: { job: Job }, - ): Promise> { - return await this.jobService.processOneJob(job); - } - - @Get('/job/message/:id') - async getMessagesByJobId( - @Param('id') id: number, - ): Promise> { - return returnSucceed( - await this.prisma.message.findMany({ where: { jobId: Number(id) } }), - ); - } } diff --git a/packages/api/src/notification/notification.module.ts b/packages/api/src/notification/notification.module.ts index 25b2cf0..bf9f321 100644 --- a/packages/api/src/notification/notification.module.ts +++ b/packages/api/src/notification/notification.module.ts @@ -1,32 +1,14 @@ import { Module } from '@nestjs/common'; -import { SenderService } from './sender.service'; -import { RecipientsService } from './recipients.service'; -import { RecipientAddressService } from './recipient.address.service'; -import { NotifyPolicyService } from './notify.policy.service'; -import { NotifyRuleService } from './notify.rule.service'; import { TemplateService } from './template.service'; import { TemplateContentService } from './template.content.service'; -import { JobService } from './job.service'; -import { MessageService } from './message.service'; import { NotificationController } from './notification.controller'; import { PrismaModule } from '../prisma/prisma.module'; import { ScheduleModule } from '@nestjs/schedule'; -import { TermiPassController } from './termipass.controller'; import { SystemController } from './system.controller'; @Module({ imports: [PrismaModule, ScheduleModule.forRoot()], - controllers: [NotificationController, TermiPassController, SystemController], - providers: [ - SenderService, - RecipientsService, - RecipientAddressService, - NotifyPolicyService, - NotifyRuleService, - TemplateService, - TemplateContentService, - JobService, - MessageService, - ], + controllers: [NotificationController, SystemController], + providers: [TemplateService, TemplateContentService], }) export class NotificationModule {} diff --git a/packages/api/src/notification/notify.policy.service.ts b/packages/api/src/notification/notify.policy.service.ts deleted file mode 100644 index 8005d2e..0000000 --- a/packages/api/src/notification/notify.policy.service.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PrismaService } from 'src/prisma/prisma.service'; -import { NotifyPolicy } from '@notifications/database'; - -@Injectable() -export class NotifyPolicyService { - constructor(private prisma: PrismaService) {} - - async create(data: NotifyPolicy): Promise { - return this.prisma.notifyPolicy.create({ - data, - }); - } - - async findAll(): Promise { - return this.prisma.notifyPolicy.findMany({ where: {} }); - } - - async findOne(id: number): Promise { - return this.prisma.notifyPolicy.findUnique({ where: { id } }); - } - - async findDefault(): Promise { - return this.prisma.notifyPolicy.findFirst({ where: { isDefault: true } }); - } - - async findByName(name: string): Promise { - return this.prisma.notifyPolicy.findFirst({ where: { name } }); - } - - async update(id: number, data: NotifyPolicy): Promise { - return this.prisma.notifyPolicy.update({ - where: { id }, - data: data, - }); - } - - async remove(id: number): Promise { - return this.prisma.notifyPolicy.delete({ where: { id } }); - } -} diff --git a/packages/api/src/notification/notify.rule.service.ts b/packages/api/src/notification/notify.rule.service.ts deleted file mode 100644 index 9296de4..0000000 --- a/packages/api/src/notification/notify.rule.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PrismaService } from 'src/prisma/prisma.service'; -import { NotifyRule } from '@notifications/database'; - -@Injectable() -export class NotifyRuleService { - constructor(private prisma: PrismaService) {} - - async create(data: NotifyRule): Promise { - return this.prisma.notifyRule.create({ - data, - }); - } - - async findAll(): Promise { - return this.prisma.notifyRule.findMany({ where: {} }); - } - - async findOne(id: number): Promise { - return this.prisma.notifyRule.findUnique({ where: { id } }); - } - - async findByPolicyId(notifyPolicyId: number): Promise { - return this.prisma.notifyRule.findMany({ where: { notifyPolicyId } }); - } - - async update(id: number, data: NotifyRule): Promise { - return this.prisma.notifyRule.update({ - where: { id }, - data: data, - }); - } - - async remove(id: number): Promise { - return this.prisma.notifyRule.delete({ where: { id } }); - } -} diff --git a/packages/api/src/notification/recipient.address.service.ts b/packages/api/src/notification/recipient.address.service.ts deleted file mode 100644 index f11f9eb..0000000 --- a/packages/api/src/notification/recipient.address.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PrismaService } from 'src/prisma/prisma.service'; -import { RecipientAddress } from '@notifications/database'; - -@Injectable() -export class RecipientAddressService { - constructor(private prisma: PrismaService) {} - - async findAll(): Promise { - return this.prisma.recipientAddress.findMany({ where: {} }); - } - - async findOne(id: number): Promise { - return this.prisma.recipientAddress.findUnique({ where: { id } }); - } - - async findByRecipientId(recipientsId: number): Promise { - return this.prisma.recipientAddress.findMany({ where: { recipientsId } }); - } - - async update(id: number, data: RecipientAddress): Promise { - return this.prisma.recipientAddress.update({ - where: { id }, - data: data, - }); - } - - async remove(id: number): Promise { - return this.prisma.recipientAddress.delete({ where: { id } }); - } -} diff --git a/packages/api/src/notification/recipients.service.ts b/packages/api/src/notification/recipients.service.ts deleted file mode 100644 index e78cc04..0000000 --- a/packages/api/src/notification/recipients.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PrismaService } from 'src/prisma/prisma.service'; -import { Recipients } from '@notifications/database'; - -@Injectable() -export class RecipientsService { - constructor(private prisma: PrismaService) {} - - async create(data: Recipients): Promise { - return this.prisma.recipients.create({ - data, - }); - } - - async findAll(): Promise { - return this.prisma.recipients.findMany({ where: {} }); - } - - async findOne(id: number): Promise { - return this.prisma.recipients.findUnique({ where: { id } }); - } - - async update(id: number, data: Recipients): Promise { - return this.prisma.recipients.update({ - where: { id }, - data: data, - }); - } - - async remove(id: number): Promise { - return this.prisma.recipients.delete({ where: { id } }); - } -} diff --git a/packages/api/src/notification/sender.service.ts b/packages/api/src/notification/sender.service.ts deleted file mode 100644 index 0133bf6..0000000 --- a/packages/api/src/notification/sender.service.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { PrismaService } from 'src/prisma/prisma.service'; -import { Sender, SenderType } from '@notifications/database'; -import { LOCAL_CREDENTIAL } from './global'; -import { NotificationCredential } from '@notifications/database'; - -@Injectable() -export class SenderService { - private readonly logger = new Logger(SenderService.name); - - constructor(private prisma: PrismaService) {} - - async create( - sender: Sender, - credential: NotificationCredential, - ): Promise { - this.logger.verbose(sender); - this.logger.verbose(credential); - if (sender.type === SenderType.Application) { - const app = await this.prisma.sender.findFirst({ - where: { app: sender.app }, - }); - if (app) { - throw Error('Application already has sender'); - } - } - - const res = await this.prisma.sender.create({ - data: sender, - }); - - if (LOCAL_CREDENTIAL) { - await this.prisma.credential.create({ - data: { - senderId: res.id, - type: sender.type, - data: credential, - }, - }); - } else { - // - } - - return res; - } - - async findAll(): Promise { - return this.prisma.sender.findMany({ where: {} }); - } - - async findOne(id: number): Promise { - return this.prisma.sender.findUnique({ where: { id } }); - } - - async update(id: number, data: Sender): Promise { - return this.prisma.sender.update({ - where: { id }, - data: data, - }); - } - - async remove(id: number): Promise { - return this.prisma.sender.delete({ where: { id } }); - } -} diff --git a/packages/api/src/notification/system.controller.ts b/packages/api/src/notification/system.controller.ts index 9e97f4e..a476efa 100644 --- a/packages/api/src/notification/system.controller.ts +++ b/packages/api/src/notification/system.controller.ts @@ -1,21 +1,14 @@ import { Controller, Post, Body, Logger, HttpCode } from '@nestjs/common'; import { Result, returnSucceed } from '@bytetrade/core'; -import { JobService } from './job.service'; import { TemplateService } from './template.service'; import { KubeSphereNotification, Payload } from './global'; -import { NotifyPolicyService } from './notify.policy.service'; -import { NotifyPolicy } from '@notifications/database'; @Controller('/notification/system') export class SystemController { private readonly logger = new Logger(SystemController.name); - constructor( - private readonly jobService: JobService, - private readonly templateService: TemplateService, - private readonly notifyPolicyService: NotifyPolicyService, - ) {} + constructor(private readonly templateService: TemplateService) {} async handleNoTemplate(payload: Payload): Promise> { if (payload.eventType == 'user.login') { @@ -26,27 +19,20 @@ export class SystemController { } this.logger.debug(template); - const notifyPolicy: NotifyPolicy = - await this.notifyPolicyService.findDefault(); - if (!notifyPolicy) { - this.logger.warn('default policy template not found'); - return returnSucceed(null); - } - this.logger.debug(notifyPolicy); - - this.jobService.processOneJob({ - templateId: template.id, - notifyPolicyId: notifyPolicy.id, - language: this.jobService.language, - rawMessage: { - vars: { - time: new Date().toLocaleString(), - username: payload.eventData.user, - device: '', - location: '', - }, - }, - }); + // this.jobService.processOneJob({ + // templateId: template.id, + // user: user, + // // notifyPolicyId: notifyPolicy.id, + // language: this.jobService.language, + // rawMessage: { + // vars: { + // time: new Date().toLocaleString(), + // username: payload.eventData.user, + // device: '', + // location: '', + // }, + // }, + // }); } else if (payload.eventType == 'app.install') { // } else { @@ -57,6 +43,7 @@ export class SystemController { @Post('/push') @HttpCode(200) async push(@Body() body: KubeSphereNotification): Promise> { + this.logger.log('push'); this.logger.log(body); try { @@ -64,34 +51,20 @@ export class SystemController { const payload: Payload = JSON.parse(body.commonLabels.payload); this.logger.log(payload.eventType); - const template = await this.templateService.findTemplate( - payload.eventType, - ); - if (!template) { - this.logger.warn('template not found ' + payload.eventType); - return await this.handleNoTemplate(payload); - } - this.logger.debug(template); - - let notifyPolicy: NotifyPolicy = null; - if (template.notifyGroup == '') { - notifyPolicy = await this.notifyPolicyService.findDefault(); - } else { - notifyPolicy = await this.notifyPolicyService.findByName( - template.notifyGroup, - ); - } - if (!notifyPolicy) { - this.logger.warn('default policy template not found'); - return returnSucceed(null); - } + // const template = await this.templateService.findTemplate( + // payload.eventType, + // ); + // if (!template) { + // this.logger.warn('template not found ' + payload.eventType); + // return await this.handleNoTemplate(payload); + // } + // this.logger.debug(template); - this.jobService.processOneJob({ - templateId: template.id, - notifyPolicyId: notifyPolicy.id, - language: this.jobService.language, - rawMessage: JSON.parse(body.commonAnnotations.message), - }); + // // this.natsService.pushMessage( + // // templateId: template.id, + // // user: user, + // // payload, + // // ); } else { this.logger.warn('error type' + body.commonLabels.type); } diff --git a/packages/api/src/notification/template.service.ts b/packages/api/src/notification/template.service.ts index ed21fcb..7c539f7 100644 --- a/packages/api/src/notification/template.service.ts +++ b/packages/api/src/notification/template.service.ts @@ -1,9 +1,10 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service'; import { Template, TemplateContent } from '@notifications/database'; @Injectable() export class TemplateService { + private readonly logger = new Logger(TemplateService.name); constructor(private prisma: PrismaService) {} async create( @@ -26,16 +27,30 @@ export class TemplateService { } } + const res = await this.findTemplateByApplicationIDandApplicationTemplateId( + template.appId, + template.appTemplateId, + ); + if (res) { + this.logger.warn( + 'template exists ', + template.appId, + template.appTemplateId, + ); + return res; + } + return this.prisma.template.create({ data: { topic: template.topic, name: template.name, appId: template.appId, appName: template.appName, - appTemplateName: template.appTemplateName, + appTemplateId: template.appTemplateId, defaultLanguage: template.defaultLanguage, - notifyGroup: template.notifyGroup, user: template.user, + isSystem: template.isSystem, + level: template.level, status: template.status, variables: template.variables, content: { @@ -57,15 +72,37 @@ export class TemplateService { return this.prisma.template.delete({ where: { id } }); } - async findTemplate(name: string): Promise