feat: upgrade plugin-notifications

This commit is contained in:
chenos 2021-12-07 19:24:26 +08:00
parent 30e31a2e79
commit 17b5839f51
16 changed files with 327 additions and 4 deletions

View File

@ -4,6 +4,6 @@ export * from './utils';
export { Database as default } from './database';
export * from './relation-repository/belongs-to-many-repository';
export * from './relation-repository/belongs-to-repository';
export { Model } from 'sequelize';
export { Model, ModelCtor } from 'sequelize';
export * from './fields';
export * from './update-associations';

View File

@ -56,9 +56,7 @@ export type WhiteList = string[];
export type BlackList = string[];
export type AssociationKeysToBeUpdate = string[];
export type Values = {
[key: string]: string | number | Values | Array<number | string | Values>;
};
export type Values = any;
export interface CountOptions extends Omit<SequelizeCreateOptions, 'distinct' | 'where' | 'include'>, TransactionAble {
fields?: Fields;

View File

@ -0,0 +1,7 @@
node_modules
*.log
docs
__tests__
tsconfig.json
src
.fatherrc.ts

View File

@ -0,0 +1,19 @@
{
"name": "@nocobase/plugin-notifications",
"version": "0.6.0-alpha.0",
"main": "lib/index.js",
"license": "MIT",
"scripts": {
"build": "rimraf -rf lib esm dist && npm run build:cjs && npm run build:esm",
"build:cjs": "tsc --project tsconfig.build.json",
"build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir esm"
},
"dependencies": {
"nodemailer": "^6.6.1"
},
"devDependencies": {
"@types/nodemailer": "6.4.4",
"nodemailer-mock": "^1.5.11"
},
"gitHead": "f0b335ac30f29f25c95d7d137655fa64d8d67f1e"
}

View File

@ -0,0 +1,54 @@
import Database from '@nocobase/database';
import { Notification, NotificationService } from '../models';
import nodemailerMock from 'nodemailer-mock';
import { mockServer } from '@nocobase/test';
import _ from 'lodash';
import plugin from '../server';
jest.setTimeout(300000);
describe('notifications', () => {
let db: Database;
beforeEach(async () => {
const app = mockServer();
app.plugin(plugin);
await app.load();
db = app.db;
await db.sync();
NotificationService.createTransport = nodemailerMock.createTransport;
});
afterEach(() => db.close());
it('create', async () => {
const Notification = db.getCollection('notifications');
const notification = await Notification.repository.create({
values: {
subject: 'Subject',
body: 'hell world',
receiver_options: {
data: 'to@nocobase.com',
fromTable: 'users',
filter: {},
dataField: 'email',
},
service: {
type: 'email',
title: '阿里云邮件推送',
options: {
host: 'smtpdm.aliyun.com',
port: 465,
secure: true,
auth: {
user: 'from@nocobase.com',
pass: 'pass',
},
from: 'NocoBase<from@nocobase.com>',
},
},
},
}) as Notification;
await notification.send();
});
});

View File

@ -0,0 +1,25 @@
import { CollectionOptions } from '@nocobase/database';
import { NotificationLog } from '../models';
export default {
name: 'notification_logs',
model: NotificationLog,
title: '通知日志',
fields: [
{
title: '接收人',
type: 'json',
name: 'receiver',
},
{
title: '状态',
type: 'string',
name: 'state',
},
{
title: '详情',
type: 'json',
name: 'response',
},
]
} as CollectionOptions;

View File

@ -0,0 +1,25 @@
import { CollectionOptions } from '@nocobase/database';
import { NotificationService } from '../models';
export default {
name: 'notification_services',
model: NotificationService,
title: '通知服务',
fields: [
{
title: '类型',
type: 'string',
name: 'type',
},
{
title: '服务名称',
type: 'string',
name: 'title',
},
{
title: '配置信息',
type: 'json',
name: 'options',
},
]
} as CollectionOptions;

View File

@ -0,0 +1,42 @@
import { CollectionOptions } from '@nocobase/database';
import { Notification } from '../models';
export default {
name: 'notifications',
model: Notification,
title: '通知',
fields: [
{
type: 'uid',
name: 'name',
prefix: 'n_',
},
{
title: '主题',
type: 'string',
name: 'subject',
},
{
title: '内容',
type: 'text',
name: 'body',
},
{
title: '接收人配置',
type: 'json',
name: 'receiver_options',
},
{
title: '发送服务',
type: 'belongsTo',
name: 'service',
target: 'notification_services',
},
{
title: '日志',
type: 'hasMany',
name: 'logs',
target: 'notification_logs',
},
]
} as CollectionOptions;

View File

@ -0,0 +1,74 @@
import Database, { Model } from '@nocobase/database';
import { NotificationService } from './NotificationService';
import _ from 'lodash';
export class Notification extends Model {
[key: string]: any;
get db(): Database {
return this.constructor['database'];
}
async getReceiversByOptions(): Promise<any[]> {
const { data, fromTable, filter, dataField } = this.receiver_options;
let receivers = [];
if (data) {
receivers = Array.isArray(data) ? data : [data];
} else if (fromTable) {
const collection = this.db.getCollection(fromTable);
const rows = await collection.repository.find({
filter,
});
receivers = rows.map(row => row[dataField]);
}
return receivers;
}
async send(options: any = {}) {
if (!this.service) {
this.service = await this.getService();
}
const receivers = await this.getReceiversByOptions();
let { to } = options;
if (to) {
to = Array.isArray(to) ? to : [to];
receivers.push(...to);
}
console.log(receivers)
for (const receiver of receivers) {
try {
const response = await (this.service as NotificationService).send({
to: receiver,
subject: this.getSubject(),
html: this.getBody(options),
});
await this.createLog({
receiver,
state: 'success',
response,
});
await new Promise((resolve) => {
setTimeout(resolve, 100);
});
} catch (error) {
console.error(error);
await this.createLog({
receiver,
state: 'fail',
response: {},
});
}
}
}
getSubject() {
return this.subject;
}
getBody(data) {
const compiled = _.template(this.body)
const body = compiled(data);
return body;
}
}

View File

@ -0,0 +1,5 @@
import { Model } from '@nocobase/database';
export class NotificationLog extends Model {
}

View File

@ -0,0 +1,26 @@
import { Model } from '@nocobase/database';
import nodemailer from 'nodemailer';
export class NotificationService extends Model {
[key: string]: any;
static createTransport = nodemailer.createTransport;
private _transporter = null;
get transporter() {
if (this._transporter) {
return this._transporter;
}
return this._transporter = NotificationService.createTransport(this.options);
}
async send(options) {
const { from } = this.options;
const mailOptions = {
from,
...options,
};
return this.transporter.sendMail(mailOptions);
}
}

View File

@ -0,0 +1,3 @@
export * from './Notification';
export * from './NotificationLog';
export * from './NotificationService';

View File

@ -0,0 +1,11 @@
import path from 'path';
import { PluginOptions } from '@nocobase/server';
export default {
name: 'notifications',
async load() {
await this.app.db.import({
directory: path.resolve(__dirname, 'collections'),
});
}
} as PluginOptions

View File

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"outDir": "./lib",
"declaration": true
},
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
"exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"]
}

View File

@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.json",
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
"exclude": ["./esm/*", "./lib/*"]
}

View File

@ -2437,6 +2437,13 @@
resolved "https://registry.npmjs.org/@types/node/-/node-14.17.34.tgz#fe4b38b3f07617c0fa31ae923fca9249641038f0"
integrity sha512-USUftMYpmuMzeWobskoPfzDi+vkpe0dvcOBRNOscFrGxVp4jomnRxWuVohgqBow2xyIPC0S3gjxV/5079jhmDg==
"@types/nodemailer@6.4.4":
version "6.4.4"
resolved "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.4.tgz#c265f7e7a51df587597b3a49a023acaf0c741f4b"
integrity sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw==
dependencies:
"@types/node" "*"
"@types/normalize-package-data@^2.4.0":
version "2.4.1"
resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
@ -9584,6 +9591,19 @@ node-releases@^2.0.1:
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==
nodemailer-mock@^1.5.11:
version "1.5.11"
resolved "https://registry.npmjs.org/nodemailer-mock/-/nodemailer-mock-1.5.11.tgz#1bb6b9af44e9007380191d32e33555ea136a819f"
integrity sha512-RbqkppKkptTgSzry3q8u/YD8pxulln/hYQ30O5brFRki8gEKv7KoAYGwfErZM2VsI7nGNBYRo5IOLnMW3NXBcw==
dependencies:
debug "^4.3.2"
nodemailer "^6.x"
nodemailer@^6.6.1, nodemailer@^6.x:
version "6.7.2"
resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0"
integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==
"nopt@2 || 3":
version "3.0.6"
resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"