mirror of https://github.com/certd/certd
perf: 支持手动上传证书并部署
parent
0069c0e399
commit
a9fffa5180
|
@ -33,6 +33,7 @@ export type ExecutorOptions = {
|
||||||
user: UserInfo;
|
user: UserInfo;
|
||||||
baseURL?: string;
|
baseURL?: string;
|
||||||
sysInfo?: SysInfo;
|
sysInfo?: SysInfo;
|
||||||
|
serviceGetter: (name: string) => any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Executor {
|
export class Executor {
|
||||||
|
|
|
@ -114,6 +114,9 @@ export type TaskInstanceContext = {
|
||||||
user: UserInfo;
|
user: UserInfo;
|
||||||
|
|
||||||
emitter: TaskEmitter;
|
emitter: TaskEmitter;
|
||||||
|
|
||||||
|
//service 容器
|
||||||
|
serviceContainer?: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||||
|
|
|
@ -23,6 +23,7 @@ export class CertReader {
|
||||||
cert: CertInfo;
|
cert: CertInfo;
|
||||||
|
|
||||||
detail: CertificateInfo;
|
detail: CertificateInfo;
|
||||||
|
//毫秒时间戳
|
||||||
expires: number;
|
expires: number;
|
||||||
constructor(certInfo: CertInfo) {
|
constructor(certInfo: CertInfo) {
|
||||||
this.cert = certInfo;
|
this.cert = certInfo;
|
||||||
|
@ -39,9 +40,13 @@ export class CertReader {
|
||||||
this.cert.one = this.cert.crt + "\n" + this.cert.key;
|
this.cert.one = this.cert.crt + "\n" + this.cert.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const { detail, expires } = this.getCrtDetail(this.cert.crt);
|
const { detail, expires } = this.getCrtDetail(this.cert.crt);
|
||||||
this.detail = detail;
|
this.detail = detail;
|
||||||
this.expires = expires.getTime();
|
this.expires = expires.getTime();
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error("证书解析失败:" + e.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getIc() {
|
getIc() {
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { IsTaskPlugin, pluginGroups, RunStrategy, Step, TaskInput } from "@certd/pipeline";
|
||||||
|
import type { CertInfo } from "../acme.js";
|
||||||
|
import { CertReader } from "../cert-reader.js";
|
||||||
|
import { CertApplyBasePlugin } from "../base.js";
|
||||||
|
|
||||||
|
export { CertReader };
|
||||||
|
export type { CertInfo };
|
||||||
|
|
||||||
|
@IsTaskPlugin({
|
||||||
|
name: "CertUpload",
|
||||||
|
icon: "ph:certificate",
|
||||||
|
title: "证书手动上传",
|
||||||
|
group: pluginGroups.cert.key,
|
||||||
|
desc: "在证书仓库手动上传后触发部署证书",
|
||||||
|
default: {
|
||||||
|
input: {
|
||||||
|
renewDays: 35,
|
||||||
|
forceUpdate: false,
|
||||||
|
},
|
||||||
|
strategy: {
|
||||||
|
runStrategy: RunStrategy.AlwaysRun,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export class CertUploadPlugin extends CertApplyBasePlugin {
|
||||||
|
@TaskInput({
|
||||||
|
title: "证书仓库ID",
|
||||||
|
component: {
|
||||||
|
name: "a-cert-select",
|
||||||
|
vModel: "value",
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
certInfoId!: string;
|
||||||
|
|
||||||
|
async onInstance() {
|
||||||
|
this.accessService = this.ctx.accessService;
|
||||||
|
this.logger = this.ctx.logger;
|
||||||
|
this.userContext = this.ctx.userContext;
|
||||||
|
this.lastStatus = this.ctx.lastStatus as Step;
|
||||||
|
}
|
||||||
|
async onInit(): Promise<void> {}
|
||||||
|
|
||||||
|
async doCertApply() {
|
||||||
|
const siteInfoService = this.ctx.serviceContainer["CertInfoService"];
|
||||||
|
|
||||||
|
const certInfo = await siteInfoService.getCertInfo({
|
||||||
|
certId: this.certInfoId,
|
||||||
|
userid: this.pipeline.userId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const certReader = new CertReader(certInfo);
|
||||||
|
if (!certReader.expires && certReader.expires < new Date().getTime()) {
|
||||||
|
throw new Error("证书已过期,停止部署");
|
||||||
|
}
|
||||||
|
|
||||||
|
return certReader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new CertUploadPlugin();
|
|
@ -4,6 +4,10 @@ export function createAccessApi(from = "user") {
|
||||||
const apiPrefix = from === "sys" ? "/sys/access" : "/pi/access";
|
const apiPrefix = from === "sys" ? "/sys/access" : "/pi/access";
|
||||||
return {
|
return {
|
||||||
async GetList(query: any) {
|
async GetList(query: any) {
|
||||||
|
if (query?.query) {
|
||||||
|
delete query.query.access;
|
||||||
|
}
|
||||||
|
|
||||||
return await request({
|
return await request({
|
||||||
url: apiPrefix + "/page",
|
url: apiPrefix + "/page",
|
||||||
method: "post",
|
method: "post",
|
||||||
|
|
|
@ -77,7 +77,7 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||||
type: "dict-select",
|
type: "dict-select",
|
||||||
dict: AccessTypeDictRef,
|
dict: AccessTypeDictRef,
|
||||||
search: {
|
search: {
|
||||||
show: false
|
show: true
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 200,
|
width: 200,
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, useFormWrapper, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, useFormWrapper, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||||
import { certInfoApi } from "./api";
|
import { certInfoApi } from "./api";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useUserStore } from "/@/store/modules/user";
|
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { useModal } from "/@/use/use-modal";
|
import { useModal } from "/@/use/use-modal";
|
||||||
import * as api from "/@/views/certd/pipeline/api";
|
|
||||||
import { notification } from "ant-design-vue";
|
import { notification } from "ant-design-vue";
|
||||||
import CertView from "/@/views/certd/pipeline/cert-view.vue";
|
import CertView from "/@/views/certd/pipeline/cert-view.vue";
|
||||||
|
|
||||||
|
@ -54,6 +52,69 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function openUpload(id?: any) {
|
||||||
|
function createCrudOptions() {
|
||||||
|
return {
|
||||||
|
crudOptions: {
|
||||||
|
request: {
|
||||||
|
// addRequest: async (form: any) => {
|
||||||
|
// return await api.Upload(form);
|
||||||
|
// },
|
||||||
|
// editRequest: async (form: any) => {
|
||||||
|
// return await api.Upload(form);
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
id: {
|
||||||
|
title: "ID",
|
||||||
|
type: "number",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cert.crt": {
|
||||||
|
title: "证书",
|
||||||
|
type: "textarea",
|
||||||
|
form: {
|
||||||
|
component: {
|
||||||
|
rows: 4
|
||||||
|
},
|
||||||
|
rules: [{ required: true, message: "此项必填" }],
|
||||||
|
col: { span: 24 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cert.key": {
|
||||||
|
title: "私钥",
|
||||||
|
type: "textarea",
|
||||||
|
form: {
|
||||||
|
component: {
|
||||||
|
rows: 4
|
||||||
|
},
|
||||||
|
rules: [{ required: true, message: "此项必填" }],
|
||||||
|
col: { span: 24 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
wrapper: {
|
||||||
|
title: "上传自定义证书"
|
||||||
|
},
|
||||||
|
async doSubmit({ form }: any) {
|
||||||
|
if (!id) {
|
||||||
|
delete form.id;
|
||||||
|
} else {
|
||||||
|
form.id = id;
|
||||||
|
}
|
||||||
|
return await api.Upload(form);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const { crudOptions } = createCrudOptions();
|
||||||
|
const wrapperRef = await openCrudFormDialog({ crudOptions });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
request: {
|
request: {
|
||||||
|
@ -83,64 +144,19 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
add: {
|
add: {
|
||||||
text: "上传自定义证书",
|
text: "上传自定义证书",
|
||||||
type: "primary",
|
type: "primary",
|
||||||
show: false,
|
show: true,
|
||||||
async click() {
|
async click() {
|
||||||
function createCrudOptions() {
|
await openUpload();
|
||||||
return {
|
|
||||||
crudOptions: {
|
|
||||||
request: {
|
|
||||||
addRequest: async (form: any) => {
|
|
||||||
return await api.Upload(form);
|
|
||||||
},
|
|
||||||
editRequest: async (form: any) => {
|
|
||||||
return await api.Upload(form);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
columns: {
|
|
||||||
id: {
|
|
||||||
title: "ID",
|
|
||||||
type: "number",
|
|
||||||
form: {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cert.crt": {
|
|
||||||
title: "证书",
|
|
||||||
type: "textarea",
|
|
||||||
form: {
|
|
||||||
component: {
|
|
||||||
rows: 4
|
|
||||||
},
|
|
||||||
rules: [{ required: true, message: "此项必填" }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cert.key": {
|
|
||||||
title: "私钥",
|
|
||||||
type: "textarea",
|
|
||||||
form: {
|
|
||||||
component: {
|
|
||||||
rows: 4
|
|
||||||
},
|
|
||||||
rules: [{ required: true, message: "此项必填" }]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
form: {
|
tabs: {
|
||||||
wrapper: {
|
name: "fromType",
|
||||||
title: "上传自定义证书"
|
show: true
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const { crudOptions } = createCrudOptions();
|
|
||||||
const wrapperRef = await openCrudFormDialog({ crudOptions });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
width: 100,
|
width: 140,
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
buttons: {
|
buttons: {
|
||||||
view: { show: false },
|
view: { show: false },
|
||||||
|
@ -155,7 +171,24 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
},
|
},
|
||||||
copy: { show: false },
|
copy: { show: false },
|
||||||
edit: { show: false },
|
edit: { show: false },
|
||||||
remove: { show: false }
|
upload: {
|
||||||
|
show: compute(({ row }) => {
|
||||||
|
return row.fromType === "upload";
|
||||||
|
}),
|
||||||
|
order: 4,
|
||||||
|
title: "更新证书",
|
||||||
|
type: "link",
|
||||||
|
icon: "ph:upload",
|
||||||
|
async click({ row }) {
|
||||||
|
await openUpload(row.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
order: 10,
|
||||||
|
show: compute(({ row }) => {
|
||||||
|
return row.fromType === "upload";
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
|
@ -176,25 +209,37 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// domain: {
|
fromType: {
|
||||||
// title: "主域名",
|
title: "来源",
|
||||||
// search: {
|
search: {
|
||||||
// show: true
|
show: true
|
||||||
// },
|
},
|
||||||
// type: "text",
|
type: "dict-select",
|
||||||
// form: {
|
dict: dict({
|
||||||
// show: false
|
data: [
|
||||||
// },
|
{ label: "流水线", value: "pipeline" },
|
||||||
// column: {
|
{ label: "手动上传", value: "upload" }
|
||||||
// width: 180,
|
]
|
||||||
// sorter: true,
|
}),
|
||||||
// component: {
|
form: {
|
||||||
// name: "fs-values-format"
|
show: false
|
||||||
// }
|
},
|
||||||
// }
|
column: {
|
||||||
// },
|
width: 100,
|
||||||
|
sorter: true,
|
||||||
|
component: {
|
||||||
|
color: "auto"
|
||||||
|
},
|
||||||
|
conditionalRender: false
|
||||||
|
},
|
||||||
|
valueBuilder({ value, row, key }) {
|
||||||
|
if (!value) {
|
||||||
|
row[key] = "pipeline";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
domains: {
|
domains: {
|
||||||
title: "全部域名",
|
title: "域名",
|
||||||
search: {
|
search: {
|
||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
|
|
|
@ -177,13 +177,13 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
align: "center",
|
align: "center",
|
||||||
width: 100
|
width: 110
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
certDomains: {
|
certDomains: {
|
||||||
title: "证书域名",
|
title: "证书域名",
|
||||||
search: {
|
search: {
|
||||||
show: false
|
show: true
|
||||||
},
|
},
|
||||||
type: "text",
|
type: "text",
|
||||||
form: {
|
form: {
|
||||||
|
@ -294,7 +294,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 100,
|
width: 110,
|
||||||
align: "center",
|
align: "center",
|
||||||
sorter: true
|
sorter: true
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 90,
|
width: 110,
|
||||||
sorter: true
|
sorter: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="title flex items-center">
|
<div class="title flex items-center">
|
||||||
站点证书监控
|
站点证书监控
|
||||||
<div class="sub flex-1">
|
<div class="sub flex-1">
|
||||||
<div>每天0点,检查网站证书的过期时间,并发出提醒;</div>
|
<div>每天0点,检查网站证书的过期时间,到期前10天时将发出提醒(使用默认通知渠道);</div>
|
||||||
<div class="flex items-center">基础版限制1条,专业版以上无限制,当前<vip-button class="ml-5" mode="nav"></vip-button></div>
|
<div class="flex items-center">基础版限制1条,专业版以上无限制,当前<vip-button class="ml-5" mode="nav"></vip-button></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -504,6 +504,20 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
|
||||||
width: 150
|
width: 150
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lastVars.certExpiresTime": {
|
||||||
|
title: "过期时间",
|
||||||
|
search: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
type: "datetime",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
sorter: true,
|
||||||
|
align: "center"
|
||||||
|
}
|
||||||
|
},
|
||||||
status: {
|
status: {
|
||||||
title: "状态",
|
title: "状态",
|
||||||
type: "dict-select",
|
type: "dict-select",
|
||||||
|
|
|
@ -24,11 +24,17 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||||
async page(@Body(ALL) body: any) {
|
async page(@Body(ALL) body: any) {
|
||||||
body.query = body.query ?? {};
|
body.query = body.query ?? {};
|
||||||
body.query.userId = this.getUserId();
|
body.query.userId = this.getUserId();
|
||||||
|
const domains = body.query?.domains;
|
||||||
|
delete body.query.domains;
|
||||||
const res = await this.service.page({
|
const res = await this.service.page({
|
||||||
query: body.query,
|
query: body.query,
|
||||||
page: body.page,
|
page: body.page,
|
||||||
sort: body.sort,
|
sort: body.sort,
|
||||||
|
buildQuery: (bq) => {
|
||||||
|
if (domains) {
|
||||||
|
bq.andWhere('domains like :domains', { domains: `%${domains}%` });
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const records = res.records;
|
const records = res.records;
|
||||||
|
@ -88,7 +94,11 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||||
@Post('/upload', { summary: Constants.per.authOnly })
|
@Post('/upload', { summary: Constants.per.authOnly })
|
||||||
async upload(@Body(ALL) body: any) {
|
async upload(@Body(ALL) body: any) {
|
||||||
if (body.id) {
|
if (body.id) {
|
||||||
|
//修改
|
||||||
await this.service.checkUserId(body.id, this.getUserId());
|
await this.service.checkUserId(body.id, this.getUserId());
|
||||||
|
}else{
|
||||||
|
//添加
|
||||||
|
body.userId = this.getUserId();
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await this.service.upload(body);
|
const res = await this.service.upload(body);
|
||||||
|
|
|
@ -10,9 +10,10 @@ export type UploadCertReq = {
|
||||||
id?: number;
|
id?: number;
|
||||||
certReader: CertReader;
|
certReader: CertReader;
|
||||||
fromType?: string;
|
fromType?: string;
|
||||||
|
userId?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
@Provide()
|
@Provide("CertInfoService")
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class CertInfoService extends BaseService<CertInfoEntity> {
|
export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||||
@InjectEntityModel(CertInfoEntity)
|
@InjectEntityModel(CertInfoEntity)
|
||||||
|
@ -147,7 +148,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||||
|
|
||||||
private async updateCert(req: UploadCertReq) {
|
private async updateCert(req: UploadCertReq) {
|
||||||
const bean = new CertInfoEntity();
|
const bean = new CertInfoEntity();
|
||||||
const { id, fromType, certReader } = req;
|
const { id, fromType,userId, certReader } = req;
|
||||||
if (id) {
|
if (id) {
|
||||||
bean.id = id;
|
bean.id = id;
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,13 +163,13 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||||
bean.domainCount = domains.length;
|
bean.domainCount = domains.length;
|
||||||
bean.expiresTime = certReader.expires;
|
bean.expiresTime = certReader.expires;
|
||||||
bean.certProvider = certReader.detail.issuer.commonName;
|
bean.certProvider = certReader.detail.issuer.commonName;
|
||||||
|
bean.userId = userId
|
||||||
await this.addOrUpdate(bean);
|
await this.addOrUpdate(bean);
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
async upload(body: { id?: number; cert: CertInfo }) {
|
async upload(body: { id?: number; userId?:number ;cert: CertInfo }) {
|
||||||
const { id, cert } = body;
|
const { id, userId, cert } = body;
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
throw new CommonException("cert can't be empty");
|
throw new CommonException("cert can't be empty");
|
||||||
}
|
}
|
||||||
|
@ -176,6 +177,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||||
id,
|
id,
|
||||||
certReader: new CertReader(cert),
|
certReader: new CertReader(cert),
|
||||||
fromType: 'upload',
|
fromType: 'upload',
|
||||||
|
userId
|
||||||
});
|
});
|
||||||
return res.id;
|
return res.id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,9 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
async sendExpiresNotify(site: SiteInfoEntity) {
|
async sendExpiresNotify(site: SiteInfoEntity) {
|
||||||
|
|
||||||
|
const tipDays = 10
|
||||||
|
|
||||||
const expires = site.certExpiresTime;
|
const expires = site.certExpiresTime;
|
||||||
const validDays = dayjs(expires).diff(dayjs(), 'day');
|
const validDays = dayjs(expires).diff(dayjs(), 'day');
|
||||||
const url = await this.notificationService.getBindUrl('#/monitor/site');
|
const url = await this.notificationService.getBindUrl('#/monitor/site');
|
||||||
|
@ -190,7 +193,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||||
证书域名: ${site.certDomains} \n
|
证书域名: ${site.certDomains} \n
|
||||||
证书颁发者: ${site.certProvider} \n
|
证书颁发者: ${site.certProvider} \n
|
||||||
过期时间: ${dayjs(site.certExpiresTime).format('YYYY-MM-DD')} \n`;
|
过期时间: ${dayjs(site.certExpiresTime).format('YYYY-MM-DD')} \n`;
|
||||||
if (validDays >= 0 && validDays < 10) {
|
if (validDays >= 0 && validDays < tipDays) {
|
||||||
// 发通知
|
// 发通知
|
||||||
await this.notificationService.send(
|
await this.notificationService.send(
|
||||||
{
|
{
|
||||||
|
|
|
@ -475,6 +475,12 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
|
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
|
||||||
sysInfo.title = siteInfo.title;
|
sysInfo.title = siteInfo.title;
|
||||||
}
|
}
|
||||||
|
const serviceContainer = {
|
||||||
|
CertInfoService: this.certInfoService
|
||||||
|
}
|
||||||
|
const serviceGetter = (name: string) => {
|
||||||
|
return serviceContainer[name]
|
||||||
|
}
|
||||||
const executor = new Executor({
|
const executor = new Executor({
|
||||||
user,
|
user,
|
||||||
pipeline,
|
pipeline,
|
||||||
|
@ -488,6 +494,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
notificationService: notificationGetter,
|
notificationService: notificationGetter,
|
||||||
fileRootDir: this.certdConfig.fileRootDir,
|
fileRootDir: this.certdConfig.fileRootDir,
|
||||||
sysInfo,
|
sysInfo,
|
||||||
|
serviceGetter
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
runningTasks.set(historyId, executor);
|
runningTasks.set(historyId, executor);
|
||||||
|
|
Loading…
Reference in New Issue