mirror of
https://github.com/certd/certd.git
synced 2026-04-23 11:37:23 +08:00
perf: 支持邮件模版设置
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { Rule, RuleType } from "@midwayjs/validate";
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||
import { BaseController, Constants, SysSettingsService } from "@certd/lib-server";
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||
import { Rule, RuleType } from "@midwayjs/validate";
|
||||
import { CaptchaService } from "../../modules/basic/service/captcha-service.js";
|
||||
import { CodeService } from "../../modules/basic/service/code-service.js";
|
||||
import { EmailService } from "../../modules/basic/service/email-service.js";
|
||||
import { CaptchaService } from "../../modules/basic/service/captcha-service.js";
|
||||
import { AddonGetterService } from "../../modules/pipeline/service/addon-getter-service.js";
|
||||
|
||||
export class SmsCodeReq {
|
||||
@Rule(RuleType.string().required())
|
||||
@@ -49,6 +50,9 @@ export class BasicController extends BaseController {
|
||||
@Inject()
|
||||
captchaService: CaptchaService;
|
||||
|
||||
@Inject()
|
||||
addonGetterService: AddonGetterService;
|
||||
|
||||
@Post('/captcha/get', { summary: Constants.per.guest })
|
||||
async getCaptcha(@Query("captchaAddonId") captchaAddonId:number) {
|
||||
const form = await this.captchaService.getCaptcha(captchaAddonId)
|
||||
@@ -83,17 +87,18 @@ export class BasicController extends BaseController {
|
||||
const opts = {
|
||||
verificationType: body.verificationType,
|
||||
verificationCodeLength: undefined,
|
||||
title: undefined,
|
||||
content: undefined,
|
||||
duration: undefined,
|
||||
};
|
||||
|
||||
if(body?.verificationType === 'forgotPassword') {
|
||||
opts.title = '找回密码';
|
||||
opts.content = '验证码:${code}。您正在找回密码,请输入验证码并完成操作。如非本人操作请忽略';
|
||||
opts.duration = FORGOT_PASSWORD_CODE_DURATION;
|
||||
opts.verificationCodeLength = 6;
|
||||
}else{
|
||||
opts.duration = 10;
|
||||
opts.verificationCodeLength = 6;
|
||||
}
|
||||
|
||||
|
||||
await this.codeService.checkCaptcha(body.captcha);
|
||||
await this.codeService.sendEmailCode(body.email, opts);
|
||||
// 设置缓存内容
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||
import {
|
||||
addonRegistry,
|
||||
AddonService,
|
||||
CrudController,
|
||||
SysPrivateSettings,
|
||||
SysPublicSettings,
|
||||
@@ -30,6 +31,8 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
pipelineService: PipelineService;
|
||||
@Inject()
|
||||
codeService: CodeService;
|
||||
@Inject()
|
||||
addonService: AddonService;
|
||||
|
||||
getService() {
|
||||
return this.service;
|
||||
@@ -86,6 +89,25 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
return this.ok(conf);
|
||||
}
|
||||
|
||||
@Post('/getEmailTemplates', { summary: 'sys:settings:view' })
|
||||
async getEmailTemplates(@Body(ALL) body) {
|
||||
const conf = await getEmailSettings(this.service, this.userSettingsService);
|
||||
const templates = conf.templates || {}
|
||||
|
||||
const emailTemplateProviders = await this.addonService.getDefineList("emailTemplate")
|
||||
|
||||
const proviers = []
|
||||
for (const item of emailTemplateProviders) {
|
||||
const templateConf = templates[item.name] || {}
|
||||
proviers.push({
|
||||
name: item.name,
|
||||
title: item.title,
|
||||
addonId : templateConf.addonId,
|
||||
})
|
||||
}
|
||||
return this.ok(proviers);
|
||||
}
|
||||
|
||||
@Post('/saveEmailSettings', { summary: 'sys:settings:edit' })
|
||||
async saveEmailSettings(@Body(ALL) body) {
|
||||
const conf = await getEmailSettings(this.service, this.userSettingsService);
|
||||
|
||||
@@ -18,24 +18,24 @@ export class EmailController extends BaseController {
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
public async list() {
|
||||
const userId = super.getUserId();
|
||||
const res = await this.emailService.list(userId);
|
||||
return this.ok(res);
|
||||
}
|
||||
// @Post('/list', { summary: Constants.per.authOnly })
|
||||
// public async list() {
|
||||
// const userId = super.getUserId();
|
||||
// const res = await this.emailService.list(userId);
|
||||
// return this.ok(res);
|
||||
// }
|
||||
|
||||
@Post('/add', { summary: Constants.per.authOnly })
|
||||
public async add(@Body('email') email) {
|
||||
const userId = super.getUserId();
|
||||
await this.emailService.add(userId, email);
|
||||
return this.ok({});
|
||||
}
|
||||
// @Post('/add', { summary: Constants.per.authOnly })
|
||||
// public async add(@Body('email') email) {
|
||||
// const userId = super.getUserId();
|
||||
// await this.emailService.add(userId, email);
|
||||
// return this.ok({});
|
||||
// }
|
||||
|
||||
@Post('/delete', { summary: Constants.per.authOnly })
|
||||
public async delete(@Body('email') email) {
|
||||
const userId = super.getUserId();
|
||||
await this.emailService.delete(userId, email);
|
||||
return this.ok({});
|
||||
}
|
||||
// @Post('/delete', { summary: Constants.per.authOnly })
|
||||
// public async delete(@Body('email') email) {
|
||||
// const userId = super.getUserId();
|
||||
// await this.emailService.delete(userId, email);
|
||||
// return this.ok({});
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -130,7 +130,8 @@ export class AutoCRegisterCron {
|
||||
title,
|
||||
content,
|
||||
errorMessage:title,
|
||||
url
|
||||
url,
|
||||
notificationType: "vipExpireRemind",
|
||||
}
|
||||
},adminUser.id)
|
||||
}
|
||||
@@ -182,7 +183,8 @@ export class AutoCRegisterCron {
|
||||
title,
|
||||
content,
|
||||
errorMessage: title,
|
||||
url
|
||||
url,
|
||||
notificationType: "userExpireRemind",
|
||||
}
|
||||
}, user.id)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { cache, isDev, randomNumber, simpleNanoId } from '@certd/basic';
|
||||
import { SysSettingsService, SysSiteInfo } from '@certd/lib-server';
|
||||
import { SmsServiceFactory } from '../sms/factory.js';
|
||||
import { AccessService, AccessSysGetter, CodeErrorException, SysSettingsService } from '@certd/lib-server';
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { ISmsService } from '../sms/api.js';
|
||||
import { CodeErrorException } from '@certd/lib-server';
|
||||
import { EmailService } from './email-service.js';
|
||||
import { AccessService } from '@certd/lib-server';
|
||||
import { AccessSysGetter } from '@certd/lib-server';
|
||||
import { isComm } from '@certd/plus-core';
|
||||
import { SmsServiceFactory } from '../sms/factory.js';
|
||||
import { CaptchaService } from "./captcha-service.js";
|
||||
import { EmailService } from './email-service.js';
|
||||
|
||||
// {data: '<svg.../svg>', text: 'abcd'}
|
||||
/**
|
||||
@@ -84,8 +80,6 @@ export class CodeService {
|
||||
async sendEmailCode(
|
||||
email: string,
|
||||
opts?: {
|
||||
title?: string,
|
||||
content?: string,
|
||||
duration?: number,
|
||||
verificationType?: string,
|
||||
verificationCodeLength?: number,
|
||||
@@ -96,32 +90,27 @@ export class CodeService {
|
||||
}
|
||||
|
||||
|
||||
let siteTitle = 'Certd';
|
||||
if (isComm()) {
|
||||
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
|
||||
if (siteInfo) {
|
||||
siteTitle = siteInfo.title || siteTitle;
|
||||
}
|
||||
}
|
||||
|
||||
const verificationCodeLength = Math.floor(Math.max(Math.min(opts?.verificationCodeLength || 4, 8), 4));
|
||||
const duration = Math.floor(Math.max(Math.min(opts?.duration || 5, 15), 1));
|
||||
|
||||
const code = randomNumber(verificationCodeLength);
|
||||
|
||||
|
||||
const templateData = {
|
||||
code, duration, siteTitle
|
||||
code, duration,
|
||||
title: "验证码",
|
||||
content:`您的验证码是${code},请勿泄露`,
|
||||
notificationType: "registerCode"
|
||||
}
|
||||
|
||||
const titleTemplate = opts?.title?
|
||||
|
||||
const title = `【${siteTitle}】${!!opts?.title ? opts.title : '验证码'}`;
|
||||
const content = !!opts.content ? this.compile(opts.content)(templateData) : `您的验证码是${code},请勿泄露`;
|
||||
|
||||
await this.emailService.send({
|
||||
subject: title,
|
||||
content: content,
|
||||
receivers: [email],
|
||||
if (opts?.verificationType === 'forgotPassword') {
|
||||
templateData.title = '找回密码';
|
||||
templateData.notificationType = "forgotPassword"
|
||||
}
|
||||
await this.emailService.sendByTemplate({
|
||||
type: templateData.notificationType,
|
||||
data: templateData,
|
||||
email:{
|
||||
receivers: [email],
|
||||
},
|
||||
});
|
||||
|
||||
const key = this.buildEmailCodeKey(email,opts?.verificationType);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import type { EmailSend } from '@certd/pipeline';
|
||||
import type { EmailSend, EmailSendByTemplateReq } from '@certd/pipeline';
|
||||
import { IEmailService } from '@certd/pipeline';
|
||||
|
||||
import { logger } from '@certd/basic';
|
||||
@@ -8,9 +8,11 @@ import { isComm, isPlus } from '@certd/plus-core';
|
||||
import nodemailer from 'nodemailer';
|
||||
import { SendMailOptions } from 'nodemailer';
|
||||
import { UserSettingsService } from '../../mine/service/user-settings-service.js';
|
||||
import { PlusService, SysSettingsService, SysSiteInfo } from '@certd/lib-server';
|
||||
import { AddonService, PlusService, SysEmailConf, SysSettingsService, SysSiteInfo } from '@certd/lib-server';
|
||||
import { getEmailSettings } from '../../sys/settings/fix.js';
|
||||
import { UserEmailSetting } from "../../mine/service/models.js";
|
||||
import { AddonGetterService } from '../../pipeline/service/addon-getter-service.js';
|
||||
import { EmailContent, ITemplateProvider } from '../../../plugins/plugin-template/api.js';
|
||||
|
||||
export type EmailConfig = {
|
||||
host: string;
|
||||
@@ -38,6 +40,12 @@ export class EmailService implements IEmailService {
|
||||
@Inject()
|
||||
plusService: PlusService;
|
||||
|
||||
@Inject()
|
||||
addonGetterService: AddonGetterService;
|
||||
@Inject()
|
||||
addonService: AddonService
|
||||
|
||||
|
||||
async sendByPlus(email: EmailSend) {
|
||||
if (!isPlus()) {
|
||||
throw new Error('plus not enabled');
|
||||
@@ -49,7 +57,6 @@ export class EmailService implements IEmailService {
|
||||
* content: string;
|
||||
* receivers: string[];
|
||||
*/
|
||||
|
||||
await this.plusService.sendEmail(email);
|
||||
}
|
||||
|
||||
@@ -62,26 +69,6 @@ export class EmailService implements IEmailService {
|
||||
throw new Error('收件人不能为空');
|
||||
}
|
||||
|
||||
const emailConf = await getEmailSettings(this.sysSettingsService, this.settingsService);
|
||||
|
||||
if (!emailConf.host && emailConf.usePlus == null) {
|
||||
if (isPlus()) {
|
||||
//自动使用plus发邮件
|
||||
return await this.sendByPlus(email);
|
||||
}
|
||||
throw new Error('邮件服务器还未设置');
|
||||
}
|
||||
|
||||
if (emailConf.usePlus && isPlus()) {
|
||||
return await this.sendByPlus(email);
|
||||
}
|
||||
await this.sendByCustom(emailConf, email);
|
||||
logger.info('sendEmail complete: ', email);
|
||||
}
|
||||
|
||||
private async sendByCustom(emailConfig: EmailConfig, email: EmailSend) {
|
||||
const transporter = nodemailer.createTransport(emailConfig);
|
||||
|
||||
let sysTitle = 'Certd';
|
||||
if (isComm()) {
|
||||
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
|
||||
@@ -93,10 +80,34 @@ export class EmailService implements IEmailService {
|
||||
if (!subject.includes(`【${sysTitle}】`)) {
|
||||
subject = `【${sysTitle}】${subject}`;
|
||||
}
|
||||
email.subject = subject;
|
||||
|
||||
const emailConf = await getEmailSettings(this.sysSettingsService, this.settingsService);
|
||||
|
||||
if (!emailConf.host && emailConf.usePlus == null) {
|
||||
if (isPlus()) {
|
||||
//自动使用plus发邮件
|
||||
return await this.sendByPlus(email);
|
||||
}
|
||||
throw new Error('邮件服务器还未设置');
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (emailConf.usePlus && isPlus()) {
|
||||
return await this.sendByPlus(email);
|
||||
}
|
||||
await this.sendByCustom(emailConf, email, sysTitle);
|
||||
logger.info('sendEmail complete: ', email);
|
||||
}
|
||||
|
||||
private async sendByCustom(emailConfig: EmailConfig, email: EmailSend, sysTitle: string) {
|
||||
const transporter = nodemailer.createTransport(emailConfig);
|
||||
|
||||
const mailOptions = {
|
||||
from: `${sysTitle} <${emailConfig.sender}>`,
|
||||
to: email.receivers.join(', '), // list of receivers
|
||||
subject: subject,
|
||||
subject: email.subject,
|
||||
text: email.content,
|
||||
html: email.html,
|
||||
attachments: email.attachments,
|
||||
@@ -105,30 +116,72 @@ export class EmailService implements IEmailService {
|
||||
}
|
||||
|
||||
async test(userId: number, receiver: string) {
|
||||
await this.send({
|
||||
receivers: [receiver],
|
||||
subject: '测试邮件,from certd',
|
||||
content: '测试邮件,from certd',
|
||||
await this.sendByTemplate({
|
||||
type:"common",
|
||||
data:{
|
||||
title: '测试邮件,from certd',
|
||||
content: '测试邮件,from certd',
|
||||
},
|
||||
email: {
|
||||
receivers: [receiver],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async list(userId: any) {
|
||||
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId,UserEmailSetting)
|
||||
return userEmailSetting.list;
|
||||
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, UserEmailSetting)
|
||||
return userEmailSetting.list;
|
||||
}
|
||||
|
||||
async delete(userId: any, email: string) {
|
||||
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId,UserEmailSetting)
|
||||
userEmailSetting.list = userEmailSetting.list.filter(item=>item !== email);
|
||||
await this.settingsService.saveSetting(userId,userEmailSetting)
|
||||
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, UserEmailSetting)
|
||||
userEmailSetting.list = userEmailSetting.list.filter(item => item !== email);
|
||||
await this.settingsService.saveSetting(userId, userEmailSetting)
|
||||
}
|
||||
async add(userId: any, email: string) {
|
||||
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId,UserEmailSetting)
|
||||
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, UserEmailSetting)
|
||||
//如果已存在
|
||||
if(userEmailSetting.list.includes(email)){
|
||||
if (userEmailSetting.list.includes(email)) {
|
||||
return
|
||||
}
|
||||
userEmailSetting.list.unshift(email)
|
||||
await this.settingsService.saveSetting(userId,userEmailSetting)
|
||||
await this.settingsService.saveSetting(userId, userEmailSetting)
|
||||
}
|
||||
|
||||
|
||||
async sendByTemplate(req: EmailSendByTemplateReq) {
|
||||
const emailConf = await this.sysSettingsService.getSetting<SysEmailConf>(SysEmailConf);
|
||||
|
||||
const template = emailConf?.templates?.[req.type]
|
||||
let content = null
|
||||
if (template && template.addonId) {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(template.addonId, true, 0)
|
||||
if (addon) {
|
||||
content = await addon.buildContent({ data: req.data })
|
||||
}
|
||||
}
|
||||
if (!content) {
|
||||
//看看有没有通用模版
|
||||
if (emailConf?.templates?.common && emailConf?.templates?.common.addonId) {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(emailConf.templates.common.addonId, true, 0)
|
||||
if (addon) {
|
||||
content = await addon.buildContent({ data: req.data })
|
||||
}
|
||||
}
|
||||
}
|
||||
// 没有找到模版,使用默认模版
|
||||
if (!content) {
|
||||
try {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getBlank(req.type, "默认")
|
||||
content = await addon.buildDefaultContent({ data: req.data })
|
||||
} catch (e) {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getBlank("common", "默认")
|
||||
content = await addon.buildDefaultContent({ data: req.data })
|
||||
}
|
||||
}
|
||||
return await this.send({
|
||||
...req.email,
|
||||
...content
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +268,8 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
url,
|
||||
title: `站点证书${fromIpCheck ? "(IP)" : ""}检查出错<${site.name}>`,
|
||||
content: `站点名称: ${site.name} \n站点域名: ${site.domain} \n错误信息:${site.error}`,
|
||||
errorMessage: site.error
|
||||
errorMessage: site.error,
|
||||
notificationType: "siteCheckError",
|
||||
}
|
||||
},
|
||||
site.userId
|
||||
@@ -295,7 +296,8 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
title: `站点证书即将过期,剩余${validDays}天,<${site.name}>`,
|
||||
content,
|
||||
url,
|
||||
errorMessage: "站点证书即将过期"
|
||||
errorMessage: "站点证书即将过期",
|
||||
notificationType: "siteCertExpireRemind",
|
||||
}
|
||||
},
|
||||
site.userId
|
||||
@@ -311,7 +313,8 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
title: `站点证书已过期${-validDays}天<${site.name}>`,
|
||||
content,
|
||||
url,
|
||||
errorMessage: "站点证书已过期"
|
||||
errorMessage: "站点证书已过期",
|
||||
notificationType: "siteCertExpireRemind",
|
||||
}
|
||||
},
|
||||
site.userId
|
||||
|
||||
@@ -62,4 +62,11 @@ export class AddonGetterService {
|
||||
return await this.getAddonById(id, true, userId);
|
||||
}
|
||||
|
||||
|
||||
async getBlank(type:string,name:string){
|
||||
return await this.getAddonById(null,false,0,{
|
||||
type,name
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,4 +39,5 @@ export * from './plugin-captcha/index.js'
|
||||
export * from './plugin-xinnet/index.js'
|
||||
export * from './plugin-xinnetconnet/index.js'
|
||||
export * from './plugin-oauth/index.js'
|
||||
export * from './plugin-cmcc/index.js'
|
||||
export * from './plugin-cmcc/index.js'
|
||||
export * from './plugin-template/index.js'
|
||||
@@ -132,6 +132,7 @@ nohup sh -c '$RESTART_CERT' >/dev/null 2>&1 & echo '10秒后重启' && exit
|
||||
title: `${this.repoName} 新版本 ${this.lastVersion} 发布`,
|
||||
content: `${body}\n\n > [Certd](https://certd.docmirror.cn),不止证书自动化,插件解锁无限可能!\n\n`,
|
||||
url: `https://github.com/${this.repoName}/releases/tag/${this.lastVersion}`,
|
||||
notificationType: "githubReleaseCheck",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,10 +21,23 @@ export class EmailNotification extends BaseNotification {
|
||||
receivers!: string[];
|
||||
|
||||
async send(body: NotificationBody) {
|
||||
await this.ctx.emailService.send({
|
||||
subject: body.title,
|
||||
content: body.content + '\n\n[查看详情](' + body.url + ')',
|
||||
receivers: this.receivers,
|
||||
});
|
||||
|
||||
const templateData = {
|
||||
...body,
|
||||
}
|
||||
await this.ctx.emailService.sendByTemplate({
|
||||
type: body.notificationType,
|
||||
data: templateData,
|
||||
email: {
|
||||
receivers: this.receivers,
|
||||
attachments: body.attachments,
|
||||
}
|
||||
})
|
||||
|
||||
// await this.ctx.emailService.send({
|
||||
// subject: body.title,
|
||||
// content: body.content + '\n\n[查看详情](' + body.url + ')',
|
||||
// receivers: this.receivers,
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,16 @@ export type BuildContentReq = {
|
||||
data: any;
|
||||
}
|
||||
|
||||
export type BuildContentReply = Record<string, string>;
|
||||
|
||||
export interface ITemplateProvider {
|
||||
buildContent: (params: BuildContentReq) => Promise<BuildContentReply>;
|
||||
}
|
||||
export interface ITemplateProvider<T=any> {
|
||||
buildContent: (params: BuildContentReq) => Promise<T>;
|
||||
|
||||
buildDefaultContent:(params: BuildContentReq) => Promise<T>;
|
||||
}
|
||||
|
||||
|
||||
export type EmailContent = {
|
||||
subject:string,
|
||||
content?:string,
|
||||
html?:string
|
||||
};
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './plugin-common.js'
|
||||
export * from './plugin-register-code.js'
|
||||
export * from './plugin-forgot-password.js'
|
||||
export * from './plugin-pipeline-result.js'
|
||||
@@ -1,52 +1,87 @@
|
||||
import { AddonInput, BaseAddon } from "@certd/lib-server";
|
||||
import { BuildContentReply, BuildContentReq, ITemplateProvider } from "../api.js";
|
||||
import { get } from "lodash-es";
|
||||
import { BuildContentReq, EmailContent, ITemplateProvider } from "../api.js";
|
||||
|
||||
|
||||
export class BaseEmailTemplateProvider extends BaseAddon implements ITemplateProvider {
|
||||
export class BaseEmailTemplateProvider extends BaseAddon implements ITemplateProvider<EmailContent> {
|
||||
@AddonInput({
|
||||
title: "配置说明",
|
||||
component:{
|
||||
name:"a-alert",
|
||||
props:{
|
||||
type:"info",
|
||||
message:"在标题和内容模版中,通过${param}引用参数,例如: 感谢注册${siteTitle},您的注册验证码为:${code}",
|
||||
component: {
|
||||
name: "a-alert",
|
||||
props: {
|
||||
type: "info",
|
||||
message: "在标题和内容模版中,通过${param}引用参数,例如: 感谢注册${siteTitle},您的注册验证码为:${code}",
|
||||
}
|
||||
},
|
||||
order: 1,
|
||||
col:{span:24},
|
||||
col: { span: 24 },
|
||||
})
|
||||
useIntro = "";
|
||||
|
||||
|
||||
@AddonInput({
|
||||
title: "邮件格式",
|
||||
component: {
|
||||
name: "a-select",
|
||||
props: {
|
||||
options: [
|
||||
{ label: "HTML", value: "html" },
|
||||
{ label: "TEXT", value: "text" },
|
||||
]
|
||||
}
|
||||
},
|
||||
order: 1,
|
||||
col: { span: 24 },
|
||||
})
|
||||
formatType = "";
|
||||
|
||||
@AddonInput({
|
||||
title: "邮件标题模版",
|
||||
required: true,
|
||||
order: 10,
|
||||
component: {
|
||||
name: "a-input",
|
||||
props: {
|
||||
placeholder: "邮件标题模版",
|
||||
}
|
||||
},
|
||||
col: { span: 24 },
|
||||
})
|
||||
titleTemplate = "";
|
||||
|
||||
@AddonInput({
|
||||
title: "邮件内容模版",
|
||||
component: {
|
||||
placeholder: "邮件内容模版",
|
||||
name: "a-textarea",
|
||||
rows: 6,
|
||||
},
|
||||
order: 20,
|
||||
col: { span: 24 },
|
||||
required: true,
|
||||
})
|
||||
contentTemplate = "";
|
||||
|
||||
|
||||
async buildContent(params: BuildContentReq) : Promise<BuildContentReply>{
|
||||
const title = this.compile(this.titleTemplate)(params.data)
|
||||
const content = this.compile(this.contentTemplate)(params.data)
|
||||
return {
|
||||
title,
|
||||
content,
|
||||
}
|
||||
async buildContent(params: BuildContentReq): Promise<EmailContent> {
|
||||
const title = this.compile(this.titleTemplate)(params.data)
|
||||
const content = this.compile(this.contentTemplate)(params.data)
|
||||
|
||||
const body: any = {
|
||||
subject: title,
|
||||
}
|
||||
if (this.formatType === "html") {
|
||||
body.html = content
|
||||
} else {
|
||||
body.content = content
|
||||
}
|
||||
return body
|
||||
};
|
||||
|
||||
async buildDefaultContent(params: BuildContentReq): Promise<EmailContent> {
|
||||
throw new Error("请实现 buildDefaultContent 方法")
|
||||
}
|
||||
|
||||
compile(templateString: string) {
|
||||
return function(data:any):string {
|
||||
return function (data: any): string {
|
||||
return templateString.replace(/\${(.*?)}/g, (match, key) => {
|
||||
const value = get(data, key, '');
|
||||
return String(value);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { AddonInput, IsAddon } from "@certd/lib-server";
|
||||
import { BuildContentReq, EmailContent, ITemplateProvider } from "../api.js";
|
||||
import { BaseEmailTemplateProvider } from "./plugin-base.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "emailTemplate",
|
||||
name: 'common',
|
||||
title: '通用邮件模版',
|
||||
desc: '通用邮件模版',
|
||||
icon: "simple-icons:email:blue",
|
||||
showTest: false,
|
||||
})
|
||||
export class CommonEmailTemplateProvider extends BaseEmailTemplateProvider implements ITemplateProvider<EmailContent> {
|
||||
@AddonInput({
|
||||
title: "可用参数",
|
||||
component: {
|
||||
name: "ParamsShow",
|
||||
params:[
|
||||
{labele:"标题",value:"title"},
|
||||
{labele:"内容",value:"content"},
|
||||
{labele:"URL",value:"url"}
|
||||
]
|
||||
},
|
||||
order: 5,
|
||||
col: { span: 24 },
|
||||
})
|
||||
paramIntro = "";
|
||||
|
||||
|
||||
async buildDefaultContent(req:BuildContentReq) {
|
||||
const defaultTemplate = new CommonEmailTemplateProvider()
|
||||
defaultTemplate.titleTemplate = "${title}"
|
||||
defaultTemplate.contentTemplate = "${content} \n\n 查看详情:${url}"
|
||||
defaultTemplate.formatType = "text"
|
||||
return await defaultTemplate.buildContent(req)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { AddonInput, IsAddon } from "@certd/lib-server";
|
||||
import { BuildContentReq, EmailContent, ITemplateProvider } from "../api.js";
|
||||
import { BaseEmailTemplateProvider } from "./plugin-base.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "emailTemplate",
|
||||
name: 'forgotPassword',
|
||||
title: '忘记密码邮件模版',
|
||||
desc: '忘记密码邮件模版',
|
||||
icon: "simple-icons:email:blue",
|
||||
showTest: false,
|
||||
})
|
||||
export class ForgotPasswordEmailTemplateProvider extends BaseEmailTemplateProvider implements ITemplateProvider<EmailContent> {
|
||||
@AddonInput({
|
||||
title: "可用参数",
|
||||
component: {
|
||||
name: "ParamsShow",
|
||||
params:[
|
||||
{labele:"验证码",value:"code"}
|
||||
]
|
||||
},
|
||||
order: 5,
|
||||
col: { span: 24 },
|
||||
})
|
||||
paramIntro = "";
|
||||
|
||||
|
||||
async buildDefaultContent(req:BuildContentReq) {
|
||||
const defaultTemplate = new ForgotPasswordEmailTemplateProvider()
|
||||
defaultTemplate.titleTemplate = "忘记密码"
|
||||
defaultTemplate.contentTemplate = "您的验证码是:${code},请勿泄露"
|
||||
defaultTemplate.formatType = "text"
|
||||
return await defaultTemplate.buildContent(req)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { AddonInput, IsAddon } from "@certd/lib-server";
|
||||
import { BuildContentReq, EmailContent, ITemplateProvider } from "../api.js";
|
||||
import { BaseEmailTemplateProvider } from "./plugin-base.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "emailTemplate",
|
||||
name: 'pipelineResult',
|
||||
title: '流水线执行结果邮件模版',
|
||||
desc: '流水线执行结果邮件模版',
|
||||
icon: "simple-icons:email:blue",
|
||||
showTest: false,
|
||||
})
|
||||
export class PipelineResultEmailTemplateProvider extends BaseEmailTemplateProvider implements ITemplateProvider<EmailContent> {
|
||||
@AddonInput({
|
||||
title: "可用参数",
|
||||
component: {
|
||||
name: "ParamsShow",
|
||||
params:[
|
||||
{labele:"运行结果",value:"pipelineResult"},
|
||||
{labele:"流水线标题",value:"pipelineTitle"},
|
||||
{labele:"流水线ID",value:"pipelineId"},
|
||||
{labele:"运行Id",value:"historyId"},
|
||||
{labele:"错误信息",value:"errors"},
|
||||
{labele:"URL",value:"url"},
|
||||
]
|
||||
},
|
||||
order: 5,
|
||||
col: { span: 24 },
|
||||
})
|
||||
paramIntro = "";
|
||||
|
||||
|
||||
async buildDefaultContent(req:BuildContentReq) {
|
||||
const defaultTemplate = new PipelineResultEmailTemplateProvider()
|
||||
|
||||
const subject = "${result},${pipelineTitle}【${pipelineId}】";
|
||||
const content = "流水线ID:${pipelineId},运行ID:${runtimeId} \n\n ${errors}";
|
||||
defaultTemplate.titleTemplate = subject
|
||||
defaultTemplate.contentTemplate = content
|
||||
defaultTemplate.formatType = "text"
|
||||
return await defaultTemplate.buildContent(req)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { AddonInput, IsAddon } from "@certd/lib-server";
|
||||
import { BuildContentReq, EmailContent, ITemplateProvider } from "../api.js";
|
||||
import { BaseEmailTemplateProvider } from "./plugin-base.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "emailTemplate",
|
||||
name: 'registerCode',
|
||||
title: '注册验证码邮件模版',
|
||||
desc: '注册验证码邮件模版',
|
||||
icon: "simple-icons:email:blue",
|
||||
showTest: false,
|
||||
})
|
||||
export class RegisterCodeEmailTemplateProvider extends BaseEmailTemplateProvider implements ITemplateProvider<EmailContent> {
|
||||
@AddonInput({
|
||||
title: "可用参数",
|
||||
component: {
|
||||
name: "ParamsShow",
|
||||
params:[
|
||||
{labele:"验证码",value:"code"}
|
||||
]
|
||||
},
|
||||
order: 5,
|
||||
col: { span: 24 },
|
||||
})
|
||||
paramIntro = "";
|
||||
|
||||
|
||||
async buildDefaultContent(req:BuildContentReq) {
|
||||
const defaultTemplate = new RegisterCodeEmailTemplateProvider()
|
||||
defaultTemplate.titleTemplate = "注册验证码"
|
||||
defaultTemplate.contentTemplate = "您的注册验证码是:${code},请勿泄露"
|
||||
defaultTemplate.formatType = "text"
|
||||
return await defaultTemplate.buildContent(req)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { AddonInput, IsAddon } from "@certd/lib-server";
|
||||
import { BaseEmailTemplateProvider } from "./plugin-base.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "emailTemplate",
|
||||
name: 'register',
|
||||
title: '注册邮件模版',
|
||||
desc: '注册邮件模版',
|
||||
icon:"simple-icons:gitee:red",
|
||||
showTest: false,
|
||||
})
|
||||
export class RegisterEmailTemplateProvider extends BaseEmailTemplateProvider {
|
||||
|
||||
@AddonInput({
|
||||
title: "可用参数",
|
||||
component:{
|
||||
name:"a-alert",
|
||||
props:{
|
||||
type:"info",
|
||||
message:"站点名称:${siteTitle};注册验证码:${code};有效期:${duration}分钟",
|
||||
}
|
||||
},
|
||||
order: 5,
|
||||
col:{span:24},
|
||||
})
|
||||
paramIntro = "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./email/index.js"
|
||||
Reference in New Issue
Block a user