mirror of https://github.com/certd/certd
perf: OpenAPI支持autoApply参数
parent
609ac9c9a2
commit
42f4d1477d
|
@ -107,5 +107,13 @@ export const Constants = {
|
||||||
code: 20012,
|
code: 20012,
|
||||||
message: '证书还未生成',
|
message: '证书还未生成',
|
||||||
},
|
},
|
||||||
|
openCertApplying: {
|
||||||
|
code: 20013,
|
||||||
|
message: '证书正在申请中,请稍后重新获取(需要事先在“域名管理”页面配置好校验方式)',
|
||||||
|
},
|
||||||
|
openEmailNotFound: {
|
||||||
|
code: 20021,
|
||||||
|
message: '用户邮箱还未配置',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,13 +11,13 @@ export class CommonException extends BaseException {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CodeException extends BaseException {
|
export class CodeException extends BaseException {
|
||||||
constructor(res: { code: number; message: string }) {
|
constructor(res: { code: number; message: string; data?: any }) {
|
||||||
super("CodeException", res.code, res.message);
|
super("CodeException", res.code, res.message, res.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TextException extends BaseException {
|
export class TextException extends BaseException {
|
||||||
constructor(name, code,message, data?) {
|
constructor(name, code, message, data?) {
|
||||||
super(name, code, message, data);
|
super(name, code, message, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,6 +470,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||||
const domain = fullDomain.replaceAll("*.", "");
|
const domain = fullDomain.replaceAll("*.", "");
|
||||||
const mainDomain = await domainParser.parse(domain);
|
const mainDomain = await domainParser.parse(domain);
|
||||||
const planSetting: DomainVerifyPlanInput = verifyPlanSetting[mainDomain];
|
const planSetting: DomainVerifyPlanInput = verifyPlanSetting[mainDomain];
|
||||||
|
if (planSetting == null) {
|
||||||
|
throw new Error(`没有找到域名(${domain})的校验计划`);
|
||||||
|
}
|
||||||
if (planSetting.type === "dns") {
|
if (planSetting.type === "dns") {
|
||||||
plan[domain] = await this.createDnsDomainVerifyPlan(planSetting, domain, mainDomain);
|
plan[domain] = await this.createDnsDomainVerifyPlan(planSetting, domain, mainDomain);
|
||||||
} else if (planSetting.type === "cname") {
|
} else if (planSetting.type === "cname") {
|
||||||
|
@ -498,6 +501,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||||
|
|
||||||
for (const domain in verifiers) {
|
for (const domain in verifiers) {
|
||||||
const verifier = verifiers[domain];
|
const verifier = verifiers[domain];
|
||||||
|
if (verifier == null) {
|
||||||
|
throw new Error(`没有找到与该域名(${domain})匹配的校验方式,请先到‘域名管理’页面添加校验方式`);
|
||||||
|
}
|
||||||
if (verifier.type === "dns") {
|
if (verifier.type === "dns") {
|
||||||
plan[domain] = await this.createDnsDomainVerifyPlan(verifier.dns, domain, verifier.mainDomain);
|
plan[domain] = await this.createDnsDomainVerifyPlan(verifier.dns, domain, verifier.mainDomain);
|
||||||
} else if (verifier.type === "cname") {
|
} else if (verifier.type === "cname") {
|
||||||
|
|
|
@ -46,6 +46,20 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
|
|
||||||
const { openSiteIpMonitorDialog } = useSiteIpMonitor();
|
const { openSiteIpMonitorDialog } = useSiteIpMonitor();
|
||||||
const { openSiteImportDialog } = useSiteImport();
|
const { openSiteImportDialog } = useSiteImport();
|
||||||
|
|
||||||
|
function checkAll() {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t("certd.monitor.confirmTitle"), // "确认"
|
||||||
|
content: t("certd.monitor.confirmContent"), // "确认触发检查全部站点证书吗?"
|
||||||
|
onOk: async () => {
|
||||||
|
await siteInfoApi.CheckAll();
|
||||||
|
notification.success({
|
||||||
|
message: t("certd.monitor.checkSubmitted"), // "检查任务已提交"
|
||||||
|
description: t("certd.monitor.pleaseRefresh"), // "请稍后刷新页面查看结果"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
id: "siteMonitorCrud",
|
id: "siteMonitorCrud",
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
|
@ -114,6 +128,14 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
checkAll: {
|
||||||
|
show: true,
|
||||||
|
text: t("certd.monitor.checkAll"),
|
||||||
|
type: "primary",
|
||||||
|
click() {
|
||||||
|
checkAll();
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
|
|
|
@ -14,9 +14,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="more">
|
|
||||||
<a-button type="primary" @click="checkAll">{{ t("certd.monitor.checkAll") }}</a-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
|
@ -35,19 +32,6 @@ defineOptions({
|
||||||
name: "SiteCertMonitor",
|
name: "SiteCertMonitor",
|
||||||
});
|
});
|
||||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
|
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
|
||||||
function checkAll() {
|
|
||||||
Modal.confirm({
|
|
||||||
title: t("certd.monitor.confirmTitle"), // "确认"
|
|
||||||
content: t("certd.monitor.confirmContent"), // "确认触发检查全部站点证书吗?"
|
|
||||||
onOk: async () => {
|
|
||||||
await siteInfoApi.CheckAll();
|
|
||||||
notification.success({
|
|
||||||
message: t("certd.monitor.checkSubmitted"), // "检查任务已提交"
|
|
||||||
description: t("certd.monitor.pleaseRefresh"), // "请稍后刷新页面查看结果"
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 页面打开后获取列表数据
|
// 页面打开后获取列表数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
@ -125,6 +125,7 @@ export function useCertPipelineCreator() {
|
||||||
const pluginStore = usePluginStore();
|
const pluginStore = usePluginStore();
|
||||||
const randomHour = Math.floor(Math.random() * 6);
|
const randomHour = Math.floor(Math.random() * 6);
|
||||||
const randomMin = Math.floor(Math.random() * 60);
|
const randomMin = Math.floor(Math.random() * 60);
|
||||||
|
const randomCron = `0 ${randomMin} ${randomHour} * * *`;
|
||||||
|
|
||||||
const groupDictRef = dict({
|
const groupDictRef = dict({
|
||||||
url: "/pi/pipeline/group/all",
|
url: "/pi/pipeline/group/all",
|
||||||
|
@ -193,7 +194,7 @@ export function useCertPipelineCreator() {
|
||||||
title: t("certd.pipelineForm.triggerCronTitle"),
|
title: t("certd.pipelineForm.triggerCronTitle"),
|
||||||
type: "text",
|
type: "text",
|
||||||
form: {
|
form: {
|
||||||
value: `0 ${randomMin} ${randomHour} * * *`,
|
value: randomCron,
|
||||||
component: {
|
component: {
|
||||||
name: "cron-editor",
|
name: "cron-editor",
|
||||||
vModel: "modelValue",
|
vModel: "modelValue",
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core';
|
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||||
import { CodeException, Constants, EncryptService } from '@certd/lib-server';
|
import { CodeException, Constants, EncryptService } from "@certd/lib-server";
|
||||||
import { CertInfoService } from '../../../modules/monitor/service/cert-info-service.js';
|
import { CertInfo } from "@certd/plugin-cert";
|
||||||
import { CertInfo } from '@certd/plugin-cert';
|
import { OpenKey } from "../../../modules/open/service/open-key-service.js";
|
||||||
import { OpenKey } from '../../../modules/open/service/open-key-service.js';
|
import { BaseOpenController } from "../base-open-controller.js";
|
||||||
import { BaseOpenController } from '../base-open-controller.js';
|
import { CertInfoFacade } from "../../../modules/monitor/facade/cert-info-facade.js";
|
||||||
|
import { merge } from "lodash-es";
|
||||||
|
|
||||||
export type CertGetReq = {
|
export type CertGetReq = {
|
||||||
domains?: string;
|
domains?: string;
|
||||||
certId: number;
|
certId: number;
|
||||||
|
autoApply?:boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +18,7 @@ export type CertGetReq = {
|
||||||
@Controller('/api/v1/cert')
|
@Controller('/api/v1/cert')
|
||||||
export class OpenCertController extends BaseOpenController {
|
export class OpenCertController extends BaseOpenController {
|
||||||
@Inject()
|
@Inject()
|
||||||
certInfoService: CertInfoService;
|
certInfoFacade: CertInfoFacade;
|
||||||
@Inject()
|
@Inject()
|
||||||
encryptService: EncryptService;
|
encryptService: EncryptService;
|
||||||
|
|
||||||
|
@ -29,10 +31,13 @@ export class OpenCertController extends BaseOpenController {
|
||||||
throw new CodeException(Constants.res.openKeyError);
|
throw new CodeException(Constants.res.openKeyError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const res: CertInfo = await this.certInfoService.getCertInfo({
|
const req = merge({}, bean, query)
|
||||||
|
|
||||||
|
const res: CertInfo = await this.certInfoFacade.getCertInfo({
|
||||||
userId,
|
userId,
|
||||||
domains: bean.domains || query.domains,
|
domains: req.domains,
|
||||||
certId: bean.certId || query.certId,
|
certId: req.certId,
|
||||||
|
autoApply: req.autoApply??false,
|
||||||
});
|
});
|
||||||
return this.ok(res);
|
return this.ok(res);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||||
|
import { CodeException, Constants } from "@certd/lib-server";
|
||||||
|
import { CertInfoEntity } from "../entity/cert-info.js";
|
||||||
|
import { utils } from "@certd/basic";
|
||||||
|
import { PipelineService } from "../../pipeline/service/pipeline-service.js";
|
||||||
|
import { UserSettingsService } from "../../mine/service/user-settings-service.js";
|
||||||
|
import { UserEmailSetting } from "../../mine/service/models.js";
|
||||||
|
import { PipelineEntity } from "../../pipeline/entity/pipeline.js";
|
||||||
|
import { CertInfoService } from "../service/cert-info-service.js";
|
||||||
|
|
||||||
|
|
||||||
|
@Provide("CertInfoFacade")
|
||||||
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
|
export class CertInfoFacade {
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
pipelineService: PipelineService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
certInfoService: CertInfoService ;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
userSettingsService : UserSettingsService
|
||||||
|
|
||||||
|
async getCertInfo(req: { domains?: string; certId?: number; userId: number,autoApply?:boolean }) {
|
||||||
|
const { domains, certId, userId } = req;
|
||||||
|
if (certId) {
|
||||||
|
return await this.certInfoService.getCertInfoById({ id: certId, userId });
|
||||||
|
}
|
||||||
|
const domainArr = domains.split(',');
|
||||||
|
|
||||||
|
const matchedList = await this.certInfoService.getMatchCertList({domains:domainArr,userId})
|
||||||
|
let matched: CertInfoEntity = null
|
||||||
|
if (matchedList.length === 0 ) {
|
||||||
|
if(req.autoApply === true){
|
||||||
|
//自动申请,先创建自动申请流水线
|
||||||
|
const pipeline:PipelineEntity = await this.createAutoPipeline({domains:domainArr,userId})
|
||||||
|
await this.triggerApplyPipeline({pipelineId:pipeline.id})
|
||||||
|
}else{
|
||||||
|
throw new CodeException(Constants.res.openCertNotFound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
matched = null;
|
||||||
|
for (const item of matchedList) {
|
||||||
|
if (item.expiresTime>0 && item.expiresTime < new Date().getTime()) {
|
||||||
|
matched = item;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!matched) {
|
||||||
|
if(req.autoApply === true){
|
||||||
|
//如果没有找到有效期内的证书,则自动触发一次申请
|
||||||
|
const first = matchedList[0]
|
||||||
|
await this.triggerApplyPipeline({pipelineId:first.pipelineId})
|
||||||
|
return
|
||||||
|
}else{
|
||||||
|
throw new CodeException(Constants.res.openCertNotFound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.certInfoService.getCertInfoById({ id: matched.id, userId: userId });
|
||||||
|
}
|
||||||
|
|
||||||
|
async createAutoPipeline(req:{domains:string[],userId:number}){
|
||||||
|
const userEmailSetting = await this.userSettingsService.getSetting<UserEmailSetting>(req.userId,UserEmailSetting)
|
||||||
|
if(!userEmailSetting.list){
|
||||||
|
throw new CodeException(Constants.res.openEmailNotFound)
|
||||||
|
}
|
||||||
|
const email = userEmailSetting.list[0]
|
||||||
|
|
||||||
|
return await this.pipelineService.createAutoPipeline({
|
||||||
|
domains: req.domains,
|
||||||
|
email,
|
||||||
|
userId: req.userId,
|
||||||
|
from:"OpenAPI"
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async triggerApplyPipeline(req:{pipelineId:number}){
|
||||||
|
//查询流水线状态
|
||||||
|
const status = await this.pipelineService.getStatus(req.pipelineId)
|
||||||
|
if (status != 'running') {
|
||||||
|
await this.pipelineService.trigger(req.pipelineId)
|
||||||
|
await utils.sleep(1000)
|
||||||
|
}
|
||||||
|
throw new CodeException({
|
||||||
|
...Constants.res.openCertApplying,
|
||||||
|
data:{
|
||||||
|
pipelineId:req.pipelineId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
import {Provide, Scope, ScopeEnum} from "@midwayjs/core";
|
import { Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||||
import {BaseService, CodeException, Constants, PageReq} from "@certd/lib-server";
|
import { BaseService, CodeException, Constants, PageReq } from "@certd/lib-server";
|
||||||
import {InjectEntityModel} from "@midwayjs/typeorm";
|
import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||||
import {MoreThan, Repository} from "typeorm";
|
import { Repository } from "typeorm";
|
||||||
import {CertInfoEntity} from "../entity/cert-info.js";
|
import { CertInfoEntity } from "../entity/cert-info.js";
|
||||||
import {utils} from "@certd/basic";
|
import { utils } from "@certd/basic";
|
||||||
import {CertInfo, CertReader} from "@certd/plugin-cert";
|
import { CertInfo, CertReader } from "@certd/plugin-cert";
|
||||||
|
|
||||||
export type UploadCertReq = {
|
export type UploadCertReq = {
|
||||||
id?: number;
|
id?: number;
|
||||||
|
@ -71,6 +71,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.addOrUpdate(bean);
|
await this.addOrUpdate(bean);
|
||||||
|
return bean.id
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteByPipelineId(id: number) {
|
async deleteByPipelineId(id: number) {
|
||||||
|
@ -82,44 +83,28 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCertInfo(params: { domains?: string; certId?: number; userId: number }) {
|
async getMatchCertList(params: { domains: string[]; userId: number }) {
|
||||||
const { domains, certId, userId } = params;
|
|
||||||
if (certId) {
|
|
||||||
return await this.getCertInfoById({ id: certId, userId });
|
|
||||||
}
|
|
||||||
return await this.getCertInfoByDomains({
|
|
||||||
domains,
|
|
||||||
userId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getCertInfoByDomains(params: { domains: string; userId: number }) {
|
|
||||||
const { domains, userId } = params;
|
const { domains, userId } = params;
|
||||||
if (!domains) {
|
if (!domains) {
|
||||||
throw new CodeException(Constants.res.openCertNotFound);
|
throw new CodeException(Constants.res.openCertNotFound);
|
||||||
}
|
}
|
||||||
const domainArr = domains.split(',');
|
|
||||||
|
|
||||||
const list = await this.find({
|
const list = await this.find({
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
domains: true,
|
domains: true,
|
||||||
|
expiresTime:true,
|
||||||
|
pipelineId:true,
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
userId,
|
userId,
|
||||||
expiresTime: MoreThan(new Date().getTime())
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
//遍历查找
|
//遍历查找
|
||||||
const matched = list.find(item => {
|
return list.filter(item => {
|
||||||
const itemDomains = item.domains.split(',');
|
const itemDomains = item.domains.split(',');
|
||||||
return utils.domain.match(domainArr, itemDomains);
|
return utils.domain.match(domains, itemDomains);
|
||||||
});
|
});
|
||||||
if (!matched) {
|
|
||||||
throw new CodeException(Constants.res.openCertNotFound);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.getCertInfoById({ id: matched.id, userId: userId });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCertInfoById(req: { id: number; userId: number }) {
|
async getCertInfoById(req: { id: number; userId: number }) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {Config, Inject, Provide, Scope, ScopeEnum, sleep} from "@midwayjs/core";
|
import { Config, Inject, Provide, Scope, ScopeEnum, sleep } from "@midwayjs/core";
|
||||||
import {InjectEntityModel} from "@midwayjs/typeorm";
|
import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||||
import {In, MoreThan, Repository} from "typeorm";
|
import { In, MoreThan, Repository } from "typeorm";
|
||||||
import {
|
import {
|
||||||
AccessService,
|
AccessService,
|
||||||
BaseService,
|
BaseService,
|
||||||
|
@ -11,8 +11,8 @@ import {
|
||||||
SysSettingsService,
|
SysSettingsService,
|
||||||
SysSiteInfo
|
SysSiteInfo
|
||||||
} from "@certd/lib-server";
|
} from "@certd/lib-server";
|
||||||
import {PipelineEntity} from "../entity/pipeline.js";
|
import { PipelineEntity } from "../entity/pipeline.js";
|
||||||
import {PipelineDetail} from "../entity/vo/pipeline-detail.js";
|
import { PipelineDetail } from "../entity/vo/pipeline-detail.js";
|
||||||
import {
|
import {
|
||||||
Executor,
|
Executor,
|
||||||
IAccessService,
|
IAccessService,
|
||||||
|
@ -25,33 +25,32 @@ import {
|
||||||
SysInfo,
|
SysInfo,
|
||||||
UserInfo
|
UserInfo
|
||||||
} from "@certd/pipeline";
|
} from "@certd/pipeline";
|
||||||
import {DbStorage} from "./db-storage.js";
|
import { DbStorage } from "./db-storage.js";
|
||||||
import {StorageService} from "./storage-service.js";
|
import { StorageService } from "./storage-service.js";
|
||||||
import {Cron} from "../../cron/cron.js";
|
import { Cron } from "../../cron/cron.js";
|
||||||
import {HistoryService} from "./history-service.js";
|
import { HistoryService } from "./history-service.js";
|
||||||
import {HistoryEntity} from "../entity/history.js";
|
import { HistoryEntity } from "../entity/history.js";
|
||||||
import {HistoryLogEntity} from "../entity/history-log.js";
|
import { HistoryLogEntity } from "../entity/history-log.js";
|
||||||
import {HistoryLogService} from "./history-log-service.js";
|
import { HistoryLogService } from "./history-log-service.js";
|
||||||
import {EmailService} from "../../basic/service/email-service.js";
|
import { EmailService } from "../../basic/service/email-service.js";
|
||||||
import {UserService} from "../../sys/authority/service/user-service.js";
|
import { UserService } from "../../sys/authority/service/user-service.js";
|
||||||
import {CnameRecordService} from "../../cname/service/cname-record-service.js";
|
import { CnameRecordService } from "../../cname/service/cname-record-service.js";
|
||||||
import {PluginConfigGetter} from "../../plugin/service/plugin-config-getter.js";
|
import { PluginConfigGetter } from "../../plugin/service/plugin-config-getter.js";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {DbAdapter} from "../../db/index.js";
|
import { DbAdapter } from "../../db/index.js";
|
||||||
import {isComm, isPlus} from "@certd/plus-core";
|
import { isComm, isPlus } from "@certd/plus-core";
|
||||||
import {logger} from "@certd/basic";
|
import { logger } from "@certd/basic";
|
||||||
import {UrlService} from "./url-service.js";
|
import { UrlService } from "./url-service.js";
|
||||||
import {NotificationService} from "./notification-service.js";
|
import { NotificationService } from "./notification-service.js";
|
||||||
import {UserSuiteEntity, UserSuiteService} from "@certd/commercial-core";
|
import { UserSuiteEntity, UserSuiteService } from "@certd/commercial-core";
|
||||||
import {CertInfoService} from "../../monitor/service/cert-info-service.js";
|
import { CertInfoService } from "../../monitor/service/cert-info-service.js";
|
||||||
import {TaskServiceBuilder} from "./getter/task-service-getter.js";
|
import { TaskServiceBuilder } from "./getter/task-service-getter.js";
|
||||||
import {nanoid} from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import {set} from "lodash-es";
|
import { set } from "lodash-es";
|
||||||
|
|
||||||
const runningTasks: Map<string | number, Executor> = new Map();
|
const runningTasks: Map<string | number, Executor> = new Map();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 证书申请
|
* 证书申请
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +90,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
@Inject()
|
@Inject()
|
||||||
cron: Cron;
|
cron: Cron;
|
||||||
|
|
||||||
@Config('certd')
|
@Config("certd")
|
||||||
private certdConfig: any;
|
private certdConfig: any;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
|
@ -112,31 +111,31 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async add(bean: PipelineEntity) {
|
async add(bean: PipelineEntity) {
|
||||||
bean.status = ResultType.none
|
bean.status = ResultType.none;
|
||||||
await this.save(bean);
|
await this.save(bean);
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
async page(pageReq: PageReq<PipelineEntity>) {
|
async page(pageReq: PageReq<PipelineEntity>) {
|
||||||
//模版流水线不要被查询出来
|
//模版流水线不要被查询出来
|
||||||
set(pageReq,"query.isTemplate",false)
|
set(pageReq, "query.isTemplate", false);
|
||||||
const result = await super.page(pageReq);
|
const result = await super.page(pageReq);
|
||||||
await this.fillLastVars(result.records);
|
await this.fillLastVars(result.records);
|
||||||
|
|
||||||
for (const item of result.records) {
|
for (const item of result.records) {
|
||||||
if (!item.content){
|
if (!item.content) {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
const pipeline = JSON.parse(item.content);
|
const pipeline = JSON.parse(item.content);
|
||||||
let stepCount = 0
|
let stepCount = 0;
|
||||||
RunnableCollection.each(pipeline.stages, (runnable: any) => {
|
RunnableCollection.each(pipeline.stages, (runnable: any) => {
|
||||||
stepCount++
|
stepCount++;
|
||||||
})
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
item.stepCount = stepCount
|
item.stepCount = stepCount;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
item.triggerCount = pipeline.triggers.length
|
item.triggerCount = pipeline.triggers.length;
|
||||||
delete item.content
|
delete item.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -148,7 +147,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
for (const record of records) {
|
for (const record of records) {
|
||||||
pipelineIds.push(record.id);
|
pipelineIds.push(record.id);
|
||||||
recordMap[record.id] = record;
|
recordMap[record.id] = record;
|
||||||
record.title = record.title + '';
|
record.title = record.title + "";
|
||||||
}
|
}
|
||||||
if (pipelineIds?.length > 0) {
|
if (pipelineIds?.length > 0) {
|
||||||
const vars = await this.storageService.findPipelineVars(pipelineIds);
|
const vars = await this.storageService.findPipelineVars(pipelineIds);
|
||||||
|
@ -169,17 +168,17 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
const info = await this.info(pipelineId);
|
const info = await this.info(pipelineId);
|
||||||
if (info && !info.disabled) {
|
if (info && !info.disabled) {
|
||||||
const pipeline = JSON.parse(info.content);
|
const pipeline = JSON.parse(info.content);
|
||||||
this.registerTriggers(pipeline,false);
|
this.registerTriggers(pipeline, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async registerTrigger(info:PipelineEntity) {
|
public async registerTrigger(info: PipelineEntity) {
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (info && !info.disabled) {
|
if (info && !info.disabled) {
|
||||||
const pipeline = JSON.parse(info.content);
|
const pipeline = JSON.parse(info.content);
|
||||||
this.registerTriggers(pipeline,false);
|
this.registerTriggers(pipeline, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,12 +205,12 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
const isUpdate = bean.id > 0 && old != null;
|
const isUpdate = bean.id > 0 && old != null;
|
||||||
|
|
||||||
|
|
||||||
const pipeline = JSON.parse(bean.content || '{}');
|
const pipeline = JSON.parse(bean.content || "{}");
|
||||||
RunnableCollection.initPipelineRunnableType(pipeline);
|
RunnableCollection.initPipelineRunnableType(pipeline);
|
||||||
let domains = [];
|
let domains = [];
|
||||||
if (pipeline.stages) {
|
if (pipeline.stages) {
|
||||||
RunnableCollection.each(pipeline.stages, (runnable: any) => {
|
RunnableCollection.each(pipeline.stages, (runnable: any) => {
|
||||||
if (runnable.runnableType === 'step' && runnable.type.indexOf('CertApply')>=0) {
|
if (runnable.runnableType === "step" && runnable.type.indexOf("CertApply") >= 0) {
|
||||||
domains = runnable.input.domains || [];
|
domains = runnable.input.domains || [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -222,7 +221,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
await this.checkMaxPipelineCount(bean, pipeline, domains);
|
await this.checkMaxPipelineCount(bean, pipeline, domains);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bean.status ){
|
if (!bean.status) {
|
||||||
bean.status = ResultType.none;
|
bean.status = ResultType.none;
|
||||||
}
|
}
|
||||||
if (!isUpdate) {
|
if (!isUpdate) {
|
||||||
|
@ -233,9 +232,11 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
await this.doUpdatePipelineJson(bean, pipeline);
|
await this.doUpdatePipelineJson(bean, pipeline);
|
||||||
|
|
||||||
//保存域名信息到certInfo表
|
//保存域名信息到certInfo表
|
||||||
let fromType = 'pipeline';
|
let fromType = "pipeline";
|
||||||
if (bean.type === 'cert_upload') {
|
if (bean.type === "cert_upload") {
|
||||||
fromType = 'upload';
|
fromType = "upload";
|
||||||
|
}else if (bean.type === "cert_auto") {
|
||||||
|
fromType = "auto";
|
||||||
}
|
}
|
||||||
await this.certInfoService.updateDomains(pipeline.id, pipeline.userId || bean.userId, domains, fromType);
|
await this.certInfoService.updateDomains(pipeline.id, pipeline.userId || bean.userId, domains, fromType);
|
||||||
return bean;
|
return bean;
|
||||||
|
@ -246,7 +247,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
* @param bean
|
* @param bean
|
||||||
* @param pipeline
|
* @param pipeline
|
||||||
*/
|
*/
|
||||||
async doUpdatePipelineJson(bean: PipelineEntity, pipeline:Pipeline) {
|
async doUpdatePipelineJson(bean: PipelineEntity, pipeline: Pipeline) {
|
||||||
await this.clearTriggers(bean);
|
await this.clearTriggers(bean);
|
||||||
if (pipeline.title) {
|
if (pipeline.title) {
|
||||||
bean.title = pipeline.title;
|
bean.title = pipeline.title;
|
||||||
|
@ -277,7 +278,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
throw new NeedSuiteException(`对不起,您最多只能添加${userSuite.domainCount.max}个域名,请购买或升级套餐`);
|
throw new NeedSuiteException(`对不起,您最多只能添加${userSuite.domainCount.max}个域名,请购买或升级套餐`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
//非商业版校验用户最大流水线数量
|
//非商业版校验用户最大流水线数量
|
||||||
const userId = bean.userId;
|
const userId = bean.userId;
|
||||||
const userIsAdmin = await this.userService.isAdmin(userId);
|
const userIsAdmin = await this.userService.isAdmin(userId);
|
||||||
|
@ -296,12 +297,12 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
async foreachPipeline(callback: (pipeline: PipelineEntity) => void) {
|
async foreachPipeline(callback: (pipeline: PipelineEntity) => void) {
|
||||||
const idEntityList = await this.repository.find({
|
const idEntityList = await this.repository.find({
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
templateId: 0,
|
templateId: 0
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
const ids = idEntityList.map(item => {
|
const ids = idEntityList.map(item => {
|
||||||
return item.id;
|
return item.id;
|
||||||
|
@ -321,7 +322,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
//分段加载记录
|
//分段加载记录
|
||||||
for (const idArr of idsSpan) {
|
for (const idArr of idsSpan) {
|
||||||
const list = await this.repository.findBy({
|
const list = await this.repository.findBy({
|
||||||
id: In(idArr),
|
id: In(idArr)
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const entity of list) {
|
for (const entity of list) {
|
||||||
|
@ -346,14 +347,14 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
if (onlyAdminUser && entity.userId !== 1) {
|
if (onlyAdminUser && entity.userId !== 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const pipeline = JSON.parse(entity.content ?? '{}');
|
const pipeline = JSON.parse(entity.content ?? "{}");
|
||||||
try {
|
try {
|
||||||
await this.registerTriggers(pipeline, immediateTriggerOnce);
|
await this.registerTriggers(pipeline, immediateTriggerOnce);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('加载定时trigger失败:', e);
|
logger.error("加载定时trigger失败:", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
logger.info('定时器数量:', this.cron.getTaskSize());
|
logger.info("定时器数量:", this.cron.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerTriggers(pipeline?: Pipeline, immediateTriggerOnce = false) {
|
async registerTriggers(pipeline?: Pipeline, immediateTriggerOnce = false) {
|
||||||
|
@ -375,18 +376,18 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
if (isComm()) {
|
if (isComm()) {
|
||||||
await this.checkHasDeployCount(id, entity.userId);
|
await this.checkHasDeployCount(id, entity.userId);
|
||||||
}
|
}
|
||||||
await this.checkUserStatus(entity.userId)
|
await this.checkUserStatus(entity.userId);
|
||||||
this.cron.register({
|
this.cron.register({
|
||||||
name: `pipeline.${id}.trigger.once`,
|
name: `pipeline.${id}.trigger.once`,
|
||||||
cron: null,
|
cron: null,
|
||||||
job: async () => {
|
job: async () => {
|
||||||
logger.info('用户手动启动job');
|
logger.info("用户手动启动job");
|
||||||
try {
|
try {
|
||||||
await this.doRun(entity, null, stepId);
|
await this.doRun(entity, null, stepId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('手动job执行失败:', e);
|
logger.error("手动job执行失败:", e);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,7 +399,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
logger.error(e.message);
|
logger.error(e.message);
|
||||||
await this.update({
|
await this.update({
|
||||||
id: pipelineId,
|
id: pipelineId,
|
||||||
status: 'no_deploy_count',
|
status: "no_deploy_count"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -406,7 +407,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
async delete(id:any) {
|
async delete(id: any) {
|
||||||
await this.clearTriggers(id);
|
await this.clearTriggers(id);
|
||||||
//TODO 删除storage
|
//TODO 删除storage
|
||||||
// const storage = new DbStorage(pipeline.userId, this.storageService);
|
// const storage = new DbStorage(pipeline.userId, this.storageService);
|
||||||
|
@ -421,11 +422,11 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let pipeline:PipelineEntity = null
|
let pipeline: PipelineEntity = null;
|
||||||
if (typeof id === 'number') {
|
if (typeof id === "number") {
|
||||||
pipeline = await this.info(id);
|
pipeline = await this.info(id);
|
||||||
}else{
|
} else {
|
||||||
pipeline = id
|
pipeline = id;
|
||||||
}
|
}
|
||||||
if (!pipeline) {
|
if (!pipeline) {
|
||||||
return;
|
return;
|
||||||
|
@ -445,7 +446,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
|
|
||||||
registerCron(pipelineId, trigger) {
|
registerCron(pipelineId, trigger) {
|
||||||
if (pipelineId == null) {
|
if (pipelineId == null) {
|
||||||
logger.warn('pipelineId为空,无法注册定时任务');
|
logger.warn("pipelineId为空,无法注册定时任务");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,11 +455,11 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cron = cron.trim();
|
cron = cron.trim();
|
||||||
if (cron.startsWith('* *')) {
|
if (cron.startsWith("* *")) {
|
||||||
cron = cron.replace('* *', '0 0');
|
cron = cron.replace("* *", "0 0");
|
||||||
}
|
}
|
||||||
if (cron.startsWith('*')) {
|
if (cron.startsWith("*")) {
|
||||||
cron = cron.replace('*', '0');
|
cron = cron.replace("*", "0");
|
||||||
}
|
}
|
||||||
const triggerId = trigger.id;
|
const triggerId = trigger.id;
|
||||||
const name = this.buildCronKey(pipelineId, triggerId);
|
const name = this.buildCronKey(pipelineId, triggerId);
|
||||||
|
@ -467,19 +468,19 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
name,
|
name,
|
||||||
cron,
|
cron,
|
||||||
job: async () => {
|
job: async () => {
|
||||||
logger.info('定时任务触发:', pipelineId, triggerId);
|
logger.info("定时任务触发:", pipelineId, triggerId);
|
||||||
if (pipelineId == null) {
|
if (pipelineId == null) {
|
||||||
logger.warn('pipelineId为空,无法执行');
|
logger.warn("pipelineId为空,无法执行");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.run(pipelineId, triggerId);
|
await this.run(pipelineId, triggerId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('定时job执行失败:', e);
|
logger.error("定时job执行失败:", e);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
logger.info('当前定时器数量:', this.cron.getTaskSize());
|
logger.info("当前定时器数量:", this.cron.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -499,11 +500,11 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
if (isComm()) {
|
if (isComm()) {
|
||||||
suite = await this.checkHasDeployCount(id, entity.userId);
|
suite = await this.checkHasDeployCount(id, entity.userId);
|
||||||
}
|
}
|
||||||
try{
|
try {
|
||||||
await this.checkUserStatus(entity.userId)
|
await this.checkUserStatus(entity.userId);
|
||||||
}catch (e) {
|
} catch (e) {
|
||||||
logger.info(e.message)
|
logger.info(e.message);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -521,7 +522,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (triggerType === 'timer') {
|
if (triggerType === "timer") {
|
||||||
if (entity.disabled) {
|
if (entity.disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -530,25 +531,25 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
const onChanged = async (history: RunHistory) => {
|
const onChanged = async (history: RunHistory) => {
|
||||||
//保存执行历史
|
//保存执行历史
|
||||||
try {
|
try {
|
||||||
logger.info('保存执行历史:', history.id);
|
logger.info("保存执行历史:", history.id);
|
||||||
await this.saveHistory(history);
|
await this.saveHistory(history);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const pipelineEntity = new PipelineEntity();
|
const pipelineEntity = new PipelineEntity();
|
||||||
pipelineEntity.id = id;
|
pipelineEntity.id = id;
|
||||||
pipelineEntity.status = 'error';
|
pipelineEntity.status = "error";
|
||||||
pipelineEntity.lastHistoryTime = history.pipeline.status.startTime;
|
pipelineEntity.lastHistoryTime = history.pipeline.status.startTime;
|
||||||
await this.update(pipelineEntity);
|
await this.update(pipelineEntity);
|
||||||
logger.error('保存执行历史失败:', e);
|
logger.error("保存执行历史失败:", e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const userId = entity.userId;
|
const userId = entity.userId;
|
||||||
const historyId = await this.historyService.start(entity,triggerType);
|
const historyId = await this.historyService.start(entity, triggerType);
|
||||||
const userIsAdmin = await this.userService.isAdmin(userId);
|
const userIsAdmin = await this.userService.isAdmin(userId);
|
||||||
const user: UserInfo = {
|
const user: UserInfo = {
|
||||||
id: userId,
|
id: userId,
|
||||||
role: userIsAdmin ? 'admin' : 'user',
|
role: userIsAdmin ? "admin" : "user"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -559,11 +560,11 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const taskServiceGetter = this.taskServiceBuilder.create({
|
const taskServiceGetter = this.taskServiceBuilder.create({
|
||||||
userId,
|
userId
|
||||||
})
|
});
|
||||||
const accessGetter = await taskServiceGetter.get<IAccessService>("accessService")
|
const accessGetter = await taskServiceGetter.get<IAccessService>("accessService");
|
||||||
const notificationGetter =await taskServiceGetter.get<INotificationService>("notificationService")
|
const notificationGetter = await taskServiceGetter.get<INotificationService>("notificationService");
|
||||||
const cnameProxyService =await taskServiceGetter.get<ICnameProxyService>("cnameProxyService")
|
const cnameProxyService = await taskServiceGetter.get<ICnameProxyService>("cnameProxyService");
|
||||||
const executor = new Executor({
|
const executor = new Executor({
|
||||||
user,
|
user,
|
||||||
pipeline,
|
pipeline,
|
||||||
|
@ -577,7 +578,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
notificationService: notificationGetter,
|
notificationService: notificationGetter,
|
||||||
fileRootDir: this.certdConfig.fileRootDir,
|
fileRootDir: this.certdConfig.fileRootDir,
|
||||||
sysInfo,
|
sysInfo,
|
||||||
serviceGetter:taskServiceGetter
|
serviceGetter: taskServiceGetter
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
runningTasks.set(historyId, executor);
|
runningTasks.set(historyId, executor);
|
||||||
|
@ -595,7 +596,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('执行失败:', e);
|
logger.error("执行失败:", e);
|
||||||
// throw e;
|
// throw e;
|
||||||
} finally {
|
} finally {
|
||||||
runningTasks.delete(historyId);
|
runningTasks.delete(historyId);
|
||||||
|
@ -619,7 +620,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTriggerType(triggerId, pipeline) {
|
private getTriggerType(triggerId, pipeline) {
|
||||||
let triggerType = 'user';
|
let triggerType = "user";
|
||||||
if (triggerId != null) {
|
if (triggerId != null) {
|
||||||
//如果不是手动触发
|
//如果不是手动触发
|
||||||
//查找trigger
|
//查找trigger
|
||||||
|
@ -629,8 +630,8 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
this.cron.remove(this.buildCronKey(pipeline.id, triggerId));
|
this.cron.remove(this.buildCronKey(pipeline.id, triggerId));
|
||||||
triggerType = null;
|
triggerType = null;
|
||||||
} else {
|
} else {
|
||||||
logger.info('timer trigger:' + found.id, found.title, found.cron);
|
logger.info("timer trigger:" + found.id, found.title, found.cron);
|
||||||
triggerType = 'timer';
|
triggerType = "timer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return triggerType;
|
return triggerType;
|
||||||
|
@ -653,7 +654,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
//修改pipeline状态
|
//修改pipeline状态
|
||||||
const pipelineEntity = new PipelineEntity();
|
const pipelineEntity = new PipelineEntity();
|
||||||
pipelineEntity.id = parseInt(history.pipeline.id);
|
pipelineEntity.id = parseInt(history.pipeline.id);
|
||||||
pipelineEntity.status = history.pipeline.status.result + '';
|
pipelineEntity.status = history.pipeline.status.result + "";
|
||||||
pipelineEntity.lastHistoryTime = history.pipeline.status.startTime;
|
pipelineEntity.lastHistoryTime = history.pipeline.status.startTime;
|
||||||
await this.update(pipelineEntity);
|
await this.update(pipelineEntity);
|
||||||
|
|
||||||
|
@ -677,8 +678,8 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
async count(param: { userId?: any }) {
|
async count(param: { userId?: any }) {
|
||||||
const count = await this.repository.count({
|
const count = await this.repository.count({
|
||||||
where: {
|
where: {
|
||||||
userId: param.userId,
|
userId: param.userId
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -686,12 +687,12 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
async statusCount(param: { userId?: any } = {}) {
|
async statusCount(param: { userId?: any } = {}) {
|
||||||
const statusCount = await this.repository
|
const statusCount = await this.repository
|
||||||
.createQueryBuilder()
|
.createQueryBuilder()
|
||||||
.select('status')
|
.select("status")
|
||||||
.addSelect('count(1)', 'count')
|
.addSelect("count(1)", "count")
|
||||||
.where({
|
.where({
|
||||||
userId: param.userId,
|
userId: param.userId
|
||||||
})
|
})
|
||||||
.groupBy('status')
|
.groupBy("status")
|
||||||
.getRawMany();
|
.getRawMany();
|
||||||
return statusCount;
|
return statusCount;
|
||||||
}
|
}
|
||||||
|
@ -701,11 +702,11 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
title: true,
|
title: true,
|
||||||
status: true,
|
status: true
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
userId,
|
userId
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
await this.fillLastVars(list);
|
await this.fillLastVars(list);
|
||||||
list = list.filter(item => {
|
list = list.filter(item => {
|
||||||
|
@ -719,16 +720,16 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async createCountPerDay(param: { days: number } = { days: 7 }) {
|
async createCountPerDay(param: { days: number } = { days: 7 }) {
|
||||||
const todayEnd = dayjs().endOf('day');
|
const todayEnd = dayjs().endOf("day");
|
||||||
const result = await this.getRepository()
|
const result = await this.getRepository()
|
||||||
.createQueryBuilder('main')
|
.createQueryBuilder("main")
|
||||||
.select(`${this.dbAdapter.date('main.createTime')} AS date`) // 将UNIX时间戳转换为日期
|
.select(`${this.dbAdapter.date("main.createTime")} AS date`) // 将UNIX时间戳转换为日期
|
||||||
.addSelect('COUNT(1) AS count')
|
.addSelect("COUNT(1) AS count")
|
||||||
.where({
|
.where({
|
||||||
// 0点
|
// 0点
|
||||||
createTime: MoreThan(todayEnd.add(-param.days, 'day').toDate()),
|
createTime: MoreThan(todayEnd.add(-param.days, "day").toDate())
|
||||||
})
|
})
|
||||||
.groupBy('date')
|
.groupBy("date")
|
||||||
.getRawMany();
|
.getRawMany();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -745,48 +746,48 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
await this.repository.update(
|
await this.repository.update(
|
||||||
{
|
{
|
||||||
id: In(ids),
|
id: In(ids),
|
||||||
userId,
|
userId
|
||||||
},
|
},
|
||||||
{ groupId }
|
{ groupId }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async batchUpdateTrigger(ids: number[], trigger: any, userId: any){
|
async batchUpdateTrigger(ids: number[], trigger: any, userId: any) {
|
||||||
|
|
||||||
const list = await this.find({
|
const list = await this.find({
|
||||||
where:{
|
where: {
|
||||||
id: In(ids),
|
id: In(ids),
|
||||||
userId
|
userId
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
const pipeline = JSON.parse(item.content);
|
const pipeline = JSON.parse(item.content);
|
||||||
pipeline.triggers = [{
|
pipeline.triggers = [{
|
||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
title: '定时触发',
|
title: "定时触发",
|
||||||
...trigger
|
...trigger
|
||||||
}]
|
}];
|
||||||
await this.doUpdatePipelineJson(item,pipeline)
|
await this.doUpdatePipelineJson(item, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async batchUpdateNotifications(ids: number[], notification: Notification, userId: any){
|
async batchUpdateNotifications(ids: number[], notification: Notification, userId: any) {
|
||||||
|
|
||||||
const list = await this.find({
|
const list = await this.find({
|
||||||
where:{
|
where: {
|
||||||
id: In(ids),
|
id: In(ids),
|
||||||
userId
|
userId
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
const pipeline = JSON.parse(item.content);
|
const pipeline = JSON.parse(item.content);
|
||||||
pipeline.notifications = [{
|
pipeline.notifications = [{
|
||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
title: '通知',
|
title: "通知",
|
||||||
/**
|
/**
|
||||||
* type: NotificationType;
|
* type: NotificationType;
|
||||||
* when: NotificationWhen[];
|
* when: NotificationWhen[];
|
||||||
|
@ -797,44 +798,44 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
*/
|
*/
|
||||||
type: "other",
|
type: "other",
|
||||||
...notification
|
...notification
|
||||||
}]
|
}];
|
||||||
await this.doUpdatePipelineJson(item,pipeline)
|
await this.doUpdatePipelineJson(item, pipeline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async batchRerun(ids: number[], userId: any) {
|
async batchRerun(ids: number[], userId: any) {
|
||||||
if (!isPlus()){
|
if (!isPlus()) {
|
||||||
throw new NeedVIPException("此功能需要升级专业版")
|
throw new NeedVIPException("此功能需要升级专业版");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userId || ids.length === 0) {
|
if (!userId || ids.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const list = await this.repository.find({
|
const list = await this.repository.find({
|
||||||
select:{
|
select: {
|
||||||
id:true
|
id: true
|
||||||
},
|
},
|
||||||
where:{
|
where: {
|
||||||
id: In(ids),
|
id: In(ids),
|
||||||
userId
|
userId
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
ids = list.map(item=>item.id)
|
ids = list.map(item => item.id);
|
||||||
|
|
||||||
//异步执行
|
//异步执行
|
||||||
this.startBatchRerun(ids)
|
this.startBatchRerun(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
async startBatchRerun(ids: number[]){
|
async startBatchRerun(ids: number[]) {
|
||||||
//20条一批
|
//20条一批
|
||||||
const batchSize = 20;
|
const batchSize = 20;
|
||||||
for (let i = 0; i < ids.length; i += batchSize) {
|
for (let i = 0; i < ids.length; i += batchSize) {
|
||||||
const batchIds = ids.slice(i, i + batchSize);
|
const batchIds = ids.slice(i, i + batchSize);
|
||||||
const batchPromises = batchIds.map(async (id)=>{
|
const batchPromises = batchIds.map(async (id) => {
|
||||||
await this.run(id,null,"ALL")
|
await this.run(id, null, "ALL");
|
||||||
});
|
});
|
||||||
await Promise.all(batchPromises)
|
await Promise.all(batchPromises);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -847,35 +848,130 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
return await this.repository.find({
|
return await this.repository.find({
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
title: true,
|
title: true
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
id: In(pipelineIds),
|
id: In(pipelineIds),
|
||||||
userId,
|
userId
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async checkUserStatus(userId: number) {
|
private async checkUserStatus(userId: number) {
|
||||||
const userEntity = await this.userService.info(userId);
|
const userEntity = await this.userService.info(userId);
|
||||||
if(userEntity == null){
|
if (userEntity == null) {
|
||||||
throw new Error('用户不存在');
|
throw new Error("用户不存在");
|
||||||
}
|
}
|
||||||
if(userEntity.status === 0){
|
if (userEntity.status === 0) {
|
||||||
const message = `账户${userId}已被禁用,禁止运行流水线`
|
const message = `账户${userId}已被禁用,禁止运行流水线`;
|
||||||
throw new Error(message)
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
const sysPublic = await this.sysSettingsService.getPublicSettings()
|
const sysPublic = await this.sysSettingsService.getPublicSettings();
|
||||||
if(isPlus() && sysPublic.userValidTimeEnabled === true){
|
if (isPlus() && sysPublic.userValidTimeEnabled === true) {
|
||||||
//校验用户有效期是否设置
|
//校验用户有效期是否设置
|
||||||
if(userEntity.validTime!= null && userEntity.validTime > 0){
|
if (userEntity.validTime != null && userEntity.validTime > 0) {
|
||||||
if(userEntity.validTime < new Date().getTime()){
|
if (userEntity.validTime < new Date().getTime()) {
|
||||||
//用户已过期
|
//用户已过期
|
||||||
const message = `账户${userId}已过有效期,禁止运行流水线`
|
const message = `账户${userId}已过有效期,禁止运行流水线`;
|
||||||
throw new Error(message)
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createAutoPipeline(req: { domains: string[]; email: string; userId: number ,from:string}) {
|
||||||
|
|
||||||
|
const randomHour = Math.floor(Math.random() * 6);
|
||||||
|
const randomMin = Math.floor(Math.random() * 60);
|
||||||
|
const randomCron = `0 ${randomMin} ${randomHour} * * *`;
|
||||||
|
|
||||||
|
let pipeline: any = {
|
||||||
|
title: req.domains[0] + `证书自动申请【${req.from??"OpenAPI"}】`,
|
||||||
|
runnableType: "pipeline",
|
||||||
|
triggers: [
|
||||||
|
{
|
||||||
|
id: nanoid(),
|
||||||
|
title: "定时触发",
|
||||||
|
cron: randomCron,
|
||||||
|
type: "cron"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
notifications: [
|
||||||
|
{
|
||||||
|
id: nanoid(),
|
||||||
|
type: "custom",
|
||||||
|
when: ["error", "turnToSuccess", "success"],
|
||||||
|
notificationId: 0,
|
||||||
|
title: "默认通知",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
stages: [
|
||||||
|
{
|
||||||
|
id: nanoid(),
|
||||||
|
title: "证书申请阶段",
|
||||||
|
maxTaskCount: 1,
|
||||||
|
runnableType: "stage",
|
||||||
|
tasks: [
|
||||||
|
{
|
||||||
|
id: nanoid(),
|
||||||
|
title: "证书申请任务",
|
||||||
|
runnableType: "task",
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: nanoid(),
|
||||||
|
title: "申请证书",
|
||||||
|
runnableType: "step",
|
||||||
|
input: {
|
||||||
|
renewDays: 35,
|
||||||
|
domains: req.domains,
|
||||||
|
email: req.email,
|
||||||
|
"challengeType": "auto",
|
||||||
|
"sslProvider": "letsencrypt",
|
||||||
|
"privateKeyType": "rsa_2048",
|
||||||
|
"certProfile": "classic",
|
||||||
|
"useProxy": false,
|
||||||
|
"skipLocalVerify": false,
|
||||||
|
"maxCheckRetryCount": 20,
|
||||||
|
"waitDnsDiffuseTime": 30,
|
||||||
|
"pfxArgs": "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES",
|
||||||
|
"successNotify": true
|
||||||
|
},
|
||||||
|
strategy: {
|
||||||
|
runStrategy: 0 // 正常执行
|
||||||
|
},
|
||||||
|
type: "CertApply"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const bean = new PipelineEntity();
|
||||||
|
bean.title = pipeline.title;
|
||||||
|
bean.content = JSON.stringify(pipeline);
|
||||||
|
bean.userId = req.userId;
|
||||||
|
bean.status = "none";
|
||||||
|
bean.type = "cert_auto";
|
||||||
|
bean.disabled = false
|
||||||
|
bean.keepHistoryCount = 30
|
||||||
|
await this.save(bean)
|
||||||
|
|
||||||
|
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStatus(pipelineId: number) {
|
||||||
|
const res = await this.repository.findOne({
|
||||||
|
select: {
|
||||||
|
status: true
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
id: pipelineId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res?.status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue