Compare commits

...

18 Commits

Author SHA1 Message Date
xiaojunnuo
e96a83a528 v1.26.4 2024-10-14 12:35:07 +08:00
xiaojunnuo
fbddd7ead8 build: prepare to build 2024-10-14 12:33:40 +08:00
xiaojunnuo
762a2058d3 chore: pg sql自动转换脚本 2024-10-14 12:33:09 +08:00
xiaojunnuo
2bc0a4bd14 fix: 2024-10-14 11:52:37 +08:00
xiaojunnuo
e052e304bd docs: 2024-10-14 11:41:34 +08:00
xiaojunnuo
50c56d134e pref: 启动输出版本和站点id 2024-10-14 10:57:12 +08:00
xiaojunnuo
4caa2fad9d chore: 2024-10-14 10:27:11 +08:00
xiaojunnuo
07043aff0c perf: EAB授权支持绑定邮箱,支持公共EAB设置 2024-10-14 03:17:10 +08:00
xiaojunnuo
e8b617b80c perf: [comm] 支持插件管理 2024-10-14 00:19:55 +08:00
xiaojunnuo
417971d15d chore: 目录调整,controller转移到外部单独的目录 2024-10-13 21:59:29 +08:00
xiaojunnuo
ccfe72a0d9 chore: plugin管理 2024-10-13 01:27:08 +08:00
xiaojunnuo
6f8fe62087 chore: 2024-10-12 23:51:05 +08:00
xiaojunnuo
5601bc4ab2 chore: 2024-10-12 18:30:40 +08:00
xiaojunnuo
67ba17286c Merge branch 'refs/heads/v2' into v2-dev 2024-10-12 17:24:01 +08:00
xiaojunnuo
a10b8aa042 chore: 2024-10-12 17:04:53 +08:00
xiaojunnuo
273ab6139f perf: 新增代理设置功能 2024-10-12 16:49:49 +08:00
xiaojunnuo
9b68009eb3 build: publish 2024-10-12 15:07:02 +08:00
xiaojunnuo
aec2448406 build: trigger build image 2024-10-12 15:06:44 +08:00
132 changed files with 2016 additions and 648 deletions

View File

@@ -3,6 +3,14 @@
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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
### Performance Improvements
* [comm] 支持插件管理 ([e8b617b](https://github.com/certd/certd/commit/e8b617b80ce882dd63006f0cfc719a80a1cc6acc))
* 新增代理设置功能 ([273ab61](https://github.com/certd/certd/commit/273ab6139f5807f4d7fe865cc353b97f51b9a668))
* EAB授权支持绑定邮箱支持公共EAB设置 ([07043af](https://github.com/certd/certd/commit/07043aff0ca7fd29c56dd3c363002cb15d78b464))
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
### Performance Improvements ### Performance Improvements

View File

@@ -9,11 +9,11 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的工具。
## 一、特性 ## 一、特性
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。 本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
* 全自动申请证书(支持阿里云、腾讯云、华为云、Cloudflare等各种途径注册的域名) * 全自动申请证书(支持所有注册商注册的域名)
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等) * 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等目前已支持30+部署插件
* 支持通配符域名/泛域名,支持多个域名打到一个证书上 * 支持通配符域名/泛域名,支持多个域名打到一个证书上
* 邮件通知 * 邮件通知
* 私有化部署,保障安全 * 私有化部署,保障数据安全
* 免费、免费、免费([阿里云单个通配符域名证书最便宜也要1800/年](https://yundun.console.aliyun.com/?p=cas#/certExtend/buy/cn-hangzhou) * 免费、免费、免费([阿里云单个通配符域名证书最便宜也要1800/年](https://yundun.console.aliyun.com/?p=cas#/certExtend/buy/cn-hangzhou)
@@ -124,6 +124,7 @@ git clone https://github.com/certd/certd
cd certd cd certd
# 启动服务 # 启动服务
./start.sh ./start.sh
# 数据默认保存在 ./packages/ui/certd-server/data 目录下,注意数据备份
``` ```
如果是windows请先安装`git for windows` ,然后右键,选择`open git bash here`打开终端,再执行`./start.sh`命令 如果是windows请先安装`git for windows` ,然后右键,选择`open git bash here`打开终端,再执行`./start.sh`命令
@@ -169,6 +170,7 @@ docker compose up -d
* [google证书](./doc/google/google.md) * [google证书](./doc/google/google.md)
* [群晖部署certd及证书更新教程](./doc/synology/index.md) * [群晖部署certd及证书更新教程](./doc/synology/index.md)
* [CNAME证书校验方式说明](./doc/cname/index.md)
## 八、问题处理 ## 八、问题处理
### 7.1 忘记管理员密码 ### 7.1 忘记管理员密码

View File

@@ -1 +1 @@
13:39 15:06

BIN
doc/cname/images/cname1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
doc/cname/images/cname2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
doc/cname/images/cname3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

BIN
doc/cname/images/cname4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

27
doc/cname/index.md Normal file
View File

@@ -0,0 +1,27 @@
# CNAME代理校验方式说明
## 1. 前言
申请域名证书是需要校验域名所有权的。
目前有两种校验方式:
1. http-01 在网站根目录下放置一份txt文件Certd不支持
2. dns-01 需要给域名添加txt解析记录通配符域名只能用这种方式Certd采用这种方式
DNS-01方式需要开发适配DNS服务商的接口目前已实现主流域名注册商的接口阿里云、腾讯云、华为云、Cloudflare、西数
如果域名不在这几家那么就只能通过CNAME代理校验方式来实现
## 2. 使用步骤
1. 假设你要申请证书的域名叫need.cert.com ,它是在其他服务商注册的
2. 现在你需要另外一个域名cname.foo.com这个域名属于是在阿里云、腾讯云、华为云、Cloudflare、西数或者你把这个域名的DNS服务器转到这几家。
3. 到Certd的 CNAME服务管理界面`cname.foo.com`创建一条默认的CNAME服务需要提供DNS提供商授权。
![](./images/cname1.png)
4. 申请证书时Certd会生成一个随机的CNAME记录例如`_acme-challenge.need`->`xxxxxx.cname.foo.com`
![](./images/cname2.png)
5. 您需要手动添加这条CNAME记录到你要申请证书的域名解析中点击校验校验成功后就可以开始申请证书了 (此操作每个域名只需要做一次后续可以重复使用注意不要删除添加的CNAME记录)
![](./images/cname3.png)
6. ![](./images/cname4.png)
6. 申请过程中Certd会在`xxxxxx.cname.foo.com`下自动添加验证TXT记录。
7. 由于您配置了`_acme-challenge.need`的CNAME所以这个TXT记录会被解析到`_acme-challenge.need.cert.com`下,从而完成域名校验。

View File

@@ -9,5 +9,5 @@
} }
}, },
"npmClient": "pnpm", "npmClient": "pnpm",
"version": "1.26.3" "version": "1.26.4"
} }

View File

@@ -14,11 +14,12 @@
"i-all": "lerna link && lerna exec npm install ", "i-all": "lerna link && lerna exec npm install ",
"publish": "npm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits --create-release github && npm run afterpublishOnly && npm run commitAll", "publish": "npm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits --create-release github && npm run afterpublishOnly && npm run commitAll",
"afterpublishOnly": "time /t >build.trigger && git add ./build.trigger && 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",
"transform-sql":"cd ./packages/ui/certd-server/db/ && node --experimental-json-modules transform.js",
"commitAll": "git add . && git commit -m \"build: publish\" && git push && npm run commitPro", "commitAll": "git add . && git commit -m \"build: publish\" && git push && npm run commitPro",
"commitPro": "cd ./packages/core/ && git add . && git commit -m \"build: publish\" && git push", "commitPro": "cd ./packages/core/ && git add . && git commit -m \"build: publish\" && git push",
"prepublishOnly1": "npm run check && lerna run build ", "prepublishOnly1": "npm run check && lerna run build ",
"prepublishOnly2": "npm run check && npm run before-build && lerna run build ", "prepublishOnly2": "npm run check && npm run before-build && lerna run build ",
"before-build": "cd ./packages/core/basic && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"", "before-build": "npm run transform-sql && cd ./packages/core/basic && 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",
"init": "lerna run build" "init": "lerna run build"

View File

@@ -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.26.4](https://github.com/publishlab/node-acme-client/compare/v1.26.3...v1.26.4) (2024-10-14)
**Note:** Version bump only for package @certd/acme-client
## [1.26.3](https://github.com/publishlab/node-acme-client/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/publishlab/node-acme-client/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/acme-client **Note:** Version bump only for package @certd/acme-client

View File

@@ -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.26.3", "version": "1.26.4",
"main": "src/index.js", "main": "src/index.js",
"types": "types/index.d.ts", "types": "types/index.d.ts",
"license": "MIT", "license": "MIT",
@@ -59,5 +59,5 @@
"bugs": { "bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues" "url": "https://github.com/publishlab/node-acme-client/issues"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -3,6 +3,12 @@
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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
### Performance Improvements
* 新增代理设置功能 ([273ab61](https://github.com/certd/certd/commit/273ab6139f5807f4d7fe865cc353b97f51b9a668))
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/basic **Note:** Version bump only for package @certd/basic

View File

@@ -1 +1 @@
15:04 12:33

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/basic", "name": "@certd/basic",
"private": false, "private": false,
"version": "1.26.3", "version": "1.26.4",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js", "module": "./dist/index.js",
@@ -64,5 +64,5 @@
"vite": "^4.3.8", "vite": "^4.3.8",
"vue-tsc": "^1.6.5" "vue-tsc": "^1.6.5"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -47,6 +47,21 @@ export class HttpError extends Error {
} }
export const HttpCommonError = HttpError; export const HttpCommonError = HttpError;
let defaultAgents = createAgent();
export function setGlobalProxy(opts: { httpProxy?: string; httpsProxy?: string }) {
logger.info('setGlobalProxy:', opts);
if (opts.httpProxy) {
process.env.HTTP_PROXY = opts.httpProxy;
}
if (opts.httpsProxy) {
process.env.HTTPS_PROXY = opts.httpsProxy;
}
defaultAgents = createAgent();
}
/** /**
* @description 创建请求实例 * @description 创建请求实例
*/ */
@@ -54,7 +69,6 @@ export function createAxiosService({ logger }: { logger: Logger }) {
// 创建一个 axios 实例 // 创建一个 axios 实例
const service = axios.create(); const service = axios.create();
const defaultAgents = createAgent();
// 请求拦截 // 请求拦截
service.interceptors.request.use( service.interceptors.request.use(
(config: any) => { (config: any) => {

View File

@@ -3,6 +3,13 @@
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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
### Performance Improvements
* [comm] 支持插件管理 ([e8b617b](https://github.com/certd/certd/commit/e8b617b80ce882dd63006f0cfc719a80a1cc6acc))
* EAB授权支持绑定邮箱支持公共EAB设置 ([07043af](https://github.com/certd/certd/commit/07043aff0ca7fd29c56dd3c363002cb15d78b464))
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/pipeline **Note:** Version bump only for package @certd/pipeline

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/pipeline", "name": "@certd/pipeline",
"private": false, "private": false,
"version": "1.26.3", "version": "1.26.4",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
@@ -15,8 +15,8 @@
"test": "mocha --loader=ts-node/esm" "test": "mocha --loader=ts-node/esm"
}, },
"dependencies": { "dependencies": {
"@certd/basic": "^1.26.3", "@certd/basic": "^1.26.4",
"@certd/plus-core": "^1.26.3", "@certd/plus-core": "^1.26.4",
"axios": "^1.7.2", "axios": "^1.7.2",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"fix-path": "^4.0.0", "fix-path": "^4.0.0",
@@ -66,5 +66,5 @@
"vite": "^4.3.8", "vite": "^4.3.8",
"vue-tsc": "^1.6.5" "vue-tsc": "^1.6.5"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -1,18 +1,16 @@
import { ConcurrencyStrategy, NotificationWhen, Pipeline, ResultType, Runnable, RunStrategy, Stage, Step, Task } from "../dt/index.js"; import { ConcurrencyStrategy, NotificationWhen, Pipeline, ResultType, Runnable, RunStrategy, Stage, Step, Task } from "../dt/index.js";
import _ from "lodash-es";
import { RunHistory, RunnableCollection } from "./run-history.js"; import { RunHistory, RunnableCollection } from "./run-history.js";
import { AbstractTaskPlugin, PluginDefine, pluginRegistry, TaskInstanceContext, UserInfo } from "../plugin/index.js"; import { AbstractTaskPlugin, PluginDefine, pluginRegistry, TaskInstanceContext, UserInfo } from "../plugin/index.js";
import { ContextFactory, IContext } from "./context.js"; import { ContextFactory, IContext } from "./context.js";
import { IStorage } from "./storage.js"; import { IStorage } from "./storage.js";
import { logger } from "../utils/index.js"; import { createAxiosService, hashUtils, logger, utils } from "../utils/index.js";
import { Logger } from "log4js"; import { Logger } from "log4js";
import { createAxiosService } from "../utils/index.js";
import { IAccessService } from "../access/index.js"; import { IAccessService } from "../access/index.js";
import { RegistryItem } from "../registry/index.js"; import { RegistryItem } from "../registry/index.js";
import { Decorator } from "../decorator/index.js"; import { Decorator } from "../decorator/index.js";
import { ICnameProxyService, IEmailService } from "../service/index.js"; import { ICnameProxyService, IEmailService, IPluginConfigService } from "../service/index.js";
import { FileStore } from "./file-store.js"; import { FileStore } from "./file-store.js";
import { hashUtils, utils } from "../utils/index.js"; import { cloneDeep, forEach, merge } from "lodash-es";
export type ExecutorOptions = { export type ExecutorOptions = {
pipeline: Pipeline; pipeline: Pipeline;
@@ -21,6 +19,7 @@ export type ExecutorOptions = {
accessService: IAccessService; accessService: IAccessService;
emailService: IEmailService; emailService: IEmailService;
cnameProxyService: ICnameProxyService; cnameProxyService: ICnameProxyService;
pluginConfigService: IPluginConfigService;
fileRootDir?: string; fileRootDir?: string;
user: UserInfo; user: UserInfo;
}; };
@@ -42,7 +41,7 @@ export class Executor {
onChanged: (history: RunHistory) => Promise<void>; onChanged: (history: RunHistory) => Promise<void>;
constructor(options: ExecutorOptions) { constructor(options: ExecutorOptions) {
this.options = options; this.options = options;
this.pipeline = _.cloneDeep(options.pipeline); this.pipeline = cloneDeep(options.pipeline);
this.onChanged = async (history: RunHistory) => { this.onChanged = async (history: RunHistory) => {
await options.onChanged(history); await options.onChanged(history);
}; };
@@ -218,8 +217,10 @@ export class Executor {
const instance: ITaskPlugin = new plugin.target(); const instance: ITaskPlugin = new plugin.target();
// @ts-ignore // @ts-ignore
const define: PluginDefine = plugin.define; const define: PluginDefine = plugin.define;
const pluginName = define.name;
const pluginConfig = await this.options.pluginConfigService.getPluginConfig(pluginName);
//从outputContext读取输入参数 //从outputContext读取输入参数
const input = _.cloneDeep(step.input); const input = cloneDeep(step.input);
Decorator.inject(define.input, instance, input, (item, key) => { Decorator.inject(define.input, instance, input, (item, key) => {
if (item.component?.name === "output-selector") { if (item.component?.name === "output-selector") {
const contextKey = input[key]; const contextKey = input[key];
@@ -239,6 +240,12 @@ export class Executor {
} }
}); });
const sysInput = pluginConfig.sysSetting?.input || {};
//注入系统设置参数
for (const sysInputKey in sysInput) {
input[sysInputKey] = sysInput[sysInputKey];
}
const newInputHash = hashUtils.md5(JSON.stringify(input)); const newInputHash = hashUtils.md5(JSON.stringify(input));
step.status!.inputHash = newInputHash; step.status!.inputHash = newInputHash;
//判断是否需要跳过 //判断是否需要跳过
@@ -269,6 +276,7 @@ export class Executor {
accessService: this.options.accessService, accessService: this.options.accessService,
emailService: this.options.emailService, emailService: this.options.emailService,
cnameProxyService: this.options.cnameProxyService, cnameProxyService: this.options.cnameProxyService,
pluginConfigService: this.options.pluginConfigService,
pipelineContext: this.pipelineContext, pipelineContext: this.pipelineContext,
userContext: this.contextFactory.getContext("user", this.options.user.id), userContext: this.contextFactory.getContext("user", this.options.user.id),
fileStore: new FileStore({ fileStore: new FileStore({
@@ -290,7 +298,7 @@ export class Executor {
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];
@@ -300,7 +308,7 @@ export class Executor {
if (Object.keys(instance._result.pipelineVars).length > 0) { if (Object.keys(instance._result.pipelineVars).length > 0) {
// 判断 pipelineVars 有值时更新 // 判断 pipelineVars 有值时更新
const vars = this.pipelineContext.getObj("vars"); const vars = this.pipelineContext.getObj("vars");
_.merge(vars, instance._result.pipelineVars); merge(vars, instance._result.pipelineVars);
await this.pipelineContext.setObj("vars", vars); await this.pipelineContext.setObj("vars", vars);
} }
} }

View File

@@ -8,7 +8,8 @@ import { IContext, PluginRequestHandleReq, RunnableCollection } from "../core/in
import { ILogger, logger, utils } from "../utils/index.js"; import { ILogger, logger, utils } from "../utils/index.js";
import { HttpClient } from "../utils/index.js"; import { HttpClient } from "../utils/index.js";
import dayjs from "dayjs"; import dayjs from "dayjs";
import _ from "lodash-es"; import { IPluginConfigService } from "../service/config";
import { upperFirst } from "lodash-es";
export type UserInfo = { export type UserInfo = {
role: "admin" | "user"; role: "admin" | "user";
id: any; id: any;
@@ -25,7 +26,10 @@ export type TaskOutputDefine = {
type?: string; type?: string;
}; };
export type TaskInputDefine = FormItemProps; export type TaskInputDefine = {
required?: boolean;
isSys?: boolean;
} & FormItemProps;
export type PluginDefine = Registrable & { export type PluginDefine = Registrable & {
default?: any; default?: any;
@@ -72,6 +76,8 @@ export type TaskInstanceContext = {
emailService: IEmailService; emailService: IEmailService;
//cname记录服务 //cname记录服务
cnameProxyService: ICnameProxyService; cnameProxyService: ICnameProxyService;
//插件配置服务
pluginConfigService: IPluginConfigService;
//流水线上下文 //流水线上下文
pipelineContext: IContext; pipelineContext: IContext;
//用户上下文 //用户上下文
@@ -169,7 +175,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
let methodName = req.action; let methodName = req.action;
if (!req.action.startsWith("on")) { if (!req.action.startsWith("on")) {
methodName = `on${_.upperFirst(req.action)}`; methodName = `on${upperFirst(req.action)}`;
} }
// @ts-ignore // @ts-ignore

View File

@@ -1,9 +1,9 @@
import _ from "lodash-es";
import { pluginRegistry } from "./registry.js"; import { pluginRegistry } from "./registry.js";
import { PluginDefine, TaskInputDefine, TaskOutputDefine } from "./api.js"; import { PluginDefine, TaskInputDefine, TaskOutputDefine } from "./api.js";
import { Decorator } from "../decorator/index.js"; import { Decorator } from "../decorator/index.js";
import { AUTOWIRE_KEY } from "../decorator/index.js"; import { AUTOWIRE_KEY } from "../decorator/index.js";
import "reflect-metadata"; import "reflect-metadata";
import { merge, sortBy } from "lodash-es";
// 提供一个唯一 key // 提供一个唯一 key
export const PLUGIN_CLASS_KEY = "pipeline:plugin"; export const PLUGIN_CLASS_KEY = "pipeline:plugin";
@@ -42,13 +42,13 @@ export function IsTaskPlugin(define: PluginDefine): ClassDecorator {
} }
inputArray.push([key, _input]); inputArray.push([key, _input]);
} }
inputArray = _.sortBy(inputArray, (item: any) => item[1].order); inputArray = sortBy(inputArray, (item: any) => item[1].order);
const inputMap: any = {}; const inputMap: any = {};
inputArray.forEach((item: any) => { inputArray.forEach((item: any) => {
inputMap[item[0]] = item[1]; inputMap[item[0]] = item[1];
}); });
_.merge(define, { input: inputMap, autowire: autowires, output: outputs }); merge(define, { input: inputMap, autowire: autowires, output: outputs });
Reflect.defineMetadata(PLUGIN_CLASS_KEY, define, target); Reflect.defineMetadata(PLUGIN_CLASS_KEY, define, target);

View File

@@ -0,0 +1,12 @@
export type PluginConfig = {
name: string;
disabled: boolean;
sysSetting: {
input: Record<string, any>;
};
};
//插件配置服务
export type IPluginConfigService = {
getPluginConfig: (pluginName: string) => Promise<PluginConfig>;
};

View File

@@ -1,2 +1,3 @@
export * from "./email.js"; export * from "./email.js";
export * from "./cname.js"; export * from "./cname.js";
export * from "./config.js";

View File

@@ -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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
**Note:** Version bump only for package @certd/lib-huawei
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/lib-huawei **Note:** Version bump only for package @certd/lib-huawei

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/lib-huawei", "name": "@certd/lib-huawei",
"private": false, "private": false,
"version": "1.26.3", "version": "1.26.4",
"main": "./dist/bundle.js", "main": "./dist/bundle.js",
"module": "./dist/bundle.js", "module": "./dist/bundle.js",
"types": "./dist/d/index.d.ts", "types": "./dist/d/index.d.ts",
@@ -17,5 +17,5 @@
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"rollup": "^3.7.4" "rollup": "^3.7.4"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
**Note:** Version bump only for package @certd/lib-iframe
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/lib-iframe **Note:** Version bump only for package @certd/lib-iframe

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/lib-iframe", "name": "@certd/lib-iframe",
"private": false, "private": false,
"version": "1.26.3", "version": "1.26.4",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
@@ -39,5 +39,5 @@
"tslib": "^2.5.2", "tslib": "^2.5.2",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
**Note:** Version bump only for package @certd/lib-jdcloud
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/lib-jdcloud **Note:** Version bump only for package @certd/lib-jdcloud

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/lib-jdcloud", "name": "@certd/lib-jdcloud",
"private": false, "private": false,
"version": "1.26.3", "version": "1.26.4",
"main": "./dist/bundle.mjs", "main": "./dist/bundle.mjs",
"module": "./dist/bundle.mjs", "module": "./dist/bundle.mjs",
"types": "./dist/d/index.d.ts", "types": "./dist/d/index.d.ts",
@@ -27,5 +27,5 @@
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"rollup": "^3.7.4" "rollup": "^3.7.4"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
**Note:** Version bump only for package @certd/lib-k8s
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/lib-k8s **Note:** Version bump only for package @certd/lib-k8s

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/lib-k8s", "name": "@certd/lib-k8s",
"private": false, "private": false,
"version": "1.26.3", "version": "1.26.4",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
@@ -18,7 +18,7 @@
"@kubernetes/client-node": "0.21.0" "@kubernetes/client-node": "0.21.0"
}, },
"devDependencies": { "devDependencies": {
"@certd/pipeline": "^1.26.3", "@certd/pipeline": "^1.26.4",
"@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",
@@ -40,5 +40,5 @@
"tslib": "^2.5.2", "tslib": "^2.5.2",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -3,6 +3,14 @@
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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
### Performance Improvements
* [comm] 支持插件管理 ([e8b617b](https://github.com/certd/certd/commit/e8b617b80ce882dd63006f0cfc719a80a1cc6acc))
* 新增代理设置功能 ([273ab61](https://github.com/certd/certd/commit/273ab6139f5807f4d7fe865cc353b97f51b9a668))
* EAB授权支持绑定邮箱支持公共EAB设置 ([07043af](https://github.com/certd/certd/commit/07043aff0ca7fd29c56dd3c363002cb15d78b464))
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
### Performance Improvements ### Performance Improvements

View File

@@ -1,6 +1,6 @@
{ {
"name": "@certd/lib-server", "name": "@certd/lib-server",
"version": "1.26.3", "version": "1.26.4",
"description": "midway with flyway, sql upgrade way ", "description": "midway with flyway, sql upgrade way ",
"private": false, "private": false,
"type": "module", "type": "module",
@@ -26,8 +26,8 @@
], ],
"license": "AGPL", "license": "AGPL",
"dependencies": { "dependencies": {
"@certd/basic": "^1.26.3", "@certd/basic": "^1.26.4",
"@certd/pipeline": "^1.26.3", "@certd/pipeline": "^1.26.4",
"@midwayjs/cache": "~3.14.0", "@midwayjs/cache": "~3.14.0",
"@midwayjs/core": "~3.17.1", "@midwayjs/core": "~3.17.1",
"@midwayjs/i18n": "~3.17.3", "@midwayjs/i18n": "~3.17.3",
@@ -68,5 +68,5 @@
"typeorm": "^0.3.11", "typeorm": "^0.3.11",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -1,11 +1,24 @@
import { ValidateException } from './exception/index.js'; import { ValidateException } from './exception/index.js';
import * as _ from 'lodash-es'; import * as _ from 'lodash-es';
import { PermissionException } from './exception/index.js'; import { PermissionException } from './exception/index.js';
import { In, Repository } from 'typeorm'; import { In, Repository, SelectQueryBuilder } from 'typeorm';
import { Inject } from '@midwayjs/core'; import { Inject } from '@midwayjs/core';
import { TypeORMDataSourceManager } from '@midwayjs/typeorm'; import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
import { EntityManager } from 'typeorm/entity-manager/EntityManager.js'; import { EntityManager } from 'typeorm/entity-manager/EntityManager.js';
export type PageReq<T = any> = {
page?: { offset: number; limit: number };
} & ListReq<T>;
export type ListReq<T = any> = {
query?: Partial<T>;
order?: {
prop: string;
asc: boolean;
};
buildQuery?: (bq: SelectQueryBuilder<any>) => void;
};
/** /**
* 服务基类 * 服务基类
*/ */
@@ -106,50 +119,22 @@ export abstract class BaseService<T> {
* 新增|修改|删除 之后的操作 * 新增|修改|删除 之后的操作
* @param data 对应数据 * @param data 对应数据
*/ */
async modifyAfter(data) {} // eslint-disable-next-line @typescript-eslint/no-unused-vars
async modifyAfter(data: any) {}
/** /**
* 分页查询 * 分页查询
* @param query 查询条件 bean
* @param page
* @param order
* @param buildQuery
*/ */
async page(query, page = { offset: 0, limit: 20 }, order, buildQuery) { async page(pageReq: PageReq<T>) {
const { page } = pageReq;
if (page.offset == null) { if (page.offset == null) {
page.offset = 0; page.offset = 0;
} }
if (page.limit == null) { if (page.limit == null) {
page.limit = 20; page.limit = 20;
} }
const qb = this.getRepository().createQueryBuilder('main'); const qb = this.buildListQuery(pageReq);
if (order && order.prop) {
qb.addOrderBy('main.' + order.prop, order.asc ? 'ASC' : 'DESC');
}
qb.addOrderBy('id', 'DESC');
qb.offset(page.offset).limit(page.limit); qb.offset(page.offset).limit(page.limit);
//根据bean query
if (query) {
let whereSql = '';
let index = 0;
_.forEach(query, (value, key) => {
if (!value) {
return;
}
if (index !== 0) {
whereSql += ' and ';
}
whereSql += ` main.${key} = :${key} `;
index++;
});
if (index > 0) {
qb.where(whereSql, query);
}
}
//自定义query
if (buildQuery) {
buildQuery(qb);
}
const list = await qb.getMany(); const list = await qb.getMany();
const total = await qb.getCount(); const total = await qb.getCount();
return { return {
@@ -160,19 +145,13 @@ export abstract class BaseService<T> {
}; };
} }
/** private buildListQuery(listReq: ListReq<T>) {
* 分页查询 const { query, order, buildQuery } = listReq;
* @param query 查询条件 bean
* @param order
* @param buildQuery
*/
async list(query, order, buildQuery) {
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');
//根据bean query //根据bean query
if (query) { if (query) {
let whereSql = ''; let whereSql = '';
@@ -188,13 +167,21 @@ export abstract class BaseService<T> {
index++; index++;
}); });
if (index > 0) { if (index > 0) {
qb.where(whereSql, query); qb.andWhere(whereSql, query);
} }
} }
//自定义query //自定义query
if (buildQuery) { if (buildQuery) {
buildQuery(qb); buildQuery(qb);
} }
return qb;
}
/**
* 分页查询
*/
async list(listReq: ListReq<T>) {
const qb = this.buildListQuery(listReq);
return await qb.getMany(); return await qb.getMany();
} }

View File

@@ -2,59 +2,50 @@ import { ALL, Body, Post, Query } from '@midwayjs/core';
import { BaseController } from './base-controller.js'; import { BaseController } from './base-controller.js';
export abstract class CrudController<T> extends BaseController { export abstract class CrudController<T> extends BaseController {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
abstract getService<T>(); abstract getService<T>();
@Post('/page') @Post('/page')
async page( async page(@Body(ALL) body: any) {
@Body(ALL) const pageRet = await this.getService().page({
body query: body.query ?? {},
) { page: body.page,
const pageRet = await this.getService().page(body?.query, body?.page, body?.sort, null); sort: body.sort,
bq: body.bq,
});
return this.ok(pageRet); return this.ok(pageRet);
} }
@Post('/list') @Post('/list')
async list( async list(@Body(ALL) body: any) {
@Body(ALL) const listRet = await this.getService().list({
body query: body.query ?? {},
) { order: body.order,
const listRet = await this.getService().list(body, null, null); });
return this.ok(listRet); return this.ok(listRet);
} }
@Post('/add') @Post('/add')
async add( async add(@Body(ALL) bean: any) {
@Body(ALL)
bean
) {
delete bean.id; delete bean.id;
const id = await this.getService().add(bean); const id = await this.getService().add(bean);
return this.ok(id); return this.ok(id);
} }
@Post('/info') @Post('/info')
async info( async info(@Query('id') id: number) {
@Query('id')
id
) {
const bean = await this.getService().info(id); const bean = await this.getService().info(id);
return this.ok(bean); return this.ok(bean);
} }
@Post('/update') @Post('/update')
async update( async update(@Body(ALL) bean: any) {
@Body(ALL)
bean
) {
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') id: number) {
@Query('id')
id
) {
await this.getService().delete([id]); await this.getService().delete([id]);
return this.ok(null); return this.ok(null);
} }

View File

@@ -24,13 +24,21 @@ export class SysPrivateSettings extends BaseSettings {
static __key__ = 'sys.private'; static __key__ = 'sys.private';
jwtKey?: string; jwtKey?: string;
encryptSecret?: string; encryptSecret?: string;
httpsProxy? = '';
httpProxy? = '';
removeSecret() {
delete this.jwtKey;
delete this.encryptSecret;
}
} }
export class SysInstallInfo extends BaseSettings { export class SysInstallInfo extends BaseSettings {
static __title__ = '系统安装信息'; static __title__ = '系统安装信息';
static __key__ = 'sys.install'; static __key__ = 'sys.install';
static __access__ = 'private'; static __access__ = 'private';
installTime: number; installTime?: number;
siteId?: string; siteId?: string;
bindUserId?: number; bindUserId?: number;
bindUrl?: string; bindUrl?: string;

View File

@@ -7,6 +7,7 @@ import { BaseSettings, SysPrivateSettings, SysPublicSettings } from './models.js
import * as _ from 'lodash-es'; import * as _ from 'lodash-es';
import { BaseService } from '../../../basic/index.js'; import { BaseService } from '../../../basic/index.js';
import { isComm } from '@certd/pipeline'; import { isComm } from '@certd/pipeline';
import { setGlobalProxy } from '@certd/basic';
/** /**
* 设置 * 设置
@@ -118,8 +119,25 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
await this.saveSetting(bean); await this.saveSetting(bean);
} }
async getPrivateSettings(): Promise<SysPrivateSettings> {
return await this.getSetting(SysPrivateSettings);
}
async savePrivateSettings(bean: SysPrivateSettings) { async savePrivateSettings(bean: SysPrivateSettings) {
this.saveSetting(bean); await this.saveSetting(bean);
//让设置生效
await this.reloadPrivateSettings();
}
async reloadPrivateSettings() {
const bean = await this.getPrivateSettings();
if (bean.httpProxy || bean.httpsProxy) {
setGlobalProxy({
httpProxy: bean.httpProxy,
httpsProxy: bean.httpsProxy,
});
}
} }
async updateByKey(key: string, setting: any) { async updateByKey(key: string, setting: any) {

View File

@@ -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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/midway-flyway-js **Note:** Version bump only for package @certd/midway-flyway-js

View File

@@ -1,6 +1,6 @@
{ {
"name": "@certd/midway-flyway-js", "name": "@certd/midway-flyway-js",
"version": "1.26.3", "version": "1.26.4",
"description": "midway with flyway, sql upgrade way ", "description": "midway with flyway, sql upgrade way ",
"private": false, "private": false,
"type": "module", "type": "module",
@@ -56,5 +56,5 @@
"typeorm": "^0.3.11", "typeorm": "^0.3.11",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -3,6 +3,14 @@
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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
### Performance Improvements
* [comm] 支持插件管理 ([e8b617b](https://github.com/certd/certd/commit/e8b617b80ce882dd63006f0cfc719a80a1cc6acc))
* 新增代理设置功能 ([273ab61](https://github.com/certd/certd/commit/273ab6139f5807f4d7fe865cc353b97f51b9a668))
* EAB授权支持绑定邮箱支持公共EAB设置 ([07043af](https://github.com/certd/certd/commit/07043aff0ca7fd29c56dd3c363002cb15d78b464))
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
**Note:** Version bump only for package @certd/plugin-cert **Note:** Version bump only for package @certd/plugin-cert

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/plugin-cert", "name": "@certd/plugin-cert",
"private": false, "private": false,
"version": "1.26.3", "version": "1.26.4",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
@@ -15,9 +15,9 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@certd/acme-client": "^1.26.3", "@certd/acme-client": "^1.26.4",
"@certd/basic": "^1.26.3", "@certd/basic": "^1.26.4",
"@certd/pipeline": "^1.26.3", "@certd/pipeline": "^1.26.4",
"@google-cloud/publicca": "^1.3.0", "@google-cloud/publicca": "^1.3.0",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"jszip": "^3.10.1", "jszip": "^3.10.1",
@@ -57,5 +57,5 @@
"vite": "^3.1.0", "vite": "^3.1.0",
"vue-tsc": "^0.38.9" "vue-tsc": "^0.38.9"
}, },
"gitHead": "66f9b08fcf5035577eafc609fd634d6490bc9cae" "gitHead": "4343fb1b3072b03e2444398cafdb405f230a3779"
} }

View File

@@ -26,6 +26,16 @@ export class EabAccess extends BaseAccess {
encrypt: true, encrypt: true,
}) })
hmacKey = ""; hmacKey = "";
@AccessInput({
title: "email",
component: {
placeholder: "绑定一个邮箱",
},
helper: "Google EAB 申请证书绑定邮箱后不能更换否则会导致EAB失效",
required: false,
})
email = "";
} }
new EabAccess(); new EabAccess();

View File

@@ -195,6 +195,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
async condition() { async condition() {
if (this.forceUpdate) { if (this.forceUpdate) {
this.logger.info("强制更新证书选项已勾选,准备申请新证书"); this.logger.info("强制更新证书选项已勾选,准备申请新证书");
this.logger.warn("申请完之后,切记取消强制更新,避免申请过多证书。");
return null; return null;
} }

View File

@@ -6,6 +6,7 @@ import { createDnsProvider, DnsProviderContext, IDnsProvider } from "../../dns-p
import { CertReader } from "./cert-reader.js"; import { CertReader } from "./cert-reader.js";
import { CertApplyBasePlugin } from "./base.js"; import { CertApplyBasePlugin } from "./base.js";
import { GoogleClient } from "../../libs/google.js"; import { GoogleClient } from "../../libs/google.js";
import { EabAccess } from "../../access";
export type { CertInfo }; export type { CertInfo };
export * from "./cert-reader.js"; export * from "./cert-reader.js";
@@ -103,7 +104,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
}, },
rules: [{ type: "checkCnameVerifyPlan" }], rules: [{ type: "checkCnameVerifyPlan" }],
required: true, required: true,
helper: "如果选择CNAME方式请按照上面的显示给域名添加CNAME记录添加后点击验证验证成功后不要删除记录申请和续期证书会一直用它", helper: "如果选择CNAME方式请按照上面的显示要申请证书的域名添加CNAME记录添加后点击验证验证成功后不要删除记录申请和续期证书会一直用它",
col: { col: {
span: 24, span: 24,
}, },
@@ -122,7 +123,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
domainsVerifyPlan!: DomainsVerifyPlanInput; domainsVerifyPlan!: DomainsVerifyPlanInput;
@TaskInput({ @TaskInput({
title: "证书提供商", title: "证书颁发机构",
value: "letsencrypt", value: "letsencrypt",
component: { component: {
name: "a-select", name: "a-select",
@@ -138,6 +139,13 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
}) })
sslProvider!: SSLProvider; sslProvider!: SSLProvider;
@TaskInput({
title: "Google公共EAB授权",
isSys: true,
show: false,
})
googleCommonEabAccessId!: number;
@TaskInput({ @TaskInput({
title: "EAB授权", title: "EAB授权",
component: { component: {
@@ -151,7 +159,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
mergeScript: ` mergeScript: `
return { return {
show: ctx.compute(({form})=>{ show: ctx.compute(({form})=>{
return form.sslProvider === 'zerossl' || form.sslProvider === 'google' return form.sslProvider === 'zerossl' || (form.sslProvider === 'google' && !form.googleCommonEabAccessId)
}) })
} }
`, `,
@@ -171,7 +179,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
mergeScript: ` mergeScript: `
return { return {
show: ctx.compute(({form})=>{ show: ctx.compute(({form})=>{
return form.sslProvider === 'google' return form.sslProvider === 'google' && !form.googleCommonEabAccessId
}) })
} }
`, `,
@@ -233,12 +241,13 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
acme!: AcmeService; acme!: AcmeService;
eab!: EabAccess;
async onInit() { async onInit() {
let eab: any = null; let eab: EabAccess = null;
if (this.sslProvider === "google") { if (this.sslProvider === "google") {
if (this.googleAccessId) { if (this.googleAccessId) {
this.logger.info("正在使用google服务账号授权"); this.logger.info("当前正在使用 google服务账号授权获取EAB");
const googleAccess = await this.ctx.accessService.getById(this.googleAccessId); const googleAccess = await this.ctx.accessService.getById(this.googleAccessId);
const googleClient = new GoogleClient({ const googleClient = new GoogleClient({
access: googleAccess, access: googleAccess,
@@ -246,8 +255,11 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
}); });
eab = await googleClient.getEab(); eab = await googleClient.getEab();
} else if (this.eabAccessId) { } else if (this.eabAccessId) {
this.logger.info("正在使用google EAB授权"); this.logger.info("当前正在使用 google EAB授权");
eab = await this.ctx.accessService.getById(this.eabAccessId); eab = await this.ctx.accessService.getById(this.eabAccessId);
} else if (this.googleCommonEabAccessId) {
this.logger.info("当前正在使用 google公共EAB授权");
eab = await this.ctx.accessService.getById(this.googleCommonEabAccessId);
} else { } else {
this.logger.error("google需要配置EAB授权或服务账号授权"); this.logger.error("google需要配置EAB授权或服务账号授权");
return; return;
@@ -260,7 +272,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
return; return;
} }
} }
this.eab = eab;
this.acme = new AcmeService({ this.acme = new AcmeService({
userContext: this.userContext, userContext: this.userContext,
logger: this.logger, logger: this.logger,
@@ -276,7 +288,10 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
} }
async doCertApply() { async doCertApply() {
const email = this["email"]; let email = this.email;
if (this.eab && this.eab.email) {
email = this.eab.email;
}
const domains = this["domains"]; const domains = this["domains"];
const csrInfo = _.merge( const csrInfo = _.merge(

View File

@@ -3,6 +3,14 @@
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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
### Performance Improvements
* [comm] 支持插件管理 ([e8b617b](https://github.com/certd/certd/commit/e8b617b80ce882dd63006f0cfc719a80a1cc6acc))
* 新增代理设置功能 ([273ab61](https://github.com/certd/certd/commit/273ab6139f5807f4d7fe865cc353b97f51b9a668))
* EAB授权支持绑定邮箱支持公共EAB设置 ([07043af](https://github.com/certd/certd/commit/07043aff0ca7fd29c56dd3c363002cb15d78b464))
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
### Performance Improvements ### Performance Improvements

View File

@@ -1,6 +1,6 @@
{ {
"name": "@certd/ui-client", "name": "@certd/ui-client",
"version": "1.26.3", "version": "1.26.4",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite --open", "dev": "vite --open",
@@ -61,8 +61,8 @@
"vuedraggable": "^4.1.0" "vuedraggable": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@certd/lib-iframe": "^1.26.3", "@certd/lib-iframe": "^1.26.4",
"@certd/pipeline": "^1.26.3", "@certd/pipeline": "^1.26.4",
"@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",

View File

@@ -8,11 +8,11 @@ export type SiteEnv = {
}; };
}; };
export type SiteInfo = { export type SiteInfo = {
title: string; title?: string;
slogan: string; slogan?: string;
logo: string; logo?: string;
loginLogo: string; loginLogo?: string;
icpNo: string; icpNo?: string;
licenseTo?: string; licenseTo?: string;
licenseToUrl?: string; licenseToUrl?: string;
}; };

View File

@@ -117,7 +117,7 @@ async function doActive() {
} }
const res = await api.doActive(formState); const res = await api.doActive(formState);
if (res) { if (res) {
await userStore.reInit(); await settingStore.init();
const vipLabel = settingStore.vipLabel; const vipLabel = settingStore.vipLabel;
Modal.success({ Modal.success({
title: "激活成功", title: "激活成功",

View File

@@ -77,10 +77,10 @@
<a :href="siteInfo.licenseToUrl || ''">{{ siteInfo.licenseTo }}</a> <a :href="siteInfo.licenseToUrl || ''">{{ siteInfo.licenseTo }}</a>
</template> </template>
<template v-if="siteInfo.icpNo"> <template v-if="sysPublic.icpNo">
<a-divider type="vertical" /> <a-divider type="vertical" />
<span> <span>
<a href="https://beian.miit.gov.cn/" target="_blank">{{ siteInfo.icpNo }}</a> <a href="https://beian.miit.gov.cn/" target="_blank">{{ sysPublic.icpNo }}</a>
</span> </span>
</template> </template>
</div> </div>
@@ -93,7 +93,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onErrorCaptured, ref } from "vue"; import { computed, onErrorCaptured, onMounted, ref } from "vue";
import FsMenu from "./components/menu/index.jsx"; import FsMenu from "./components/menu/index.jsx";
import FsLocale from "./components/locale/index.vue"; import FsLocale from "./components/locale/index.vue";
import FsUserInfo from "./components/user-info/index.vue"; import FsUserInfo from "./components/user-info/index.vue";
@@ -140,9 +140,16 @@ const userStore = useUserStore();
const settingStore = useSettingStore(); const settingStore = useSettingStore();
const sysPublic = computed(() => {
return settingStore.sysPublic;
});
const siteInfo = computed(() => { const siteInfo = computed(() => {
return settingStore.siteInfo; return settingStore.siteInfo;
}); });
onMounted(async () => {
await settingStore.checkUrlBound();
});
</script> </script>
<style lang="less"> <style lang="less">
@import "../style/theme/index.less"; @import "../style/theme/index.less";

View File

@@ -27,9 +27,9 @@
<a-divider type="vertical" /> <a-divider type="vertical" />
<a :href="siteInfo.licenseToUrl" target="_blank">{{ siteInfo.licenseTo }}</a> <a :href="siteInfo.licenseToUrl" target="_blank">{{ siteInfo.licenseTo }}</a>
</span> </span>
<span v-if="siteInfo.icpNo"> <span v-if="sysPublic.icpNo">
<a-divider type="vertical" /> <a-divider type="vertical" />
<a href="https://beian.miit.gov.cn/" target="_blank">{{ siteInfo.icpNo }}</a> <a href="https://beian.miit.gov.cn/" target="_blank">{{ sysPublic.icpNo }}</a>
</span> </span>
</div> </div>
</div> </div>
@@ -40,13 +40,17 @@
<script lang="ts" setup> <script lang="ts" setup>
import { env } from "/@/utils/util.env"; import { env } from "/@/utils/util.env";
import { computed, ref, Ref } from "vue"; import { computed, ref, Ref } from "vue";
import { SiteInfo, useSettingStore } from "/@/store/modules/settings"; import { useSettingStore } from "/@/store/modules/settings";
import { SiteInfo, SysPublicSetting } from "/@/api/modules/api.basic";
const envRef = ref(env); const envRef = ref(env);
const settingStore = useSettingStore(); const settingStore = useSettingStore();
const siteInfo: Ref<SiteInfo> = computed(() => { const siteInfo: Ref<SiteInfo> = computed(() => {
return settingStore.siteInfo; return settingStore.siteInfo;
}); });
const sysPublic: Ref<SysPublicSetting> = computed(() => {
return settingStore.sysPublic;
});
</script> </script>
<style lang="less"> <style lang="less">

View File

@@ -134,7 +134,7 @@ function install(app: App, options: any = {}) {
//固定label宽度 //固定label宽度
span: null, span: null,
style: { style: {
width: "120px" width: "145px"
} }
}, },
async afterSubmit({ mode }) { async afterSubmit({ mode }) {
@@ -182,86 +182,7 @@ function install(app: App, options: any = {}) {
// @ts-ignore // @ts-ignore
app.use(FsExtendsUploader, { app.use(FsExtendsUploader, {
// @ts-ignore // @ts-ignore
defaultType: "cos", defaultType: "form",
cos: {
keepName: true,
domain: "https://d2p-demo-1251260344.cos.ap-guangzhou.myqcloud.com",
bucket: "d2p-plugins-1251260344",
region: "ap-guangzhou",
secretId: "", //
secretKey: "", // 传了secretKey 和secretId 代表使用本地签名模式(不安全,生产环境不推荐)
async getAuthorization(custom: any) {
// 不传secretKey代表使用临时签名模式,此时此参数必传(安全,生产环境推荐)
const ret = request({
url: "http://www.docmirror.cn:7070/api/upload/cos/getAuthorization",
method: "get"
});
// 返回结构要求如下
// ret.data:{
// TmpSecretId,
// TmpSecretKey,
// XCosSecurityToken,
// ExpiredTime, // SDK 在 ExpiredTime 时间前,不会再次调用 getAuthorization
// }
return ret;
},
successHandle(ret: any) {
// 上传完成后可以在此处处理结果修改url什么的
console.log("success handle:", ret);
return ret;
}
},
alioss: {
keepName: true,
domain: "https://d2p-demo.oss-cn-shenzhen.aliyuncs.com",
bucket: "d2p-plugins",
region: "oss-cn-shenzhen",
accessKeyId: "",
accessKeySecret: "",
async getAuthorization(context: FsUploaderGetAuthContext): Promise<FsUploaderAliossSTS> {
// 不传accessKeySecret代表使用临时签名模式,此时此参数必传(安全,生产环境推荐)
const ret = await request({
url: "http://www.docmirror.cn:7070/api/upload/alioss/getAuthorization",
method: "get"
});
console.log("ret", ret);
// 返回结构要求如下
// ret.data:{
// TmpSecretId,
// TmpSecretKey,
// XCosSecurityToken,
// ExpiredTime, // SDK 在 ExpiredTime 时间前,不会再次调用 getAuthorization
// key //【可选】后台生成的文件key如果不传则用前端自己生成的key
// }
return ret;
},
sdkOpts: {
// sdk配置
secure: true // 默认为非https上传,为了安全设置为true
},
successHandle(ret: any) {
// 上传完成后可以在此处处理结果修改url什么的
console.log("success handle:", ret);
return ret;
}
},
qiniu: {
keepName: true,
bucket: "d2p-plugins",
async getToken(options: any) {
const ret = await request({
url: "http://www.docmirror.cn:7070/api/upload/qiniu/getToken",
method: "get"
});
return ret; // {token:xxx,expires:xxx}
},
successHandle(ret: any) {
// 上传完成后可以在此处处理结果修改url什么的
console.log("success handle:", ret);
return ret;
},
domain: "http://d2p.file.handsfree.work/"
},
form: { form: {
keepName: true, keepName: true,
action: "http://www.docmirror.cn:7070/api/upload/form/upload", action: "http://www.docmirror.cn:7070/api/upload/form/upload",
@@ -313,6 +234,11 @@ function install(app: App, options: any = {}) {
//此处演示修改官方字段类型 //此处演示修改官方字段类型
const textType = getType("text"); const textType = getType("text");
textType.search.autoSearchTrigger = "change"; //修改官方的字段类型,变化就触发 "enter"=回车键触发 textType.search.autoSearchTrigger = "change"; //修改官方的字段类型,变化就触发 "enter"=回车键触发
if (!textType.column) {
textType.column = {};
}
textType.column.ellipsis = true;
textType.column.showTitle = true;
// 此处演示自定义字段类型 // 此处演示自定义字段类型
addTypes({ addTypes({

View File

@@ -68,6 +68,48 @@ export const sysResources = [
permission: "sys:settings:view" permission: "sys:settings:view"
} }
}, },
{
title: "系统级授权",
name: "SysAccess",
path: "/sys/access",
component: "/sys/access/index.vue",
meta: {
show: () => {
const settingStore = useSettingStore();
return settingStore.isComm;
},
icon: "ion:disc-outline",
permission: "sys:settings:view"
}
},
{
title: "插件管理",
name: "SysPlugin",
path: "/sys/plugin",
component: "/sys/plugin/index.vue",
meta: {
show: () => {
const settingStore = useSettingStore();
return settingStore.isComm;
},
icon: "ion:extension-puzzle-outline",
permission: "sys:settings:view"
}
},
{
title: "证书插件配置",
name: "SysPluginConfig",
path: "/sys/plugin/config",
component: "/sys/plugin/config.vue",
meta: {
show: () => {
const settingStore = useSettingStore();
return settingStore.isComm;
},
icon: "ion:extension-puzzle",
permission: "sys:settings:view"
}
},
{ {
title: "账号绑定", title: "账号绑定",
name: "AccountBind", name: "AccountBind",

View File

@@ -44,12 +44,11 @@ const defaultThemeConfig = {
mode: "light" mode: "light"
}; };
const SETTING_THEME_KEY = "SETTING_THEME"; const SETTING_THEME_KEY = "SETTING_THEME";
const defaultSiteInfo = { const defaultSiteInfo: SiteInfo = {
title: env.TITLE || "Certd", title: env.TITLE || "Certd",
slogan: env.SLOGAN || "让你的证书永不过期", slogan: env.SLOGAN || "让你的证书永不过期",
logo: env.LOGO || "/static/images/logo/logo.svg", logo: env.LOGO || "/static/images/logo/logo.svg",
loginLogo: env.LOGIN_LOGO || "/static/images/logo/rect-block.svg", loginLogo: env.LOGIN_LOGO || "/static/images/logo/rect-block.svg",
icpNo: env.ICP_NO,
licenseTo: "", licenseTo: "",
licenseToUrl: "" licenseToUrl: ""
}; };
@@ -69,7 +68,7 @@ export const useSettingStore = defineStore({
sysPublic: { sysPublic: {
registerEnabled: false, registerEnabled: false,
managerOtherUserPipeline: false, managerOtherUserPipeline: false,
icpNo: "" icpNo: env.ICP_NO || ""
}, },
installInfo: { installInfo: {
siteId: "", siteId: "",
@@ -136,7 +135,6 @@ export const useSettingStore = defineStore({
_.merge(this.plusInfo, allSettings.plusInfo || {}); _.merge(this.plusInfo, allSettings.plusInfo || {});
//@ts-ignore //@ts-ignore
this.initSiteInfo(allSettings.siteInfo || {}); this.initSiteInfo(allSettings.siteInfo || {});
await this.checkUrlBound();
}, },
initSiteInfo(siteInfo: SiteInfo) { initSiteInfo(siteInfo: SiteInfo) {
//@ts-ignore //@ts-ignore
@@ -148,11 +146,6 @@ export const useSettingStore = defineStore({
siteInfo.loginLogo = `/api/basic/file/download?key=${siteInfo.loginLogo}`; siteInfo.loginLogo = `/api/basic/file/download?key=${siteInfo.loginLogo}`;
} }
} }
const sysPublic = this.getSysPublic;
if (sysPublic.icpNo) {
siteInfo.icpNo = sysPublic.icpNo;
}
this.siteInfo = _.merge({}, defaultSiteInfo, siteInfo); this.siteInfo = _.merge({}, defaultSiteInfo, siteInfo);
}, },
async checkUrlBound() { async checkUrlBound() {

View File

@@ -222,3 +222,8 @@ h1, h2, h3, h4, h5, h6 {
/* right: 0; */ /* right: 0; */
} }
} }
.settings-form {
width: 800px;
margin: 20px;
}

View File

@@ -1,33 +1,32 @@
// @ts-ignore // @ts-ignore
import * as api from "/@/views/certd/access/api";
import { ref } from "vue"; import { ref } from "vue";
import { getCommonColumnDefine } from "/@/views/certd/access/common"; import { getCommonColumnDefine } from "/@/views/certd/access/common";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { crudBinding } = crudExpose; const { crudBinding } = crudExpose;
const { props, ctx } = context; const { props, ctx, api } = context;
const lastResRef = ref(); const lastResRef = ref();
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => { const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query); return await context.api.GetList(query);
}; };
const editRequest = async (req: EditReq) => { const editRequest = async (req: EditReq) => {
const { form, row } = req; const { form, row } = req;
form.id = row.id; form.id = row.id;
form.type = props.type; form.type = props.type;
const res = await api.UpdateObj(form); const res = await context.api.UpdateObj(form);
lastResRef.value = res; lastResRef.value = res;
return res; return res;
}; };
const delRequest = async (req: DelReq) => { const delRequest = async (req: DelReq) => {
const { row } = req; const { row } = req;
return await api.DelObj(row.id); return await context.api.DelObj(row.id);
}; };
const addRequest = async (req: AddReq) => { const addRequest = async (req: AddReq) => {
const { form } = req; const { form } = req;
form.type = props.type; form.type = props.type;
const res = await api.AddObj(form); const res = await context.api.AddObj(form);
lastResRef.value = res; lastResRef.value = res;
return res; return res;
}; };
@@ -41,7 +40,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const typeRef = ref("aliyun"); const typeRef = ref("aliyun");
context.typeRef = typeRef; context.typeRef = typeRef;
const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef); const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api);
commonColumnsDefine.type.form.component.disabled = true; commonColumnsDefine.type.form.component.disabled = true;
return { return {
typeRef, typeRef,
@@ -109,6 +108,33 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
width: 200 width: 200
} }
}, },
from: {
title: "级别",
type: "dict-select",
dict: dict({
data: [
{ label: "系统", value: "sys" },
{ label: "用户", value: "user" }
]
}),
search: {
show: false
},
form: {
show: false
},
column: {
width: 100,
align: "center",
component: {
color: "auto"
},
order: 10
},
valueBuilder: ({ row, key, value }) => {
row[key] = row.userId > 0 ? "user" : "sys";
}
},
...commonColumnsDefine ...commonColumnsDefine
} }
} }

View File

@@ -8,6 +8,7 @@
import { defineComponent, onMounted, watch } from "vue"; import { defineComponent, onMounted, watch } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { createAccessApi } from "/@/views/certd/access/api";
export default defineComponent({ export default defineComponent({
name: "CertAccessModal", name: "CertAccessModal",
@@ -16,11 +17,16 @@ export default defineComponent({
type: String, type: String,
default: "aliyun" default: "aliyun"
}, },
from: {
type: String, //user | sys
default: "user"
},
modelValue: {} modelValue: {}
}, },
emits: ["update:modelValue"], emits: ["update:modelValue"],
setup(props, ctx) { setup(props, ctx) {
const context: any = { props, ctx }; const api = createAccessApi(props.from);
const context: any = { props, ctx, api };
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
// 你可以调用此方法重新初始化crud配置 // 你可以调用此方法重新初始化crud配置

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="access-selector"> <div class="access-selector">
<span v-if="target.name" class="mr-5 cd-flex-inline"> <span v-if="target.name" class="mr-5 cd-flex-inline">
<span class="mr-5">{{ target.name }}</span> <a-tag class="mr-5" color="green">{{ target.name }}</a-tag>
<fs-icon class="cd-icon-button" icon="ion:close-circle-outline" @click="clear"></fs-icon> <fs-icon class="cd-icon-button" icon="ion:close-circle-outline" @click="clear"></fs-icon>
</span> </span>
<span v-else class="mlr-5 text-gray">{{ placeholder }}</span> <span v-else class="mlr-5 text-gray">{{ placeholder }}</span>
@@ -9,7 +9,7 @@
<a-form-item-rest v-if="chooseForm.show"> <a-form-item-rest v-if="chooseForm.show">
<a-modal v-model:open="chooseForm.show" title="选择授权提供者" width="900px" @ok="chooseForm.ok"> <a-modal v-model:open="chooseForm.show" title="选择授权提供者" width="900px" @ok="chooseForm.ok">
<div style="height: 400px; position: relative"> <div style="height: 400px; position: relative">
<cert-access-modal v-model="selectedId" :type="type"></cert-access-modal> <cert-access-modal v-model="selectedId" :type="type" :from="from"></cert-access-modal>
</div> </div>
</a-modal> </a-modal>
</a-form-item-rest> </a-form-item-rest>
@@ -18,9 +18,8 @@
<script> <script>
import { defineComponent, reactive, ref, watch } from "vue"; import { defineComponent, reactive, ref, watch } from "vue";
import * as api from "../api";
import CertAccessModal from "./access/index.vue"; import CertAccessModal from "./access/index.vue";
import { GetProviderDefineByAccessType } from "../api"; import { createAccessApi } from "../api";
export default defineComponent({ export default defineComponent({
name: "AccessSelector", name: "AccessSelector",
@@ -41,10 +40,16 @@ export default defineComponent({
size: { size: {
type: String, type: String,
default: "middle" default: "middle"
},
from: {
type: String, //user | sys
default: "user"
} }
}, },
emits: ["update:modelValue"], emits: ["update:modelValue"],
setup(props, ctx) { setup(props, ctx) {
const api = createAccessApi(props.from);
const target = ref({}); const target = ref({});
const selectedId = ref(); const selectedId = ref();
async function refreshTarget(value) { async function refreshTarget(value) {

View File

@@ -1,57 +1,62 @@
import { request } from "/src/api/service"; import { request } from "/src/api/service";
const apiPrefix = "/pi/access";
export async function GetList(query: any) {
return await request({
url: apiPrefix + "/page",
method: "post",
data: query
});
}
export async function AddObj(obj: any) { export function createAccessApi(from = "user") {
return await request({ const apiPrefix = from === "sys" ? "/sys/access" : "/pi/access";
url: apiPrefix + "/add", return {
method: "post", async GetList(query: any) {
data: obj return await request({
}); url: apiPrefix + "/page",
} method: "post",
data: query
});
},
export async function UpdateObj(obj: any) { async AddObj(obj: any) {
return await request({ return await request({
url: apiPrefix + "/update", url: apiPrefix + "/add",
method: "post", method: "post",
data: obj data: obj
}); });
} },
export async function DelObj(id: number) { async UpdateObj(obj: any) {
return await request({ return await request({
url: apiPrefix + "/delete", url: apiPrefix + "/update",
method: "post", method: "post",
params: { id } data: obj
}); });
} },
export async function GetObj(id: number) { async DelObj(id: number) {
return await request({ return await request({
url: apiPrefix + "/info", url: apiPrefix + "/delete",
method: "post", method: "post",
params: { id } params: { id }
}); });
} },
export async function GetProviderDefine(type: string) { async GetObj(id: number) {
return await request({ return await request({
url: apiPrefix + "/define", url: apiPrefix + "/info",
method: "post", method: "post",
params: { type } params: { id }
}); });
} },
export async function GetProviderDefineByAccessType(type: string) { async GetProviderDefine(type: string) {
return await request({ return await request({
url: apiPrefix + "/defineByAccessType", url: apiPrefix + "/define",
method: "post", method: "post",
params: { type } params: { type }
}); });
},
async GetProviderDefineByAccessType(type: string) {
return await request({
url: apiPrefix + "/defineByAccessType",
method: "post",
params: { type }
});
}
};
} }

View File

@@ -1,12 +1,9 @@
import { ColumnCompositionProps, dict, compute } from "@fast-crud/fast-crud"; import { ColumnCompositionProps, dict } from "@fast-crud/fast-crud";
// @ts-ignore
import * as api from "./api";
// @ts-ignore
import _ from "lodash-es";
import { computed, ref, toRef } from "vue"; import { computed, ref, toRef } from "vue";
import { useReference } from "/@/use/use-refrence"; import { useReference } from "/@/use/use-refrence";
import { forEach, get, merge, set } from "lodash-es";
export function getCommonColumnDefine(crudExpose: any, typeRef: any) { export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
const AccessTypeDictRef = dict({ const AccessTypeDictRef = dict({
url: "/pi/access/accessTypeDict" url: "/pi/access/accessTypeDict"
}); });
@@ -27,20 +24,20 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any) {
} }
} }
console.log('crudBinding.value[mode + "Form"].columns', columnsRef.value); console.log('crudBinding.value[mode + "Form"].columns', columnsRef.value);
_.forEach(define.input, (value: any, mapKey: any) => { forEach(define.input, (value: any, mapKey: any) => {
const key = "access." + mapKey; const key = "access." + mapKey;
const field = { const field = {
...value, ...value,
key key
}; };
const column = _.merge({ title: key }, defaultPluginConfig, field); const column = merge({ title: key }, defaultPluginConfig, field);
//eval //eval
useReference(column); useReference(column);
//设置默认值 //设置默认值
if (column.value != null && _.get(form, key) == null) { if (column.value != null && get(form, key) == null) {
_.set(form, key, column.value); set(form, key, column.value);
} }
//字段配置赋值 //字段配置赋值
columnsRef.value[key] = column; columnsRef.value[key] = column;

View File

@@ -1,12 +1,12 @@
// @ts-ignore // @ts-ignore
import * as api from "./api";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { ref } from "vue"; import { ref } from "vue";
import { getCommonColumnDefine } from "/@/views/certd/access/common"; import { getCommonColumnDefine } from "/@/views/certd/access/common";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n(); const { t } = useI18n();
const api = context.api;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => { const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query); return await api.GetList(query);
}; };
@@ -28,7 +28,7 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
}; };
const typeRef = ref(); const typeRef = ref();
const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef); const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api);
return { return {
crudOptions: { crudOptions: {
request: { request: {

View File

@@ -14,11 +14,13 @@
import { defineComponent, onMounted } from "vue"; import { defineComponent, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { createAccessApi } from "/@/views/certd/access/api";
export default defineComponent({ export default defineComponent({
name: "AccessManager", name: "AccessManager",
setup() { setup() {
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} }); const api = createAccessApi("user");
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { api } });
// 页面打开后获取列表数据 // 页面打开后获取列表数据
onMounted(() => { onMounted(() => {

View File

@@ -1,5 +1,6 @@
import { request } from "/src/api/service"; import { request } from "/src/api/service";
import _ from "lodash-es"; import _ from "lodash-es";
import { PluginConfigBean, PluginSysSetting } from "/@/views/sys/plugin/api";
const apiPrefix = "/pi/plugin"; const apiPrefix = "/pi/plugin";
const defaultInputDefine = { const defaultInputDefine = {
@@ -54,3 +55,11 @@ export async function GetGroups(query: any) {
initPlugins(plugins); initPlugins(plugins);
return groups; return groups;
} }
export async function GetPluginConfig(req: { id?: number; name: string; type: string }): Promise<PluginConfigBean> {
return await request({
url: apiPrefix + "/config",
method: "post",
data: req
});
}

View File

@@ -1,10 +1,10 @@
import { compute, CreateCrudOptionsRet, dict } from "@fast-crud/fast-crud"; import { compute, CreateCrudOptionsRet, dict } from "@fast-crud/fast-crud";
import { PluginGroup } from "@certd/pipeline"; import { PluginGroup } from "@certd/pipeline";
import { useReference } from "/@/use/use-refrence"; import { useReference } from "/@/use/use-refrence";
import _ from "lodash-es"; import _, { merge } from "lodash-es";
import { useUserStore } from "/@/store/modules/user"; import { useUserStore } from "/@/store/modules/user";
import { useSettingStore } from "/@/store/modules/settings"; import { useSettingStore } from "/@/store/modules/settings";
import * as api from "../api.plugin";
export default function (certPluginGroup: PluginGroup, formWrapperRef: any): CreateCrudOptionsRet { export default function (certPluginGroup: PluginGroup, formWrapperRef: any): CreateCrudOptionsRet {
const inputs: any = {}; const inputs: any = {};
const userStore = useUserStore(); const userStore = useUserStore();
@@ -46,7 +46,7 @@ export default function (certPluginGroup: PluginGroup, formWrapperRef: any): Cre
crudOptions: { crudOptions: {
form: { form: {
wrapper: { wrapper: {
width: "1150px", width: 1350,
saveRemind: false, saveRemind: false,
title: "创建证书申请流水线" title: "创建证书申请流水线"
} }
@@ -73,6 +73,19 @@ export default function (certPluginGroup: PluginGroup, formWrapperRef: any): Cre
</ul> </ul>
); );
} }
},
valueChange: {
handle: async ({ form, value }) => {
debugger;
const config = await api.GetPluginConfig({
name: value,
type: "builtIn"
});
if (config.sysSetting?.input) {
merge(form, config.sysSetting.input);
}
},
immediate: true
} }
} }
}, },

View File

@@ -116,7 +116,7 @@ import { useUserStore } from "/@/store/modules/user";
import { compute, useCompute } from "@fast-crud/fast-crud"; import { compute, useCompute } from "@fast-crud/fast-crud";
import { useReference } from "/@/use/use-refrence"; import { useReference } from "/@/use/use-refrence";
import { useSettingStore } from "/@/store/modules/settings"; import { useSettingStore } from "/@/store/modules/settings";
import * as pluginApi from "../../../api.plugin";
export default { export default {
name: "PiStepForm", name: "PiStepForm",
// eslint-disable-next-line vue/no-unused-components // eslint-disable-next-line vue/no-unused-components
@@ -163,7 +163,7 @@ export default {
console.log("currentStepTypeChanged:", currentStep.value); console.log("currentStepTypeChanged:", currentStep.value);
}; };
const stepTypeSave = () => { const stepTypeSave = async () => {
currentStep.value._isAdd = false; currentStep.value._isAdd = false;
if (currentStep.value.type == null) { if (currentStep.value.type == null) {
message.warn("请先选择类型"); message.warn("请先选择类型");
@@ -171,7 +171,7 @@ export default {
} }
// 给step的input设置默认值 // 给step的input设置默认值
changeCurrentPlugin(currentStep.value); await changeCurrentPlugin(currentStep.value);
//合并默认值 //合并默认值
_.merge(currentStep.value, { input: {}, strategy: { runStrategy: 0 } }, currentPlugin.value.default, currentStep.value); _.merge(currentStep.value, { input: {}, strategy: { runStrategy: 0 } }, currentPlugin.value.default, currentStep.value);
@@ -229,7 +229,7 @@ export default {
const currentPlugin = doComputed(() => { const currentPlugin = doComputed(() => {
return currentPluginDefine.value; return currentPluginDefine.value;
}, getContext); }, getContext);
const changeCurrentPlugin = (step: any) => { const changeCurrentPlugin = async (step: any) => {
const stepType = step.type; const stepType = step.type;
step.type = stepType; step.type = stepType;
step._isAdd = false; step._isAdd = false;
@@ -255,6 +255,14 @@ export default {
currentStep.value.input[key] = column.default ?? column.value; currentStep.value.input[key] = column.default ?? column.value;
} }
} }
//设置系统初始值
debugger;
const pluginSysConfig = await pluginApi.GetPluginConfig({ name: pluginDefine.name, type: "builtIn" });
if (pluginSysConfig.sysSetting?.input) {
for (const key in pluginSysConfig.sysSetting?.input) {
currentStep.value.input[key] = pluginSysConfig.sysSetting?.input[key];
}
}
console.log("currentStepTypeChanged:", currentStep.value); console.log("currentStepTypeChanged:", currentStep.value);
console.log("currentStepPlugin:", currentPlugin.value); console.log("currentStepPlugin:", currentPlugin.value);

View File

@@ -20,7 +20,7 @@ export type PluginGroup = {
}; };
export type PluginDefine = { export type PluginDefine = {
key: string; name: string;
title: string; title: string;
desc?: string; desc?: string;
input: { input: {

View File

@@ -0,0 +1,36 @@
<template>
<fs-page>
<template #header>
<div class="title">
系统级授权管理
<span class="sub">管理第三方系统的授权信息(系统级)</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</fs-page>
</template>
<script lang="ts">
import { defineComponent, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "../../certd/access/crud";
import { createAccessApi } from "/@/views/certd/access/api";
export default defineComponent({
name: "SysAccessManager",
setup() {
const api = createAccessApi("/sys/access");
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { api } });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>

View File

@@ -76,18 +76,21 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
} }
}, },
domain: { domain: {
title: "域名", title: "CNAME域名",
type: "text", type: "text",
editForm: { editForm: {
component: { component: {
disabled: true disabled: true
} }
}, },
search: {
show: true
},
form: { form: {
component: { component: {
placeholder: "cname.handsfree.work" placeholder: "cname.handsfree.work"
}, },
helper: "CNAME域名一旦确定不可修改建议使用一级子域名", helper: "需要一个右边DNS提供商注册的域名也可以将其他域名的dns服务器转移到这几家来。\nCNAME域名一旦确定不可修改建议使用一级子域名",
rules: [{ required: true, message: "此项必填" }] rules: [{ required: true, message: "此项必填" }]
}, },
column: { column: {
@@ -97,6 +100,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
dnsProviderType: { dnsProviderType: {
title: "DNS提供商", title: "DNS提供商",
type: "dict-select", type: "dict-select",
search: {
show: true
},
dict: dict({ dict: dict({
url: "pi/dnsProvider/list", url: "pi/dnsProvider/list",
value: "key", value: "key",

View File

@@ -0,0 +1,102 @@
import { request } from "/src/api/service";
const apiPrefix = "/sys/plugin";
export async function GetList(query: any) {
return await request({
url: apiPrefix + "/page",
method: "post",
data: query
});
}
export async function AddObj(obj: any) {
return await request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export async function UpdateObj(obj: any) {
return await request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export async function DelObj(id: any) {
return await request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export async function GetObj(id: any) {
return await request({
url: apiPrefix + "/info",
method: "post",
params: { id }
});
}
export async function GetDetail(id: any) {
return await request({
url: apiPrefix + "/detail",
method: "post",
params: { id }
});
}
export async function DeleteBatch(ids: any[]) {
return await request({
url: apiPrefix + "/deleteByIds",
method: "post",
data: { ids }
});
}
export async function SetDisabled(data: { id?: number; name?: string; type?: string; disabled: boolean }) {
return await request({
url: apiPrefix + "/setDisabled",
method: "post",
data: data
});
}
export type PluginConfigBean = {
name: string;
disabled: boolean;
sysSetting: {
input?: Record<string, any>;
};
};
export type CertApplyPluginSysInput = {
googleCommonEabAccessId: number;
};
export type PluginSysSetting<T> = {
sysSetting: {
input?: T;
};
};
export type CommPluginConfig = {
CertApply?: PluginSysSetting<CertApplyPluginSysInput>;
};
export async function GetCommPluginConfigs(): Promise<CommPluginConfig> {
return await request({
url: apiPrefix + "/getCommPluginConfigs",
method: "post"
});
}
export async function SaveCommPluginConfigs(data: CommPluginConfig): Promise<void> {
return await request({
url: apiPrefix + "/saveCommPluginConfigs",
method: "post",
data
});
}

View File

@@ -0,0 +1,73 @@
<template>
<fs-page class="page-plugin-config">
<template #header>
<div class="title">证书插件配置</div>
</template>
<div class="sys-plugin-config settings-form">
<a-form :model="formState" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish" @finish-failed="onFinishFailed">
<a-form-item label="公共Google EAB授权" :name="['CertApply', 'sysSetting', 'input', 'googleCommonEabAccessId']">
<access-selector v-model:model-value="formState.CertApply.sysSetting.input.googleCommonEabAccessId" type="eab" from="sys"></access-selector>
<div class="helper">
<div>设置公共Google EAB授权给用户使用避免用户自己去翻墙获取Google EAB授权</div>
<div>
<a href="https://gitee.com/certd/certd/blob/v2/doc/google/google.md#21-%E7%9B%B4%E6%8E%A5%E8%8E%B7%E5%8F%96eab-%E6%8E%A8%E8%8D%90">
获取Google EAB授权方法
</a>
</div>
</div>
</a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button :loading="saveLoading" type="primary" html-type="submit">保存</a-button>
</a-form-item>
</a-form>
</div>
</fs-page>
</template>
<script lang="ts" setup>
import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
import { reactive, ref } from "vue";
import { CommPluginConfig, GetCommPluginConfigs, SaveCommPluginConfigs } from "/@/views/sys/plugin/api";
import { merge } from "lodash-es";
import { notification } from "ant-design-vue";
defineOptions({
name: "SysPluginConfig"
});
const formState = reactive<Partial<CommPluginConfig>>({
CertApply: {
sysSetting: {
input: {
googleCommonEabAccessId: null
}
}
}
});
async function loadForm() {
const res = await GetCommPluginConfigs();
merge(formState, res);
}
loadForm();
const saveLoading = ref(false);
const onFinish = async (form: any) => {
try {
saveLoading.value = true;
await SaveCommPluginConfigs(form);
notification.success({
message: "保存成功"
});
} finally {
saveLoading.value = false;
}
};
const onFinishFailed = (errorInfo: any) => {
console.log("Failed:", errorInfo);
};
</script>
<style lang="less"></style>

View File

@@ -0,0 +1,211 @@
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, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
import { useUserStore } from "/src/store/modules/user";
import { useSettingStore } from "/src/store/modules/settings";
import { Modal } from "ant-design-vue";
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
},
copy: {
show: false
},
remove: {
show: false
}
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 100
},
form: {
show: false
}
},
name: {
title: "插件名称",
type: "text",
search: {
show: true
},
form: {
show: false
},
column: {
width: 200
}
},
icon: {
title: "图标",
type: "text",
form: {
show: false
},
column: {
width: 100,
align: "center",
component: {
name: "fs-icon",
vModel: "icon",
style: {
fontSize: "22px"
}
}
}
},
title: {
title: "标题",
type: "text",
column: {
width: 300
}
},
desc: {
title: "描述",
type: "text",
column: {
width: 300
}
},
group: {
title: "分组",
type: "text",
column: {
width: 100,
align: "center"
}
},
disabled: {
title: "禁用/启用",
type: "dict-switch",
dict: dict({
data: [
{ label: "启用", value: false, color: "success" },
{ label: "禁用", value: true, color: "error" }
]
}),
form: {
value: false
},
column: {
width: 100,
align: "center",
component: {
title: "点击可禁用/启用",
on: {
async click({ value, row }) {
Modal.confirm({
title: "提示",
content: `确定要${!value ? "禁用" : "启用"}吗?`,
onOk: async () => {
await api.SetDisabled({
id: row.id,
name: row.name,
type: row.type,
disabled: !value
});
await crudExpose.doRefresh();
}
});
}
}
}
}
},
createTime: {
title: "创建时间",
type: "datetime",
form: {
show: false
},
column: {
sorter: true,
width: 160,
align: "center"
}
},
updateTime: {
title: "更新时间",
type: "datetime",
form: {
show: false
},
column: {
show: true
}
}
}
}
};
}

View 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 "./api";
defineOptions({
name: "SysPlugin"
});
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>

View File

@@ -1,6 +1,18 @@
// @ts-ignore // @ts-ignore
import { request } from "/@/api/service"; import { request } from "/@/api/service";
const apiPrefix = "/sys/settings"; const apiPrefix = "/sys/settings";
export type SysSettings = { public: SysPublicSetting; private: SysPrivateSetting };
export type SysPublicSetting = {
registerEnabled?: boolean;
managerOtherUserPipeline?: boolean;
icpNo?: string;
};
export type SysPrivateSetting = {
httpProxy?: string;
httpsProxy?: string;
};
export const SettingKeys = { export const SettingKeys = {
SysPublic: "sys.public", SysPublic: "sys.public",
@@ -8,13 +20,17 @@ export const SettingKeys = {
SysEmail: "sys.email" SysEmail: "sys.email"
}; };
export async function SettingsGet(key: string) { export async function SettingsGet(key: string) {
return await request({ const res = await request({
url: apiPrefix + "/get", url: apiPrefix + "/get",
method: "post", method: "post",
params: { params: {
key key
} }
}); });
if (!res) {
return {};
}
return JSON.parse(res.setting);
} }
export async function SettingsSave(key: string, setting: any) { export async function SettingsSave(key: string, setting: any) {
@@ -35,17 +51,31 @@ export async function EmailSettingsGet() {
}); });
} }
export async function PublicSettingsSave(setting: any) {
return await request({
url: apiPrefix + "/savePublicSettings",
method: "post",
data: setting
});
}
export async function stopOtherUserTimer() { export async function stopOtherUserTimer() {
return await request({ return await request({
url: apiPrefix + "/stopOtherUserTimer", url: apiPrefix + "/stopOtherUserTimer",
method: "post" method: "post"
}); });
} }
export async function SysSettingsGet(): Promise<SysSettings> {
return await request({
url: apiPrefix + "/getSysSettings",
method: "post"
});
}
export async function SysSettingsSave(data: SysSettings) {
return await request({
url: apiPrefix + "/saveSysSettings",
method: "post",
data: data
});
}
export async function TestProxy() {
return await request({
url: apiPrefix + "/testProxy",
method: "post"
});
}

View File

@@ -3,7 +3,7 @@
<template #header> <template #header>
<div class="title">系统设置</div> <div class="title">系统设置</div>
</template> </template>
<div class="sys-settings-form"> <div class="sys-settings-form settings-form">
<a-form <a-form
:model="formState" :model="formState"
name="basic" name="basic"
@@ -13,29 +13,31 @@
@finish="onFinish" @finish="onFinish"
@finish-failed="onFinishFailed" @finish-failed="onFinishFailed"
> >
<a-form-item label="开启自助注册" name="registerEnabled"> <a-form-item label="开启自助注册" :name="['public', 'registerEnabled']">
<a-switch v-model:checked="formState.registerEnabled" /> <a-switch v-model:checked="formState.public.registerEnabled" />
</a-form-item> </a-form-item>
<a-form-item label="管理其他用户流水线" name="managerOtherUserPipeline"> <a-form-item label="管理其他用户流水线" :name="['public', 'managerOtherUserPipeline']">
<a-switch v-model:checked="formState.managerOtherUserPipeline" /> <a-switch v-model:checked="formState.public.managerOtherUserPipeline" />
</a-form-item> </a-form-item>
<a-form-item label="ICP备案号" name="icpNo"> <a-form-item label="ICP备案号" :name="['public', 'icpNo']">
<a-input v-model:value="formState.icpNo" /> <a-input v-model:value="formState.public.icpNo" placeholder="粤ICP备xxxxxxx号" />
</a-form-item>
<a-form-item label="HTTP代理" :name="['private', 'httpProxy']" :rules="urlRules">
<a-input v-model:value="formState.private.httpProxy" placeholder="http://192.168.1.2:18010/" />
</a-form-item>
<a-form-item label="HTTPS代理" :name="['private', 'httpsProxy']" :rules="urlRules">
<div class="flex">
<a-input v-model:value="formState.private.httpsProxy" placeholder="http://192.168.1.2:18010/" />
<a-button class="ml-5" type="primary" title="保存后,再点击测试" @click="testProxy">测试</a-button>
</div>
<div class="helper">一般这两个代理填一样的</div>
</a-form-item> </a-form-item>
<!-- <a-form-item label="启动后触发流水线" name="triggerOnStartup">-->
<!-- <a-switch v-model:checked="formState.triggerOnStartup" />-->
<!-- <div class="helper">启动后自动触发一次所有已启用的流水线</div>-->
<!-- </a-form-item>-->
<a-form-item :wrapper-col="{ offset: 8, span: 16 }"> <a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button :loading="saveLoading" type="primary" html-type="submit">保存</a-button> <a-button :loading="saveLoading" 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>
@@ -43,42 +45,41 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from "vue"; import { reactive, ref } from "vue";
import * as api from "./api"; import * as api from "./api";
import { PublicSettingsSave, SettingKeys } from "./api"; import { SysSettings } from "./api";
import { notification } from "ant-design-vue"; import { notification } from "ant-design-vue";
import { useSettingStore } from "/@/store/modules/settings"; import { useSettingStore } from "/@/store/modules/settings";
import { merge } from "lodash-es";
defineOptions({ defineOptions({
name: "SysSettings" name: "SysSettings"
}); });
interface FormState { const formState = reactive<Partial<SysSettings>>({
registerEnabled: boolean; public: {
managerOtherUserPipeline: boolean; registerEnabled: false,
icpNo: string; managerOtherUserPipeline: false,
} icpNo: ""
},
const formState = reactive<Partial<FormState>>({ private: {}
registerEnabled: false,
managerOtherUserPipeline: false,
icpNo: ""
}); });
async function loadSysPublicSettings() { const urlRules = ref({
const data: any = await api.SettingsGet(SettingKeys.SysPublic); type: "url",
if (data == null) { message: "请输入正确的URL"
return; });
}
const setting = JSON.parse(data.setting); async function loadSysSettings() {
Object.assign(formState, setting); const data: any = await api.SysSettingsGet();
merge(formState, data);
} }
const saveLoading = ref(false); const saveLoading = ref(false);
loadSysPublicSettings(); loadSysSettings();
const settingsStore = useSettingStore(); const settingsStore = useSettingStore();
const onFinish = async (form: any) => { const onFinish = async (form: any) => {
try { try {
saveLoading.value = true; saveLoading.value = true;
await api.PublicSettingsSave(form); await api.SysSettingsSave(form);
await settingsStore.loadSysSettings(); await settingsStore.loadSysSettings();
notification.success({ notification.success({
message: "保存成功" message: "保存成功"
@@ -98,6 +99,15 @@ async function stopOtherUserTimer() {
message: "停止成功" message: "停止成功"
}); });
} }
async function testProxy() {
const res = await api.TestProxy();
const content = `测试google:${res.google === true ? "成功" : "失败" + res.google},测试百度:${res.baidu === true ? "成功" : "失败:" + res.baidu}`;
notification.success({
message: "测试完成",
description: content
});
}
</script> </script>
<style lang="less"> <style lang="less">

View File

@@ -4,23 +4,11 @@
# server: # server:
# baseUrl: 'http://127.0.0.1:11007' # baseUrl: 'http://127.0.0.1:11007'
#flyway:
# scriptDir: './db/migration-pg'
#typeorm: #typeorm:
# dataSource: # dataSource:
# default: # default:
# type: postgres # database: './data/db.sqlite'
# host: localhost
# port: 5433
# username: postgres
# password: root
# database: postgres
typeorm:
dataSource:
default:
database: './data/db.sqlite'
plus: plus:
server: server:
baseUrls: ['https://api.ai.handsfree.work', 'https://api.ai.docmirror.cn'] baseUrls: ['https://api.ai.handsfree.work', 'https://api.ai.docmirror.cn']

View File

@@ -0,0 +1,21 @@
flyway:
scriptDir: './db/migration-pg'
typeorm:
dataSource:
default:
type: postgres
host: 192.168.42.245
port: 5432
username: root
password: Baode@1234567
database: certd
#plus:
# server:
# baseUrl: 'https://api.ai.handsfree.work'
plus:
server:
baseUrl: 'http://127.0.0.1:11007'

View File

@@ -17,3 +17,5 @@ run/
/test/setup.ts /test/setup.ts
/data/ /data/
.clinic .clinic
.env.pgpl.yaml

View File

@@ -3,6 +3,14 @@
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.26.4](https://github.com/certd/certd/compare/v1.26.3...v1.26.4) (2024-10-14)
### Performance Improvements
* [comm] 支持插件管理 ([e8b617b](https://github.com/certd/certd/commit/e8b617b80ce882dd63006f0cfc719a80a1cc6acc))
* 新增代理设置功能 ([273ab61](https://github.com/certd/certd/commit/273ab6139f5807f4d7fe865cc353b97f51b9a668))
* EAB授权支持绑定邮箱支持公共EAB设置 ([07043af](https://github.com/certd/certd/commit/07043aff0ca7fd29c56dd3c363002cb15d78b464))
## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12) ## [1.26.3](https://github.com/certd/certd/compare/v1.26.2...v1.26.3) (2024-10-12)
### Performance Improvements ### Performance Improvements

View File

@@ -0,0 +1,18 @@
CREATE TABLE "pi_plugin"
(
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(100) NOT NULL,
"icon" varchar(100),
"title" varchar(200),
"desc" varchar(500),
"group" varchar(100),
"version" varchar(100),
"setting" text,
"sys_setting" text,
"content" text,
"type" varchar(100) NOT NULL,
"disabled" boolean NOT NULL,
"create_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);

View File

@@ -0,0 +1,18 @@
CREATE TABLE "pi_plugin"
(
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(100) NOT NULL,
"icon" varchar(100),
"title" varchar(200),
"desc" varchar(500),
"group" varchar(100),
"version" varchar(100),
"setting" text,
"sys_setting" text,
"content" text,
"type" varchar(100) NOT NULL,
"disabled" boolean NOT NULL,
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);

View File

@@ -1,24 +1,24 @@
## sqlite与postgres不同点 ## sqlite与postgres不同点
1. 1.
sl: AUTOINCREAMENT sqlite: AUTOINCREAMENT
pg: GENERATED BY DEFAULT AS IDENTITY postgresql: GENERATED BY DEFAULT AS IDENTITY
2. 2.
datetime sqlite: datetime
timestamp postgresql: timestamp
3. 3.
update sqlite_sequence set seq = 1000 where name = 'sys_role' ; sqlite: update sqlite_sequence set seq = 1000 where name = 'sys_role' ;
select setval('sys_role_id_seq', 1000); postgresql: select setval('sys_role_id_seq', 1000);
4. 4.
"disabled" boolean DEFAULT (0) sqlite: "disabled" boolean DEFAULT (0)
"disabled" boolean DEFAULT (false) postgresql: "disabled" boolean DEFAULT (false)
5. 5.
last_insert_rowid() sqlite: last_insert_rowid()
LASTVAL() postgresql: LASTVAL()
6. 6.
sl: integer sqlite: integer
pg: bigint postgresql: bigint

View File

@@ -0,0 +1,53 @@
import fs from 'fs';
/**
* ## sqlite与postgres不同点
* 1.
* sqlite: AUTOINCREAMENT
* postgresql: GENERATED BY DEFAULT AS IDENTITY
*
* 2.
* sqlite: datetime
* postgresql: timestamp
*
* 3.
* sqlite: update sqlite_sequence set seq = 1000 where name = 'sys_role' ;
* postgresql: select setval('sys_role_id_seq', 1000);
*
* 4.
* sqlite: "disabled" boolean DEFAULT (0)
* postgresql: "disabled" boolean DEFAULT (false)
*
* 5.
* sqlite: last_insert_rowid()
* postgresql: LASTVAL()
*
* 6.
* sqlite: integer
* postgresql: bigint
*/
function transform() {
// 读取文件列表
const sqliteFiles = fs.readdirSync('./migration/');
const pgFiles = fs.readdirSync('./migration-pg');
//找出pg里面没有的文件
const notFiles = sqliteFiles.filter(file => !pgFiles.includes(file));
for (const notFile of notFiles) {
//开始转换
const sqliteSql = fs.readFileSync(`./migration/${notFile}`, 'utf-8');
let pgSql = sqliteSql.replace(/AUTOINCREMENT/g, 'GENERATED BY DEFAULT AS IDENTITY');
pgSql = pgSql.replace(/datetime/g, 'timestamp');
pgSql = pgSql.replace(/boolean DEFAULT \(0\)/g, 'boolean DEFAULT (false)');
pgSql = pgSql.replace(/integer/g, 'bigint');
pgSql = pgSql.replace(/last_insert_rowid\(\)/g, 'LASTVAL()');
fs.writeFileSync(`./migration-pg/${notFile}`, pgSql);
}
if (notFiles.length > 0) {
console.log('sqlite->pg 转换完成');
throw new Error('sqlite->pg 转换完成有更新需要测试pg');
} else {
console.log('sql无需更新');
}
}
transform();

View File

@@ -1,6 +1,6 @@
{ {
"name": "@certd/ui-server", "name": "@certd/ui-server",
"version": "1.26.3", "version": "1.26.4",
"description": "fast-server base midway", "description": "fast-server base midway",
"private": true, "private": true,
"type": "module", "type": "module",
@@ -10,6 +10,9 @@
"commdev": "cross-env NODE_ENV=commdev mwtsc --watch --run @midwayjs/mock/app", "commdev": "cross-env NODE_ENV=commdev mwtsc --watch --run @midwayjs/mock/app",
"commpro": "cross-env NODE_ENV=commpro mwtsc --watch --run @midwayjs/mock/app", "commpro": "cross-env NODE_ENV=commpro mwtsc --watch --run @midwayjs/mock/app",
"pgdev": "cross-env NODE_ENV=pgdev mwtsc --watch --run @midwayjs/mock/app", "pgdev": "cross-env NODE_ENV=pgdev mwtsc --watch --run @midwayjs/mock/app",
"pgpl": "cross-env NODE_ENV=pgpl mwtsc --watch --run @midwayjs/mock/app",
"dev-new": "npm run rm-db-new && cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app",
"rm-db-new": "rimraf ./data/db-new.sqlite",
"test": "cross-env NODE_ENV=unittest mocha", "test": "cross-env NODE_ENV=unittest mocha",
"cov": "cross-env c8 --all --reporter=text --reporter=lcovonly npm run test", "cov": "cross-env c8 --all --reporter=text --reporter=lcovonly npm run test",
"lint": "mwts check", "lint": "mwts check",
@@ -19,22 +22,22 @@
"dev-build": "echo 1", "dev-build": "echo 1",
"build-on-docker": "node ./before-build.js && npm run build", "build-on-docker": "node ./before-build.js && npm run build",
"up-mw-deps": "npx midway-version -u -w", "up-mw-deps": "npx midway-version -u -w",
"heap": "clinic heapprofiler -- node ./bootstrap.js", "heap": "cross-env NODE_ENV=pgpl clinic heapprofiler -- node ./bootstrap.js",
"flame": "clinic flame -- node ./bootstrap.js" "flame": "clinic flame -- node ./bootstrap.js"
}, },
"dependencies": { "dependencies": {
"@alicloud/pop-core": "^1.7.10", "@alicloud/pop-core": "^1.7.10",
"@certd/acme-client": "^1.26.3", "@certd/acme-client": "^1.26.4",
"@certd/commercial-core": "^1.26.3", "@certd/commercial-core": "^1.26.4",
"@certd/lib-huawei": "^1.26.3", "@certd/lib-huawei": "^1.26.4",
"@certd/lib-jdcloud": "^1.26.3", "@certd/lib-jdcloud": "^1.26.4",
"@certd/lib-k8s": "^1.26.3", "@certd/lib-k8s": "^1.26.4",
"@certd/lib-server": "^1.26.3", "@certd/lib-server": "^1.26.4",
"@certd/midway-flyway-js": "^1.26.3", "@certd/midway-flyway-js": "^1.26.4",
"@certd/pipeline": "^1.26.3", "@certd/pipeline": "^1.26.4",
"@certd/plugin-cert": "^1.26.3", "@certd/plugin-cert": "^1.26.4",
"@certd/plugin-plus": "^1.26.3", "@certd/plugin-plus": "^1.26.4",
"@certd/plus-core": "^1.26.3", "@certd/plus-core": "^1.26.4",
"@koa/cors": "^5.0.0", "@koa/cors": "^5.0.0",
"@midwayjs/bootstrap": "~3.17.1", "@midwayjs/bootstrap": "~3.17.1",
"@midwayjs/cache": "~3.14.0", "@midwayjs/cache": "~3.14.0",
@@ -102,6 +105,7 @@
"mocha": "^10.2.0", "mocha": "^10.2.0",
"mwts": "^1.3.0", "mwts": "^1.3.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },

View File

@@ -66,7 +66,7 @@ const development = {
type: 'better-sqlite3', type: 'better-sqlite3',
database: './data/db.sqlite', database: './data/db.sqlite',
synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true
logging: false, logging: true,
// 配置实体模型 或者 entities: '/entity', // 配置实体模型 或者 entities: '/entity',
entities: ['**/modules/**/entity/*.js', ...libServerEntities, ...commercialEntities, PipelineEntity, FlywayHistory, UserEntity], entities: ['**/modules/**/entity/*.js', ...libServerEntities, ...commercialEntities, PipelineEntity, FlywayHistory, UserEntity],

View File

@@ -5,7 +5,7 @@ import * as cache from '@midwayjs/cache';
import * as validate from '@midwayjs/validate'; import * as validate from '@midwayjs/validate';
import * as info from '@midwayjs/info'; import * as info from '@midwayjs/info';
import * as staticFile from '@midwayjs/static-file'; import * as staticFile from '@midwayjs/static-file';
import * as cron from './modules/plugin/cron/index.js'; import * as cron from './modules/cron/index.js';
import * as flyway from '@certd/midway-flyway-js'; import * as flyway from '@certd/midway-flyway-js';
import cors from '@koa/cors'; import cors from '@koa/cors';
import { GlobalExceptionMiddleware } from './middleware/global-exception.js'; import { GlobalExceptionMiddleware } from './middleware/global-exception.js';

View File

@@ -3,8 +3,8 @@ import { ALL, Inject } from '@midwayjs/core';
import { Body } from '@midwayjs/core'; import { Body } from '@midwayjs/core';
import { Controller, Post, Provide } from '@midwayjs/core'; import { Controller, Post, Provide } from '@midwayjs/core';
import { BaseController } from '@certd/lib-server'; import { BaseController } from '@certd/lib-server';
import { CodeService } from '../service/code-service.js'; import { CodeService } from '../../modules/basic/service/code-service.js';
import { EmailService } from '../service/email-service.js'; import { EmailService } from '../../modules/basic/service/email-service.js';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';
export class SmsCodeReq { export class SmsCodeReq {
@Rule(RuleType.number().required()) @Rule(RuleType.number().required())

View File

@@ -1,6 +1,6 @@
import { Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController } from '@certd/lib-server'; import { BaseController } from '@certd/lib-server';
import { EmailService } from '../service/email-service.js'; import { EmailService } from '../../modules/basic/service/email-service.js';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';
/** /**

View File

@@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController, Constants } from '@certd/lib-server'; import { BaseController, Constants } from '@certd/lib-server';
import { CnameRecordService } from '../service/cname-record-service.js'; import { CnameRecordService } from '../../modules/cname/service/cname-record-service.js';
import { CnameProviderService } from '../../sys/cname/service/cname-provider-service.js'; import { CnameProviderService } from '../../modules/cname/service/cname-provider-service.js';
/** /**
* *

View File

@@ -1,6 +1,6 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController } from '@certd/lib-server'; import { Constants, CrudController } from '@certd/lib-server';
import { CnameRecordService } from '../service/cname-record-service.js'; import { CnameRecordService } from '../../modules/cname/service/cname-record-service.js';
/** /**
* *
@@ -24,11 +24,16 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
const bq = qb => { const bq = qb => {
if (domain) { if (domain) {
qb.where('domain like :domain', { domain: `%${domain}%` }); qb.andWhere('domain like :domain', { domain: `%${domain}%` });
} }
}; };
const pageRet = await this.getService().page(body?.query, body?.page, body?.sort, bq); const pageRet = await this.getService().page({
query: body.query,
page: body.page,
order: body.order,
buildQuery: bq,
});
return this.ok(pageRet); return this.ok(pageRet);
} }

View File

@@ -1,5 +1,5 @@
import { Body, Controller, Inject, Post, Provide, ALL } from '@midwayjs/core'; import { Body, Controller, Inject, Post, Provide, ALL } from '@midwayjs/core';
import { LoginService } from '../service/login-service.js'; import { LoginService } from '../../modules/login/service/login-service.js';
import { BaseController } from '@certd/lib-server'; import { BaseController } from '@certd/lib-server';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';

View File

@@ -1,8 +1,8 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController } from '@certd/lib-server'; import { BaseController } from '@certd/lib-server';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';
import { UserService } from '../../sys/authority/service/user-service.js'; import { UserService } from '../../modules/sys/authority/service/user-service.js';
import { UserEntity } from '../../sys/authority/entity/user.js'; import { UserEntity } from '../../modules/sys/authority/entity/user.js';
import { SysSettingsService } from '@certd/lib-server'; import { SysSettingsService } from '@certd/lib-server';
/** /**

View File

@@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController, Constants } from '@certd/lib-server'; import { BaseController, Constants } from '@certd/lib-server';
import { UserService } from '../../sys/authority/service/user-service.js'; import { UserService } from '../../modules/sys/authority/service/user-service.js';
import { RoleService } from '../../sys/authority/service/role-service.js'; import { RoleService } from '../../modules/sys/authority/service/role-service.js';
/** /**
*/ */

View File

@@ -1,8 +1,8 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { CrudController } from '@certd/lib-server'; import { CrudController } from '@certd/lib-server';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';
import { UserSettingsService } from '../service/user-settings-service.js'; import { UserSettingsService } from '../../modules/mine/service/user-settings-service.js';
import { UserSettingsEntity } from '../entity/user-settings.js'; import { UserSettingsEntity } from '../../modules/mine/entity/user-settings.js';
/** /**
*/ */

View File

@@ -1,6 +1,6 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { CrudController } from '@certd/lib-server'; import { CrudController } from '@certd/lib-server';
import { AccessService } from '../service/access-service.js'; import { AccessService } from '../../modules/pipeline/service/access-service.js';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';
/** /**
@@ -19,8 +19,17 @@ export class AccessController extends CrudController<AccessService> {
@Post('/page', { summary: Constants.per.authOnly }) @Post('/page', { summary: Constants.per.authOnly })
async page(@Body(ALL) body) { async page(@Body(ALL) body) {
body.query = body.query ?? {}; body.query = body.query ?? {};
body.query.userId = this.getUserId(); delete body.query.userId;
return await super.page(body); const buildQuery = qb => {
qb.andWhere('user_id = :userId', { userId: this.getUserId() });
};
const res = await this.service.page({
query: body.query,
page: body.page,
order: body.order,
buildQuery,
});
return this.ok(res);
} }
@Post('/list', { summary: Constants.per.authOnly }) @Post('/list', { summary: Constants.per.authOnly })

View File

@@ -1,5 +1,5 @@
import { ALL, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { DnsProviderService } from '../service/dns-provider-service.js'; import { DnsProviderService } from '../../modules/pipeline/service/dns-provider-service.js';
import { BaseController } from '@certd/lib-server'; import { BaseController } from '@certd/lib-server';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';

View File

@@ -13,9 +13,9 @@ import {
utils, utils,
} from '@certd/pipeline'; } from '@certd/pipeline';
import { BaseController } from '@certd/lib-server'; import { BaseController } from '@certd/lib-server';
import { AccessService } from '../service/access-service.js'; import { AccessService } from '../../modules/pipeline/service/access-service.js';
import { EmailService } from '../../basic/service/email-service.js'; import { EmailService } from '../../modules/basic/service/email-service.js';
import { AccessGetter } from '../service/access-getter.js'; import { AccessGetter } from '../../modules/pipeline/service/access-getter.js';
@Provide() @Provide()
@Controller('/api/pi/handle') @Controller('/api/pi/handle')

View File

@@ -1,14 +1,14 @@
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core';
import { CommonException, Constants, CrudController, PermissionException } from '@certd/lib-server'; import { CommonException, Constants, CrudController, PermissionException } from '@certd/lib-server';
import { PipelineEntity } from '../entity/pipeline.js'; import { PipelineEntity } from '../../modules/pipeline/entity/pipeline.js';
import { HistoryService } from '../service/history-service.js'; import { HistoryService } from '../../modules/pipeline/service/history-service.js';
import { HistoryLogService } from '../service/history-log-service.js'; import { HistoryLogService } from '../../modules/pipeline/service/history-log-service.js';
import { HistoryEntity } from '../entity/history.js'; import { HistoryEntity } from '../../modules/pipeline/entity/history.js';
import { HistoryLogEntity } from '../entity/history-log.js'; import { HistoryLogEntity } from '../../modules/pipeline/entity/history-log.js';
import { PipelineService } from '../service/pipeline-service.js'; import { PipelineService } from '../../modules/pipeline/service/pipeline-service.js';
import * as fs from 'fs'; import * as fs from 'fs';
import { logger } from '@certd/pipeline'; import { logger } from '@certd/pipeline';
import { AuthService } from '../../sys/authority/service/auth-service.js'; import { AuthService } from '../../modules/sys/authority/service/auth-service.js';
import { SysSettingsService } from '@certd/lib-server'; import { SysSettingsService } from '@certd/lib-server';
import { In } from 'typeorm'; import { In } from 'typeorm';
@@ -48,21 +48,29 @@ export class HistoryController extends CrudController<HistoryService> {
let pipelineIds: any = null; let pipelineIds: any = null;
const pipelineTitle = body.query?.pipelineTitle; const pipelineTitle = body.query?.pipelineTitle;
if (pipelineTitle) { if (pipelineTitle) {
const pipelines = await this.pipelineService.list(pipelineQuery, null, qb => { const pipelines = await this.pipelineService.list({
qb.where('title like :title', { title: `%${pipelineTitle}%` }); query: pipelineQuery,
buildQuery: qb => {
qb.andWhere('title like :title', { title: `%${pipelineTitle}%` });
},
}); });
pipelineIds = pipelines.map(p => p.id); pipelineIds = pipelines.map(p => p.id);
} }
const buildQuery = qb => { const buildQuery = qb => {
if (pipelineIds) { if (pipelineIds) {
qb.where({ qb.andWhere({
pipelineId: In(pipelineIds), pipelineId: In(pipelineIds),
}); });
} }
}; };
const res = await this.service.page(body?.query, body?.page, body?.sort, buildQuery); const res = await this.service.page({
query: body.query,
page: body.page,
order: body.order,
buildQuery,
});
return this.ok(res); return this.ok(res);
} }
@@ -78,7 +86,11 @@ export class HistoryController extends CrudController<HistoryService> {
const buildQuery = qb => { const buildQuery = qb => {
qb.limit(10); qb.limit(10);
}; };
const listRet = await this.getService().list(body, { prop: 'id', asc: false }, buildQuery); const listRet = await this.getService().list({
query: body,
order: { prop: 'id', asc: false },
buildQuery,
});
return this.ok(listRet); return this.ok(listRet);
} }

View File

@@ -1,9 +1,9 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController, SysSettingsService } from '@certd/lib-server'; import { Constants, CrudController, SysSettingsService } from '@certd/lib-server';
import { PipelineService } from '../service/pipeline-service.js'; import { PipelineService } from '../../modules/pipeline/service/pipeline-service.js';
import { PipelineEntity } from '../entity/pipeline.js'; import { PipelineEntity } from '../../modules/pipeline/entity/pipeline.js';
import { HistoryService } from '../service/history-service.js'; import { HistoryService } from '../../modules/pipeline/service/history-service.js';
import { AuthService } from '../../sys/authority/service/auth-service.js'; import { AuthService } from '../../modules/sys/authority/service/auth-service.js';
/** /**
* *
@@ -37,14 +37,19 @@ export class PipelineController extends CrudController<PipelineService> {
const buildQuery = qb => { const buildQuery = qb => {
if (title) { if (title) {
qb.where('title like :title', { title: `%${title}%` }); qb.andWhere('title like :title', { title: `%${title}%` });
} }
}; };
if (!body.sort || !body.sort?.prop) { if (!body.sort || !body.sort?.prop) {
body.sort = { prop: 'order', asc: false }; body.sort = { prop: 'order', asc: false };
} }
const pageRet = await this.getService().page(body?.query, body?.page, body?.sort, buildQuery); const pageRet = await this.getService().page({
query: body.query,
page: body.page,
order: body.order,
buildQuery,
});
return this.ok(pageRet); return this.ok(pageRet);
} }

Some files were not shown because too many files have changed in this diff Show More