feat: 邮件通知

This commit is contained in:
xiaojunnuo
2023-06-25 15:30:18 +08:00
parent 64afebecd4
commit 937e3fac19
32 changed files with 790 additions and 88 deletions
@@ -10,7 +10,7 @@ export abstract class BaseController {
* 成功返回
* @param data 返回数据
*/
ok(data) {
ok(data: any) {
const res = {
...Constants.res.success,
data: undefined,
@@ -22,12 +22,21 @@ export abstract class BaseController {
}
/**
* 失败返回
* @param message
* @param msg
* @param code
*/
fail(msg, code) {
fail(msg: string, code: any) {
return {
code: code ? code : Constants.res.error.code,
msg: msg ? msg : Constants.res.error.code,
};
}
getUserId() {
const userId = this.ctx.user?.id;
if (userId == null) {
throw new Error('Token已过期');
}
return userId;
}
}
@@ -187,14 +187,19 @@ export abstract class BaseService<T> {
return await qb.getMany();
}
async checkUserId(id = 0, userId, userKey = 'userId') {
async checkUserId(
id: any = 0,
userId,
userKey = 'userId',
queryIdKey = 'id'
) {
// @ts-ignore
const res = await this.getRepository().findOne({
// @ts-ignore
select: { [userKey]: true },
// @ts-ignore
where: {
// @ts-ignore
id,
[queryIdKey]: id,
},
});
// @ts-ignore
@@ -1,9 +1,5 @@
import { Provide } from '@midwayjs/decorator';
import {
IWebMiddleware,
IMidwayKoaContext,
NextFunction,
} from '@midwayjs/koa';
import { IWebMiddleware, IMidwayKoaContext, NextFunction } from '@midwayjs/koa';
import { logger } from '../utils/logger';
import { Result } from '../basic/result';
@@ -20,7 +16,10 @@ export class GlobalExceptionMiddleware implements IWebMiddleware {
} catch (err) {
logger.error('请求异常:', url, Date.now() - startTime + 'ms', err);
ctx.status = 200;
ctx.body = Result.error(err.code != null ? err.code : 1, err.message);
if (err.code == null || typeof err.code !== 'number') {
err.code = 1;
}
ctx.body = Result.error(err.code, err.message);
}
};
}
@@ -1,9 +1,10 @@
import { Rule,RuleType } from '@midwayjs/validate';
import { Rule, RuleType } from '@midwayjs/validate';
import { ALL, Inject } from '@midwayjs/decorator';
import { Body } from '@midwayjs/decorator';
import { Controller, Post, Provide } from '@midwayjs/decorator';
import { BaseController } from '../../../basic/base-controller';
import { CodeService } from '../service/code-service';
import { EmailService } from '../service/email-service';
export class SmsCodeReq {
@Rule(RuleType.number().required())
phoneCode: number;
@@ -18,22 +19,17 @@ export class SmsCodeReq {
imgCode: string;
}
// const enumsMap = {};
// glob('src/modules/**/enums/*.ts', {}, (err, matches) => {
// console.log('matched', matches);
// for (const filePath of matches) {
// const module = require('/' + filePath);
// console.log('modules', module);
// }
// });
/**
*/
@Provide()
@Controller('/api/basic')
@Controller('/api/basic/code')
export class BasicController extends BaseController {
@Inject()
codeService: CodeService;
@Inject()
emailService: EmailService;
@Post('/sendSmsCode')
public sendSmsCode(
@Body(ALL)
@@ -53,4 +49,3 @@ export class BasicController extends BaseController {
return this.ok(captcha.data);
}
}
@@ -0,0 +1,22 @@
import { Body, Controller, Inject, Post, Provide } from '@midwayjs/decorator';
import { BaseController } from '../../../basic/base-controller';
import { EmailService } from '../service/email-service';
/**
*/
@Provide()
@Controller('/api/basic/email')
export class EmailController extends BaseController {
@Inject()
emailService: EmailService;
@Post('/test')
public async test(
@Body('receiver')
receiver
) {
const userId = super.getUserId();
await this.emailService.test(userId, receiver);
return this.ok({});
}
}
@@ -0,0 +1,60 @@
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/decorator';
import type { EmailSend } from '@certd/pipeline';
import { IEmailService } from '@certd/pipeline';
import nodemailer from 'nodemailer';
import { SettingsService } from '../../system/service/settings-service';
import type SMTPConnection from 'nodemailer/lib/smtp-connection';
export type EmailConfig = {
host: string;
port: number;
auth: {
user: string;
pass: string;
};
secure: boolean; // use TLS
tls: {
// do not fail on invalid certs
rejectUnauthorized: boolean;
};
sender: string;
} & SMTPConnection.Options;
@Provide()
@Scope(ScopeEnum.Singleton)
export class EmailService implements IEmailService {
@Inject()
settingsService: SettingsService;
/**
*/
async send(email: EmailSend) {
console.log('sendEmail', email);
const emailConfigEntity = await this.settingsService.getByKey(
'email',
email.userId
);
if (emailConfigEntity == null || !emailConfigEntity.setting) {
throw new Error('email settings 未设置');
}
const emailConfig = JSON.parse(emailConfigEntity.setting) as EmailConfig;
const transporter = nodemailer.createTransport(emailConfig);
const mailOptions = {
from: emailConfig.sender,
to: email.receivers.join(', '), // list of receivers
subject: email.subject,
text: email.content,
};
await transporter.sendMail(mailOptions);
console.log('sendEmail success', email);
}
async test(userId: number, receiver: string) {
await this.send({
userId,
receivers: [receiver],
subject: '测试邮件,from certd',
content: '测试邮件,from certd',
});
}
}
@@ -1,4 +1,4 @@
import { Autoload, Init, Inject, Scope, ScopeEnum } from "@midwayjs/decorator";
import { Autoload, Init, Inject, Scope, ScopeEnum } from '@midwayjs/decorator';
import { PipelineService } from '../service/pipeline-service';
import { logger } from '../../../utils/logger';
@@ -14,6 +14,7 @@ import { HistoryEntity } from '../entity/history';
import { HistoryLogEntity } from '../entity/history-log';
import { HistoryLogService } from './history-log-service';
import { logger } from '../../../utils/logger';
import { EmailService } from '../../basic/service/email-service';
/**
* 证书申请
@@ -23,7 +24,8 @@ import { logger } from '../../../utils/logger';
export class PipelineService extends BaseService<PipelineEntity> {
@InjectEntityModel(PipelineEntity)
repository: Repository<PipelineEntity>;
@Inject()
emailService: EmailService;
@Inject()
accessService: AccessService;
@Inject()
@@ -191,6 +193,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
onChanged,
accessService: this.accessService,
storage: new DbStorage(userId, this.storageService),
emailService: this.emailService,
});
try {
await executor.init();
@@ -1,6 +1,15 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/decorator";
import { CrudController } from "../../../basic/crud-controller";
import { SettingsService } from "../service/settings-service";
import {
ALL,
Body,
Controller,
Inject,
Post,
Provide,
Query,
} from '@midwayjs/decorator';
import { CrudController } from '../../../basic/crud-controller';
import { SettingsService } from '../service/settings-service';
import { SettingsEntity } from '../entity/settings';
/**
*/
@@ -50,4 +59,18 @@ export class SettingsController extends CrudController<SettingsService> {
return super.delete(id);
}
@Post('/save')
async save(@Body(ALL) bean: SettingsEntity) {
await this.service.checkUserId(bean.key, this.ctx.user.id, 'userId', 'key');
bean.userId = this.ctx.user.id;
await this.service.save(bean);
return this.ok({});
}
@Post('/get')
async get(@Query('key') key: string) {
await this.service.checkUserId(key, this.ctx.user.id, 'userId', 'key');
const entity = await this.service.getByKey(key, this.ctx.user.id);
return this.ok(entity);
}
}
@@ -8,8 +8,10 @@ export class SettingsEntity {
id: number;
@Column({ name: 'user_id', comment: '用户id' })
userId: number;
@Column({ comment: 'key', length: 100 })
key: string;
@Column({ comment: '名称', length: 100 })
name: string;
title: string;
@Column({ name: 'setting', comment: '设置', length: 1024, nullable: true })
setting: string;
@@ -1,17 +1,15 @@
import { Provide, Scope, ScopeEnum } from "@midwayjs/decorator";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository } from "typeorm";
import { BaseService } from "../../../basic/base-service";
import { SettingsEntity } from "../entity/settings";
import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { BaseService } from '../../../basic/base-service';
import { SettingsEntity } from '../entity/settings';
/**
* 授权
*/
@Provide()
@Scope(ScopeEnum.Singleton)
export class SettingsService
extends BaseService<SettingsEntity>
{
export class SettingsService extends BaseService<SettingsEntity> {
@InjectEntityModel(SettingsEntity)
repository: Repository<SettingsEntity>;
@@ -19,8 +17,11 @@ export class SettingsService
return this.repository;
}
async getById(id: any): Promise<any> {
async getById(id: any): Promise<SettingsEntity | null> {
const entity = await this.info(id);
if (!entity) {
return null;
}
// const access = accessRegistry.get(entity.type);
const setting = JSON.parse(entity.setting);
return {
@@ -29,5 +30,38 @@ export class SettingsService
};
}
async getByKey(key: string, userId: number): Promise<SettingsEntity | null> {
if (!key || !userId) {
return null;
}
return await this.repository.findOne({
where: {
key,
userId,
},
});
}
async getSettingByKey(key: string, userId: number): Promise<any | null> {
const entity = await this.getByKey(key, userId);
if (!entity) {
return null;
}
return JSON.parse(entity.setting);
}
async save(bean: SettingsEntity) {
const entity = await this.repository.findOne({
where: {
key: bean.key,
},
});
if (entity) {
entity.setting = bean.setting;
await this.repository.save(entity);
} else {
bean.title = bean.key;
await this.repository.save(bean);
}
}
}