mirror of
https://github.com/certd/certd.git
synced 2026-04-14 20:40:53 +08:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67934cdebd | ||
|
|
6765a48706 | ||
|
|
b4252033d5 | ||
|
|
f78ae93eed | ||
|
|
0227155ab4 | ||
|
|
330b84de33 | ||
|
|
f47f86b669 | ||
|
|
95eeb93822 | ||
|
|
367f807313 | ||
|
|
a954629ff9 | ||
|
|
3bbbc41062 | ||
|
|
bf63b0d73f | ||
|
|
5362df55f4 | ||
|
|
59897c4cea | ||
|
|
a9717b9a0d | ||
|
|
680941af11 | ||
|
|
1cf8d4e5e7 | ||
|
|
70ce6be0bf | ||
|
|
9187e87419 | ||
|
|
6ed1e18c7d | ||
|
|
8d27f07213 | ||
|
|
e4f4570b29 | ||
|
|
d86fc9569a | ||
|
|
fa7a983bcb | ||
|
|
9ac908ebee | ||
|
|
6e594ee66e | ||
|
|
c26d3e9c38 | ||
|
|
5db5607faa | ||
|
|
728f27e0a0 |
55
.github/workflows/deploy-demo.yml
vendored
Normal file
55
.github/workflows/deploy-demo.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
name: deploy-demo
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ['v2']
|
||||||
|
paths:
|
||||||
|
- "deploy.trigger"
|
||||||
|
workflow_run:
|
||||||
|
workflows: [ "build-image" ]
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
|
||||||
|
# schedule:
|
||||||
|
# - # 国际时间 19:17 执行,北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
|
||||||
|
# - cron: '17 19 * * *'
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-certd-demo:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: get_certd_version
|
||||||
|
id: get_certd_version
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
result-encoding: string
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const jsonFilePath = "./packages/ui/certd-server/package.json";
|
||||||
|
const jsonContent = fs.readFileSync(jsonFilePath, 'utf-8');
|
||||||
|
const pkg = JSON.parse(jsonContent)
|
||||||
|
console.log("certd_version:",pkg.version);
|
||||||
|
return pkg.version
|
||||||
|
- uses: GuillaumeFalourd/wait-sleep-action@v1
|
||||||
|
with:
|
||||||
|
time: '10' # for 60 seconds
|
||||||
|
- name: Send HTTP request
|
||||||
|
id: request
|
||||||
|
uses: tyrrrz/action-http-request@master
|
||||||
|
with:
|
||||||
|
url: http://flow-openapi.aliyun.com/pipeline/webhook/lzCzlGrLCOHQaTMMt0mG
|
||||||
|
method: POST
|
||||||
|
headers: |
|
||||||
|
Content-Type: application/json
|
||||||
|
body: |
|
||||||
|
{
|
||||||
|
"CERTD_VERSION": "${{steps.get_certd_version.outputs.result}}"
|
||||||
|
}
|
||||||
|
retry-count: 3
|
||||||
|
retry-delay: 5000
|
||||||
|
|
||||||
|
|
||||||
26
CHANGELOG.md
26
CHANGELOG.md
@@ -3,6 +3,32 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.22.8](https://github.com/certd/certd/compare/v1.22.7...v1.22.8) (2024-08-05)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 修复删除历史记录没有删除log的bug,新增history管理页面,演示站点启动时不自动启动非管理员用户的定时任务 ([f78ae93](https://github.com/certd/certd/commit/f78ae93eedfe214008c3d071ca3d77c962137a64))
|
||||||
|
* 优化pipeline删除时,删除其他history ([b425203](https://github.com/certd/certd/commit/b4252033d56a9ad950f3e204ff021497c3978015))
|
||||||
|
|
||||||
|
## [1.22.7](https://github.com/certd/certd/compare/v1.22.6...v1.22.7) (2024-08-04)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复保存配置报id不能为空的bug ([367f807](https://github.com/certd/certd/commit/367f80731396003416665c22853dfbc09c2c03a0))
|
||||||
|
|
||||||
|
## [1.22.6](https://github.com/certd/certd/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复在相同的cron时偶尔无法触发定时任务的bug ([680941a](https://github.com/certd/certd/commit/680941af119619006b592e3ab6fb112cb5556a8b))
|
||||||
|
* 修复pg下pipeline title 类型问题 ([a9717b9](https://github.com/certd/certd/commit/a9717b9a0df7b5a64d4fe03314fecad4f59774cc))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 流水线支持名称模糊查询 ([59897c4](https://github.com/certd/certd/commit/59897c4ceae992ebe2972ca9e8f9196616ffdfd7))
|
||||||
|
* 腾讯云clb支持更多大区选择 ([e4f4570](https://github.com/certd/certd/commit/e4f4570b29f26c60f1ee9660a4c507cbeaba3d7e))
|
||||||
|
* 优化前置任务输出为空的提示 ([6ed1e18](https://github.com/certd/certd/commit/6ed1e18c7d9c46d964ecc6abc90f3908297b7632))
|
||||||
|
|
||||||
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
6
|
22:33
|
||||||
|
|||||||
1
deploy.trigger
Normal file
1
deploy.trigger
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5
|
||||||
8
doc/server/free.md
Normal file
8
doc/server/free.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
# 免费服务器部署
|
||||||
|
|
||||||
|
## 1. 注册koyeb账号
|
||||||
|
|
||||||
|
https://app.koyeb.com/
|
||||||
|
|
||||||
|
## 2. 创建应用
|
||||||
@@ -11,6 +11,12 @@ services:
|
|||||||
ports: # 端口映射
|
ports: # 端口映射
|
||||||
# ↓↓↓↓ ----------------------------------------------------------3、如果端口有冲突,可以修改第一个7001为其他不冲突的端口号【可选】
|
# ↓↓↓↓ ----------------------------------------------------------3、如果端口有冲突,可以修改第一个7001为其他不冲突的端口号【可选】
|
||||||
- "7001:7001"
|
- "7001:7001"
|
||||||
|
dns:
|
||||||
|
# 如果出现getaddrinfo ENOTFOUND等错误,可以尝试修改或注释dns配置
|
||||||
|
- 223.5.5.5
|
||||||
|
- 223.6.6.6
|
||||||
|
- 8.8.8.8
|
||||||
|
- 8.8.4.4
|
||||||
environment: # 环境变量
|
environment: # 环境变量
|
||||||
- TZ=Asia/Shanghai
|
- TZ=Asia/Shanghai
|
||||||
- certd_system_resetAdminPassword=false
|
- certd_system_resetAdminPassword=false
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npmClient": "pnpm",
|
"npmClient": "pnpm",
|
||||||
"version": "1.22.5"
|
"version": "1.22.8"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,9 @@
|
|||||||
"start": "lerna bootstrap --hoist",
|
"start": "lerna bootstrap --hoist",
|
||||||
"i-all": "lerna link && lerna exec npm install ",
|
"i-all": "lerna link && lerna exec npm install ",
|
||||||
"publish": "npm run prepublishOnly1 && lerna publish --conventional-commits --create-release github && npm run afterpublishOnly",
|
"publish": "npm run prepublishOnly1 && lerna publish --conventional-commits --create-release github && npm run afterpublishOnly",
|
||||||
"afterpublishOnly": "time /t >build.trigger && git add ./build.md && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && git push",
|
"afterpublishOnly": "time /t >build.trigger && git add ./build.trigger && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && git push",
|
||||||
"prepublishOnly1": "npm run check && npm run before-build && lerna run build ",
|
"prepublishOnly1": "npm run check && lerna run build ",
|
||||||
|
"prepublishOnly2": "npm run check && npm run before-build && lerna run build ",
|
||||||
"before-build": "cd ./packages/core/pipeline && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
|
"before-build": "cd ./packages/core/pipeline && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
|
||||||
"deploy1": "node --experimental-json-modules deploy.js ",
|
"deploy1": "node --experimental-json-modules deploy.js ",
|
||||||
"check": "node --experimental-json-modules publish-check.js",
|
"check": "node --experimental-json-modules publish-check.js",
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.22.6](https://github.com/publishlab/node-acme-client/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/acme-client
|
||||||
|
|
||||||
## [1.22.4](https://github.com/publishlab/node-acme-client/compare/v1.22.3...v1.22.4) (2024-07-26)
|
## [1.22.4](https://github.com/publishlab/node-acme-client/compare/v1.22.3...v1.22.4) (2024-07-26)
|
||||||
|
|
||||||
### Performance Improvements
|
### Performance Improvements
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "Simple and unopinionated ACME client",
|
"description": "Simple and unopinionated ACME client",
|
||||||
"private": false,
|
"private": false,
|
||||||
"author": "nmorsman",
|
"author": "nmorsman",
|
||||||
"version": "1.22.4",
|
"version": "1.22.6",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"types": "types/index.d.ts",
|
"types": "types/index.d.ts",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
2
packages/core/pipeline/.gitignore
vendored
2
packages/core/pipeline/.gitignore
vendored
@@ -24,3 +24,5 @@ dist-ssr
|
|||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
test/user.secret.*
|
test/user.secret.*
|
||||||
|
test/**/*.js
|
||||||
|
src/**/*.spec.ts
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extension": ["ts"],
|
"extension": ["ts"],
|
||||||
"spec": "test/**/*.test.ts",
|
"spec": "src/**/*.spec.ts"
|
||||||
"require": "ts-node/register"
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
node_modules
|
node_modules
|
||||||
src
|
src
|
||||||
|
dist/**/*.spec.*
|
||||||
@@ -3,6 +3,27 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.22.8](https://github.com/certd/certd/compare/v1.22.7...v1.22.8) (2024-08-05)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 优化pipeline删除时,删除其他history ([b425203](https://github.com/certd/certd/commit/b4252033d56a9ad950f3e204ff021497c3978015))
|
||||||
|
|
||||||
|
## [1.22.7](https://github.com/certd/certd/compare/v1.22.6...v1.22.7) (2024-08-04)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|
||||||
|
## [1.22.6](https://github.com/certd/certd/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复在相同的cron时偶尔无法触发定时任务的bug ([680941a](https://github.com/certd/certd/commit/680941af119619006b592e3ab6fb112cb5556a8b))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 流水线支持名称模糊查询 ([59897c4](https://github.com/certd/certd/commit/59897c4ceae992ebe2972ca9e8f9196616ffdfd7))
|
||||||
|
* 优化前置任务输出为空的提示 ([6ed1e18](https://github.com/certd/certd/commit/6ed1e18c7d9c46d964ecc6abc90f3908297b7632))
|
||||||
|
|
||||||
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/pipeline
|
**Note:** Version bump only for package @certd/pipeline
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
23:14
|
22:30
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/pipeline",
|
"name": "@certd/pipeline",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.22.5",
|
"version": "1.22.8",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@@ -10,10 +10,10 @@
|
|||||||
"build": "tsc --skipLibCheck",
|
"build": "tsc --skipLibCheck",
|
||||||
"build3": "rollup -c",
|
"build3": "rollup -c",
|
||||||
"build2": "vue-tsc --noEmit && vite build",
|
"build2": "vue-tsc --noEmit && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"test": "mocha --loader=ts-node/esm"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash-es": "^4.17.12",
|
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"fix-path": "^4.0.0",
|
"fix-path": "^4.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
"@rollup/plugin-terser": "^0.4.3",
|
"@rollup/plugin-terser": "^0.4.3",
|
||||||
"@rollup/plugin-typescript": "^11.0.0",
|
"@rollup/plugin-typescript": "^11.0.0",
|
||||||
"@types/chai": "^4.3.10",
|
"@types/chai": "^4.3.10",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/mocha": "^10.0.1",
|
"@types/mocha": "^10.0.1",
|
||||||
"@types/node-forge": "^1.3.2",
|
"@types/node-forge": "^1.3.2",
|
||||||
"@types/uuid": "^9.0.2",
|
"@types/uuid": "^9.0.2",
|
||||||
|
|||||||
@@ -213,7 +213,12 @@ export class Executor {
|
|||||||
if (contextKey != null) {
|
if (contextKey != null) {
|
||||||
const value = this.runtime.context[contextKey];
|
const value = this.runtime.context[contextKey];
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
currentLogger.warn(`[step init] input ${define.title} is null`);
|
currentLogger.warn(`[step init] input ${define.title} is null,前置任务步骤输出值为空,请按如下步骤排查:`);
|
||||||
|
currentLogger.log(`1、检查前置任务(证书申请任务)是否是配置了成功后跳过,如果是,请改为正常执行`);
|
||||||
|
currentLogger.log(
|
||||||
|
`2、是否曾经删除过前置任务(证书申请任务),然后又重新添加了,如果是,请重新编辑当前任务,重新选择一下前置任务输出的参数(域名证书那一栏)`
|
||||||
|
);
|
||||||
|
currentLogger.log(`3、以上都不是,联系作者吧`);
|
||||||
}
|
}
|
||||||
step.input[key] = value;
|
step.input[key] = value;
|
||||||
}
|
}
|
||||||
@@ -241,18 +246,26 @@ export class Executor {
|
|||||||
|
|
||||||
await instance.onInstance();
|
await instance.onInstance();
|
||||||
await instance.execute();
|
await instance.execute();
|
||||||
|
//执行结果处理
|
||||||
if (instance._result.clearLastStatus) {
|
if (instance._result.clearLastStatus) {
|
||||||
|
//是否需要清除所有状态
|
||||||
this.lastStatusMap.clear();
|
this.lastStatusMap.clear();
|
||||||
}
|
}
|
||||||
//输出到output context
|
//输出上下文变量到output context
|
||||||
_.forEach(define.output, (item: any, key: any) => {
|
_.forEach(define.output, (item: any, key: any) => {
|
||||||
step.status!.output[key] = instance[key];
|
step.status!.output[key] = instance[key];
|
||||||
const stepOutputKey = `step.${step.id}.${key}`;
|
const stepOutputKey = `step.${step.id}.${key}`;
|
||||||
this.runtime.context[stepOutputKey] = instance[key];
|
this.runtime.context[stepOutputKey] = instance[key];
|
||||||
});
|
});
|
||||||
|
|
||||||
step.status!.files = instance.getFiles();
|
step.status!.files = instance.getFiles();
|
||||||
|
|
||||||
|
//更新pipeline vars
|
||||||
|
if (Object.keys(instance._result.pipelineVars).length > 0) {
|
||||||
|
// 判断 pipelineVars 有值时更新
|
||||||
|
const vars = this.pipelineContext.getObj("vars");
|
||||||
|
_.merge(vars, instance._result.pipelineVars);
|
||||||
|
await this.pipelineContext.setObj("vars", vars);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async notification(when: NotificationWhen, error?: any) {
|
async notification(when: NotificationWhen, error?: any) {
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ export interface IFileStore {
|
|||||||
|
|
||||||
export class FileStore {
|
export class FileStore {
|
||||||
rootDir: string;
|
rootDir: string;
|
||||||
|
// pipelineId
|
||||||
scope: string;
|
scope: string;
|
||||||
|
// historyId
|
||||||
parent: string;
|
parent: string;
|
||||||
constructor(options?: FileStoreOptions) {
|
constructor(options?: FileStoreOptions) {
|
||||||
this.rootDir = fileUtils.getFileRootDir(options?.rootDir);
|
this.rootDir = fileUtils.getFileRootDir(options?.rootDir);
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ export * from "./run-history.js";
|
|||||||
export * from "./context.js";
|
export * from "./context.js";
|
||||||
export * from "./storage.js";
|
export * from "./storage.js";
|
||||||
export * from "./file-store.js";
|
export * from "./file-store.js";
|
||||||
|
export * from "./license.js";
|
||||||
|
|||||||
15
packages/core/pipeline/src/core/license.spec.ts
Normal file
15
packages/core/pipeline/src/core/license.spec.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { isPlus, verify } from "./license.js";
|
||||||
|
import { equal } from "assert";
|
||||||
|
describe("license", function () {
|
||||||
|
it("#license", async function () {
|
||||||
|
const req = {
|
||||||
|
appKey: "z4nXOeTeSnnpUpnmsV",
|
||||||
|
subjectId: "999",
|
||||||
|
license: "",
|
||||||
|
};
|
||||||
|
const plus = isPlus();
|
||||||
|
equal(plus, false);
|
||||||
|
const res = await verify(req);
|
||||||
|
equal(res, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
85
packages/core/pipeline/src/core/license.ts
Normal file
85
packages/core/pipeline/src/core/license.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { createVerify } from "node:crypto";
|
||||||
|
import { logger } from "../utils/index.js";
|
||||||
|
|
||||||
|
const SecreteKey =
|
||||||
|
"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQXY3TGtMaUp1dGM0NzhTU3RaTExjajVGZXh1YjJwR2NLMGxwa0hwVnlZWjhMY29rRFhuUlAKUGQ5UlJSTVRTaGJsbFl2Mzd4QUhOV1ZIQ0ZsWHkrQklVU001bUlBU1NDQTV0azlJNmpZZ2F4bEFDQm1BY0lGMwozKzBjeGZIYVkrVW9YdVluMkZ6YUt2Ym5GdFZIZ0lkMDg4a3d4clZTZzlCT3BDRVZIR1pxR2I5TWN5MXVHVXhUClFTVENCbmpoTWZlZ0p6cXVPYWVOY0ZPSE5tbmtWRWpLTythbTBPeEhNS1lyS3ZnQnVEbzdoVnFENlBFMUd6V3AKZHdwZUV4QXZDSVJxL2pWTkdRK3FtMkRWOVNJZ3U5bmF4MktmSUtFeU50dUFFS1VpekdqL0VmRFhDM1cxMExhegpKaGNYNGw1SUFZU1o3L3JWVmpGbExWSVl0WDU1T054L1Z3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K";
|
||||||
|
const appKey = "z4nXOeTeSnnpUpnmsV";
|
||||||
|
export type LicenseVerifyReq = {
|
||||||
|
subjectId: string;
|
||||||
|
license: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type License = {
|
||||||
|
appKey: string;
|
||||||
|
code: string;
|
||||||
|
subjectId: string;
|
||||||
|
expireTime: number;
|
||||||
|
activeTime: number;
|
||||||
|
duration: number;
|
||||||
|
version: number;
|
||||||
|
secret: string;
|
||||||
|
signature: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LicenseHolder {
|
||||||
|
isPlus = false;
|
||||||
|
}
|
||||||
|
const holder = new LicenseHolder();
|
||||||
|
holder.isPlus = false;
|
||||||
|
|
||||||
|
class LicenseVerifier {
|
||||||
|
checked = false;
|
||||||
|
licenseReq?: LicenseVerifyReq = undefined;
|
||||||
|
async reVerify(req: LicenseVerifyReq) {
|
||||||
|
this.checked = false;
|
||||||
|
return await this.verify(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPlus(value: boolean) {
|
||||||
|
holder.isPlus = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
async verify(req: LicenseVerifyReq) {
|
||||||
|
this.licenseReq = req;
|
||||||
|
if (this.checked) {
|
||||||
|
return this.setPlus(false);
|
||||||
|
}
|
||||||
|
const license = req?.license;
|
||||||
|
if (!license) {
|
||||||
|
this.checked = true;
|
||||||
|
return this.setPlus(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenseJson = Buffer.from(Buffer.from(license, "hex").toString(), "base64").toString();
|
||||||
|
const json: License = JSON.parse(licenseJson);
|
||||||
|
if (json.expireTime < Date.now()) {
|
||||||
|
logger.warn("授权已过期");
|
||||||
|
return this.setPlus(false);
|
||||||
|
}
|
||||||
|
const content = `${appKey},${this.licenseReq.subjectId},${json.code},${json.secret},${json.activeTime},${json.duration},${json.expireTime},${json.version}`;
|
||||||
|
const publicKey = Buffer.from(SecreteKey, "base64").toString();
|
||||||
|
const res = this.verifySignature(content, json.signature, publicKey);
|
||||||
|
this.checked = true;
|
||||||
|
if (!res) {
|
||||||
|
logger.warn("授权校验失败");
|
||||||
|
return this.setPlus(false);
|
||||||
|
}
|
||||||
|
return this.setPlus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
verifySignature(content: string, signature: any, publicKey: string) {
|
||||||
|
const verify = createVerify("RSA-SHA256");
|
||||||
|
verify.update(content);
|
||||||
|
return verify.verify(publicKey, signature, "base64");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifier = new LicenseVerifier();
|
||||||
|
|
||||||
|
export function isPlus() {
|
||||||
|
return holder.isPlus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function verify(req: LicenseVerifyReq) {
|
||||||
|
return await verifier.reVerify(req);
|
||||||
|
}
|
||||||
@@ -51,6 +51,7 @@ export type ITaskPlugin = {
|
|||||||
export type TaskResult = {
|
export type TaskResult = {
|
||||||
clearLastStatus?: boolean;
|
clearLastStatus?: boolean;
|
||||||
files?: FileItem[];
|
files?: FileItem[];
|
||||||
|
pipelineVars: Record<string, any>;
|
||||||
};
|
};
|
||||||
export type TaskInstanceContext = {
|
export type TaskInstanceContext = {
|
||||||
pipeline: Pipeline;
|
pipeline: Pipeline;
|
||||||
@@ -66,7 +67,7 @@ export type TaskInstanceContext = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||||
_result: TaskResult = { clearLastStatus: false, files: [] };
|
_result: TaskResult = { clearLastStatus: false, files: [], pipelineVars: {} };
|
||||||
ctx!: TaskInstanceContext;
|
ctx!: TaskInstanceContext;
|
||||||
clearLastStatus() {
|
clearLastStatus() {
|
||||||
this._result.clearLastStatus = true;
|
this._result.clearLastStatus = true;
|
||||||
@@ -83,12 +84,6 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
|||||||
randomFileId() {
|
randomFileId() {
|
||||||
return Math.random().toString(36).substring(2, 9);
|
return Math.random().toString(36).substring(2, 9);
|
||||||
}
|
}
|
||||||
linkFile(file: FileItem) {
|
|
||||||
this._result.files?.push({
|
|
||||||
...file,
|
|
||||||
id: this.randomFileId(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
saveFile(filename: string, file: Buffer) {
|
saveFile(filename: string, file: Buffer) {
|
||||||
const filePath = this.ctx.fileStore.writeFile(filename, file);
|
const filePath = this.ctx.fileStore.writeFile(filename, file);
|
||||||
logger.info(`saveFile:${filePath}`);
|
logger.info(`saveFile:${filePath}`);
|
||||||
|
|||||||
@@ -5,4 +5,3 @@ export default function (timeout: number) {
|
|||||||
}, timeout);
|
}, timeout);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import "mocha";
|
import "mocha";
|
||||||
import { EchoPlugin } from "./echo-plugin";
|
import { EchoPlugin } from "./echo-plugin.js";
|
||||||
describe("task_plugin", function () {
|
describe("task_plugin", function () {
|
||||||
it("#taskplugin", function () {
|
it("#taskplugin", function () {
|
||||||
console.log("before new plugin");
|
console.log("before new plugin");
|
||||||
|
|||||||
1
packages/core/pipeline/test/pipeline/.gitignore
vendored
Normal file
1
packages/core/pipeline/test/pipeline/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
license.*
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
"exclude": [
|
"exclude": [
|
||||||
"*.js",
|
"*.js",
|
||||||
"*.ts",
|
"*.ts",
|
||||||
|
"*.spec.ts",
|
||||||
"dist",
|
"dist",
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"test"
|
"test"
|
||||||
|
|||||||
@@ -3,6 +3,18 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.22.8](https://github.com/certd/certd/compare/v1.22.7...v1.22.8) (2024-08-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
|
## [1.22.7](https://github.com/certd/certd/compare/v1.22.6...v1.22.7) (2024-08-04)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
|
## [1.22.6](https://github.com/certd/certd/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|
||||||
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/lib-k8s
|
**Note:** Version bump only for package @certd/lib-k8s
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/lib-k8s",
|
"name": "@certd/lib-k8s",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.22.5",
|
"version": "1.22.8",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"shelljs": "^0.8.5"
|
"shelljs": "^0.8.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@certd/pipeline": "^1.22.5",
|
"@certd/pipeline": "^1.22.8",
|
||||||
"@rollup/plugin-commonjs": "^23.0.4",
|
"@rollup/plugin-commonjs": "^23.0.4",
|
||||||
"@rollup/plugin-json": "^6.0.0",
|
"@rollup/plugin-json": "^6.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.22.6](https://github.com/certd/certd/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|
||||||
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
|
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/midway-flyway-js",
|
"name": "@certd/midway-flyway-js",
|
||||||
"version": "1.22.3",
|
"version": "1.22.6",
|
||||||
"description": "midway with flyway, sql upgrade way ",
|
"description": "midway with flyway, sql upgrade way ",
|
||||||
"private": false,
|
"private": false,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -3,6 +3,20 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.22.8](https://github.com/certd/certd/compare/v1.22.7...v1.22.8) (2024-08-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-cert
|
||||||
|
|
||||||
|
## [1.22.7](https://github.com/certd/certd/compare/v1.22.6...v1.22.7) (2024-08-04)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/plugin-cert
|
||||||
|
|
||||||
|
## [1.22.6](https://github.com/certd/certd/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 流水线支持名称模糊查询 ([59897c4](https://github.com/certd/certd/commit/59897c4ceae992ebe2972ca9e8f9196616ffdfd7))
|
||||||
|
|
||||||
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/plugin-cert
|
**Note:** Version bump only for package @certd/plugin-cert
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/plugin-cert",
|
"name": "@certd/plugin-cert",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.22.5",
|
"version": "1.22.8",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@certd/acme-client": "^1.22.4",
|
"@certd/acme-client": "^1.22.6",
|
||||||
"@certd/pipeline": "^1.22.5",
|
"@certd/pipeline": "^1.22.8",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"node-forge": "^0.10.0",
|
"node-forge": "^0.10.0",
|
||||||
"psl": "^1.9.0"
|
"psl": "^1.9.0"
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
|||||||
const cert: CertInfo = certReader.toCertInfo();
|
const cert: CertInfo = certReader.toCertInfo();
|
||||||
this.cert = cert;
|
this.cert = cert;
|
||||||
|
|
||||||
|
this._result.pipelineVars.certExpiresTime = dayjs(certReader.detail.validity.notAfter).valueOf();
|
||||||
|
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
const applyTime = dayjs(certReader.detail.validity.notBefore).format("YYYYMMDD_HHmmss");
|
const applyTime = dayjs(certReader.detail.validity.notBefore).format("YYYYMMDD_HHmmss");
|
||||||
await this.zipCert(cert, applyTime);
|
await this.zipCert(cert, applyTime);
|
||||||
|
|||||||
@@ -3,6 +3,26 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.22.8](https://github.com/certd/certd/compare/v1.22.7...v1.22.8) (2024-08-05)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 修复删除历史记录没有删除log的bug,新增history管理页面,演示站点启动时不自动启动非管理员用户的定时任务 ([f78ae93](https://github.com/certd/certd/commit/f78ae93eedfe214008c3d071ca3d77c962137a64))
|
||||||
|
|
||||||
|
## [1.22.7](https://github.com/certd/certd/compare/v1.22.6...v1.22.7) (2024-08-04)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @certd/ui-client
|
||||||
|
|
||||||
|
## [1.22.6](https://github.com/certd/certd/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复在相同的cron时偶尔无法触发定时任务的bug ([680941a](https://github.com/certd/certd/commit/680941af119619006b592e3ab6fb112cb5556a8b))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 流水线支持名称模糊查询 ([59897c4](https://github.com/certd/certd/commit/59897c4ceae992ebe2972ca9e8f9196616ffdfd7))
|
||||||
|
|
||||||
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
||||||
|
|
||||||
**Note:** Version bump only for package @certd/ui-client
|
**Note:** Version bump only for package @certd/ui-client
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/ui-client",
|
"name": "@certd/ui-client",
|
||||||
"version": "1.22.5",
|
"version": "1.22.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --open",
|
"dev": "vite --open",
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
"vuedraggable": "^2.24.3"
|
"vuedraggable": "^2.24.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@certd/pipeline": "^1.22.5",
|
"@certd/pipeline": "^1.22.8",
|
||||||
"@rollup/plugin-commonjs": "^25.0.7",
|
"@rollup/plugin-commonjs": "^25.0.7",
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@types/chai": "^4.3.12",
|
"@types/chai": "^4.3.12",
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { request } from "../service";
|
import { request } from "../service";
|
||||||
|
|
||||||
export type SysPublicSetting = {
|
export type SysPublicSetting = {
|
||||||
registerEnabled:boolean
|
registerEnabled: boolean;
|
||||||
}
|
managerOtherUserPipeline: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export async function getSysPublicSettings(): Promise<SysPublicSetting> {
|
export async function getSysPublicSettings(): Promise<SysPublicSetting> {
|
||||||
return await request({
|
return await request({
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export interface UserInfoRes {
|
|||||||
id: string | number;
|
id: string | number;
|
||||||
username: string;
|
username: string;
|
||||||
nickName: string;
|
nickName: string;
|
||||||
|
roles: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoginRes {
|
export interface LoginRes {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ function install(app: App, options: any = {}) {
|
|||||||
},
|
},
|
||||||
size: "small",
|
size: "small",
|
||||||
pagination: false,
|
pagination: false,
|
||||||
onResizeColumn: (w: number, col: any) => {
|
onResizeColumn: (w: number | string, col: any) => {
|
||||||
if (crudBinding.value?.table?.columnsMap && crudBinding.value?.table?.columnsMap[col.key]) {
|
if (crudBinding.value?.table?.columnsMap && crudBinding.value?.table?.columnsMap[col.key]) {
|
||||||
crudBinding.value.table.columnsMap[col.key].width = w;
|
crudBinding.value.table.columnsMap[col.key].width = w;
|
||||||
}
|
}
|
||||||
@@ -336,6 +336,23 @@ function install(app: App, options: any = {}) {
|
|||||||
return columnProps;
|
return columnProps;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerMergeColumnPlugin({
|
||||||
|
name: "resize-column-plugin",
|
||||||
|
order: 2,
|
||||||
|
handle: (columnProps: ColumnCompositionProps) => {
|
||||||
|
if (!columnProps.column) {
|
||||||
|
columnProps.column = {};
|
||||||
|
}
|
||||||
|
columnProps.column.resizable = true;
|
||||||
|
if (!columnProps.column.width) {
|
||||||
|
columnProps.column.width = 100;
|
||||||
|
} else if (typeof columnProps.column?.width === "string" && columnProps.column.width.indexOf("px") > -1) {
|
||||||
|
columnProps.column.width = parseInt(columnProps.column.width.replace("px", ""));
|
||||||
|
}
|
||||||
|
return columnProps;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -27,6 +27,15 @@ export const certdResources = [
|
|||||||
isMenu: false
|
isMenu: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "执行历史记录",
|
||||||
|
name: "pipelineHistory",
|
||||||
|
path: "/certd/history",
|
||||||
|
component: "/certd/history/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:timer-outline"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "授权管理",
|
title: "授权管理",
|
||||||
name: "access",
|
name: "access",
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ import _ from "lodash-es";
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { LocalStorage } from "/src/utils/util.storage";
|
import { LocalStorage } from "/src/utils/util.storage";
|
||||||
|
|
||||||
|
import * as basicApi from "/@/api/modules/api.basic";
|
||||||
import { SysPublicSetting } from "/@/api/modules/api.basic";
|
import { SysPublicSetting } from "/@/api/modules/api.basic";
|
||||||
import * as basicApi from '/@/api/modules/api.basic'
|
|
||||||
import _ from "lodash-es";
|
|
||||||
|
|
||||||
export type ThemeToken = {
|
export type ThemeToken = {
|
||||||
token: {
|
token: {
|
||||||
@@ -21,7 +20,7 @@ export type ThemeConfig = {
|
|||||||
export interface SettingState {
|
export interface SettingState {
|
||||||
themeConfig?: ThemeConfig;
|
themeConfig?: ThemeConfig;
|
||||||
themeToken: ThemeToken;
|
themeToken: ThemeToken;
|
||||||
sysPublic?: SysPublicSetting
|
sysPublic?: SysPublicSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultThemeConfig = {
|
const defaultThemeConfig = {
|
||||||
@@ -38,21 +37,22 @@ export const useSettingStore = defineStore({
|
|||||||
algorithm: theme.defaultAlgorithm
|
algorithm: theme.defaultAlgorithm
|
||||||
},
|
},
|
||||||
sysPublic: {
|
sysPublic: {
|
||||||
registerEnabled: false
|
registerEnabled: false,
|
||||||
|
managerOtherUserPipeline: false
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getThemeConfig(): any {
|
getThemeConfig(): any {
|
||||||
return this.themeConfig || _.merge({}, defaultThemeConfig, LocalStorage.get(SETTING_THEME_KEY) || {});
|
return this.themeConfig || _.merge({}, defaultThemeConfig, LocalStorage.get(SETTING_THEME_KEY) || {});
|
||||||
},
|
},
|
||||||
getSysPublic():SysPublicSetting{
|
getSysPublic(): SysPublicSetting {
|
||||||
return this.sysPublic
|
return this.sysPublic;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async loadSysSettings(){
|
async loadSysSettings() {
|
||||||
const settings = await basicApi.getSysPublicSettings()
|
const settings = await basicApi.getSysPublicSettings();
|
||||||
_.merge(this.sysPublic,settings)
|
_.merge(this.sysPublic, settings);
|
||||||
},
|
},
|
||||||
persistThemeConfig() {
|
persistThemeConfig() {
|
||||||
LocalStorage.set(SETTING_THEME_KEY, this.getThemeConfig);
|
LocalStorage.set(SETTING_THEME_KEY, this.getThemeConfig);
|
||||||
@@ -92,7 +92,7 @@ export const useSettingStore = defineStore({
|
|||||||
},
|
},
|
||||||
async init() {
|
async init() {
|
||||||
await this.setThemeConfig(this.getThemeConfig);
|
await this.setThemeConfig(this.getThemeConfig);
|
||||||
await this.loadSysSettings()
|
await this.loadSysSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ export const useUserStore = defineStore({
|
|||||||
},
|
},
|
||||||
getToken(): string {
|
getToken(): string {
|
||||||
return this.token || LocalStorage.get(TOKEN_KEY);
|
return this.token || LocalStorage.get(TOKEN_KEY);
|
||||||
|
},
|
||||||
|
isAdmin(): boolean {
|
||||||
|
return this.getUserInfo?.id === 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ export function useReference(form: any) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const reference of form.reference) {
|
for (const reference of form.reference) {
|
||||||
debugger;
|
|
||||||
_.set(
|
_.set(
|
||||||
form,
|
form,
|
||||||
reference.dest,
|
reference.dest,
|
||||||
compute<any>((scope) => {
|
compute<any>((scope) => {
|
||||||
debugger;
|
|
||||||
return _.get(scope, reference.src);
|
return _.get(scope, reference.src);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
59
packages/ui/certd-client/src/views/certd/history/api.ts
Normal file
59
packages/ui/certd-client/src/views/certd/history/api.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { request } from "/src/api/service";
|
||||||
|
|
||||||
|
const apiPrefix = "/pi/history";
|
||||||
|
|
||||||
|
export function GetList(query: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/page",
|
||||||
|
method: "post",
|
||||||
|
data: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AddObj(obj: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/add",
|
||||||
|
method: "post",
|
||||||
|
data: obj
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UpdateObj(obj: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/update",
|
||||||
|
method: "post",
|
||||||
|
data: obj
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DelObj(id: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/delete",
|
||||||
|
method: "post",
|
||||||
|
params: { id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetObj(id: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/info",
|
||||||
|
method: "post",
|
||||||
|
params: { id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetDetail(id: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/detail",
|
||||||
|
method: "post",
|
||||||
|
params: { id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DeleteBatch(ids: any[]) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/deleteByIds",
|
||||||
|
method: "post",
|
||||||
|
data: { ids }
|
||||||
|
});
|
||||||
|
}
|
||||||
154
packages/ui/certd-client/src/views/certd/history/crud.tsx
Normal file
154
packages/ui/certd-client/src/views/certd/history/crud.tsx
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
import * as api from "./api";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { computed, Ref, ref } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
|
||||||
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
|
||||||
|
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
|
const router = useRouter();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||||
|
return await api.GetList(query);
|
||||||
|
};
|
||||||
|
const editRequest = async ({ form, row }: EditReq) => {
|
||||||
|
form.id = row.id;
|
||||||
|
const res = await api.UpdateObj(form);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
const delRequest = async ({ row }: DelReq) => {
|
||||||
|
return await api.DelObj(row.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addRequest = async ({ form }: AddReq) => {
|
||||||
|
form.content = JSON.stringify({
|
||||||
|
title: form.title
|
||||||
|
});
|
||||||
|
const res = await api.AddObj(form);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
const selectedRowKeys: Ref<any[]> = ref([]);
|
||||||
|
context.selectedRowKeys = selectedRowKeys;
|
||||||
|
|
||||||
|
return {
|
||||||
|
crudOptions: {
|
||||||
|
settings: {
|
||||||
|
plugins: {
|
||||||
|
//这里使用行选择插件,生成行选择crudOptions配置,最终会与crudOptions合并
|
||||||
|
rowSelection: {
|
||||||
|
enabled: true,
|
||||||
|
order: -2,
|
||||||
|
before: true,
|
||||||
|
// handle: (pluginProps,useCrudProps)=>CrudOptions,
|
||||||
|
props: {
|
||||||
|
multiple: true,
|
||||||
|
crossPage: true,
|
||||||
|
selectedRowKeys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
pageRequest,
|
||||||
|
addRequest,
|
||||||
|
editRequest,
|
||||||
|
delRequest
|
||||||
|
},
|
||||||
|
actionbar: {
|
||||||
|
buttons: {
|
||||||
|
add: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rowHandle: {
|
||||||
|
minWidth: 200,
|
||||||
|
fixed: "right",
|
||||||
|
buttons: {
|
||||||
|
edit: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
id: {
|
||||||
|
title: "ID",
|
||||||
|
key: "id",
|
||||||
|
type: "number",
|
||||||
|
column: {
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
title: "用户Id",
|
||||||
|
type: "number",
|
||||||
|
search: {
|
||||||
|
show: computed(() => {
|
||||||
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
show: computed(() => {
|
||||||
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pipelineId: {
|
||||||
|
title: "流水线Id",
|
||||||
|
type: "number",
|
||||||
|
search: {
|
||||||
|
show: true
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pipelineTitle: {
|
||||||
|
title: "流水线名称",
|
||||||
|
type: "link",
|
||||||
|
search: {
|
||||||
|
show: true,
|
||||||
|
component: {
|
||||||
|
name: "a-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createTime: {
|
||||||
|
title: "创建时间",
|
||||||
|
type: "datetime",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
sorter: true,
|
||||||
|
width: 125,
|
||||||
|
align: "center"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateTime: {
|
||||||
|
title: "更新时间",
|
||||||
|
type: "datetime",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
51
packages/ui/certd-client/src/views/certd/history/index.vue
Normal file
51
packages/ui/certd-client/src/views/certd/history/index.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<fs-page class="page-cert">
|
||||||
|
<template #header>
|
||||||
|
<div class="title">流水线执行记录</div>
|
||||||
|
</template>
|
||||||
|
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||||
|
<template #pagination-left>
|
||||||
|
<a-tooltip title="批量删除">
|
||||||
|
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</fs-crud>
|
||||||
|
</fs-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
import { useFs } from "@fast-crud/fast-crud";
|
||||||
|
import createCrudOptions from "./crud";
|
||||||
|
import { message, Modal } from "ant-design-vue";
|
||||||
|
import { DeleteBatch } from "/@/views/certd/history/api";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "PipelineHistory"
|
||||||
|
});
|
||||||
|
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
|
||||||
|
|
||||||
|
const selectedRowKeys = context.selectedRowKeys;
|
||||||
|
const handleBatchDelete = () => {
|
||||||
|
if (selectedRowKeys.value?.length > 0) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "确认",
|
||||||
|
content: `确定要批量删除这${selectedRowKeys.value.length}条记录吗`,
|
||||||
|
async onOk() {
|
||||||
|
await DeleteBatch(selectedRowKeys.value);
|
||||||
|
message.info("删除成功");
|
||||||
|
crudExpose.doRefresh();
|
||||||
|
selectedRowKeys.value = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error("请先勾选记录");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 页面打开后获取列表数据
|
||||||
|
onMounted(() => {
|
||||||
|
crudExpose.doRefresh();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less"></style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||||
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
||||||
@@ -8,6 +8,8 @@ import { nanoid } from "nanoid";
|
|||||||
import { message, Modal } from "ant-design-vue";
|
import { message, Modal } from "ant-design-vue";
|
||||||
import { env } from "/@/utils/util.env";
|
import { env } from "/@/utils/util.env";
|
||||||
import { useUserStore } from "/@/store/modules/user";
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
|
||||||
export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -93,6 +95,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const settingStore = useSettingStore();
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
request: {
|
request: {
|
||||||
@@ -125,6 +128,8 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
|
minWidth: 200,
|
||||||
|
fixed: "right",
|
||||||
buttons: {
|
buttons: {
|
||||||
view: {
|
view: {
|
||||||
click({ row }) {
|
click({ row }) {
|
||||||
@@ -189,6 +194,23 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
userId: {
|
||||||
|
title: "用户Id",
|
||||||
|
type: "number",
|
||||||
|
search: {
|
||||||
|
show: computed(() => {
|
||||||
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
show: computed(() => {
|
||||||
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
title: {
|
title: {
|
||||||
title: "流水线名称",
|
title: "流水线名称",
|
||||||
type: "link",
|
type: "link",
|
||||||
@@ -200,6 +222,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 300,
|
width: 300,
|
||||||
|
sorter: true,
|
||||||
component: {
|
component: {
|
||||||
on: {
|
on: {
|
||||||
// 注意:必须要on前缀
|
// 注意:必须要on前缀
|
||||||
@@ -210,11 +233,35 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
lastVars: {
|
||||||
|
title: "到期剩余",
|
||||||
|
type: "number",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
cellRender({ row }) {
|
||||||
|
if (!row.lastVars?.certExpiresTime) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
const leftDays = dayjs(row.lastVars.certExpiresTime).diff(dayjs(), "day");
|
||||||
|
const color = leftDays < 20 ? "red" : "#389e0d";
|
||||||
|
const percent = (leftDays / 90) * 100;
|
||||||
|
return <a-progress percent={percent} strokeColor={color} format={(percent: number) => `${leftDays} 天`} />;
|
||||||
|
},
|
||||||
|
width: 110
|
||||||
|
}
|
||||||
|
},
|
||||||
lastHistoryTime: {
|
lastHistoryTime: {
|
||||||
title: "最后运行",
|
title: "最后运行",
|
||||||
type: "datetime",
|
type: "datetime",
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
sorter: true,
|
||||||
|
width: 120,
|
||||||
|
align: "center"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
@@ -225,6 +272,11 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
}),
|
}),
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
sorter: true,
|
||||||
|
width: 80,
|
||||||
|
align: "center"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -242,6 +294,9 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
|
sorter: true,
|
||||||
|
width: 80,
|
||||||
|
align: "center",
|
||||||
component: {
|
component: {
|
||||||
name: "fs-dict-switch",
|
name: "fs-dict-switch",
|
||||||
vModel: "checked"
|
vModel: "checked"
|
||||||
@@ -254,12 +309,25 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
keepHistoryCount: {
|
keepHistoryCount: {
|
||||||
title: "历史记录保持数",
|
title: "历史记录保持数",
|
||||||
type: "number",
|
type: "number",
|
||||||
form: {
|
form: {
|
||||||
value: 30,
|
value: 30,
|
||||||
helper: "历史记录保持条数,多余的会被删除"
|
helper: "历史记录保持条数,多余的会被删除"
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
title: "排序号",
|
||||||
|
type: "number",
|
||||||
|
column: {
|
||||||
|
sorter: true,
|
||||||
|
align: "center",
|
||||||
|
width: 80
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createTime: {
|
createTime: {
|
||||||
@@ -267,6 +335,11 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
type: "datetime",
|
type: "datetime",
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
sorter: true,
|
||||||
|
width: 125,
|
||||||
|
align: "center"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateTime: {
|
updateTime: {
|
||||||
@@ -274,6 +347,9 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||||||
type: "datetime",
|
type: "datetime",
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
show: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<a-form ref="formRef" class="user-layout-login" name="custom-validation" :model="formState" :rules="rules" v-bind="layout" @finish="handleFinish" @finishFailed="handleFinishFailed">
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
class="user-layout-login"
|
||||||
|
name="custom-validation"
|
||||||
|
:model="formState"
|
||||||
|
:rules="rules"
|
||||||
|
v-bind="layout"
|
||||||
|
@finish="handleFinish"
|
||||||
|
@finish-failed="handleFinishFailed"
|
||||||
|
>
|
||||||
<!-- <div class="login-title">登录</div>-->
|
<!-- <div class="login-title">登录</div>-->
|
||||||
<a-tabs :active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
<a-tabs :active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
||||||
<a-tab-pane key="password" tab="用户名密码登录">
|
<a-tab-pane key="password" tab="用户名密码登录">
|
||||||
@@ -55,7 +64,13 @@
|
|||||||
</a-input>
|
</a-input>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col class="gutter-row" :span="8">
|
<a-col class="gutter-row" :span="8">
|
||||||
<a-button class="getCaptcha" tabindex="-1" :disabled="smsSendBtnDisabled" @click="sendSmsCode" v-text="smsTime <= 0 ? '发送' : smsTime + ' s'"></a-button>
|
<a-button
|
||||||
|
class="getCaptcha"
|
||||||
|
tabindex="-1"
|
||||||
|
:disabled="smsSendBtnDisabled"
|
||||||
|
@click="sendSmsCode"
|
||||||
|
v-text="smsTime <= 0 ? '发送' : smsTime + ' s'"
|
||||||
|
></a-button>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -75,13 +90,13 @@
|
|||||||
import { defineComponent, reactive, ref, toRaw, computed } from "vue";
|
import { defineComponent, reactive, ref, toRaw, computed } from "vue";
|
||||||
import { useUserStore } from "/src/store/modules/user";
|
import { useUserStore } from "/src/store/modules/user";
|
||||||
import { useSettingStore } from "/@/store/modules/settings";
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
import {utils} from "@fast-crud/fast-crud";
|
import { utils } from "@fast-crud/fast-crud";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "LoginPage",
|
name: "LoginPage",
|
||||||
setup() {
|
setup() {
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const settingStore = useSettingStore()
|
const settingStore = useSettingStore();
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const formState = reactive({
|
const formState = reactive({
|
||||||
username: "",
|
username: "",
|
||||||
@@ -168,7 +183,7 @@ export default defineComponent({
|
|||||||
function sendSmsCode() {
|
function sendSmsCode() {
|
||||||
//api.sendSmsCode();
|
//api.sendSmsCode();
|
||||||
}
|
}
|
||||||
const sysPublicSettings = settingStore.getSysPublic
|
const sysPublicSettings = settingStore.getSysPublic;
|
||||||
return {
|
return {
|
||||||
loading,
|
loading,
|
||||||
formState,
|
formState,
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<a-form ref="formRef" class="user-layout-register" name="custom-validation" :model="formState" :rules="rules" v-bind="layout" @finish="handleFinish" @finishFailed="handleFinishFailed">
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
class="user-layout-register"
|
||||||
|
name="custom-validation"
|
||||||
|
:model="formState"
|
||||||
|
:rules="rules"
|
||||||
|
v-bind="layout"
|
||||||
|
:label-col="{ span: 5 }"
|
||||||
|
@finish="handleFinish"
|
||||||
|
@finish-failed="handleFinishFailed"
|
||||||
|
>
|
||||||
<a-tabs :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
<a-tabs :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
||||||
<a-tab-pane key="register" tab="用户注册"> </a-tab-pane>
|
<a-tab-pane key="register" tab="用户注册"> </a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
@@ -39,7 +49,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, ref, toRaw } from "vue";
|
import { defineComponent, reactive, ref, toRaw } from "vue";
|
||||||
import { useUserStore } from "/src/store/modules/user";
|
import { useUserStore } from "/src/store/modules/user";
|
||||||
import {utils} from "@fast-crud/fast-crud";
|
import { utils } from "@fast-crud/fast-crud";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "RegisterPage",
|
name: "RegisterPage",
|
||||||
setup() {
|
setup() {
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ const apiPrefix = "/sys/settings";
|
|||||||
|
|
||||||
export const SettingKeys = {
|
export const SettingKeys = {
|
||||||
SysPublic: "sys.public",
|
SysPublic: "sys.public",
|
||||||
SysPrivate: "sys.private",
|
SysPrivate: "sys.private"
|
||||||
|
|
||||||
};
|
};
|
||||||
export async function SettingsGet(key: string) {
|
export async function SettingsGet(key: string) {
|
||||||
return await request({
|
return await request({
|
||||||
@@ -17,22 +16,28 @@ export async function SettingsGet(key: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function SettingsSave(key: string,setting: any) {
|
export async function SettingsSave(key: string, setting: any) {
|
||||||
await request({
|
await request({
|
||||||
url: apiPrefix + "/save",
|
url: apiPrefix + "/save",
|
||||||
method: "post",
|
method: "post",
|
||||||
data: {
|
data: {
|
||||||
key,
|
key,
|
||||||
setting: JSON.stringify(setting),
|
setting: JSON.stringify(setting)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function PublicSettingsSave(setting: any) {
|
export async function PublicSettingsSave(setting: any) {
|
||||||
await request({
|
await request({
|
||||||
url: apiPrefix + "/savePublicSettings",
|
url: apiPrefix + "/savePublicSettings",
|
||||||
method: "post",
|
method: "post",
|
||||||
data: setting
|
data: setting
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function stopOtherUserTimer() {
|
||||||
|
await request({
|
||||||
|
url: apiPrefix + "/stopOtherUserTimer",
|
||||||
|
method: "post"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,14 +4,31 @@
|
|||||||
<div class="title">系统设置</div>
|
<div class="title">系统设置</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="sys-settings-form">
|
<div class="sys-settings-form">
|
||||||
<a-form :model="formState" name="basic" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish" @finish-failed="onFinishFailed">
|
<a-form
|
||||||
|
:model="formState"
|
||||||
|
name="basic"
|
||||||
|
:label-col="{ span: 8 }"
|
||||||
|
:wrapper-col="{ span: 16 }"
|
||||||
|
autocomplete="off"
|
||||||
|
@finish="onFinish"
|
||||||
|
@finish-failed="onFinishFailed"
|
||||||
|
>
|
||||||
<a-form-item label="开启自助注册" name="registerEnabled">
|
<a-form-item label="开启自助注册" name="registerEnabled">
|
||||||
<a-switch v-model:checked="formState.registerEnabled" />
|
<a-switch v-model:checked="formState.registerEnabled" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="管理其他用户流水线" name="managerOtherUserPipeline">
|
||||||
|
<a-switch v-model:checked="formState.managerOtherUserPipeline" />
|
||||||
|
</a-form-item>
|
||||||
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
|
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
|
||||||
<a-button type="primary" html-type="submit">保存</a-button>
|
<a-button type="primary" html-type="submit">保存</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|
||||||
|
<!-- <a-descriptions label="系统维护操作">-->
|
||||||
|
<!-- <a-descriptions-item label="自动化任务">-->
|
||||||
|
<!-- <a-button @click="stopOtherUserTimer">停止所有其他用户的定时任务</a-button>-->
|
||||||
|
<!-- </a-descriptions-item>-->
|
||||||
|
<!-- </a-descriptions>-->
|
||||||
</div>
|
</div>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
@@ -25,11 +42,10 @@ import { useSettingStore } from "/@/store/modules/settings";
|
|||||||
|
|
||||||
interface FormState {
|
interface FormState {
|
||||||
registerEnabled: boolean;
|
registerEnabled: boolean;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const formState = reactive<Partial<FormState>>({
|
const formState = reactive<Partial<FormState>>({
|
||||||
registerEnabled:false
|
registerEnabled: false
|
||||||
});
|
});
|
||||||
|
|
||||||
async function loadSysPublicSettings() {
|
async function loadSysPublicSettings() {
|
||||||
@@ -39,11 +55,11 @@ async function loadSysPublicSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadSysPublicSettings();
|
loadSysPublicSettings();
|
||||||
const settingsStore= useSettingStore()
|
const settingsStore = useSettingStore();
|
||||||
const onFinish = async (form: any) => {
|
const onFinish = async (form: any) => {
|
||||||
console.log("Success:", form);
|
console.log("Success:", form);
|
||||||
await api.PublicSettingsSave(form);
|
await api.PublicSettingsSave(form);
|
||||||
await settingsStore.loadSysSettings()
|
await settingsStore.loadSysSettings();
|
||||||
notification.success({
|
notification.success({
|
||||||
message: "保存成功"
|
message: "保存成功"
|
||||||
});
|
});
|
||||||
@@ -53,6 +69,12 @@ const onFinishFailed = (errorInfo: any) => {
|
|||||||
// console.log("Failed:", errorInfo);
|
// console.log("Failed:", errorInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function stopOtherUserTimer() {
|
||||||
|
await api.stopOtherUserTimer();
|
||||||
|
notification.success({
|
||||||
|
message: "停止成功"
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|||||||
@@ -3,6 +3,31 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.22.8](https://github.com/certd/certd/compare/v1.22.7...v1.22.8) (2024-08-05)
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 修复删除历史记录没有删除log的bug,新增history管理页面,演示站点启动时不自动启动非管理员用户的定时任务 ([f78ae93](https://github.com/certd/certd/commit/f78ae93eedfe214008c3d071ca3d77c962137a64))
|
||||||
|
* 优化pipeline删除时,删除其他history ([b425203](https://github.com/certd/certd/commit/b4252033d56a9ad950f3e204ff021497c3978015))
|
||||||
|
|
||||||
|
## [1.22.7](https://github.com/certd/certd/compare/v1.22.6...v1.22.7) (2024-08-04)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复保存配置报id不能为空的bug ([367f807](https://github.com/certd/certd/commit/367f80731396003416665c22853dfbc09c2c03a0))
|
||||||
|
|
||||||
|
## [1.22.6](https://github.com/certd/certd/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复在相同的cron时偶尔无法触发定时任务的bug ([680941a](https://github.com/certd/certd/commit/680941af119619006b592e3ab6fb112cb5556a8b))
|
||||||
|
* 修复pg下pipeline title 类型问题 ([a9717b9](https://github.com/certd/certd/commit/a9717b9a0df7b5a64d4fe03314fecad4f59774cc))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* 流水线支持名称模糊查询 ([59897c4](https://github.com/certd/certd/commit/59897c4ceae992ebe2972ca9e8f9196616ffdfd7))
|
||||||
|
* 腾讯云clb支持更多大区选择 ([e4f4570](https://github.com/certd/certd/commit/e4f4570b29f26c60f1ee9660a4c507cbeaba3d7e))
|
||||||
|
|
||||||
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ INSERT INTO sys_settings (key, title, setting,access) VALUES ('sys.install','安
|
|||||||
|
|
||||||
ALTER TABLE sys_user ADD COLUMN password_version integer DEFAULT 1;
|
ALTER TABLE sys_user ADD COLUMN password_version integer DEFAULT 1;
|
||||||
ALTER TABLE sys_user ADD COLUMN password_salt varchar(36);
|
ALTER TABLE sys_user ADD COLUMN password_salt varchar(36);
|
||||||
ALTER TABLE sys_user ALTER COLUMN password varchar(100);
|
alter table sys_user alter column password type varchar(100) using password::varchar(100);
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
alter table pi_pipeline alter column title type varchar(100) using title::varchar(100);
|
||||||
|
alter table pi_pipeline alter column content type text using content::text;
|
||||||
|
alter table pi_storage alter column value type text using value::text;
|
||||||
|
|
||||||
|
alter table pi_pipeline add "order" integer default 0;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
alter table pi_pipeline add COLUMN "order" integer default 0;
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@certd/ui-server",
|
"name": "@certd/ui-server",
|
||||||
"version": "1.22.5",
|
"version": "1.22.8",
|
||||||
"description": "fast-server base midway",
|
"description": "fast-server base midway",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -21,12 +21,12 @@
|
|||||||
"@alicloud/cs20151215": "^3.0.3",
|
"@alicloud/cs20151215": "^3.0.3",
|
||||||
"@alicloud/openapi-client": "^0.4.0",
|
"@alicloud/openapi-client": "^0.4.0",
|
||||||
"@alicloud/pop-core": "^1.7.10",
|
"@alicloud/pop-core": "^1.7.10",
|
||||||
"@certd/acme-client": "^1.22.4",
|
"@certd/acme-client": "^1.22.6",
|
||||||
"@certd/lib-huawei": "^1.22.1",
|
"@certd/lib-huawei": "^1.22.1",
|
||||||
"@certd/lib-k8s": "^1.22.5",
|
"@certd/lib-k8s": "^1.22.8",
|
||||||
"@certd/midway-flyway-js": "^1.22.3",
|
"@certd/midway-flyway-js": "^1.22.6",
|
||||||
"@certd/pipeline": "^1.22.5",
|
"@certd/pipeline": "^1.22.8",
|
||||||
"@certd/plugin-cert": "^1.22.5",
|
"@certd/plugin-cert": "^1.22.8",
|
||||||
"@koa/cors": "^3.4.3",
|
"@koa/cors": "^3.4.3",
|
||||||
"@midwayjs/bootstrap": "^3.16.2",
|
"@midwayjs/bootstrap": "^3.16.2",
|
||||||
"@midwayjs/cache": "^3.14.0",
|
"@midwayjs/cache": "^3.14.0",
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"better-sqlite3": "^11.1.2",
|
"better-sqlite3": "^11.1.2",
|
||||||
"cache-manager": "^3.6.3",
|
"cache-manager": "^3.6.3",
|
||||||
|
"cron-parser": "^4.9.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"glob": "^10.4.5",
|
"glob": "^10.4.5",
|
||||||
"https-proxy-agent": "^7.0.4",
|
"https-proxy-agent": "^7.0.4",
|
||||||
@@ -56,7 +57,6 @@
|
|||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
"mwtsc": "^1.4.0",
|
"mwtsc": "^1.4.0",
|
||||||
"nanoid": "^4.0.0",
|
"nanoid": "^4.0.0",
|
||||||
"node-cron": "^3.0.2",
|
|
||||||
"nodemailer": "^6.9.3",
|
"nodemailer": "^6.9.3",
|
||||||
"pg": "^8.12.0",
|
"pg": "^8.12.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export abstract class BaseController {
|
|||||||
* 成功返回
|
* 成功返回
|
||||||
* @param data 返回数据
|
* @param data 返回数据
|
||||||
*/
|
*/
|
||||||
ok(data: any) {
|
ok(data?: any) {
|
||||||
const res = {
|
const res = {
|
||||||
...Constants.res.success,
|
...Constants.res.success,
|
||||||
data: undefined,
|
data: undefined,
|
||||||
|
|||||||
@@ -118,10 +118,9 @@ export abstract class BaseService<T> {
|
|||||||
}
|
}
|
||||||
const qb = this.getRepository().createQueryBuilder('main');
|
const qb = this.getRepository().createQueryBuilder('main');
|
||||||
if (order && order.prop) {
|
if (order && order.prop) {
|
||||||
qb.orderBy('main.' + order.prop, order.asc ? 'ASC' : 'DESC');
|
qb.addOrderBy('main.' + order.prop, order.asc ? 'ASC' : 'DESC');
|
||||||
} else {
|
|
||||||
qb.orderBy('id', 'DESC');
|
|
||||||
}
|
}
|
||||||
|
qb.addOrderBy('id', 'DESC');
|
||||||
qb.offset(page.offset).limit(page.limit);
|
qb.offset(page.offset).limit(page.limit);
|
||||||
//根据bean query
|
//根据bean query
|
||||||
if (query) {
|
if (query) {
|
||||||
|
|||||||
@@ -9,12 +9,7 @@ export abstract class CrudController<T> extends BaseController {
|
|||||||
@Body(ALL)
|
@Body(ALL)
|
||||||
body
|
body
|
||||||
) {
|
) {
|
||||||
const pageRet = await this.getService().page(
|
const pageRet = await this.getService().page(body?.query, body?.page, body?.sort, null);
|
||||||
body?.query,
|
|
||||||
body?.page,
|
|
||||||
body?.sort,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
return this.ok(pageRet);
|
return this.ok(pageRet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +49,7 @@ export abstract class CrudController<T> extends BaseController {
|
|||||||
await this.getService().update(bean);
|
await this.getService().update(bean);
|
||||||
return this.ok(null);
|
return this.ok(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/delete')
|
@Post('/delete')
|
||||||
async delete(
|
async delete(
|
||||||
@Query('id')
|
@Query('id')
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import fs from 'fs';
|
|||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import * as _ from 'lodash-es';
|
import * as _ from 'lodash-es';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
import path from 'path';
|
||||||
const KEYS_FILE = './data/keys.yaml';
|
const KEYS_FILE = './data/keys.yaml';
|
||||||
export class Keys {
|
export class Keys {
|
||||||
jwtKey: string = nanoid();
|
jwtKey: string = nanoid();
|
||||||
@@ -19,6 +20,12 @@ export class Keys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
|
const parent = path.dirname(KEYS_FILE);
|
||||||
|
if (!fs.existsSync(parent)) {
|
||||||
|
fs.mkdirSync(parent, {
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
fs.writeFileSync(KEYS_FILE, yaml.dump(this));
|
fs.writeFileSync(KEYS_FILE, yaml.dump(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Config, Inject, Provide } from '@midwayjs/core';
|
import { Config, Inject, MidwayWebRouterService, Provide } from '@midwayjs/core';
|
||||||
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { Constants } from '../basic/constants.js';
|
import { Constants } from '../basic/constants.js';
|
||||||
import { MidwayWebRouterService } from '@midwayjs/core';
|
|
||||||
import { RoleService } from '../modules/authority/service/role-service.js';
|
|
||||||
import { logger } from '../utils/logger.js';
|
import { logger } from '../utils/logger.js';
|
||||||
|
import { AuthService } from '../modules/authority/service/auth-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 权限校验
|
* 权限校验
|
||||||
@@ -16,7 +15,7 @@ export class AuthorityMiddleware implements IWebMiddleware {
|
|||||||
@Inject()
|
@Inject()
|
||||||
webRouterService: MidwayWebRouterService;
|
webRouterService: MidwayWebRouterService;
|
||||||
@Inject()
|
@Inject()
|
||||||
roleService: RoleService;
|
authService: AuthService;
|
||||||
|
|
||||||
resolve() {
|
resolve() {
|
||||||
return async (ctx: IMidwayKoaContext, next: NextFunction) => {
|
return async (ctx: IMidwayKoaContext, next: NextFunction) => {
|
||||||
@@ -59,11 +58,8 @@ export class AuthorityMiddleware implements IWebMiddleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (permission !== Constants.per.authOnly) {
|
if (permission !== Constants.per.authOnly) {
|
||||||
//如果不是仅校验登录,还需要校验是否拥有权限
|
const pass = await this.authService.checkPermission(ctx, permission);
|
||||||
const roleIds: number[] = ctx.user.roles;
|
if (!pass) {
|
||||||
const permissions = await this.roleService.getCachedPermissionSetByRoleIds(roleIds);
|
|
||||||
|
|
||||||
if (!permissions.has(permission)) {
|
|
||||||
logger.info('not permission: ', ctx.req.url);
|
logger.info('not permission: ', ctx.req.url);
|
||||||
ctx.status = 401;
|
ctx.status = 401;
|
||||||
ctx.body = Constants.res.permission;
|
ctx.body = Constants.res.permission;
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
|
import { RoleService } from './role-service.js';
|
||||||
|
import { BaseService } from '../../../basic/base-service.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限校验
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
@Scope(ScopeEnum.Singleton)
|
||||||
|
export class AuthService {
|
||||||
|
@Inject()
|
||||||
|
roleService: RoleService;
|
||||||
|
|
||||||
|
async checkPermission(ctx: any, permission: string) {
|
||||||
|
//如果不是仅校验登录,还需要校验是否拥有权限
|
||||||
|
const roleIds: number[] = ctx.user.roles;
|
||||||
|
const permissions = await this.roleService.getCachedPermissionSetByRoleIds(roleIds);
|
||||||
|
if (!permissions.has(permission)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async isAdmin(ctx: any) {
|
||||||
|
const roleIds: number[] = ctx.user.roles;
|
||||||
|
if (roleIds.includes(1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkEntityUserId(ctx: any, service: BaseService<any>, id: any = 0, userKey = 'userId') {
|
||||||
|
const isAdmin = await this.isAdmin(ctx);
|
||||||
|
if (isAdmin) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
await service.checkUserId(id, ctx.user.id, userKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,8 @@ import { logger } from '../../utils/logger.js';
|
|||||||
import { UserService } from '../authority/service/user-service.js';
|
import { UserService } from '../authority/service/user-service.js';
|
||||||
import { SysSettingsService } from '../system/service/sys-settings-service.js';
|
import { SysSettingsService } from '../system/service/sys-settings-service.js';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { SysInstallInfo } from '../system/service/models.js';
|
import { SysInstallInfo, SysLicenseInfo } from '../system/service/models.js';
|
||||||
|
import { verify } from '@certd/pipeline';
|
||||||
|
|
||||||
export type InstallInfo = {
|
export type InstallInfo = {
|
||||||
installTime: number;
|
installTime: number;
|
||||||
@@ -32,6 +33,14 @@ export class AutoInitSite {
|
|||||||
await this.sysSettingsService.saveSetting(installInfo);
|
await this.sysSettingsService.saveSetting(installInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 授权许可
|
||||||
|
const licenseInfo: SysLicenseInfo = await this.sysSettingsService.getSetting(SysLicenseInfo);
|
||||||
|
const req = {
|
||||||
|
subjectId: installInfo.siteId,
|
||||||
|
license: licenseInfo.license,
|
||||||
|
};
|
||||||
|
await verify(req);
|
||||||
|
|
||||||
logger.info('初始化站点完成');
|
logger.info('初始化站点完成');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { PipelineService } from '../service/pipeline-service.js';
|
import { PipelineService } from '../pipeline/service/pipeline-service.js';
|
||||||
import { logger } from '../../../utils/logger.js';
|
import { logger } from '../../utils/logger.js';
|
||||||
|
|
||||||
@Autoload()
|
@Autoload()
|
||||||
@Scope(ScopeEnum.Singleton)
|
@Scope(ScopeEnum.Singleton)
|
||||||
@@ -8,6 +8,9 @@ export class AutoRegisterCron {
|
|||||||
@Inject()
|
@Inject()
|
||||||
pipelineService: PipelineService;
|
pipelineService: PipelineService;
|
||||||
|
|
||||||
|
@Config('preview.enabled')
|
||||||
|
private preview: boolean;
|
||||||
|
|
||||||
// @Inject()
|
// @Inject()
|
||||||
// echoPlugin: EchoPlugin;
|
// echoPlugin: EchoPlugin;
|
||||||
@Config('cron.immediateTriggerOnce')
|
@Config('cron.immediateTriggerOnce')
|
||||||
@@ -16,7 +19,7 @@ export class AutoRegisterCron {
|
|||||||
@Init()
|
@Init()
|
||||||
async init() {
|
async init() {
|
||||||
logger.info('加载定时trigger开始');
|
logger.info('加载定时trigger开始');
|
||||||
await this.pipelineService.onStartup(this.immediateTriggerOnce);
|
await this.pipelineService.onStartup(this.immediateTriggerOnce, this.preview);
|
||||||
// logger.info(this.echoPlugin, this.echoPlugin.test);
|
// logger.info(this.echoPlugin, this.echoPlugin.test);
|
||||||
// logger.info('加载定时trigger完成');
|
// logger.info('加载定时trigger完成');
|
||||||
//
|
//
|
||||||
@@ -29,9 +29,7 @@ export class BasicSettingsController extends BaseController {
|
|||||||
|
|
||||||
@Get('/public', { summary: Constants.per.guest })
|
@Get('/public', { summary: Constants.per.guest })
|
||||||
public async getSysPublic() {
|
public async getSysPublic() {
|
||||||
const settings = await this.sysSettingsService.getSetting(
|
const settings = await this.sysSettingsService.getSetting(SysPublicSettings);
|
||||||
SysPublicSettings
|
|
||||||
);
|
|
||||||
return this.ok(settings);
|
return this.ok(settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import { CommonException } from '../../../basic/exception/common-exception.js';
|
|||||||
import { PermissionException } from '../../../basic/exception/permission-exception.js';
|
import { PermissionException } from '../../../basic/exception/permission-exception.js';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { logger } from '../../../utils/logger.js';
|
import { logger } from '../../../utils/logger.js';
|
||||||
|
import { AuthService } from '../../authority/service/auth-service.js';
|
||||||
|
import { SysSettingsService } from '../../system/service/sys-settings-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 证书
|
* 证书
|
||||||
@@ -25,19 +27,35 @@ export class HistoryController extends CrudController<HistoryService> {
|
|||||||
@Inject()
|
@Inject()
|
||||||
logService: HistoryLogService;
|
logService: HistoryLogService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
authService: AuthService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
sysSettingsService: SysSettingsService;
|
||||||
|
|
||||||
getService() {
|
getService() {
|
||||||
return this.service;
|
return this.service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/page', { summary: Constants.per.authOnly })
|
@Post('/page', { summary: Constants.per.authOnly })
|
||||||
async page(@Body(ALL) body) {
|
async page(@Body(ALL) body) {
|
||||||
body.query.userId = this.ctx.user.id;
|
const isAdmin = await this.authService.isAdmin(this.ctx);
|
||||||
return super.page(body);
|
const publicSettings = await this.sysSettingsService.getPublicSettings();
|
||||||
|
if (!(publicSettings.managerOtherUserPipeline && isAdmin)) {
|
||||||
|
body.query.userId = this.ctx.user.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await super.page(body);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/list', { summary: Constants.per.authOnly })
|
@Post('/list', { summary: Constants.per.authOnly })
|
||||||
async list(@Body(ALL) body) {
|
async list(@Body(ALL) body) {
|
||||||
body.userId = this.ctx.user.id;
|
const isAdmin = await this.authService.isAdmin(this.ctx);
|
||||||
|
if (!isAdmin) {
|
||||||
|
body.userId = this.ctx.user.id;
|
||||||
|
}
|
||||||
if (body.pipelineId == null) {
|
if (body.pipelineId == null) {
|
||||||
return this.ok([]);
|
return this.ok([]);
|
||||||
}
|
}
|
||||||
@@ -56,7 +74,7 @@ export class HistoryController extends CrudController<HistoryService> {
|
|||||||
|
|
||||||
@Post('/update', { summary: Constants.per.authOnly })
|
@Post('/update', { summary: Constants.per.authOnly })
|
||||||
async update(@Body(ALL) bean) {
|
async update(@Body(ALL) bean) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
return super.update(bean);
|
return super.update(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +82,7 @@ export class HistoryController extends CrudController<HistoryService> {
|
|||||||
async save(@Body(ALL) bean: HistoryEntity) {
|
async save(@Body(ALL) bean: HistoryEntity) {
|
||||||
bean.userId = this.ctx.user.id;
|
bean.userId = this.ctx.user.id;
|
||||||
if (bean.id > 0) {
|
if (bean.id > 0) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
}
|
}
|
||||||
await this.service.save(bean);
|
await this.service.save(bean);
|
||||||
return this.ok(bean.id);
|
return this.ok(bean.id);
|
||||||
@@ -74,7 +92,7 @@ export class HistoryController extends CrudController<HistoryService> {
|
|||||||
async saveLog(@Body(ALL) bean: HistoryLogEntity) {
|
async saveLog(@Body(ALL) bean: HistoryLogEntity) {
|
||||||
bean.userId = this.ctx.user.id;
|
bean.userId = this.ctx.user.id;
|
||||||
if (bean.id > 0) {
|
if (bean.id > 0) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
}
|
}
|
||||||
await this.logService.save(bean);
|
await this.logService.save(bean);
|
||||||
return this.ok(bean.id);
|
return this.ok(bean.id);
|
||||||
@@ -82,26 +100,37 @@ export class HistoryController extends CrudController<HistoryService> {
|
|||||||
|
|
||||||
@Post('/delete', { summary: Constants.per.authOnly })
|
@Post('/delete', { summary: Constants.per.authOnly })
|
||||||
async delete(@Query('id') id) {
|
async delete(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
return super.delete(id);
|
await super.delete(id);
|
||||||
|
return this.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/deleteByIds', { summary: Constants.per.authOnly })
|
||||||
|
async deleteByIds(@Body(ALL) body) {
|
||||||
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), body.ids);
|
||||||
|
const isAdmin = await this.authService.isAdmin(this.ctx);
|
||||||
|
const userId = isAdmin ? null : this.ctx.user.id;
|
||||||
|
await this.getService().deleteByIds(body.ids, userId);
|
||||||
|
return this.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/detail', { summary: Constants.per.authOnly })
|
@Post('/detail', { summary: Constants.per.authOnly })
|
||||||
async detail(@Query('id') id) {
|
async detail(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
const detail = await this.service.detail(id);
|
const detail = await this.service.detail(id);
|
||||||
return this.ok(detail);
|
return this.ok(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/logs', { summary: Constants.per.authOnly })
|
@Post('/logs', { summary: Constants.per.authOnly })
|
||||||
async logs(@Query('id') id) {
|
async logs(@Query('id') id) {
|
||||||
await this.logService.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.logService, id);
|
||||||
const logInfo = await this.logService.info(id);
|
const logInfo = await this.logService.info(id);
|
||||||
return this.ok(logInfo);
|
return this.ok(logInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/files', { summary: Constants.per.authOnly })
|
@Post('/files', { summary: Constants.per.authOnly })
|
||||||
async files(@Query('pipelineId') pipelineId, @Query('historyId') historyId) {
|
async files(@Query('pipelineId') pipelineId, @Query('historyId') historyId) {
|
||||||
|
await this.authService.checkEntityUserId(this.ctx, this.service, historyId);
|
||||||
const files = await this.getFiles(historyId, pipelineId);
|
const files = await this.getFiles(historyId, pipelineId);
|
||||||
return this.ok(files);
|
return this.ok(files);
|
||||||
}
|
}
|
||||||
@@ -125,6 +154,7 @@ export class HistoryController extends CrudController<HistoryService> {
|
|||||||
|
|
||||||
@Get('/download', { summary: Constants.per.authOnly })
|
@Get('/download', { summary: Constants.per.authOnly })
|
||||||
async download(@Query('pipelineId') pipelineId, @Query('historyId') historyId, @Query('fileId') fileId) {
|
async download(@Query('pipelineId') pipelineId, @Query('historyId') historyId, @Query('fileId') fileId) {
|
||||||
|
await this.authService.checkEntityUserId(this.ctx, this.service, historyId);
|
||||||
const files = await this.getFiles(historyId, pipelineId);
|
const files = await this.getFiles(historyId, pipelineId);
|
||||||
const file = files.find(f => f.id === fileId);
|
const file = files.find(f => f.id === fileId);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { PipelineService } from '../service/pipeline-service.js';
|
|||||||
import { PipelineEntity } from '../entity/pipeline.js';
|
import { PipelineEntity } from '../entity/pipeline.js';
|
||||||
import { Constants } from '../../../basic/constants.js';
|
import { Constants } from '../../../basic/constants.js';
|
||||||
import { HistoryService } from '../service/history-service.js';
|
import { HistoryService } from '../service/history-service.js';
|
||||||
|
import { AuthService } from '../../authority/service/auth-service.js';
|
||||||
|
import { SysSettingsService } from '../../system/service/sys-settings-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 证书
|
* 证书
|
||||||
@@ -15,6 +17,10 @@ export class PipelineController extends CrudController<PipelineService> {
|
|||||||
service: PipelineService;
|
service: PipelineService;
|
||||||
@Inject()
|
@Inject()
|
||||||
historyService: HistoryService;
|
historyService: HistoryService;
|
||||||
|
@Inject()
|
||||||
|
authService: AuthService;
|
||||||
|
@Inject()
|
||||||
|
sysSettingsService: SysSettingsService;
|
||||||
|
|
||||||
getService() {
|
getService() {
|
||||||
return this.service;
|
return this.service;
|
||||||
@@ -22,10 +28,24 @@ export class PipelineController extends CrudController<PipelineService> {
|
|||||||
|
|
||||||
@Post('/page', { summary: Constants.per.authOnly })
|
@Post('/page', { summary: Constants.per.authOnly })
|
||||||
async page(@Body(ALL) body) {
|
async page(@Body(ALL) body) {
|
||||||
body.query.userId = this.ctx.user.id;
|
const isAdmin = await this.authService.isAdmin(this.ctx);
|
||||||
|
const publicSettings = await this.sysSettingsService.getPublicSettings();
|
||||||
|
if (!(publicSettings.managerOtherUserPipeline && isAdmin)) {
|
||||||
|
body.query.userId = this.ctx.user.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = body.query.title;
|
||||||
|
delete body.query.title;
|
||||||
|
|
||||||
const buildQuery = qb => {
|
const buildQuery = qb => {
|
||||||
qb.where({});
|
if (title) {
|
||||||
|
qb.where('title like :title', { title: `%${title}%` });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
if (!body.sort || !body.sort?.prop) {
|
||||||
|
body.sort = { prop: 'order', asc: false };
|
||||||
|
}
|
||||||
|
|
||||||
return super.page({ ...body, buildQuery });
|
return super.page({ ...body, buildQuery });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +57,7 @@ export class PipelineController extends CrudController<PipelineService> {
|
|||||||
|
|
||||||
@Post('/update', { summary: Constants.per.authOnly })
|
@Post('/update', { summary: Constants.per.authOnly })
|
||||||
async update(@Body(ALL) bean) {
|
async update(@Body(ALL) bean) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
return super.update(bean);
|
return super.update(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,37 +65,36 @@ export class PipelineController extends CrudController<PipelineService> {
|
|||||||
async save(@Body(ALL) bean: PipelineEntity) {
|
async save(@Body(ALL) bean: PipelineEntity) {
|
||||||
bean.userId = this.ctx.user.id;
|
bean.userId = this.ctx.user.id;
|
||||||
if (bean.id > 0) {
|
if (bean.id > 0) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
}
|
}
|
||||||
await this.service.save(bean);
|
await this.service.save(bean);
|
||||||
await this.service.registerTriggerById(bean.id);
|
|
||||||
return this.ok(bean.id);
|
return this.ok(bean.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/delete', { summary: Constants.per.authOnly })
|
@Post('/delete', { summary: Constants.per.authOnly })
|
||||||
async delete(@Query('id') id) {
|
async delete(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
await this.service.delete(id);
|
await this.service.delete(id);
|
||||||
return this.ok({});
|
return this.ok({});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/detail', { summary: Constants.per.authOnly })
|
@Post('/detail', { summary: Constants.per.authOnly })
|
||||||
async detail(@Query('id') id) {
|
async detail(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
const detail = await this.service.detail(id);
|
const detail = await this.service.detail(id);
|
||||||
return this.ok(detail);
|
return this.ok(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/trigger', { summary: Constants.per.authOnly })
|
@Post('/trigger', { summary: Constants.per.authOnly })
|
||||||
async trigger(@Query('id') id) {
|
async trigger(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
await this.service.trigger(id);
|
await this.service.trigger(id);
|
||||||
return this.ok({});
|
return this.ok({});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/cancel', { summary: Constants.per.authOnly })
|
@Post('/cancel', { summary: Constants.per.authOnly })
|
||||||
async cancel(@Query('historyId') historyId) {
|
async cancel(@Query('historyId') historyId) {
|
||||||
await this.historyService.checkUserId(historyId, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.historyService, historyId);
|
||||||
await this.service.cancel(historyId);
|
await this.service.cancel(historyId);
|
||||||
return this.ok({});
|
return this.ok({});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,4 +35,13 @@ export class HistoryEntity {
|
|||||||
default: () => 'CURRENT_TIMESTAMP',
|
default: () => 'CURRENT_TIMESTAMP',
|
||||||
})
|
})
|
||||||
updateTime: Date;
|
updateTime: Date;
|
||||||
|
|
||||||
|
pipelineTitle: string;
|
||||||
|
|
||||||
|
fillPipelineTitle() {
|
||||||
|
if (this.pipeline) {
|
||||||
|
const pipeline = JSON.parse(this.pipeline);
|
||||||
|
this.pipelineTitle = pipeline.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export class PipelineEntity {
|
|||||||
userId: number;
|
userId: number;
|
||||||
|
|
||||||
@Column({ name: 'title', comment: '标题' })
|
@Column({ name: 'title', comment: '标题' })
|
||||||
title: number;
|
title: string;
|
||||||
|
|
||||||
@Column({ comment: '配置', length: 40960 })
|
@Column({ comment: '配置', length: 40960 })
|
||||||
content: string;
|
content: string;
|
||||||
@@ -37,6 +37,16 @@ export class PipelineEntity {
|
|||||||
})
|
})
|
||||||
lastHistoryTime: number;
|
lastHistoryTime: number;
|
||||||
|
|
||||||
|
// 变量
|
||||||
|
lastVars: any;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
name: 'order',
|
||||||
|
comment: '排序',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
order: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
name: 'create_time',
|
name: 'create_time',
|
||||||
comment: '创建时间',
|
comment: '创建时间',
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class DbStorage implements IStorage {
|
|||||||
this.storageService = storageService;
|
this.storageService = storageService;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(scope: string, namespace: string, version: string, key: string): Promise<void> {
|
async remove(scope: string, namespace: string, version: string, key: string): Promise<void> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { BaseService } from '../../../basic/base-service.js';
|
import { BaseService } from '../../../basic/base-service.js';
|
||||||
import { HistoryLogEntity } from '../entity/history-log.js';
|
import { HistoryLogEntity } from '../entity/history-log.js';
|
||||||
|
|
||||||
@@ -24,4 +24,15 @@ export class HistoryLogService extends BaseService<HistoryLogEntity> {
|
|||||||
await this.add(bean);
|
await this.add(bean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteByHistoryIds(numbers: number[]) {
|
||||||
|
if (numbers.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.repository.delete({ historyId: In(numbers) });
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteByPipelineId(id: number) {
|
||||||
|
await this.repository.delete({ pipelineId: id });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { BaseService } from '../../../basic/base-service.js';
|
import { BaseService } from '../../../basic/base-service.js';
|
||||||
import { HistoryEntity } from '../entity/history.js';
|
import { HistoryEntity } from '../entity/history.js';
|
||||||
import { PipelineEntity } from '../entity/pipeline.js';
|
import { PipelineEntity } from '../entity/pipeline.js';
|
||||||
@@ -28,6 +28,14 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
|||||||
return this.repository;
|
return this.repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async page(query, page, sort, buildQuery) {
|
||||||
|
const res = await super.page(query, page, sort, buildQuery);
|
||||||
|
for (const item of res.records) {
|
||||||
|
item.fillPipelineTitle();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
async save(bean: HistoryEntity) {
|
async save(bean: HistoryEntity) {
|
||||||
if (bean.id > 0) {
|
if (bean.id > 0) {
|
||||||
await this.update(bean);
|
await this.update(bean);
|
||||||
@@ -51,7 +59,7 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
|||||||
};
|
};
|
||||||
const { id } = await this.add(bean);
|
const { id } = await this.add(bean);
|
||||||
//清除大于pipeline.keepHistoryCount的历史记录
|
//清除大于pipeline.keepHistoryCount的历史记录
|
||||||
this.clear(pipeline.id, pipeline.keepHistoryCount);
|
await this.clear(pipeline.id, pipeline.keepHistoryCount);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +93,6 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
|||||||
skip: 0,
|
skip: 0,
|
||||||
take: deleteCountBatch,
|
take: deleteCountBatch,
|
||||||
});
|
});
|
||||||
await this.repository.remove(list);
|
|
||||||
|
|
||||||
for (const historyEntity of list) {
|
for (const historyEntity of list) {
|
||||||
const id = historyEntity.id;
|
const id = historyEntity.id;
|
||||||
@@ -95,6 +102,9 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
|||||||
logger.error('删除文件失败', e);
|
logger.error('删除文件失败', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await this.repository.remove(list);
|
||||||
|
|
||||||
|
await this.logService.deleteByHistoryIds(list.map(item => item.id));
|
||||||
|
|
||||||
shouldDeleteCount -= deleteCountBatch;
|
shouldDeleteCount -= deleteCountBatch;
|
||||||
}
|
}
|
||||||
@@ -124,4 +134,29 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
|||||||
});
|
});
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteByIds(ids: number[], userId: number) {
|
||||||
|
await this.repository.delete({
|
||||||
|
id: In(ids),
|
||||||
|
userId,
|
||||||
|
});
|
||||||
|
await this.logService.deleteByHistoryIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteByPipelineId(id: number) {
|
||||||
|
await this.repository.delete({
|
||||||
|
pipelineId: id,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileStore = new FileStore({
|
||||||
|
rootDir: this.certdConfig.fileRootDir,
|
||||||
|
scope: id + '',
|
||||||
|
parent: '0',
|
||||||
|
});
|
||||||
|
fileStore.deleteByParent(id + '', '');
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('删除文件失败', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,23 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
return this.repository;
|
return this.repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(entity) {
|
async page(query: any, page: { offset: number; limit: number }, order: any, buildQuery: any) {
|
||||||
await super.update(entity);
|
const result = await super.page(query, page, order, buildQuery);
|
||||||
|
const pipelineIds: number[] = [];
|
||||||
|
const recordMap = {};
|
||||||
|
for (const record of result.records) {
|
||||||
|
pipelineIds.push(record.id);
|
||||||
|
recordMap[record.id] = record;
|
||||||
|
}
|
||||||
|
const vars = await this.storageService.findPipelineVars(pipelineIds);
|
||||||
|
for (const varEntity of vars) {
|
||||||
|
const record = recordMap[varEntity.namespace];
|
||||||
|
if (record) {
|
||||||
|
const value = JSON.parse(varEntity.value);
|
||||||
|
record.lastVars = value.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async registerTriggerById(pipelineId) {
|
public async registerTriggerById(pipelineId) {
|
||||||
@@ -71,17 +86,21 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
return new PipelineDetail(pipeline);
|
return new PipelineDetail(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async update(bean: PipelineEntity) {
|
||||||
|
await this.clearTriggers(bean.id);
|
||||||
|
await super.update(bean);
|
||||||
|
await this.registerTriggerById(bean.id);
|
||||||
|
}
|
||||||
|
|
||||||
async save(bean: PipelineEntity) {
|
async save(bean: PipelineEntity) {
|
||||||
|
await this.clearTriggers(bean.id);
|
||||||
const pipeline = JSON.parse(bean.content);
|
const pipeline = JSON.parse(bean.content);
|
||||||
bean.title = pipeline.title;
|
bean.title = pipeline.title;
|
||||||
await this.addOrUpdate(bean);
|
await this.addOrUpdate(bean);
|
||||||
|
await this.registerTriggerById(bean.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async foreachPipeline(callback: (pipeline: PipelineEntity) => void) {
|
||||||
* 应用启动后初始加载记录
|
|
||||||
*/
|
|
||||||
async onStartup(immediateTriggerOnce: boolean) {
|
|
||||||
logger.info('加载定时trigger开始');
|
|
||||||
const idEntityList = await this.repository.find({
|
const idEntityList = await this.repository.find({
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
@@ -112,15 +131,36 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const entity of list) {
|
for (const entity of list) {
|
||||||
const pipeline = JSON.parse(entity.content ?? '{}');
|
await callback(entity);
|
||||||
try {
|
|
||||||
await this.registerTriggers(pipeline, immediateTriggerOnce);
|
|
||||||
} catch (e) {
|
|
||||||
logger.error('加载定时trigger失败:', e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info('定时器数量:', this.cron.getListSize());
|
}
|
||||||
|
|
||||||
|
async stopOtherUserPipeline(userId: number) {
|
||||||
|
await this.foreachPipeline(async entity => {
|
||||||
|
if (entity.userId !== userId) {
|
||||||
|
await this.clearTriggers(entity.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用启动后初始加载记录
|
||||||
|
*/
|
||||||
|
async onStartup(immediateTriggerOnce: boolean, preview: boolean) {
|
||||||
|
logger.info('加载定时trigger开始');
|
||||||
|
await this.foreachPipeline(async entity => {
|
||||||
|
if (preview && entity.userId !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pipeline = JSON.parse(entity.content ?? '{}');
|
||||||
|
try {
|
||||||
|
await this.registerTriggers(pipeline, immediateTriggerOnce);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('加载定时trigger失败:', e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
logger.info('定时器数量:', this.cron.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerTriggers(pipeline?: Pipeline, immediateTriggerOnce = false) {
|
async registerTriggers(pipeline?: Pipeline, immediateTriggerOnce = false) {
|
||||||
@@ -153,6 +193,19 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async delete(id: number) {
|
async delete(id: number) {
|
||||||
|
await this.clearTriggers(id);
|
||||||
|
//TODO 删除storage
|
||||||
|
// const storage = new DbStorage(pipeline.userId, this.storageService);
|
||||||
|
// await storage.remove(pipeline.id);
|
||||||
|
await super.delete([id]);
|
||||||
|
await this.historyService.deleteByPipelineId(id);
|
||||||
|
await this.historyLogService.deleteByPipelineId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clearTriggers(id: number) {
|
||||||
|
if (id == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const pipeline = await this.info(id);
|
const pipeline = await this.info(id);
|
||||||
if (!pipeline) {
|
if (!pipeline) {
|
||||||
return;
|
return;
|
||||||
@@ -163,7 +216,6 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
this.removeCron(id, trigger);
|
this.removeCron(id, trigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await super.delete([id]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeCron(pipelineId, trigger) {
|
removeCron(pipelineId, trigger) {
|
||||||
@@ -176,6 +228,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
if (cron == null) {
|
if (cron == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
cron = cron.trim();
|
||||||
if (cron.startsWith('*')) {
|
if (cron.startsWith('*')) {
|
||||||
cron = '0' + cron.substring(1, cron.length);
|
cron = '0' + cron.substring(1, cron.length);
|
||||||
}
|
}
|
||||||
@@ -183,7 +236,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
this.cron.remove(name);
|
this.cron.remove(name);
|
||||||
this.cron.register({
|
this.cron.register({
|
||||||
name,
|
name,
|
||||||
cron: cron,
|
cron,
|
||||||
job: async () => {
|
job: async () => {
|
||||||
logger.info('定时任务触发:', pipelineId, trigger.id);
|
logger.info('定时任务触发:', pipelineId, trigger.id);
|
||||||
try {
|
try {
|
||||||
@@ -193,11 +246,12 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
logger.info('当前定时器数量:', this.cron.getListSize());
|
logger.info('当前定时器数量:', this.cron.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(id: number, triggerId: string) {
|
async run(id: number, triggerId: string) {
|
||||||
const entity: PipelineEntity = await this.info(id);
|
const entity: PipelineEntity = await this.info(id);
|
||||||
|
|
||||||
const pipeline = JSON.parse(entity.content);
|
const pipeline = JSON.parse(entity.content);
|
||||||
|
|
||||||
if (!pipeline.stages || pipeline.stages.length === 0) {
|
if (!pipeline.stages || pipeline.stages.length === 0) {
|
||||||
@@ -209,9 +263,16 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (triggerType === 'timer') {
|
||||||
|
if (entity.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const onChanged = async (history: RunHistory) => {
|
const onChanged = async (history: RunHistory) => {
|
||||||
//保存执行历史
|
//保存执行历史
|
||||||
try {
|
try {
|
||||||
|
logger.info('保存执行历史:', history.id);
|
||||||
await this.saveHistory(history);
|
await this.saveHistory(history);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const pipelineEntity = new PipelineEntity();
|
const pipelineEntity = new PipelineEntity();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { BaseService } from '../../../basic/base-service.js';
|
import { BaseService } from '../../../basic/base-service.js';
|
||||||
import { StorageEntity } from '../entity/storage.js';
|
import { StorageEntity } from '../entity/storage.js';
|
||||||
|
|
||||||
@@ -41,4 +41,14 @@ export class StorageService extends BaseService<StorageEntity> {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findPipelineVars(pipelineIds: number[]) {
|
||||||
|
return await this.repository.find({
|
||||||
|
where: {
|
||||||
|
scope: 'pipeline',
|
||||||
|
namespace: In(pipelineIds),
|
||||||
|
key: 'vars',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import cron from 'node-cron';
|
import parser from 'cron-parser';
|
||||||
export type CronTask = {
|
import { ILogger } from '@certd/pipeline';
|
||||||
|
|
||||||
|
export type CronTaskReq = {
|
||||||
/**
|
/**
|
||||||
* 为空则为单次执行
|
* 为空则为单次执行
|
||||||
*/
|
*/
|
||||||
@@ -7,39 +9,90 @@ export type CronTask = {
|
|||||||
job: () => Promise<void>;
|
job: () => Promise<void>;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class CronTask {
|
||||||
|
logger: ILogger;
|
||||||
|
cron: string;
|
||||||
|
job: () => Promise<void>;
|
||||||
|
name: string;
|
||||||
|
stoped = false;
|
||||||
|
|
||||||
|
timeoutId: any;
|
||||||
|
|
||||||
|
constructor(req: CronTaskReq, logger: ILogger) {
|
||||||
|
this.cron = req.cron;
|
||||||
|
this.job = req.job;
|
||||||
|
this.name = req.name;
|
||||||
|
this.logger = logger;
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
if (!this.cron) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.stoped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const interval = parser.parseExpression(this.cron);
|
||||||
|
const next = interval.next().getTime();
|
||||||
|
const now = Date.now();
|
||||||
|
const delay = next - now;
|
||||||
|
this.timeoutId = setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
if (this.stoped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.job();
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`[cron] job error : [${this.name}]`, e);
|
||||||
|
}
|
||||||
|
this.start();
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.stoped = true;
|
||||||
|
clearTimeout(this.timeoutId);
|
||||||
|
}
|
||||||
|
}
|
||||||
export class Cron {
|
export class Cron {
|
||||||
logger;
|
logger: ILogger;
|
||||||
immediateTriggerOnce: boolean;
|
immediateTriggerOnce: boolean;
|
||||||
constructor(opts) {
|
|
||||||
|
bucket: Record<string, CronTask> = {};
|
||||||
|
|
||||||
|
constructor(opts: any) {
|
||||||
this.logger = opts.logger;
|
this.logger = opts.logger;
|
||||||
this.immediateTriggerOnce = opts.immediateTriggerOnce;
|
this.immediateTriggerOnce = opts.immediateTriggerOnce;
|
||||||
}
|
}
|
||||||
|
|
||||||
register(task: CronTask) {
|
register(req: CronTaskReq) {
|
||||||
if (!task.cron) {
|
if (!req.cron) {
|
||||||
this.logger.info(`[cron] register once : [${task.name}]`);
|
this.logger.info(`[cron] register once : [${req.name}]`);
|
||||||
task.job();
|
req.job().catch(e => {
|
||||||
|
this.logger.error(`job execute error : [${req.name}]`, e);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.logger.info(`[cron] register cron : [${task.name}] ,${task.cron}`);
|
this.logger.info(`[cron] register cron : [${req.name}] ,${req.cron}`);
|
||||||
cron.schedule(task.cron, task.job, {
|
|
||||||
name: task.name,
|
const task = new CronTask(req, this.logger);
|
||||||
});
|
this.bucket[task.name] = task;
|
||||||
this.logger.info('当前定时任务数量:', this.getListSize());
|
this.logger.info('当前定时任务数量:', this.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(taskName: string) {
|
remove(taskName: string) {
|
||||||
this.logger.info(`[cron] remove : [${taskName}]`);
|
this.logger.info(`[cron] remove : [${taskName}]`);
|
||||||
const tasks = cron.getTasks() as Map<any, any>;
|
const task = this.bucket[taskName];
|
||||||
const node = tasks.get(taskName);
|
if (task) {
|
||||||
if (node) {
|
task.stop();
|
||||||
node.stop();
|
delete this.bucket[taskName];
|
||||||
tasks.delete(taskName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getListSize() {
|
getTaskSize() {
|
||||||
const tasks = cron.getTasks();
|
const tasks = Object.keys(this.bucket);
|
||||||
return tasks.size;
|
return tasks.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { SysSettingsService } from '../service/sys-settings-service.js';
|
|||||||
import { SysSettingsEntity } from '../entity/sys-settings.js';
|
import { SysSettingsEntity } from '../entity/sys-settings.js';
|
||||||
import { SysPublicSettings } from '../service/models.js';
|
import { SysPublicSettings } from '../service/models.js';
|
||||||
import * as _ from 'lodash-es';
|
import * as _ from 'lodash-es';
|
||||||
|
import { PipelineService } from '../../pipeline/service/pipeline-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@@ -12,6 +13,8 @@ import * as _ from 'lodash-es';
|
|||||||
export class SysSettingsController extends CrudController<SysSettingsService> {
|
export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||||
@Inject()
|
@Inject()
|
||||||
service: SysSettingsService;
|
service: SysSettingsService;
|
||||||
|
@Inject()
|
||||||
|
pipelineService: PipelineService;
|
||||||
|
|
||||||
getService() {
|
getService() {
|
||||||
return this.service;
|
return this.service;
|
||||||
@@ -73,4 +76,9 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
|||||||
await this.service.savePublicSettings(setting);
|
await this.service.savePublicSettings(setting);
|
||||||
return this.ok({});
|
return this.ok({});
|
||||||
}
|
}
|
||||||
|
@Post('/stopOtherUserTimer', { summary: 'sys:settings:edit' })
|
||||||
|
async stopOtherUserTimer(@Body(ALL) body) {
|
||||||
|
await this.pipelineService.stopOtherUserPipeline(1);
|
||||||
|
return this.ok({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export class SysPublicSettings extends BaseSettings {
|
|||||||
static __title__ = '系统公共设置';
|
static __title__ = '系统公共设置';
|
||||||
static __access__ = 'public';
|
static __access__ = 'public';
|
||||||
registerEnabled = false;
|
registerEnabled = false;
|
||||||
|
managerOtherUserPipeline = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SysPrivateSettings extends BaseSettings {
|
export class SysPrivateSettings extends BaseSettings {
|
||||||
@@ -27,3 +28,10 @@ export class SysInstallInfo extends BaseSettings {
|
|||||||
installTime: number;
|
installTime: number;
|
||||||
siteId?: string;
|
siteId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SysLicenseInfo extends BaseSettings {
|
||||||
|
static __title__ = '授权许可信息';
|
||||||
|
static __key__ = 'sys.license';
|
||||||
|
static __access__ = 'private';
|
||||||
|
license?: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
|
|||||||
default: 'cn-hangzhou',
|
default: 'cn-hangzhou',
|
||||||
component: {
|
component: {
|
||||||
name: 'a-select',
|
name: 'a-select',
|
||||||
|
mode: 'tags',
|
||||||
vModel: 'value',
|
vModel: 'value',
|
||||||
options: ZoneOptions,
|
options: ZoneOptions,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export class CloudflareDeployToCDNPlugin extends AbstractTaskPlugin {
|
|||||||
component: {
|
component: {
|
||||||
//前端组件配置,具体配置见组件文档 https://www.antdv.com/components/select-cn
|
//前端组件配置,具体配置见组件文档 https://www.antdv.com/components/select-cn
|
||||||
name: 'a-select',
|
name: 'a-select',
|
||||||
|
mode: 'tags',
|
||||||
options: [
|
options: [
|
||||||
{ value: '1', label: '选项1' },
|
{ value: '1', label: '选项1' },
|
||||||
{ value: '2', label: '选项2' },
|
{ value: '2', label: '选项2' },
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export class DemoTestPlugin extends AbstractTaskPlugin {
|
|||||||
component: {
|
component: {
|
||||||
//前端组件配置,具体配置见组件文档 https://www.antdv.com/components/select-cn
|
//前端组件配置,具体配置见组件文档 https://www.antdv.com/components/select-cn
|
||||||
name: 'a-select',
|
name: 'a-select',
|
||||||
|
mode: 'tags',
|
||||||
options: [
|
options: [
|
||||||
{ value: '1', label: '选项1' },
|
{ value: '1', label: '选项1' },
|
||||||
{ value: '2', label: '选项2' },
|
{ value: '2', label: '选项2' },
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export class DnspodAccess {
|
|||||||
component: {
|
component: {
|
||||||
placeholder: 'endpoint',
|
placeholder: 'endpoint',
|
||||||
name: 'a-select',
|
name: 'a-select',
|
||||||
|
mode: 'tags',
|
||||||
vModel: 'value',
|
vModel: 'value',
|
||||||
options: [
|
options: [
|
||||||
{ value: 'https://dnsapi.cn', label: '中国站' },
|
{ value: 'https://dnsapi.cn', label: '中国站' },
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import { Autowire, HttpClient, ILogger } from '@certd/pipeline';
|
import { Autowire, HttpClient, ILogger } from '@certd/pipeline';
|
||||||
import {
|
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||||
AbstractDnsProvider,
|
|
||||||
CreateRecordOptions,
|
|
||||||
IsDnsProvider,
|
|
||||||
RemoveRecordOptions,
|
|
||||||
} from '@certd/plugin-cert';
|
|
||||||
import * as _ from 'lodash-es';
|
import * as _ from 'lodash-es';
|
||||||
import { DnspodAccess } from '../access/index.js';
|
import { DnspodAccess } from '../access/index.js';
|
||||||
|
|
||||||
@@ -50,9 +45,7 @@ export class DnspodDnsProvider extends AbstractDnsProvider {
|
|||||||
if (!ret || !ret.status) {
|
if (!ret || !ret.status) {
|
||||||
const code = ret.status.code;
|
const code = ret.status.code;
|
||||||
if (code !== '1' || !successCodes.includes(code)) {
|
if (code !== '1' || !successCodes.includes(code)) {
|
||||||
throw new Error(
|
throw new Error('请求失败:' + ret.status.message + ',api=' + config.url);
|
||||||
'请求失败:' + ret.status.message + ',api=' + config.url
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -87,12 +80,7 @@ export class DnspodDnsProvider extends AbstractDnsProvider {
|
|||||||
},
|
},
|
||||||
['104']
|
['104']
|
||||||
); // 104错误码为记录已存在,无需再次添加
|
); // 104错误码为记录已存在,无需再次添加
|
||||||
this.logger.info(
|
this.logger.info('添加域名解析成功:', fullRecord, value, JSON.stringify(ret.record));
|
||||||
'添加域名解析成功:',
|
|
||||||
fullRecord,
|
|
||||||
value,
|
|
||||||
JSON.stringify(ret.record)
|
|
||||||
);
|
|
||||||
return ret.record;
|
return ret.record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,28 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
|
|||||||
default: 'ap-guangzhou',
|
default: 'ap-guangzhou',
|
||||||
component: {
|
component: {
|
||||||
name: 'a-select',
|
name: 'a-select',
|
||||||
options: [{ value: 'ap-guangzhou' }],
|
mode: 'tags',
|
||||||
|
options: [
|
||||||
|
{ value: 'ap-guangzhou' },
|
||||||
|
{ value: 'ap-beijing' },
|
||||||
|
{ value: 'ap-chengdu' },
|
||||||
|
{ value: 'ap-chongqing' },
|
||||||
|
{ value: 'ap-hongkong' },
|
||||||
|
{ value: 'ap-jakarta' },
|
||||||
|
{ value: 'ap-mumbai' },
|
||||||
|
{ value: 'ap-nanjing' },
|
||||||
|
{ value: 'ap-seoul' },
|
||||||
|
{ value: 'ap-shanghai' },
|
||||||
|
{ value: 'ap-shanghai-fsi' },
|
||||||
|
{ value: 'ap-shenzhen-fsi' },
|
||||||
|
{ value: 'ap-singapore' },
|
||||||
|
{ value: 'ap-tokyo' },
|
||||||
|
{ value: 'eu-frankfurt' },
|
||||||
|
{ value: 'na-ashburn' },
|
||||||
|
{ value: 'na-siliconvalley' },
|
||||||
|
{ value: 'na-toronto' },
|
||||||
|
{ value: 'sa-saopaulo' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user