mirror of
https://github.com/certd/certd.git
synced 2026-04-08 09:00:56 +08:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff1d7b115a | ||
|
|
98bd5149e9 | ||
|
|
4efa2e0c6a | ||
|
|
f805036054 | ||
|
|
3c723c4325 | ||
|
|
14a83f6b52 | ||
|
|
ff0686670c | ||
|
|
3198d07553 | ||
|
|
c7e2896326 | ||
|
|
0db5381a8b | ||
|
|
cb86151deb | ||
|
|
d6c7326467 | ||
|
|
92c6c45e77 | ||
|
|
c6fff4950d | ||
|
|
81a8123725 | ||
|
|
d0d3e74d55 | ||
|
|
b54ae272eb | ||
|
|
3af6d96e6e | ||
|
|
f38b33ea39 | ||
|
|
dd2b0a1595 | ||
|
|
c96fcb7afc | ||
|
|
b805a29259 | ||
|
|
5450246f06 | ||
|
|
d9a00eeaf7 | ||
|
|
131ed13df1 | ||
|
|
5f8d70028a | ||
|
|
c222b702c3 | ||
|
|
de43391e4c | ||
|
|
547c0b8399 | ||
|
|
fcbb5e46a1 | ||
|
|
7c5166c8bb | ||
|
|
fab66606b3 | ||
|
|
1d143f7103 | ||
|
|
4955fcd12a | ||
|
|
817e9663fa | ||
|
|
85ca850453 | ||
|
|
3baefb2b60 | ||
|
|
ffea5a0e02 | ||
|
|
be55695691 | ||
|
|
ea27c96362 | ||
|
|
7a73a01999 | ||
|
|
018dee6c38 | ||
|
|
c7cf2e6f16 | ||
|
|
9ab9a6e8b0 | ||
|
|
67ccff3e86 | ||
|
|
40c09ce26a | ||
|
|
3e0d4a0bed | ||
|
|
e8a6d38ac6 | ||
|
|
80159ecca8 | ||
|
|
c82bb730b2 | ||
|
|
26dad399d5 | ||
|
|
2689e6d6c0 | ||
|
|
90d1b68bd6 | ||
|
|
c7c4318c11 | ||
|
|
d6a2e4aee9 | ||
|
|
c6488b58f5 | ||
|
|
18bfcc24ad | ||
|
|
d8a134fe7e | ||
|
|
989f48c47a | ||
|
|
111a32b5e8 | ||
|
|
993ca754b5 | ||
|
|
381a37fbaa | ||
|
|
0ca61b4d99 | ||
|
|
16748a75d5 | ||
|
|
0e33dfa019 | ||
|
|
4a2f7ebf87 | ||
|
|
e9f18b79ea | ||
|
|
66629a591a | ||
|
|
8f22a358cf | ||
|
|
1f5f1596e5 | ||
|
|
fc9ac23725 | ||
|
|
0f426b9c19 | ||
|
|
a7d4710702 | ||
|
|
6946279f03 |
2
.npmrc
2
.npmrc
@@ -1,2 +1,2 @@
|
||||
link-workspace-packages=true
|
||||
link-workspace-packages=deep
|
||||
prefer-workspace-packages=true
|
||||
|
||||
49
CHANGELOG.md
49
CHANGELOG.md
@@ -3,6 +3,55 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package root
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复关键字查询bug ([fab6660](https://github.com/certd/certd/commit/fab66606b35a540fac31fee902331ba1ffdebc16))
|
||||
* 修复CNAME时子域名级数超出限制的问题 ([3af6d96](https://github.com/certd/certd/commit/3af6d96e6e353c9b2111cff81679b79c55195a0a))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 谷歌EAB绑定邮箱改成必填 ([81a8123](https://github.com/certd/certd/commit/81a8123725d7bf4bd6a32a64a066bd760b7b6a7f))
|
||||
* 华为云密钥获取提示及访问链接 ([de43391](https://github.com/certd/certd/commit/de43391e4c12dc3ad976f8fa8787f4eb70a41e75))
|
||||
* 通知管理 ([d9a00ee](https://github.com/certd/certd/commit/d9a00eeaf72735ced67c59d7983d84e3c730064a))
|
||||
* 通知渠道支持测试按钮 ([b54ae27](https://github.com/certd/certd/commit/b54ae272ebc2d31b32b049d44e2299a6be7f153c))
|
||||
* 优化插件开发,dnsProvider无需写http logger 变量 ([fcbb5e4](https://github.com/certd/certd/commit/fcbb5e46a112174150a62648319b8224fce3b7ed))
|
||||
* 支持部署到阿里云WAF ([c96fcb7](https://github.com/certd/certd/commit/c96fcb7afced979435cffa73591275008033c90d))
|
||||
* 支持企业微信群聊机器人通知 ([b805a29](https://github.com/certd/certd/commit/b805a2925984144a31575b8aaa622f0c30d41b56))
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* .env 读取 \r 问题 ([0e33dfa](https://github.com/certd/certd/commit/0e33dfa019a55ea76193c428ec756af386adeb9d))
|
||||
* 修复vip试用secret报错的bug ([018dee6](https://github.com/certd/certd/commit/018dee6c383233560f078dfd30f6c2857a7e15ee))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 当步骤全部都禁用时,任务本身显示删除线 ([9ab9a6e](https://github.com/certd/certd/commit/9ab9a6e8b083e19793894f23e59f29c604ec98e5))
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复1Panel面板本身证书更新导致判定执行失败的问题 ([2689e6d](https://github.com/certd/certd/commit/2689e6d6c03aba21da90d5d45232c6ba08696be1))
|
||||
* 修复角色无法删除的bug ([66629a5](https://github.com/certd/certd/commit/66629a591aecc2d8364ea415c7afc3f9d0406562))
|
||||
* 修复Cname情况下,无法使用DNS类型的bug ([26dad39](https://github.com/certd/certd/commit/26dad399d5768b3205da099ddc11809aef7d6224))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 日志查看自动滚动到底部 ([4a2f7eb](https://github.com/certd/certd/commit/4a2f7ebf87b7c027cebff7cb763f8f35f6d2aa36))
|
||||
* 系统设置中的代理设置优化为可全局生效,环境变量中的https_proxy设置将无效 ([381a37f](https://github.com/certd/certd/commit/381a37fbaa6b61c887eda743897ae00afb825bdf))
|
||||
* 新手导航在非编辑模式下不显示 ([18bfcc2](https://github.com/certd/certd/commit/18bfcc24ad0bde57bb04db8a4209861ec6b8ff1d))
|
||||
* 优化腾讯云 cloudflare 重复解析记录时的返回值 ([90d1b68](https://github.com/certd/certd/commit/90d1b68bd6cf232fbe085234efe07d29b7690044))
|
||||
* 支持namesilo ([80159ec](https://github.com/certd/certd/commit/80159ecca895103d0495f3217311199e66056572))
|
||||
* 专业版试用,无需绑定账号 ([c7c4318](https://github.com/certd/certd/commit/c7c4318c11b65a76089787aa58939832d338a232))
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -10,7 +10,7 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
|
||||
* 全自动申请证书(支持所有注册商注册的域名)
|
||||
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等,目前已支持30+部署插件)
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
|
||||
* 邮件通知
|
||||
* 私有化部署,数据保存本地,镜像由Github Actions构建,过程公开透明
|
||||
* 支持sqlite,postgresql数据库
|
||||
@@ -115,7 +115,7 @@ docker compose up -d
|
||||
* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
* 设置每天自动运行,当证书过期前20天,会自动重新申请证书并部署
|
||||
* 设置每天自动运行,当证书过期前35天,会自动重新申请证书并部署
|
||||
|
||||
|
||||
## 七、不同平台的设置说明
|
||||
|
||||
@@ -1 +1 @@
|
||||
1
|
||||
01:43
|
||||
|
||||
@@ -3,6 +3,61 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复关键字查询bug ([fab6660](https://github.com/certd/certd/commit/fab66606b35a540fac31fee902331ba1ffdebc16))
|
||||
* 修复CNAME时子域名级数超出限制的问题 ([3af6d96](https://github.com/certd/certd/commit/3af6d96e6e353c9b2111cff81679b79c55195a0a))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 谷歌EAB绑定邮箱改成必填 ([81a8123](https://github.com/certd/certd/commit/81a8123725d7bf4bd6a32a64a066bd760b7b6a7f))
|
||||
* 华为云密钥获取提示及访问链接 ([de43391](https://github.com/certd/certd/commit/de43391e4c12dc3ad976f8fa8787f4eb70a41e75))
|
||||
* 通知管理 ([d9a00ee](https://github.com/certd/certd/commit/d9a00eeaf72735ced67c59d7983d84e3c730064a))
|
||||
* 通知渠道支持测试按钮 ([b54ae27](https://github.com/certd/certd/commit/b54ae272ebc2d31b32b049d44e2299a6be7f153c))
|
||||
* 优化插件开发,dnsProvider无需写http logger 变量 ([fcbb5e4](https://github.com/certd/certd/commit/fcbb5e46a112174150a62648319b8224fce3b7ed))
|
||||
* 支持部署到阿里云WAF ([c96fcb7](https://github.com/certd/certd/commit/c96fcb7afced979435cffa73591275008033c90d))
|
||||
* 支持企业微信群聊机器人通知 ([b805a29](https://github.com/certd/certd/commit/b805a2925984144a31575b8aaa622f0c30d41b56))
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* .env 读取 \r 问题 ([0e33dfa](https://github.com/certd/certd/commit/0e33dfa019a55ea76193c428ec756af386adeb9d))
|
||||
* 修复vip试用secret报错的bug ([018dee6](https://github.com/certd/certd/commit/018dee6c383233560f078dfd30f6c2857a7e15ee))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 当步骤全部都禁用时,任务本身显示删除线 ([9ab9a6e](https://github.com/certd/certd/commit/9ab9a6e8b083e19793894f23e59f29c604ec98e5))
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复1Panel面板本身证书更新导致判定执行失败的问题 ([2689e6d](https://github.com/certd/certd/commit/2689e6d6c03aba21da90d5d45232c6ba08696be1))
|
||||
* 修复角色无法删除的bug ([66629a5](https://github.com/certd/certd/commit/66629a591aecc2d8364ea415c7afc3f9d0406562))
|
||||
* 修复Cname情况下,无法使用DNS类型的bug ([26dad39](https://github.com/certd/certd/commit/26dad399d5768b3205da099ddc11809aef7d6224))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 日志查看自动滚动到底部 ([4a2f7eb](https://github.com/certd/certd/commit/4a2f7ebf87b7c027cebff7cb763f8f35f6d2aa36))
|
||||
* 系统设置中的代理设置优化为可全局生效,环境变量中的https_proxy设置将无效 ([381a37f](https://github.com/certd/certd/commit/381a37fbaa6b61c887eda743897ae00afb825bdf))
|
||||
* 新手导航在非编辑模式下不显示 ([18bfcc2](https://github.com/certd/certd/commit/18bfcc24ad0bde57bb04db8a4209861ec6b8ff1d))
|
||||
* 优化腾讯云 cloudflare 重复解析记录时的返回值 ([90d1b68](https://github.com/certd/certd/commit/90d1b68bd6cf232fbe085234efe07d29b7690044))
|
||||
* 支持namesilo ([80159ec](https://github.com/certd/certd/commit/80159ecca895103d0495f3217311199e66056572))
|
||||
* 专业版试用,无需绑定账号 ([c7c4318](https://github.com/certd/certd/commit/c7c4318c11b65a76089787aa58939832d338a232))
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复未设置pfx密码,导致jks转换报错的bug ([c3cfbd8](https://github.com/certd/certd/commit/c3cfbd8474155aed4379f91075de37d5d8c73ef0))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 公共cname服务支持关闭 ([f4ae512](https://github.com/certd/certd/commit/f4ae5125dc4cd97816976779cb3586b5ee78947e))
|
||||
|
||||
## [1.27.3](https://github.com/certd/certd/compare/v1.27.2...v1.27.3) (2024-11-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
建议nodejs版本 `20.x` 及以上
|
||||
|
||||
## 1.本地调试运行
|
||||
## 一、本地调试运行
|
||||
|
||||
### 克隆代码
|
||||
```shell
|
||||
@@ -57,7 +57,7 @@ npm run dev
|
||||
|
||||
```
|
||||
|
||||
## 开发插件
|
||||
## 二、开发插件
|
||||
进入 `packages/ui/certd-server/src/plugins`
|
||||
|
||||
### 1.复制`plugin-demo`目录作为你的插件目录
|
||||
@@ -91,8 +91,22 @@ export * from './plugins/plugin-deploy-to-xx'
|
||||
export * from "./plugin-cloudflare.js"
|
||||
```
|
||||
|
||||
## 重启服务进行调试
|
||||
### 6. 重启服务进行调试
|
||||
刷新浏览器,检查你的插件是否工作正常, 确保能够正常进行证书申请和部署
|
||||
|
||||
## 提交PR
|
||||
## 三、提交PR
|
||||
我们将尽快审核PR
|
||||
|
||||
## 四、 注意事项
|
||||
### 1. 如何让任务报错停止
|
||||
|
||||
```js
|
||||
// 抛出异常即可使任务停止,否则会判定为成功
|
||||
throw new Error("错误信息")
|
||||
```
|
||||
|
||||
|
||||
## 五、贡献插件送激活码
|
||||
|
||||
- PR要求,插件功能完整,代码规范
|
||||
- PR通过后,联系我们,送您一个专业版激活码
|
||||
@@ -26,7 +26,7 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
||||
* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
* 设置每天自动运行,当证书过期前20天,会自动重新申请证书并部署
|
||||
* 设置每天自动运行,当证书过期前35天,会自动重新申请证书并部署
|
||||
|
||||
## 三、证书颁发机构对比
|
||||
* Let's Encrypt:申请最简单。
|
||||
|
||||
@@ -48,4 +48,4 @@ admin/123456
|
||||
|
||||
## 五、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
将备份的`db.sqlite`覆盖到原来的位置,重启certd即可
|
||||
|
||||
@@ -81,4 +81,4 @@ services:
|
||||
|
||||
## 五、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
将备份的`db.sqlite`覆盖到原来的位置,重启certd即可
|
||||
|
||||
@@ -71,4 +71,4 @@ docker compose up -d
|
||||
|
||||
## 四、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
将备份的`db.sqlite`覆盖到原来的位置,重启certd即可
|
||||
@@ -42,4 +42,4 @@ kill -9 $(lsof -t -i:7001)
|
||||
|
||||
## 四、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
将备份的`db.sqlite`覆盖到原来的位置,重启certd即可
|
||||
|
||||
@@ -8,4 +8,14 @@
|
||||
ALIYUN_CLIENT_CONNECT_TIMEOUT=10000 # 连接超时,单位毫秒
|
||||
ALIYUN_CLIENT_READ_TIMEOUT=10000 #读取数据超时,单位毫秒
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
|
||||
## 阿里云Access权限设置
|
||||
|
||||
|
||||
* 申请证书 :`AliyunDNSFullAccess`
|
||||
* 上传证书到阿里云: `AliyunYundunCertFullAccess`
|
||||
* 部署证书到OSS: `AliyunYundunCertFullAccess`、`AliyunOSSFullAccess`
|
||||
* 部署证书到CDN: `AliyunYundunCertFullAccess`、`AliyunCDNFullAccess`
|
||||
* 部署证书到DCDN: `AliyunYundunCertFullAccess`、`AliyunDCDNFullAccess`
|
||||
@@ -27,4 +27,4 @@
|
||||
|
||||
## 三、备份恢复
|
||||
|
||||
将备份的`db.sqlite`覆盖到原来的位置即可
|
||||
将备份的`db.sqlite`覆盖到原来的位置,重启certd即可
|
||||
@@ -18,6 +18,10 @@ const res = await ctx.http.request({
|
||||
key : certKey
|
||||
}
|
||||
})
|
||||
if(!res || res.code !== 0){
|
||||
//抛异常才能让任务失败
|
||||
throw new Error("上传失败")
|
||||
}
|
||||
//不能用console.log,需要用ctx.logger 才能把日志打印在ui上
|
||||
ctx.logger.info("上传成功",res.data)
|
||||
|
||||
@@ -79,3 +83,4 @@ type CustomScriptPlugin = {
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.27.4"
|
||||
"version": "1.27.8"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/publishlab/node-acme-client/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.27.7](https://github.com/publishlab/node-acme-client/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.27.6](https://github.com/publishlab/node-acme-client/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.27.5](https://github.com/publishlab/node-acme-client/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.27.4](https://github.com/publishlab/node-acme-client/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.27.4",
|
||||
"@certd/basic": "^1.27.8",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
@@ -65,5 +65,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
link-workspace-packages=true
|
||||
link-workspace-packages=deep
|
||||
prefer-workspace-packages=true
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 系统设置中的代理设置优化为可全局生效,环境变量中的https_proxy设置将无效 ([381a37f](https://github.com/certd/certd/commit/381a37fbaa6b61c887eda743897ae00afb825bdf))
|
||||
* 新手导航在非编辑模式下不显示 ([18bfcc2](https://github.com/certd/certd/commit/18bfcc24ad0bde57bb04db8a4209861ec6b8ff1d))
|
||||
* 优化腾讯云 cloudflare 重复解析记录时的返回值 ([90d1b68](https://github.com/certd/certd/commit/90d1b68bd6cf232fbe085234efe07d29b7690044))
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
21:51
|
||||
02:04
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -43,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -178,7 +178,10 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
);
|
||||
logger.error('返回数据:', JSON.stringify(error.response?.data));
|
||||
if (error.response?.data) {
|
||||
error.message = error.response.data.message || error.response.data.msg || error.response.data.error || error.response.data;
|
||||
const message = error.response.data.message || error.response.data.msg || error.response.data.error;
|
||||
if (typeof message === 'string') {
|
||||
error.message = message;
|
||||
}
|
||||
}
|
||||
if (error instanceof AggregateError) {
|
||||
logger.error('AggregateError', error);
|
||||
@@ -202,6 +205,9 @@ export type HttpClient = {
|
||||
request<D = any, R = any>(config: HttpRequestConfig<D>): Promise<HttpClientResponse<R>>;
|
||||
};
|
||||
|
||||
// const http_proxy_backup = process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
// const https_proxy_backup = process.env.HTTPS_PROXY || process.env.https_proxy;
|
||||
|
||||
export type CreateAgentOptions = {
|
||||
httpProxy?: string;
|
||||
httpsProxy?: string;
|
||||
@@ -216,20 +222,28 @@ export function createAgent(opts: CreateAgentOptions = {}) {
|
||||
);
|
||||
|
||||
let httpAgent, httpsAgent;
|
||||
const httpProxy = opts.httpProxy || process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
const httpProxy = opts.httpProxy;
|
||||
if (httpProxy) {
|
||||
process.env.HTTP_PROXY = httpProxy;
|
||||
process.env.http_proxy = httpProxy;
|
||||
logger.info('use httpProxy:', httpProxy);
|
||||
httpAgent = new HttpProxyAgent(httpProxy, opts as any);
|
||||
merge(httpAgent.options, opts);
|
||||
} else {
|
||||
process.env.HTTP_PROXY = '';
|
||||
process.env.http_proxy = '';
|
||||
httpAgent = new nodeHttp.Agent(opts);
|
||||
}
|
||||
const httpsProxy = opts.httpsProxy || process.env.HTTPS_PROXY || process.env.https_proxy;
|
||||
const httpsProxy = opts.httpsProxy;
|
||||
if (httpsProxy) {
|
||||
process.env.HTTPS_PROXY = httpProxy;
|
||||
process.env.https_proxy = httpProxy;
|
||||
logger.info('use httpsProxy:', httpsProxy);
|
||||
httpsAgent = new HttpsProxyAgent(httpsProxy, opts as any);
|
||||
merge(httpsAgent.options, opts);
|
||||
} else {
|
||||
process.env.HTTPS_PROXY = '';
|
||||
process.env.https_proxy = '';
|
||||
httpsAgent = new https.Agent(opts);
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
link-workspace-packages=true
|
||||
link-workspace-packages=deep
|
||||
prefer-workspace-packages=true
|
||||
|
||||
@@ -3,6 +3,29 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 通知管理 ([d9a00ee](https://github.com/certd/certd/commit/d9a00eeaf72735ced67c59d7983d84e3c730064a))
|
||||
* 通知渠道支持测试按钮 ([b54ae27](https://github.com/certd/certd/commit/b54ae272ebc2d31b32b049d44e2299a6be7f153c))
|
||||
* 优化插件开发,dnsProvider无需写http logger 变量 ([fcbb5e4](https://github.com/certd/certd/commit/fcbb5e46a112174150a62648319b8224fce3b7ed))
|
||||
* 支持企业微信群聊机器人通知 ([b805a29](https://github.com/certd/certd/commit/b805a2925984144a31575b8aaa622f0c30d41b56))
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 新手导航在非编辑模式下不显示 ([18bfcc2](https://github.com/certd/certd/commit/18bfcc24ad0bde57bb04db8a4209861ec6b8ff1d))
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -16,8 +16,8 @@
|
||||
"test": "mocha --loader=ts-node/esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.27.4",
|
||||
"@certd/plus-core": "^1.27.4",
|
||||
"@certd/basic": "^1.27.8",
|
||||
"@certd/plus-core": "^1.27.8",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
@@ -43,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,15 @@ import { Registrable } from "../registry/index.js";
|
||||
import { FormItemProps } from "../dt/index.js";
|
||||
import { HttpClient, ILogger, utils } from "@certd/basic";
|
||||
import * as _ from "lodash-es";
|
||||
import { AccessRequestHandleReq } from "../core";
|
||||
import { PluginRequestHandleReq } from "../plugin/index.js";
|
||||
|
||||
export type AccessRequestHandleReqInput<T = any> = {
|
||||
id?: number;
|
||||
title?: string;
|
||||
access: T;
|
||||
};
|
||||
|
||||
export type AccessRequestHandleReq<T = any> = PluginRequestHandleReq<AccessRequestHandleReqInput<T>>;
|
||||
|
||||
export type AccessInputDefine = FormItemProps & {
|
||||
title: string;
|
||||
@@ -33,6 +41,10 @@ export type AccessContext = {
|
||||
export abstract class BaseAccess implements IAccess {
|
||||
ctx!: AccessContext;
|
||||
|
||||
setCtx(ctx: AccessContext) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
async onRequest(req: AccessRequestHandleReq) {
|
||||
if (!req.action) {
|
||||
throw new Error("action is required");
|
||||
|
||||
@@ -56,6 +56,6 @@ export function newAccess(type: string, input: any, ctx?: AccessContext) {
|
||||
utils,
|
||||
};
|
||||
}
|
||||
access.ctx = ctx;
|
||||
access.setCtx(ctx);
|
||||
return access;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Registry } from "../registry/index.js";
|
||||
import { createRegistry } from "../registry/index.js";
|
||||
|
||||
// @ts-ignore
|
||||
export const accessRegistry = new Registry("access");
|
||||
export const accessRegistry = createRegistry("access");
|
||||
|
||||
@@ -7,9 +7,10 @@ import { createAxiosService, hashUtils, HttpRequestConfig, ILogger, logger, util
|
||||
import { IAccessService } from "../access/index.js";
|
||||
import { RegistryItem } from "../registry/index.js";
|
||||
import { Decorator } from "../decorator/index.js";
|
||||
import { ICnameProxyService, IEmailService, IPluginConfigService } from "../service/index.js";
|
||||
import { ICnameProxyService, IEmailService, IPluginConfigService, IUrlService } from "../service/index.js";
|
||||
import { FileStore } from "./file-store.js";
|
||||
import { cloneDeep, forEach, merge } from "lodash-es";
|
||||
import { INotificationService, NotificationBody, NotificationContext, notificationRegistry } from "../notification/index.js";
|
||||
|
||||
export type ExecutorOptions = {
|
||||
pipeline: Pipeline;
|
||||
@@ -17,10 +18,13 @@ export type ExecutorOptions = {
|
||||
onChanged: (history: RunHistory) => Promise<void>;
|
||||
accessService: IAccessService;
|
||||
emailService: IEmailService;
|
||||
notificationService: INotificationService;
|
||||
cnameProxyService: ICnameProxyService;
|
||||
pluginConfigService: IPluginConfigService;
|
||||
urlService: IUrlService;
|
||||
fileRootDir?: string;
|
||||
user: UserInfo;
|
||||
baseURL?: string;
|
||||
};
|
||||
|
||||
export class Executor {
|
||||
@@ -357,20 +361,22 @@ export class Executor {
|
||||
if (!this.pipeline.notifications) {
|
||||
return;
|
||||
}
|
||||
const url = await this.options.urlService.getPipelineDetailUrl(this.pipeline.id, this.runtime.id);
|
||||
let subject = "";
|
||||
let content = "";
|
||||
const errorMessage = error?.message;
|
||||
if (when === "start") {
|
||||
subject = `【CertD】开始执行,【${this.pipeline.id}】${this.pipeline.title}`;
|
||||
content = `buildId:${this.runtime.id}`;
|
||||
subject = `【Certd】开始执行,【${this.pipeline.id}】${this.pipeline.title}`;
|
||||
content = `buildId:${this.runtime.id}\n查看详情:${url}`;
|
||||
} else if (when === "success") {
|
||||
subject = `【CertD】执行成功,【${this.pipeline.id}】${this.pipeline.title}`;
|
||||
content = `buildId:${this.runtime.id}`;
|
||||
subject = `【Certd】执行成功,【${this.pipeline.id}】${this.pipeline.title}`;
|
||||
content = `buildId:${this.runtime.id}\n查看详情:${url}`;
|
||||
} else if (when === "turnToSuccess") {
|
||||
subject = `【CertD】执行成功(错误转成功),【${this.pipeline.id}】${this.pipeline.title}`;
|
||||
content = `buildId:${this.runtime.id}`;
|
||||
subject = `【Certd】执行成功(失败转成功),【${this.pipeline.id}】${this.pipeline.title}`;
|
||||
content = `buildId:${this.runtime.id}\n查看详情:${url}`;
|
||||
} else if (when === "error") {
|
||||
subject = `【CertD】执行失败,【${this.pipeline.id}】${this.pipeline.title}`;
|
||||
content = `buildId:${this.runtime.id}\nerror:${error.message}`;
|
||||
subject = `【Certd】执行失败,【${this.pipeline.id}】${this.pipeline.title}`;
|
||||
content = `buildId:${this.runtime.id}\n查看详情:${url}\nerror:${error.message}`;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -390,6 +396,39 @@ export class Executor {
|
||||
} catch (e) {
|
||||
logger.error("send email error", e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
//构建notification插件,发送通知
|
||||
const notifyConfig = await this.options.notificationService.getById(notification.notificationId);
|
||||
const notificationPlugin = notificationRegistry.get(notifyConfig.type);
|
||||
const notificationCls: any = notificationPlugin.target;
|
||||
const notificationSender = new notificationCls();
|
||||
const notificationCtx: NotificationContext = {
|
||||
http: utils.http,
|
||||
logger,
|
||||
utils,
|
||||
emailService: this.options.emailService,
|
||||
};
|
||||
//设置参数
|
||||
merge(notificationSender, notifyConfig.setting);
|
||||
notificationSender.setCtx(notificationCtx);
|
||||
await notificationSender.onInstance();
|
||||
const body: NotificationBody = {
|
||||
title: subject,
|
||||
content,
|
||||
userId: this.pipeline.userId,
|
||||
pipeline: this.pipeline,
|
||||
result: this.lastRuntime.pipeline.status,
|
||||
pipelineId: this.pipeline.id,
|
||||
historyId: this.runtime.id,
|
||||
errorMessage,
|
||||
url,
|
||||
};
|
||||
//发送通知
|
||||
await notificationSender.send(body);
|
||||
} catch (e) {
|
||||
logger.error("send notification error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { HttpClient, ILogger, utils } from "@certd/basic";
|
||||
|
||||
export type PluginRequestHandleReq<T = any> = {
|
||||
typeName: string;
|
||||
action: string;
|
||||
input: T;
|
||||
data: any;
|
||||
};
|
||||
|
||||
export type AccessRequestHandleReqInput<T = any> = {
|
||||
id?: number;
|
||||
title?: string;
|
||||
access: T;
|
||||
};
|
||||
export type AccessRequestHandleContext = {
|
||||
http: HttpClient;
|
||||
logger: ILogger;
|
||||
utils: typeof utils;
|
||||
};
|
||||
|
||||
export type AccessRequestHandleReq<T = any> = PluginRequestHandleReq<AccessRequestHandleReqInput<T>>;
|
||||
@@ -3,5 +3,4 @@ export * from "./run-history.js";
|
||||
export * from "./context.js";
|
||||
export * from "./storage.js";
|
||||
export * from "./file-store.js";
|
||||
export * from "./handler.js";
|
||||
export * from "./exceptions.js";
|
||||
|
||||
@@ -18,7 +18,7 @@ export function NewRunHistory(obj: any) {
|
||||
return history;
|
||||
}
|
||||
export class RunHistory {
|
||||
id!: string;
|
||||
id!: any;
|
||||
pipeline!: Pipeline;
|
||||
logs: {
|
||||
[runnableId: string]: string[];
|
||||
|
||||
@@ -62,7 +62,7 @@ export type FileItem = {
|
||||
path: string;
|
||||
};
|
||||
export type Runnable = {
|
||||
id: string;
|
||||
id: any;
|
||||
title: string;
|
||||
strategy?: RunnableStrategy;
|
||||
runnableType?: string; // pipeline, stage, task , step
|
||||
@@ -83,6 +83,9 @@ export type Notification = {
|
||||
type: NotificationType;
|
||||
when: NotificationWhen[];
|
||||
options: EmailOptions;
|
||||
notificationId: number;
|
||||
title: string;
|
||||
subType: string;
|
||||
};
|
||||
|
||||
export type Pipeline = Runnable & {
|
||||
|
||||
@@ -6,3 +6,4 @@ export * from "./plugin/index.js";
|
||||
export * from "./context/index.js";
|
||||
export * from "./decorator/index.js";
|
||||
export * from "./service/index.js";
|
||||
export * from "./notification/index.js";
|
||||
|
||||
111
packages/core/pipeline/src/notification/api.ts
Normal file
111
packages/core/pipeline/src/notification/api.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { PluginRequestHandleReq } from "../plugin";
|
||||
import { Registrable } from "../registry/index.js";
|
||||
import { FormItemProps, HistoryResult, Pipeline } from "../dt/index.js";
|
||||
import { HttpClient, ILogger, utils } from "@certd/basic";
|
||||
import * as _ from "lodash-es";
|
||||
import { IEmailService } from "../service/index.js";
|
||||
|
||||
export type NotificationBody = {
|
||||
userId: number;
|
||||
title: string;
|
||||
content: string;
|
||||
pipeline: Pipeline;
|
||||
pipelineId: number;
|
||||
result?: HistoryResult;
|
||||
historyId: number;
|
||||
errorMessage?: string;
|
||||
url?: string;
|
||||
};
|
||||
|
||||
export type NotificationRequestHandleReqInput<T = any> = {
|
||||
id?: number;
|
||||
title?: string;
|
||||
access: T;
|
||||
};
|
||||
|
||||
export type NotificationRequestHandleReq<T = any> = PluginRequestHandleReq<NotificationRequestHandleReqInput<T>>;
|
||||
|
||||
export type NotificationInputDefine = FormItemProps & {
|
||||
title: string;
|
||||
required?: boolean;
|
||||
encrypt?: boolean;
|
||||
};
|
||||
export type NotificationDefine = Registrable & {
|
||||
input?: {
|
||||
[key: string]: NotificationInputDefine;
|
||||
};
|
||||
};
|
||||
|
||||
export type NotificationInstanceConfig = {
|
||||
id: number;
|
||||
type: string;
|
||||
userId: number;
|
||||
setting: {
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
|
||||
export interface INotificationService {
|
||||
getById(id: number): Promise<NotificationInstanceConfig>;
|
||||
}
|
||||
|
||||
export interface INotification {
|
||||
ctx: NotificationContext;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type NotificationContext = {
|
||||
http: HttpClient;
|
||||
logger: ILogger;
|
||||
utils: typeof utils;
|
||||
emailService: IEmailService;
|
||||
};
|
||||
|
||||
export abstract class BaseNotification implements INotification {
|
||||
ctx!: NotificationContext;
|
||||
http!: HttpClient;
|
||||
logger!: ILogger;
|
||||
abstract send(body: NotificationBody): Promise<void>;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
async onInstance() {}
|
||||
setCtx(ctx: NotificationContext) {
|
||||
this.ctx = ctx;
|
||||
this.http = ctx.http;
|
||||
this.logger = ctx.logger;
|
||||
}
|
||||
|
||||
async onRequest(req: NotificationRequestHandleReq) {
|
||||
if (!req.action) {
|
||||
throw new Error("action is required");
|
||||
}
|
||||
|
||||
let methodName = req.action;
|
||||
if (!req.action.startsWith("on")) {
|
||||
methodName = `on${_.upperFirst(req.action)}`;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const method = this[methodName];
|
||||
if (method) {
|
||||
// @ts-ignore
|
||||
return await this[methodName](req.data);
|
||||
}
|
||||
throw new Error(`action ${req.action} not found`);
|
||||
}
|
||||
|
||||
async onTestRequest() {
|
||||
await this.send({
|
||||
userId: 0,
|
||||
title: "测试通知",
|
||||
content: "测试通知",
|
||||
pipeline: {
|
||||
id: 1,
|
||||
title: "测试流水线",
|
||||
} as any,
|
||||
pipelineId: 1,
|
||||
historyId: 1,
|
||||
url: "http://www.baidu.com",
|
||||
});
|
||||
}
|
||||
}
|
||||
56
packages/core/pipeline/src/notification/decorator.ts
Normal file
56
packages/core/pipeline/src/notification/decorator.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
// src/decorator/memoryCache.decorator.ts
|
||||
import { Decorator } from "../decorator/index.js";
|
||||
import * as _ from "lodash-es";
|
||||
import { notificationRegistry } from "./registry.js";
|
||||
import { NotificationContext, NotificationDefine, NotificationInputDefine } from "./api.js";
|
||||
|
||||
// 提供一个唯一 key
|
||||
export const NOTIFICATION_CLASS_KEY = "pipeline:notification";
|
||||
export const NOTIFICATION_INPUT_KEY = "pipeline:notification:input";
|
||||
|
||||
export function IsNotification(define: NotificationDefine): ClassDecorator {
|
||||
return (target: any) => {
|
||||
target = Decorator.target(target);
|
||||
|
||||
const inputs: any = {};
|
||||
const properties = Decorator.getClassProperties(target);
|
||||
for (const property in properties) {
|
||||
const input = Reflect.getMetadata(NOTIFICATION_INPUT_KEY, target, property);
|
||||
if (input) {
|
||||
inputs[property] = input;
|
||||
}
|
||||
}
|
||||
_.merge(define, { input: inputs });
|
||||
Reflect.defineMetadata(NOTIFICATION_CLASS_KEY, define, target);
|
||||
target.define = define;
|
||||
notificationRegistry.register(define.name, {
|
||||
define,
|
||||
target,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function NotificationInput(input?: NotificationInputDefine): PropertyDecorator {
|
||||
return (target, propertyKey) => {
|
||||
target = Decorator.target(target, propertyKey);
|
||||
// const _type = Reflect.getMetadata("design:type", target, propertyKey);
|
||||
Reflect.defineMetadata(NOTIFICATION_INPUT_KEY, input, target, propertyKey);
|
||||
};
|
||||
}
|
||||
|
||||
export function newNotification(type: string, input: any, ctx: NotificationContext) {
|
||||
const register = notificationRegistry.get(type);
|
||||
if (register == null) {
|
||||
throw new Error(`notification ${type} not found`);
|
||||
}
|
||||
// @ts-ignore
|
||||
const plugin = new register.target();
|
||||
for (const key in input) {
|
||||
plugin[key] = input[key];
|
||||
}
|
||||
if (!ctx) {
|
||||
throw new Error("ctx is required");
|
||||
}
|
||||
plugin.setCtx(ctx);
|
||||
return plugin;
|
||||
}
|
||||
3
packages/core/pipeline/src/notification/index.ts
Normal file
3
packages/core/pipeline/src/notification/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./api.js";
|
||||
export * from "./registry.js";
|
||||
export * from "./decorator.js";
|
||||
4
packages/core/pipeline/src/notification/registry.ts
Normal file
4
packages/core/pipeline/src/notification/registry.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { createRegistry } from "../registry/index.js";
|
||||
|
||||
// @ts-ignore
|
||||
export const notificationRegistry = createRegistry("notification");
|
||||
@@ -3,12 +3,20 @@ import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../dt/index.j
|
||||
import { FileStore } from "../core/file-store.js";
|
||||
import { IAccessService } from "../access/index.js";
|
||||
import { ICnameProxyService, IEmailService } from "../service/index.js";
|
||||
import { CancelError, IContext, PluginRequestHandleReq, RunnableCollection } from "../core/index.js";
|
||||
import { CancelError, IContext, RunnableCollection } from "../core/index.js";
|
||||
import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
import { IPluginConfigService } from "../service/config";
|
||||
import { upperFirst } from "lodash-es";
|
||||
|
||||
export type PluginRequestHandleReq<T = any> = {
|
||||
typeName: string;
|
||||
action: string;
|
||||
input: T;
|
||||
data: any;
|
||||
};
|
||||
|
||||
export type UserInfo = {
|
||||
role: "admin" | "user";
|
||||
id: any;
|
||||
@@ -102,6 +110,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
_result: TaskResult = { clearLastStatus: false, files: [], pipelineVars: {}, pipelinePrivateVars: {} };
|
||||
ctx!: TaskInstanceContext;
|
||||
logger!: ILogger;
|
||||
http!: HttpClient;
|
||||
accessService!: IAccessService;
|
||||
|
||||
clearLastStatus() {
|
||||
@@ -122,6 +131,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
this.ctx = ctx;
|
||||
this.logger = ctx.logger;
|
||||
this.accessService = ctx.accessService;
|
||||
this.http = ctx.http;
|
||||
}
|
||||
|
||||
async getAccess<T = any>(accessId: string) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OnRegisterContext, Registry } from "../registry/index.js";
|
||||
import { createRegistry, OnRegisterContext } from "../registry/index.js";
|
||||
import { AbstractTaskPlugin } from "./api.js";
|
||||
import { pluginGroups } from "./group.js";
|
||||
|
||||
@@ -13,4 +13,4 @@ const onRegister = ({ key, value }: OnRegisterContext<AbstractTaskPlugin>) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
export const pluginRegistry = new Registry<AbstractTaskPlugin>("plugin", onRegister);
|
||||
export const pluginRegistry = createRegistry<AbstractTaskPlugin>("plugin", onRegister);
|
||||
|
||||
@@ -19,7 +19,7 @@ export type OnRegisterContext<T> = {
|
||||
value: RegistryItem<T>;
|
||||
};
|
||||
export type OnRegister<T> = (ctx: OnRegisterContext<T>) => void;
|
||||
export class Registry<T> {
|
||||
export class Registry<T = any> {
|
||||
type = "";
|
||||
storage: {
|
||||
[key: string]: RegistryItem<T>;
|
||||
@@ -88,3 +88,21 @@ export class Registry<T> {
|
||||
return item.define;
|
||||
}
|
||||
}
|
||||
|
||||
export function createRegistry<T>(type: string, onRegister?: OnRegister<T>): Registry<T> {
|
||||
const pipelineregistrycacheKey = "PIPELINE_REGISTRY_CACHE";
|
||||
// @ts-ignore
|
||||
let cached: any = global[pipelineregistrycacheKey];
|
||||
if (!cached) {
|
||||
cached = {};
|
||||
// @ts-ignore
|
||||
global[pipelineregistrycacheKey] = cached;
|
||||
}
|
||||
|
||||
if (cached[type]) {
|
||||
return cached[type];
|
||||
}
|
||||
const newRegistry = new Registry<T>(type, onRegister);
|
||||
cached[type] = newRegistry;
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./email.js";
|
||||
export * from "./cname.js";
|
||||
export * from "./config.js";
|
||||
export * from "./url.js";
|
||||
|
||||
3
packages/core/pipeline/src/service/url.ts
Normal file
3
packages/core/pipeline/src/service/url.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface IUrlService {
|
||||
getPipelineDetailUrl(pipelineId: number, historyId: number): Promise<string>;
|
||||
}
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -21,5 +21,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -30,5 +30,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -16,7 +16,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.27.4",
|
||||
"@certd/basic": "^1.27.8",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复vip试用secret报错的bug ([018dee6](https://github.com/certd/certd/commit/018dee6c383233560f078dfd30f6c2857a7e15ee))
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 专业版试用,无需绑定账号 ([c7c4318](https://github.com/certd/certd/commit/c7c4318c11b65a76089787aa58939832d338a232))
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -27,10 +27,10 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.27.4",
|
||||
"@certd/basic": "^1.27.4",
|
||||
"@certd/pipeline": "^1.27.4",
|
||||
"@certd/plus-core": "^1.27.4",
|
||||
"@certd/acme-client": "^1.27.8",
|
||||
"@certd/basic": "^1.27.8",
|
||||
"@certd/pipeline": "^1.27.8",
|
||||
"@certd/plus-core": "^1.27.8",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.17.1",
|
||||
"@midwayjs/i18n": "~3.17.3",
|
||||
@@ -61,5 +61,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -55,7 +55,9 @@ export class PlusService {
|
||||
|
||||
async bindUrl(url: string) {
|
||||
const plusRequestService = await this.getPlusRequestService();
|
||||
return await plusRequestService.bindUrl(url);
|
||||
const res = await plusRequestService.bindUrl(url);
|
||||
this.plusRequestService = null;
|
||||
return res;
|
||||
}
|
||||
|
||||
async register() {
|
||||
@@ -64,6 +66,7 @@ export class PlusService {
|
||||
if (!licenseInfo.license) {
|
||||
await plusRequestService.register();
|
||||
logger.info('站点注册成功');
|
||||
this.plusRequestService = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +111,23 @@ export class PlusService {
|
||||
return res.accessToken;
|
||||
}
|
||||
|
||||
async getVipTrial() {
|
||||
await this.register();
|
||||
const plusRequestService = await this.getPlusRequestService();
|
||||
const res = await plusRequestService.request({
|
||||
url: '/activation/subject/vip/trialGet',
|
||||
method: 'POST',
|
||||
});
|
||||
if (res.license) {
|
||||
await this.updateLicense(res.license);
|
||||
return {
|
||||
duration: res.duration,
|
||||
};
|
||||
} else {
|
||||
throw new Error('您已经领取过VIP试用了');
|
||||
}
|
||||
}
|
||||
|
||||
async requestWithToken(config: HttpRequestConfig) {
|
||||
const plusRequestService = await this.getPlusRequestService();
|
||||
const token = await this.getAccessToken();
|
||||
|
||||
@@ -18,6 +18,8 @@ export class SysPublicSettings extends BaseSettings {
|
||||
limitUserPipelineCount = 0;
|
||||
managerOtherUserPipeline = false;
|
||||
icpNo?: string;
|
||||
defaultCron?: string;
|
||||
defaultNotification?: number;
|
||||
// triggerOnStartup = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
link-workspace-packages=true
|
||||
link-workspace-packages=deep
|
||||
prefer-workspace-packages=true
|
||||
|
||||
@@ -3,6 +3,34 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 谷歌EAB绑定邮箱改成必填 ([81a8123](https://github.com/certd/certd/commit/81a8123725d7bf4bd6a32a64a066bd760b7b6a7f))
|
||||
* 优化插件开发,dnsProvider无需写http logger 变量 ([fcbb5e4](https://github.com/certd/certd/commit/fcbb5e46a112174150a62648319b8224fce3b7ed))
|
||||
* 支持企业微信群聊机器人通知 ([b805a29](https://github.com/certd/certd/commit/b805a2925984144a31575b8aaa622f0c30d41b56))
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复1Panel面板本身证书更新导致判定执行失败的问题 ([2689e6d](https://github.com/certd/certd/commit/2689e6d6c03aba21da90d5d45232c6ba08696be1))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 新手导航在非编辑模式下不显示 ([18bfcc2](https://github.com/certd/certd/commit/18bfcc24ad0bde57bb04db8a4209861ec6b8ff1d))
|
||||
* 支持namesilo ([80159ec](https://github.com/certd/certd/commit/80159ecca895103d0495f3217311199e66056572))
|
||||
* 专业版试用,无需绑定账号 ([c7c4318](https://github.com/certd/certd/commit/c7c4318c11b65a76089787aa58939832d338a232))
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -15,9 +15,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.27.4",
|
||||
"@certd/basic": "^1.27.4",
|
||||
"@certd/pipeline": "^1.27.4",
|
||||
"@certd/acme-client": "^1.27.8",
|
||||
"@certd/basic": "^1.27.8",
|
||||
"@certd/pipeline": "^1.27.8",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -40,5 +40,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1eb70d4cfd1ed2f746369658db2559fe01718324"
|
||||
"gitHead": "3198d07553493ebb17e8239166f370ee316ebd0a"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export class EabAccess extends BaseAccess {
|
||||
},
|
||||
rules: { type: "email", message: "请输入正确的邮箱" },
|
||||
helper: "Google的EAB申请证书,更换邮箱会导致EAB失效,可以在此处绑定一个邮箱避免此问题",
|
||||
required: false,
|
||||
required: true,
|
||||
})
|
||||
email = "";
|
||||
}
|
||||
|
||||
@@ -2,12 +2,17 @@ import { CreateRecordOptions, DnsProviderContext, DnsProviderDefine, IDnsProvide
|
||||
import psl from "psl";
|
||||
import { dnsProviderRegistry } from "./registry.js";
|
||||
import { Decorator } from "@certd/pipeline";
|
||||
import { HttpClient, ILogger } from "@certd/basic";
|
||||
|
||||
export abstract class AbstractDnsProvider<T = any> implements IDnsProvider<T> {
|
||||
ctx!: DnsProviderContext;
|
||||
http!: HttpClient;
|
||||
logger!: ILogger;
|
||||
|
||||
setCtx(ctx: DnsProviderContext) {
|
||||
this.ctx = ctx;
|
||||
this.logger = ctx.logger;
|
||||
this.http = ctx.http;
|
||||
}
|
||||
|
||||
abstract createRecord(options: CreateRecordOptions): Promise<T>;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { Registry } from "@certd/pipeline";
|
||||
import { createRegistry } from "@certd/pipeline";
|
||||
|
||||
export const dnsProviderRegistry = new Registry("dnsProvider");
|
||||
export const dnsProviderRegistry = createRegistry("dnsProvider");
|
||||
|
||||
@@ -6,7 +6,6 @@ import JSZip from "jszip";
|
||||
import { CertConverter } from "./convert.js";
|
||||
import fs from "fs";
|
||||
import { pick } from "lodash-es";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
|
||||
export { CertReader };
|
||||
export type { CertInfo };
|
||||
@@ -73,7 +72,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
})
|
||||
renewDays!: number;
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: "成功后邮件通知",
|
||||
value: true,
|
||||
@@ -93,7 +91,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
csrInfo!: string;
|
||||
|
||||
userContext!: IContext;
|
||||
http!: HttpClient;
|
||||
lastStatus!: Step;
|
||||
|
||||
@TaskOutput({
|
||||
@@ -103,7 +100,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
|
||||
async onInstance() {
|
||||
this.userContext = this.ctx.userContext;
|
||||
this.http = this.ctx.http;
|
||||
this.lastStatus = this.ctx.lastStatus as Step;
|
||||
await this.onInit();
|
||||
}
|
||||
@@ -141,7 +137,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
}
|
||||
this._result.pipelinePrivateVars.cert = cert;
|
||||
|
||||
if (cert.pfx == null || cert.der == null || cert.jks == null) {
|
||||
if (isNew) {
|
||||
try {
|
||||
const converter = new CertConverter({ logger: this.logger });
|
||||
const res = await converter.convert({
|
||||
@@ -152,21 +148,18 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
const pfxBuffer = fs.readFileSync(res.pfxPath);
|
||||
cert.pfx = pfxBuffer.toString("base64");
|
||||
fs.unlinkSync(res.pfxPath);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
if (cert.der == null && res.derPath) {
|
||||
const derBuffer = fs.readFileSync(res.derPath);
|
||||
cert.der = derBuffer.toString("base64");
|
||||
fs.unlinkSync(res.derPath);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
if (cert.jks == null && res.jksPath) {
|
||||
const jksBuffer = fs.readFileSync(res.jksPath);
|
||||
cert.jks = jksBuffer.toString("base64");
|
||||
fs.unlinkSync(res.jksPath);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
this.logger.info("转换证书格式成功");
|
||||
@@ -292,7 +285,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否过期,默认提前20天
|
||||
* 检查是否过期,默认提前35天
|
||||
* @param expires
|
||||
* @param maxDays
|
||||
* @returns {boolean}
|
||||
|
||||
@@ -58,7 +58,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
},
|
||||
required: true,
|
||||
helper:
|
||||
"DNS直接验证:域名是在阿里云、腾讯云、华为云、Cloudflare、西数注册的,选它。\nCNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录",
|
||||
"DNS直接验证:域名是在阿里云、腾讯云、华为云、Cloudflare、NameSilo、西数注册的,选它。\nCNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录",
|
||||
})
|
||||
challengeType!: string;
|
||||
|
||||
|
||||
@@ -96,7 +96,6 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||
this.accessService = this.ctx.accessService;
|
||||
this.logger = this.ctx.logger;
|
||||
this.userContext = this.ctx.userContext;
|
||||
this.http = this.ctx.http;
|
||||
this.lastStatus = this.ctx.lastStatus as Step;
|
||||
if (this.legoEabAccessId) {
|
||||
this.eab = await this.accessService.getById(this.legoEabAccessId);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
link-workspace-packages=true
|
||||
link-workspace-packages=deep
|
||||
prefer-workspace-packages=true
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.8](https://github.com/certd/certd/compare/v1.27.7...v1.27.8) (2024-11-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-client
|
||||
|
||||
## [1.27.7](https://github.com/certd/certd/compare/v1.27.6...v1.27.7) (2024-11-25)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 通知管理 ([d9a00ee](https://github.com/certd/certd/commit/d9a00eeaf72735ced67c59d7983d84e3c730064a))
|
||||
* 通知渠道支持测试按钮 ([b54ae27](https://github.com/certd/certd/commit/b54ae272ebc2d31b32b049d44e2299a6be7f153c))
|
||||
* 支持企业微信群聊机器人通知 ([b805a29](https://github.com/certd/certd/commit/b805a2925984144a31575b8aaa622f0c30d41b56))
|
||||
|
||||
## [1.27.6](https://github.com/certd/certd/compare/v1.27.5...v1.27.6) (2024-11-19)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 当步骤全部都禁用时,任务本身显示删除线 ([9ab9a6e](https://github.com/certd/certd/commit/9ab9a6e8b083e19793894f23e59f29c604ec98e5))
|
||||
|
||||
## [1.27.5](https://github.com/certd/certd/compare/v1.27.4...v1.27.5) (2024-11-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复1Panel面板本身证书更新导致判定执行失败的问题 ([2689e6d](https://github.com/certd/certd/commit/2689e6d6c03aba21da90d5d45232c6ba08696be1))
|
||||
* 修复Cname情况下,无法使用DNS类型的bug ([26dad39](https://github.com/certd/certd/commit/26dad399d5768b3205da099ddc11809aef7d6224))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 日志查看自动滚动到底部 ([4a2f7eb](https://github.com/certd/certd/commit/4a2f7ebf87b7c027cebff7cb763f8f35f6d2aa36))
|
||||
* 系统设置中的代理设置优化为可全局生效,环境变量中的https_proxy设置将无效 ([381a37f](https://github.com/certd/certd/commit/381a37fbaa6b61c887eda743897ae00afb825bdf))
|
||||
* 新手导航在非编辑模式下不显示 ([18bfcc2](https://github.com/certd/certd/commit/18bfcc24ad0bde57bb04db8a4209861ec6b8ff1d))
|
||||
* 专业版试用,无需绑定账号 ([c7c4318](https://github.com/certd/certd/commit/c7c4318c11b65a76089787aa58939832d338a232))
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.8",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -65,8 +65,8 @@
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.27.4",
|
||||
"@certd/pipeline": "^1.27.4",
|
||||
"@certd/lib-iframe": "^1.27.8",
|
||||
"@certd/pipeline": "^1.27.8",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
||||
@@ -24,11 +24,18 @@ export type PlusInfo = {
|
||||
isComm?: boolean;
|
||||
};
|
||||
export type SysPublicSetting = {
|
||||
registerEnabled: boolean;
|
||||
managerOtherUserPipeline: boolean;
|
||||
registerEnabled?: boolean;
|
||||
limitUserPipelineCount?: number;
|
||||
managerOtherUserPipeline?: boolean;
|
||||
icpNo?: string;
|
||||
};
|
||||
|
||||
export type SysPrivateSetting = {
|
||||
httpProxy?: string;
|
||||
httpsProxy?: string;
|
||||
dnsResultOrder?: string;
|
||||
commonCnameEnabled?: boolean;
|
||||
};
|
||||
export type SysInstallInfo = {
|
||||
siteId: string;
|
||||
};
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
@error="onError"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-5">
|
||||
<div class="mt-5 flex">
|
||||
<a-input :disabled="true" :readonly="readonly" :value="modelValue" @change="onChange"></a-input>
|
||||
<fs-icon icon="ion:close-circle" class="pointer fs-16 ml-5 color-gray" title="清除选择" @click="onClear"></fs-icon>
|
||||
</div>
|
||||
<div class="helper">下次触发时间:{{ nextTime }}</div>
|
||||
<div class="fs-helper">{{ errorMessage }}</div>
|
||||
@@ -35,11 +36,16 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const period = ref<string>("");
|
||||
if (props.modelValue == null) {
|
||||
if (props.modelValue == null || props.modelValue.endsWith("* * *")) {
|
||||
period.value = "day";
|
||||
} else if (props.modelValue.endsWith("* *")) {
|
||||
period.value = "month";
|
||||
} else if (props.modelValue.endsWith("*")) {
|
||||
period.value = "year";
|
||||
}
|
||||
const emit = defineEmits<{
|
||||
"update:modelValue": any;
|
||||
change: any;
|
||||
}>();
|
||||
|
||||
const errorMessage = ref<string | null>(null);
|
||||
@@ -73,6 +79,13 @@ const onError = (error: any) => {
|
||||
errorMessage.value = error;
|
||||
};
|
||||
|
||||
const onClear = () => {
|
||||
if (props.disabled) {
|
||||
return;
|
||||
}
|
||||
onUpdate("");
|
||||
};
|
||||
|
||||
const nextTime = computed(() => {
|
||||
if (props.modelValue == null) {
|
||||
return "请先设置正确的cron表达式";
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<div>1. 解析记录应该添加在{{ record.domain }}域名下</div>
|
||||
<div>2. 要添加的是CNAME类型的记录,不是TXT</div>
|
||||
<div>3. 核对记录值是否是:{{ record.recordValue }}</div>
|
||||
<div>
|
||||
4. 运行命令 <a-tag>nslookup -qa=txt {{ record.hostRecord }}{{ record.domain }}</a-tag> 查看解析配置是否正确
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<fs-icon class="ml-5 pointer" icon="mingcute:question-line"></fs-icon>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<span class="label">DNS类型:</span>
|
||||
<span class="input">
|
||||
<fs-dict-select
|
||||
v-model="item.dnsProviderType"
|
||||
v-model:value="item.dnsProviderType"
|
||||
size="small"
|
||||
:dict="dnsProviderTypeDict"
|
||||
placeholder="DNS提供商"
|
||||
@@ -79,6 +79,7 @@ import CnameVerifyPlan from "./cname-verify-plan.vue";
|
||||
import psl from "psl";
|
||||
import { Form } from "ant-design-vue";
|
||||
import { DomainsVerifyPlanInput } from "./type";
|
||||
import { CnameRecord } from "./api";
|
||||
defineOptions({
|
||||
name: "DomainsVerifyPlanEditor"
|
||||
});
|
||||
|
||||
@@ -11,12 +11,16 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ComponentPropsType, doRequest } from "/@/components/plugins/lib";
|
||||
import { ref } from "vue";
|
||||
import { ref, inject } from "vue";
|
||||
import { Form } from "ant-design-vue";
|
||||
|
||||
defineOptions({
|
||||
name: "ApiTest"
|
||||
});
|
||||
|
||||
const getScope: any = inject("get:scope");
|
||||
const getPluginType: any = inject("get:plugin:type");
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
const props = defineProps<{} & ComponentPropsType>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -31,16 +35,21 @@ const doTest = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
formItemContext.onFieldChange();
|
||||
|
||||
const { form } = getScope();
|
||||
const pluginType = getPluginType();
|
||||
|
||||
message.value = "";
|
||||
hasError.value = false;
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await doRequest(
|
||||
{
|
||||
type: props.type,
|
||||
typeName: props.typeName,
|
||||
type: pluginType,
|
||||
typeName: form.type,
|
||||
action: props.action,
|
||||
input: props.form
|
||||
input: pluginType === "plugin" ? form.input : form
|
||||
},
|
||||
{
|
||||
onError(err: any) {
|
||||
@@ -50,9 +59,7 @@ const doTest = async () => {
|
||||
showErrorNotify: false
|
||||
}
|
||||
);
|
||||
if (res && res.length > 0) {
|
||||
message.value = "测试请求成功";
|
||||
}
|
||||
message.value = "测试请求成功";
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ const emit = defineEmits<{
|
||||
const attrs = useAttrs();
|
||||
|
||||
const getCurrentPluginDefine: any = inject("getCurrentPluginDefine");
|
||||
const getScope: any = inject("get:scope");
|
||||
const getPluginType: any = inject("get:plugin:type");
|
||||
|
||||
const optionsRef = ref([]);
|
||||
const message = ref("");
|
||||
const hasError = ref(false);
|
||||
@@ -75,13 +78,16 @@ const getOptions = async () => {
|
||||
hasError.value = false;
|
||||
loading.value = true;
|
||||
optionsRef.value = [];
|
||||
const { form } = getScope();
|
||||
const pluginType = getPluginType();
|
||||
|
||||
try {
|
||||
const res = await doRequest(
|
||||
{
|
||||
type: props.type,
|
||||
typeName: props.typeName,
|
||||
type: pluginType,
|
||||
typeName: form.type,
|
||||
action: props.action,
|
||||
input: props.form
|
||||
input: pluginType === "plugin" ? form.input : form
|
||||
},
|
||||
{
|
||||
onError(err: any) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { request } from "/@/api/service";
|
||||
export type ComponentPropsType = {
|
||||
type: string;
|
||||
typeName: string;
|
||||
action?: string;
|
||||
form: any;
|
||||
type?: string;
|
||||
typeName?: string;
|
||||
action: string;
|
||||
form?: any;
|
||||
value?: any;
|
||||
};
|
||||
export type RequestHandleReq<T = any> = {
|
||||
@@ -15,7 +15,7 @@ export type RequestHandleReq<T = any> = {
|
||||
};
|
||||
|
||||
export async function doRequest(req: RequestHandleReq, opts: any = {}) {
|
||||
const url = req.type === "access" ? "/pi/handle/access" : "/pi/handle/plugin";
|
||||
const url = `/pi/handle/${req.type}`;
|
||||
const { typeName, action, data, input } = req;
|
||||
const res = await request({
|
||||
url,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
import { defineProps, ref, useAttrs } from "vue";
|
||||
import { defineProps, inject, ref, useAttrs } from "vue";
|
||||
import { Modal } from "ant-design-vue";
|
||||
import { ComponentPropsType, doRequest } from "/@/components/plugins/lib";
|
||||
|
||||
@@ -19,7 +19,6 @@ defineOptions({
|
||||
});
|
||||
|
||||
const props = defineProps<ComponentPropsType>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
"update:value": any;
|
||||
}>();
|
||||
@@ -27,16 +26,21 @@ const emit = defineEmits<{
|
||||
const attrs = useAttrs();
|
||||
|
||||
const otpCodeRef = ref("");
|
||||
const getScope: any = inject("get:scope");
|
||||
const getPluginType: any = inject("get:plugin:type");
|
||||
|
||||
async function loginWithOTPCode(otpCode: string) {
|
||||
const { form } = getScope();
|
||||
const pluginType = getPluginType();
|
||||
|
||||
return await doRequest({
|
||||
type: props.type,
|
||||
typeName: props.typeName,
|
||||
type: pluginType,
|
||||
typeName: form.type,
|
||||
action: "LoginWithOPTCode",
|
||||
data: {
|
||||
otpCode
|
||||
},
|
||||
input: props.form
|
||||
input: form
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ const steps = ref<Step[]>([
|
||||
title: "设置定时执行",
|
||||
descriptions: [
|
||||
"流水线测试成功,接下来配置定时触发,以后每天定时执行就不用管了",
|
||||
"推荐配置每天运行一次,在到期前20天才会重新申请新证书并部署,没到期前会自动跳过,不会重复申请。"
|
||||
"推荐配置每天运行一次,在到期前35天才会重新申请新证书并部署,没到期前会自动跳过,不会重复申请。"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,3 +7,11 @@ export async function doActive(form: any) {
|
||||
data: form
|
||||
});
|
||||
}
|
||||
|
||||
export async function getVipTrial() {
|
||||
return await request({
|
||||
url: "/sys/plus/getVipTrial",
|
||||
method: "post",
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="tsx" setup>
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { computed, reactive } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
|
||||
const settingStore = useSettingStore();
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -129,21 +130,27 @@ function goAccount() {
|
||||
router.push("/sys/account");
|
||||
}
|
||||
|
||||
async function getVipTrial() {
|
||||
const res = await api.getVipTrial();
|
||||
message.success(`恭喜,您已获得专业版${res.duration}天试用`);
|
||||
await settingStore.init();
|
||||
}
|
||||
|
||||
function openTrialModal() {
|
||||
Modal.destroyAll();
|
||||
|
||||
modal.confirm({
|
||||
title: "7天专业版试用获取",
|
||||
okText: "立即去绑定账号",
|
||||
okText: "立即获取",
|
||||
onOk() {
|
||||
goAccount();
|
||||
getVipTrial();
|
||||
},
|
||||
width: 600,
|
||||
content: () => {
|
||||
return (
|
||||
<div class="flex-col mt-10 mb-10">
|
||||
<div>感谢您对开源项目的支持</div>
|
||||
<div>绑定袖手账号后,即可获取7天专业版试用</div>
|
||||
<div>点击确认,即可获取7天专业版试用</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,17 @@ export const certdResources = [
|
||||
cache: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "通知设置",
|
||||
name: "NotificationManager",
|
||||
path: "/certd/notification",
|
||||
component: "/certd/notification/index.vue",
|
||||
meta: {
|
||||
icon: "ion:megaphone-outline",
|
||||
auth: true,
|
||||
cache: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "CNAME记录管理",
|
||||
name: "CnameRecord",
|
||||
|
||||
@@ -198,6 +198,9 @@ h1, h2, h3, h4, h5, h6 {
|
||||
.color-green {
|
||||
color: green;
|
||||
}
|
||||
.color-gray {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.iconify{
|
||||
//font-size: 16px;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<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">
|
||||
<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>
|
||||
</span>
|
||||
<span v-else class="mlr-5 text-gray">{{ placeholder }}</span>
|
||||
<a-button class="ml-5" :size="size" @click="chooseForm.open">选择</a-button>
|
||||
<a-button class="ml-5" :disabled="disabled" :size="size" @click="chooseForm.open">选择</a-button>
|
||||
<a-form-item-rest v-if="chooseForm.show">
|
||||
<a-modal v-model:open="chooseForm.show" title="选择授权提供者" width="900px" @ok="chooseForm.ok">
|
||||
<div style="height: 400px; position: relative">
|
||||
@@ -17,9 +17,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, reactive, ref, watch } from "vue";
|
||||
import { defineComponent, reactive, ref, watch, inject } from "vue";
|
||||
import CertAccessModal from "./access/index.vue";
|
||||
import { createAccessApi } from "../api";
|
||||
import { message } from "ant-design-vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AccessSelector",
|
||||
@@ -44,9 +45,13 @@ export default defineComponent({
|
||||
from: {
|
||||
type: String, //user | sys
|
||||
default: "user"
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
emits: ["update:modelValue", "change", "selectedChange"],
|
||||
setup(props, ctx) {
|
||||
const api = createAccessApi(props.from);
|
||||
|
||||
@@ -55,14 +60,32 @@ export default defineComponent({
|
||||
async function refreshTarget(value) {
|
||||
selectedId.value = value;
|
||||
if (value > 0) {
|
||||
target.value = await api.GetObj(value);
|
||||
target.value = await api.GetSimpleInfo(value);
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
selectedId.value = "";
|
||||
target.value = null;
|
||||
if (props.disabled) {
|
||||
return;
|
||||
}
|
||||
emitValue(null);
|
||||
}
|
||||
|
||||
async function emitValue(value) {
|
||||
if (pipeline?.value && target?.value && pipeline.value.userId !== target.value.userId) {
|
||||
message.error("对不起,您不能修改他人流水线的授权");
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
selectedId.value = "";
|
||||
target.value = null;
|
||||
} else {
|
||||
selectedId.value = value;
|
||||
await refreshTarget(selectedId.value);
|
||||
}
|
||||
ctx.emit("change", selectedId.value);
|
||||
ctx.emit("update:modelValue", selectedId.value);
|
||||
ctx.emit("selectedChange", target.value);
|
||||
}
|
||||
|
||||
watch(
|
||||
@@ -71,7 +94,7 @@ export default defineComponent({
|
||||
},
|
||||
async (value) => {
|
||||
selectedId.value = null;
|
||||
target.value = {};
|
||||
target.value = null;
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
@@ -99,16 +122,18 @@ export default defineComponent({
|
||||
}
|
||||
);
|
||||
|
||||
//当不在pipeline中编辑时,可能为空
|
||||
const pipeline = inject("pipeline", null);
|
||||
|
||||
const chooseForm = reactive({
|
||||
show: false,
|
||||
open() {
|
||||
chooseForm.show = true;
|
||||
},
|
||||
ok: () => {
|
||||
chooseForm.show = false;
|
||||
console.log("choose ok:", selectedId.value);
|
||||
refreshTarget(selectedId.value);
|
||||
ctx.emit("update:modelValue", selectedId.value);
|
||||
emitValue(selectedId.value);
|
||||
chooseForm.show = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -43,6 +43,14 @@ export function createAccessApi(from = "user") {
|
||||
});
|
||||
},
|
||||
|
||||
async GetSimpleInfo(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/simpleInfo",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
},
|
||||
|
||||
async GetSecretPlain(id: number, key: string) {
|
||||
return await request({
|
||||
url: apiPrefix + "/getSecretPlain",
|
||||
|
||||
@@ -6,6 +6,9 @@ import SecretPlainGetter from "/@/views/certd/access/access-selector/access/secr
|
||||
|
||||
export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||
provide("accessApi", api);
|
||||
provide("get:plugin:type", () => {
|
||||
return "access";
|
||||
});
|
||||
const AccessTypeDictRef = dict({
|
||||
url: "/pi/access/accessTypeDict"
|
||||
});
|
||||
@@ -44,6 +47,13 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||
//eval
|
||||
useReference(column);
|
||||
|
||||
if (column.required) {
|
||||
if (!column.rules) {
|
||||
column.rules = [];
|
||||
}
|
||||
column.rules.push({ required: true, message: "此项必填" });
|
||||
}
|
||||
|
||||
//设置默认值
|
||||
if (column.value != null && get(form, key) == null) {
|
||||
set(form, key, column.value);
|
||||
|
||||
@@ -115,7 +115,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
}
|
||||
},
|
||||
cnameProviderId: {
|
||||
title: "CNAME提供者",
|
||||
title: "CNAME服务",
|
||||
type: "dict-select",
|
||||
dict: dict({
|
||||
url: "/cname/provider/list",
|
||||
|
||||
@@ -138,7 +138,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
column: {
|
||||
width: 300,
|
||||
cellRender: ({ row, value }) => {
|
||||
debugger;
|
||||
return (
|
||||
<router-link to={{ path: "/certd/pipeline/detail", query: { id: row.pipelineId, editMode: false, historyId: row.id } }}>{value}</router-link>
|
||||
);
|
||||
|
||||
70
packages/ui/certd-client/src/views/certd/notification/api.ts
Normal file
70
packages/ui/certd-client/src/views/certd/notification/api.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { request } from "/src/api/service";
|
||||
|
||||
export function createApi() {
|
||||
const apiPrefix = "/pi/notification";
|
||||
return {
|
||||
async GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query
|
||||
});
|
||||
},
|
||||
|
||||
async AddObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
},
|
||||
|
||||
async UpdateObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
},
|
||||
|
||||
async DelObj(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
},
|
||||
|
||||
async GetObj(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/info",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
},
|
||||
|
||||
async GetSimpleInfo(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/simpleInfo",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
},
|
||||
|
||||
async GetProviderDefine(type: string) {
|
||||
return await request({
|
||||
url: apiPrefix + "/define",
|
||||
method: "post",
|
||||
params: { type }
|
||||
});
|
||||
},
|
||||
|
||||
async GetProviderDefineByType(type: string) {
|
||||
return await request({
|
||||
url: apiPrefix + "/defineByType",
|
||||
method: "post",
|
||||
params: { type }
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
181
packages/ui/certd-client/src/views/certd/notification/common.tsx
Normal file
181
packages/ui/certd-client/src/views/certd/notification/common.tsx
Normal file
@@ -0,0 +1,181 @@
|
||||
import { ColumnCompositionProps, compute, dict } from "@fast-crud/fast-crud";
|
||||
import { computed, provide, ref, toRef } from "vue";
|
||||
import { useReference } from "/@/use/use-refrence";
|
||||
import { forEach, get, merge, set } from "lodash-es";
|
||||
|
||||
export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||
provide("notificationApi", api);
|
||||
provide("get:plugin:type", () => {
|
||||
return "notification";
|
||||
});
|
||||
const notificationTypeDictRef = dict({
|
||||
url: "/pi/notification/getTypeDict"
|
||||
});
|
||||
const defaultPluginConfig = {
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
};
|
||||
|
||||
function buildDefineFields(define: any, form: any, mode: string) {
|
||||
const formWrapperRef = crudExpose.getFormWrapperRef();
|
||||
const columnsRef = toRef(formWrapperRef.formOptions, "columns");
|
||||
|
||||
for (const key in columnsRef.value) {
|
||||
if (key.indexOf(".") >= 0) {
|
||||
delete columnsRef.value[key];
|
||||
}
|
||||
}
|
||||
console.log('crudBinding.value[mode + "Form"].columns', columnsRef.value);
|
||||
forEach(define.input, (value: any, mapKey: any) => {
|
||||
const key = "body." + mapKey;
|
||||
const field = {
|
||||
...value,
|
||||
key
|
||||
};
|
||||
const column = merge({ title: key }, defaultPluginConfig, field);
|
||||
//eval
|
||||
useReference(column);
|
||||
|
||||
if (column.required) {
|
||||
if (!column.rules) {
|
||||
column.rules = [];
|
||||
}
|
||||
column.rules.push({ required: true, message: "此项必填" });
|
||||
}
|
||||
|
||||
//设置默认值
|
||||
if (column.value != null && get(form, key) == null) {
|
||||
set(form, key, column.value);
|
||||
}
|
||||
//字段配置赋值
|
||||
columnsRef.value[key] = column;
|
||||
console.log("form", columnsRef.value, form);
|
||||
});
|
||||
}
|
||||
|
||||
const currentDefine = ref();
|
||||
|
||||
return {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 100
|
||||
},
|
||||
form: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
type: {
|
||||
title: "通知类型",
|
||||
type: "dict-select",
|
||||
dict: notificationTypeDictRef,
|
||||
search: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
width: 200,
|
||||
component: {
|
||||
color: "auto"
|
||||
}
|
||||
},
|
||||
editForm: {
|
||||
component: {
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
form: {
|
||||
component: {
|
||||
disabled: false,
|
||||
showSearch: true,
|
||||
filterOption: (input: string, option: any) => {
|
||||
input = input?.toLowerCase();
|
||||
return option.value.toLowerCase().indexOf(input) >= 0 || option.label.toLowerCase().indexOf(input) >= 0;
|
||||
}
|
||||
},
|
||||
rules: [{ required: true, message: "请选择通知类型" }],
|
||||
valueChange: {
|
||||
immediate: true,
|
||||
async handle({ value, mode, form, immediate }) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
const lastTitle = currentDefine.value?.title;
|
||||
const define = await api.GetProviderDefine(value);
|
||||
currentDefine.value = define;
|
||||
console.log("define", define);
|
||||
|
||||
if (!immediate) {
|
||||
form.body = {};
|
||||
}
|
||||
|
||||
if (!form.name || form.name === lastTitle) {
|
||||
form.name = define.title;
|
||||
}
|
||||
buildDefineFields(define, form, mode);
|
||||
}
|
||||
},
|
||||
helper: computed(() => {
|
||||
const define = currentDefine.value;
|
||||
if (define == null) {
|
||||
return "";
|
||||
}
|
||||
return define.desc;
|
||||
})
|
||||
}
|
||||
} as ColumnCompositionProps,
|
||||
name: {
|
||||
title: "通知名称",
|
||||
search: {
|
||||
show: true
|
||||
},
|
||||
type: ["text"],
|
||||
form: {
|
||||
rules: [{ required: true, message: "请填写名称" }],
|
||||
helper: "随便填,当多个相同类型的通知时,便于区分"
|
||||
},
|
||||
column: {
|
||||
width: 200
|
||||
}
|
||||
},
|
||||
test: {
|
||||
title: "测试",
|
||||
form: {
|
||||
show: compute(({ form }) => {
|
||||
return !!form.type;
|
||||
}),
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest"
|
||||
},
|
||||
order: 999
|
||||
},
|
||||
column: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
setting: {
|
||||
column: { show: false },
|
||||
form: {
|
||||
show: false,
|
||||
valueBuilder({ value, form }) {
|
||||
form.body = {};
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
const setting = JSON.parse(value);
|
||||
for (const key in setting) {
|
||||
form.body[key] = setting[key];
|
||||
}
|
||||
},
|
||||
valueResolve({ form }) {
|
||||
const setting = form.body;
|
||||
form.setting = JSON.stringify(setting);
|
||||
}
|
||||
}
|
||||
} as ColumnCompositionProps
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// @ts-ignore
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref } from "vue";
|
||||
import { getCommonColumnDefine } from "./common";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const { t } = useI18n();
|
||||
const api = context.api;
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetList(query);
|
||||
};
|
||||
const editRequest = async (req: EditReq) => {
|
||||
const { form, row } = req;
|
||||
form.id = row.id;
|
||||
const res = await api.UpdateObj(form);
|
||||
return res;
|
||||
};
|
||||
const delRequest = async (req: DelReq) => {
|
||||
const { row } = req;
|
||||
return await api.DelObj(row.id);
|
||||
};
|
||||
|
||||
const addRequest = async (req: AddReq) => {
|
||||
const { form } = req;
|
||||
const res = await api.AddObj(form);
|
||||
return res;
|
||||
};
|
||||
|
||||
const typeRef = ref();
|
||||
const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api);
|
||||
return {
|
||||
crudOptions: {
|
||||
request: {
|
||||
pageRequest,
|
||||
addRequest,
|
||||
editRequest,
|
||||
delRequest
|
||||
},
|
||||
form: {
|
||||
labelCol: {
|
||||
span: 6
|
||||
}
|
||||
},
|
||||
rowHandle: {
|
||||
width: 200
|
||||
},
|
||||
columns: {
|
||||
...commonColumnsDefine
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<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, onActivated, onMounted } from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { createApi } from "./api";
|
||||
|
||||
export default defineComponent({
|
||||
name: "NotificationManager",
|
||||
setup() {
|
||||
const api = createApi();
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { api } });
|
||||
|
||||
// 页面打开后获取列表数据
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
return {
|
||||
crudBinding,
|
||||
crudRef
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="notification-selector">
|
||||
<span v-if="target?.name" class="mr-5 cd-flex-inline">
|
||||
<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>
|
||||
</span>
|
||||
<span v-else class="mlr-5 text-gray">{{ placeholder }}</span>
|
||||
<a-button class="ml-5" :disabled="disabled" :size="size" @click="chooseForm.open">选择</a-button>
|
||||
<a-form-item-rest v-if="chooseForm.show">
|
||||
<a-modal v-model:open="chooseForm.show" title="选择通知渠道" width="900px" @ok="chooseForm.ok">
|
||||
<div style="height: 400px; position: relative">
|
||||
<cert-notification-modal v-model="selectedId"></cert-notification-modal>
|
||||
</div>
|
||||
</a-modal>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, reactive, ref, watch, inject } from "vue";
|
||||
import CertNotificationModal from "./modal/index.vue";
|
||||
import { createApi } from "../api";
|
||||
import { message } from "ant-design-vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "NotificationSelector",
|
||||
components: { CertNotificationModal },
|
||||
props: {
|
||||
modelValue: {
|
||||
type: [Number, String],
|
||||
default: null
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请选择"
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: "middle"
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ["update:modelValue", "selectedChange", "change"],
|
||||
setup(props, ctx) {
|
||||
const api = createApi();
|
||||
|
||||
const target = ref({});
|
||||
const selectedId = ref();
|
||||
async function refreshTarget(value) {
|
||||
selectedId.value = value;
|
||||
if (value > 0) {
|
||||
target.value = await api.GetSimpleInfo(value);
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
if (props.disabled) {
|
||||
return;
|
||||
}
|
||||
emitValue(null);
|
||||
}
|
||||
|
||||
async function emitValue(value) {
|
||||
if (pipeline?.value && target?.value && pipeline.value.userId !== target.value.userId) {
|
||||
message.error("对不起,您不能修改他人流水线的通知");
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
selectedId.value = "";
|
||||
target.value = null;
|
||||
} else {
|
||||
selectedId.value = value;
|
||||
await refreshTarget(selectedId.value);
|
||||
}
|
||||
ctx.emit("change", selectedId.value);
|
||||
ctx.emit("update:modelValue", selectedId.value);
|
||||
ctx.emit("selectedChange", target.value);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return props.modelValue;
|
||||
},
|
||||
async (value) => {
|
||||
selectedId.value = null;
|
||||
target.value = null;
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
await refreshTarget(value);
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
|
||||
const providerDefine = ref({});
|
||||
|
||||
async function refreshProviderDefine(type) {
|
||||
providerDefine.value = await api.GetProviderDefine(type);
|
||||
}
|
||||
// watch(
|
||||
// () => {
|
||||
// return props.type;
|
||||
// },
|
||||
// async (value) => {
|
||||
// await refreshProviderDefine(value);
|
||||
// },
|
||||
// {
|
||||
// immediate: true
|
||||
// }
|
||||
// );
|
||||
|
||||
//当不在pipeline中编辑时,可能为空
|
||||
const pipeline = inject("pipeline", null);
|
||||
|
||||
const chooseForm = reactive({
|
||||
show: false,
|
||||
open() {
|
||||
chooseForm.show = true;
|
||||
},
|
||||
ok: () => {
|
||||
console.log("choose ok:", selectedId.value);
|
||||
emitValue(selectedId.value);
|
||||
chooseForm.show = false;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
clear,
|
||||
target,
|
||||
selectedId,
|
||||
providerDefine,
|
||||
chooseForm
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.notification-selector {
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,88 @@
|
||||
// @ts-ignore
|
||||
import { ref } from "vue";
|
||||
import { getCommonColumnDefine } from "../../common";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const { crudBinding } = crudExpose;
|
||||
const { props, ctx, api } = context;
|
||||
const lastResRef = ref();
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await context.api.GetList(query);
|
||||
};
|
||||
const editRequest = async (req: EditReq) => {
|
||||
const { form, row } = req;
|
||||
form.id = row.id;
|
||||
const res = await context.api.UpdateObj(form);
|
||||
lastResRef.value = res;
|
||||
return res;
|
||||
};
|
||||
const delRequest = async (req: DelReq) => {
|
||||
const { row } = req;
|
||||
return await context.api.DelObj(row.id);
|
||||
};
|
||||
|
||||
const addRequest = async (req: AddReq) => {
|
||||
const { form } = req;
|
||||
const res = await context.api.AddObj(form);
|
||||
lastResRef.value = res;
|
||||
return res;
|
||||
};
|
||||
|
||||
const selectedRowKey = ref([props.modelValue]);
|
||||
|
||||
const onSelectChange = (changed: any) => {
|
||||
selectedRowKey.value = changed;
|
||||
ctx.emit("update:modelValue", changed[0]);
|
||||
};
|
||||
|
||||
const typeRef = ref("");
|
||||
context.typeRef = typeRef;
|
||||
const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api);
|
||||
commonColumnsDefine.type.editForm.component.disabled = true;
|
||||
return {
|
||||
typeRef,
|
||||
crudOptions: {
|
||||
request: {
|
||||
pageRequest,
|
||||
addRequest,
|
||||
editRequest,
|
||||
delRequest
|
||||
},
|
||||
toolbar: {
|
||||
show: false
|
||||
},
|
||||
search: {
|
||||
show: false
|
||||
},
|
||||
form: {
|
||||
wrapper: {
|
||||
width: "1050px"
|
||||
}
|
||||
},
|
||||
rowHandle: {
|
||||
width: 200
|
||||
},
|
||||
table: {
|
||||
scroll: {
|
||||
x: 800
|
||||
},
|
||||
rowSelection: {
|
||||
type: "radio",
|
||||
selectedRowKeys: selectedRowKey,
|
||||
onChange: onSelectChange
|
||||
},
|
||||
customRow: (record: any) => {
|
||||
return {
|
||||
onClick: () => {
|
||||
onSelectChange([record.id]);
|
||||
} // 点击行
|
||||
};
|
||||
}
|
||||
},
|
||||
columns: {
|
||||
...commonColumnsDefine
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<fs-page class="page-cert-notification-modal">
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, watch } from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { createApi } from "../../api";
|
||||
|
||||
export default defineComponent({
|
||||
name: "CertNotificationModal",
|
||||
props: {
|
||||
modelValue: {}
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
setup(props, ctx) {
|
||||
const api = createApi();
|
||||
const context: any = { props, ctx, api };
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
return {
|
||||
crudBinding,
|
||||
crudRef
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.page-cert-notification {
|
||||
}
|
||||
</style>
|
||||
@@ -5,6 +5,7 @@ import _, { merge } from "lodash-es";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import * as api from "../api.plugin";
|
||||
import NotificationSelector from "/@/views/certd/notification/notification-selector/index.vue";
|
||||
export default function (certPluginGroup: PluginGroup, formWrapperRef: any): CreateCrudOptionsRet {
|
||||
const inputs: any = {};
|
||||
const userStore = useUserStore();
|
||||
@@ -102,30 +103,16 @@ export default function (certPluginGroup: PluginGroup, formWrapperRef: any): Cre
|
||||
order: 100
|
||||
}
|
||||
},
|
||||
emailNotify: {
|
||||
title: "失败邮件通知",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ value: true, label: "启用" },
|
||||
{ value: false, label: "不启用" }
|
||||
]
|
||||
}),
|
||||
notification: {
|
||||
title: "失败通知",
|
||||
type: "text",
|
||||
form: {
|
||||
component: {
|
||||
name: NotificationSelector,
|
||||
vModel: "modelValue"
|
||||
},
|
||||
order: 101,
|
||||
value: true,
|
||||
helper: {
|
||||
render: () => {
|
||||
if (settingStore.isPlus) {
|
||||
return "建议启用";
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
建议启用,需要配置<router-link to={{ path: "/sys/settings/email" }}>邮件服务器</router-link>才能发送邮件
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
helper: "建议设置,任务执行失败实时提醒"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import * as _ from "lodash-es";
|
||||
import { useModal } from "/@/use/use-modal";
|
||||
import CertView from "./cert-view.vue";
|
||||
import { eachStages } from "./utils";
|
||||
|
||||
import { createApi as createNotificationApi } from "../notification/api";
|
||||
export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
@@ -102,13 +102,13 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
triggers.push({ title: "定时触发", type: "timer", props: { cron: form.triggerCron } });
|
||||
}
|
||||
const notifications = [];
|
||||
if (form.emailNotify) {
|
||||
if (form.notification) {
|
||||
const notify = await createNotificationApi().GetSimpleInfo(form.notification);
|
||||
notifications.push({
|
||||
type: "email",
|
||||
type: "custom",
|
||||
when: ["error", "turnToSuccess"],
|
||||
options: {
|
||||
receivers: [form.email]
|
||||
}
|
||||
notificationId: form.notification,
|
||||
title: notify.name
|
||||
});
|
||||
}
|
||||
let pipeline = {
|
||||
|
||||
@@ -30,6 +30,7 @@ const pipelineOptions: PipelineOptions = {
|
||||
return {
|
||||
pipeline: {
|
||||
id: detail.pipeline.id,
|
||||
userId: detail.pipeline.userId,
|
||||
stages: [],
|
||||
triggers: [],
|
||||
...JSON.parse(detail.pipeline.content || "{}")
|
||||
@@ -67,7 +68,7 @@ const pipelineOptions: PipelineOptions = {
|
||||
const pipelineOptionsRef: Ref<PipelineOptions> = ref(pipelineOptions);
|
||||
|
||||
const editMode = ref(false);
|
||||
if (route.query.editMode !== "false") {
|
||||
if (route.query.editMode === "true") {
|
||||
editMode.value = true;
|
||||
}
|
||||
|
||||
@@ -140,7 +141,7 @@ async function onLoaded(pipeline: PipelineDetail) {
|
||||
}
|
||||
const res = await api.GetCount();
|
||||
LocalStorage.set("pipeline-count", res.count);
|
||||
if (res.count <= 1) {
|
||||
if (res.count <= 1 && editMode.value === true) {
|
||||
await nextTick();
|
||||
tourHandleOpen(true);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<pi-container>
|
||||
<a-form ref="notificationFormRef" class="notification-form" :model="currentNotification" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<fs-form-item
|
||||
v-if="currentNotification.type === 'email'"
|
||||
v-model="currentNotification.type"
|
||||
:item="{
|
||||
title: '类型',
|
||||
@@ -28,7 +29,10 @@
|
||||
name: 'a-select',
|
||||
vModel: 'value',
|
||||
disabled: !editMode,
|
||||
options: [{ value: 'email', label: '邮件' }]
|
||||
options: [
|
||||
{ value: 'email', label: '邮件' },
|
||||
{ value: 'other', label: '其他通知方式' }
|
||||
]
|
||||
},
|
||||
rules: [{ required: true, message: '此项必填' }]
|
||||
}"
|
||||
@@ -47,15 +51,35 @@
|
||||
options: [
|
||||
{ value: 'start', label: '开始时' },
|
||||
{ value: 'success', label: '成功时' },
|
||||
{ value: 'turnToSuccess', label: '错误转成功时' },
|
||||
{ value: 'error', label: '错误时' }
|
||||
{ value: 'turnToSuccess', label: '失败转成功时' },
|
||||
{ value: 'error', label: '失败时' }
|
||||
]
|
||||
},
|
||||
helper: `建议仅选择'错误时'和'错误转成功'两种即可`,
|
||||
helper: `建议仅选择'失败时'和'失败转成功'两种即可`,
|
||||
rules: [{ required: true, message: '此项必填' }]
|
||||
}"
|
||||
/>
|
||||
<pi-notification-form-email
|
||||
v-if="currentNotification.type === 'email'"
|
||||
ref="optionsRef"
|
||||
v-model:options="currentNotification.options"
|
||||
></pi-notification-form-email>
|
||||
|
||||
<fs-form-item
|
||||
v-else
|
||||
v-model="currentNotification.notificationId"
|
||||
:item="{
|
||||
title: '通知配置',
|
||||
key: 'type',
|
||||
component: {
|
||||
disabled: !editMode,
|
||||
name: NotificationSelector,
|
||||
onSelectedChange
|
||||
},
|
||||
helper: '请选择通知方式',
|
||||
rules: [{ required: true, message: '此项必填' }]
|
||||
}"
|
||||
/>
|
||||
<pi-notification-form-email ref="optionsRef" v-model:options="currentNotification.options"></pi-notification-form-email>
|
||||
</a-form>
|
||||
|
||||
<template #footer>
|
||||
@@ -70,14 +94,16 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Modal } from "ant-design-vue";
|
||||
import { ref } from "vue";
|
||||
import { ref, Ref } from "vue";
|
||||
import * as _ from "lodash-es";
|
||||
import { nanoid } from "nanoid";
|
||||
import PiNotificationFormEmail from "./pi-notification-form-email.vue";
|
||||
import NotificationSelector from "/@/views/certd/notification/notification-selector/index.vue";
|
||||
|
||||
export default {
|
||||
name: "PiNotificationForm",
|
||||
components: { PiNotificationFormEmail },
|
||||
// eslint-disable-next-line vue/no-unused-components
|
||||
components: { NotificationSelector, PiNotificationFormEmail },
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
@@ -93,7 +119,7 @@ export default {
|
||||
function useNotificationForm() {
|
||||
const mode = ref("add");
|
||||
const callback = ref();
|
||||
const currentNotification = ref({ type: undefined, when: [], options: {} });
|
||||
const currentNotification: Ref<any> = ref({ type: undefined, when: [], options: {}, notificationId: undefined, title: "" });
|
||||
const currentPlugin = ref({});
|
||||
const notificationFormRef = ref(null);
|
||||
const notificationDrawerVisible = ref(false);
|
||||
@@ -112,6 +138,13 @@ export default {
|
||||
required: true,
|
||||
message: "请选择通知时机"
|
||||
}
|
||||
],
|
||||
notificationId: [
|
||||
{
|
||||
type: "number",
|
||||
required: true,
|
||||
message: "请选择通知配置"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -135,7 +168,7 @@ export default {
|
||||
|
||||
const notificationAdd = (emit: any) => {
|
||||
mode.value = "add";
|
||||
const notification = { id: nanoid(), type: "email", when: ["error"] };
|
||||
const notification = { id: nanoid(), type: "custom", when: ["error", "turnToSuccess"] };
|
||||
notificationOpen(notification, emit);
|
||||
};
|
||||
|
||||
@@ -150,7 +183,10 @@ export default {
|
||||
};
|
||||
|
||||
const notificationSave = async (e: any) => {
|
||||
currentNotification.value.options = await optionsRef.value.getValue();
|
||||
if (optionsRef.value) {
|
||||
currentNotification.value.options = await optionsRef.value.getValue();
|
||||
}
|
||||
|
||||
console.log("currentNotificationSave", currentNotification.value);
|
||||
try {
|
||||
await notificationFormRef.value.validate();
|
||||
@@ -177,8 +213,13 @@ export default {
|
||||
const blankFn = () => {
|
||||
return {};
|
||||
};
|
||||
|
||||
function onSelectedChange(node: any) {
|
||||
currentNotification.value.title = node?.name || null;
|
||||
}
|
||||
return {
|
||||
notificationFormRef,
|
||||
onSelectedChange,
|
||||
mode,
|
||||
notificationAdd,
|
||||
notificationEdit,
|
||||
@@ -201,6 +242,11 @@ export default {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 }
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
NotificationSelector() {
|
||||
return NotificationSelector;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -86,13 +86,13 @@
|
||||
},
|
||||
rules: [{ required: true, message: '此项必填' }]
|
||||
}"
|
||||
:get-context-fn="blankFn"
|
||||
:get-context-fn="getScopeFunc"
|
||||
/>
|
||||
<template v-for="(item, key) in currentPlugin.input" :key="key">
|
||||
<fs-form-item v-if="item.show !== false" v-model="currentStep.input[key]" :item="item" :get-context-fn="blankFn" />
|
||||
<fs-form-item v-if="item.show !== false" v-model="currentStep.input[key]" :item="item" :get-context-fn="getScopeFunc" />
|
||||
</template>
|
||||
|
||||
<fs-form-item v-model="currentStep.strategy.runStrategy" :item="runStrategyProps" :get-context-fn="blankFn" />
|
||||
<fs-form-item v-model="currentStep.strategy.runStrategy" :item="runStrategyProps" :get-context-fn="getScopeFunc" />
|
||||
</a-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
@@ -222,6 +222,9 @@ export default {
|
||||
provide("getCurrentPluginDefine", () => {
|
||||
return currentPluginDefine;
|
||||
});
|
||||
provide("get:plugin:type", () => {
|
||||
return "plugin";
|
||||
});
|
||||
|
||||
function getContext() {
|
||||
return {
|
||||
@@ -302,8 +305,10 @@ export default {
|
||||
stepDrawerClose();
|
||||
};
|
||||
|
||||
const blankFn = () => {
|
||||
return {};
|
||||
const getScopeFunc = () => {
|
||||
return {
|
||||
form: currentStep.value
|
||||
};
|
||||
};
|
||||
|
||||
const pluginSearch = ref({
|
||||
@@ -359,7 +364,7 @@ export default {
|
||||
stepSave,
|
||||
stepDelete,
|
||||
rules,
|
||||
blankFn,
|
||||
getScopeFunc,
|
||||
stepCopy,
|
||||
fullscreen
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<a key="edit" @click="stepEdit(currentTask, element, index)">编辑</a>
|
||||
<a key="edit" @click="stepCopy(currentTask, element, index)">复制</a>
|
||||
<a key="remove" @click="stepDelete(currentTask, index)">删除</a>
|
||||
<a key="disabled" @click="element.disabled = !!!element.disabled">{{ element.disabled ? "启用" : "禁用" }}</a>
|
||||
<a key="disabled" @click="toggleDisabled(currentTask, element)">{{ element.disabled ? "启用" : "禁用" }}</a>
|
||||
<fs-icon v-plus class="icon-button handle cursor-move" title="拖动排序" icon="ion:move-outline"></fs-icon>
|
||||
</div>
|
||||
</div>
|
||||
@@ -88,6 +88,7 @@ import { CopyOutlined } from "@ant-design/icons-vue";
|
||||
import VDraggable from "vuedraggable";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import { filter } from "lodash-es";
|
||||
export default {
|
||||
name: "PiTaskForm",
|
||||
components: { CopyOutlined, PiStepForm, VDraggable },
|
||||
@@ -152,7 +153,11 @@ export default {
|
||||
});
|
||||
};
|
||||
|
||||
return { stepAdd, stepEdit, stepCopy, stepDelete, stepFormRef };
|
||||
const toggleDisabled = (task: any, step: any) => {
|
||||
step.disabled = !!!step.disabled;
|
||||
};
|
||||
|
||||
return { stepAdd, stepEdit, stepCopy, stepDelete, toggleDisabled, stepFormRef };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,7 +167,7 @@ export default {
|
||||
function useTaskForm() {
|
||||
const mode = ref("add");
|
||||
const callback = ref();
|
||||
const currentTask = ref({ title: undefined, steps: [] });
|
||||
const currentTask = ref({ title: undefined, steps: [], disabled: false });
|
||||
provide("currentTask", currentTask);
|
||||
const taskFormRef: Ref<any> = ref(null);
|
||||
const taskDrawerVisible = ref(false);
|
||||
@@ -219,6 +224,15 @@ export default {
|
||||
console.error("表单验证失败:", e);
|
||||
return;
|
||||
}
|
||||
const task: any = currentTask.value;
|
||||
const allDisabled = filter(task.steps, (item: any) => {
|
||||
return item.disabled;
|
||||
});
|
||||
if (task.steps.length > 0 && task.steps.length === allDisabled.length) {
|
||||
task.disabled = true;
|
||||
} else {
|
||||
task.disabled = false;
|
||||
}
|
||||
|
||||
callback.value("save", currentTask.value);
|
||||
taskDrawerClose();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<pi-status-show :status="item.node.status?.result" type="icon"></pi-status-show>
|
||||
</div>
|
||||
</template>
|
||||
<div class="pi-task-view-logs" style="overflow: auto">
|
||||
<div class="pi-task-view-logs" :class="item.node.id" style="overflow: auto">
|
||||
<template v-for="(logItem, index) of item.logs" :key="index">
|
||||
<span :class="logItem.color"> {{ logItem.time }}</span> <span>{{ logItem.content }}</span>
|
||||
</template>
|
||||
@@ -19,7 +19,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, inject, Ref, ref } from "vue";
|
||||
import { computed, inject, nextTick, Ref, ref, watch } from "vue";
|
||||
import { RunHistory } from "../../type";
|
||||
import PiStatusShow from "/@/views/certd/pipeline/pipeline/component/status-show.vue";
|
||||
|
||||
@@ -78,6 +78,29 @@ export default {
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return node.logs.value.length;
|
||||
},
|
||||
async () => {
|
||||
let el = document.querySelector(`.pi-task-view-logs.${node.node.id}`);
|
||||
//判断当前是否在底部
|
||||
const isBottom = el ? el.scrollHeight - el.scrollTop === el.clientHeight : true;
|
||||
await nextTick();
|
||||
el = document.querySelector(`.pi-task-view-logs.${node.node.id}`);
|
||||
//如果在底部则滚动到底部
|
||||
if (isBottom && el) {
|
||||
el?.scrollTo({
|
||||
top: el.scrollHeight,
|
||||
behavior: "smooth"
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<span class="flex-o w-100">
|
||||
<span class="ellipsis flex-1 task-title" :class="{ 'in-edit': editMode }">{{ task.title }}</span>
|
||||
<span class="ellipsis flex-1 task-title" :class="{ 'in-edit': editMode, deleted: task.disabled }">{{ task.title }}</span>
|
||||
<pi-status-show :status="task.status?.result"></pi-status-show>
|
||||
</span>
|
||||
</a-popover>
|
||||
@@ -181,7 +181,7 @@
|
||||
<div class="task">
|
||||
<a-button shape="round" @click="notificationEdit(item, ii as number)">
|
||||
<fs-icon icon="ion:notifications"></fs-icon>
|
||||
【通知】 {{ item.type }}
|
||||
【通知】 {{ item.title || item.type }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -199,8 +199,7 @@
|
||||
<div class="task">
|
||||
<a-button shape="round" @click="notificationEdit(item, index)">
|
||||
<fs-icon icon="ion:notifications"></fs-icon>
|
||||
|
||||
【通知】 {{ item.type }}
|
||||
【通知】 {{ item.title || item.type }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -304,7 +303,6 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const loadCurrentHistoryDetail = async () => {
|
||||
console.log("load history logs");
|
||||
const detail: RunHistory = await props.options?.getHistoryDetail({ historyId: currentHistory.value.id });
|
||||
currentHistory.value.logs = detail.logs;
|
||||
_.merge(currentHistory.value.pipeline, detail.pipeline);
|
||||
@@ -329,7 +327,6 @@ export default defineComponent({
|
||||
if (reload) {
|
||||
histories.value = [];
|
||||
}
|
||||
console.log("load history list");
|
||||
const historyList = await props.options.getHistoryList({ pipelineId: pipeline.value.id });
|
||||
if (!historyList) {
|
||||
return;
|
||||
@@ -885,6 +882,8 @@ export default defineComponent({
|
||||
&.in-edit {
|
||||
margin-right: 28px;
|
||||
}
|
||||
&.disabled {
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user