mirror of
https://github.com/certd/certd.git
synced 2026-04-23 11:37:23 +08:00
feat: 邮件通知
This commit is contained in:
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+7
-12
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user