mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
Merge branch 'certd:v2' into v2
This commit is contained in:
+22
-10
@@ -1,5 +1,4 @@
|
||||
FROM node:18-alpine AS builder
|
||||
EXPOSE 7001
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /workspace/
|
||||
COPY . /workspace/
|
||||
# armv7 目前只能用node18, pnpm9不支持node18,所以pnpm只能用8.15.7版本
|
||||
@@ -10,18 +9,31 @@ RUN npm install -g pnpm@8.15.7
|
||||
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
|
||||
RUN cd /workspace/certd-server && pnpm install && npm run build-on-docker
|
||||
|
||||
|
||||
FROM node:18-alpine
|
||||
FROM node:20-alpine
|
||||
EXPOSE 7001
|
||||
EXPOSE 7002
|
||||
RUN apk add --no-cache openssl
|
||||
# RUN apk add --no-cache openjdk11-jdk
|
||||
RUN apk add --no-cache openjdk8
|
||||
WORKDIR /app/
|
||||
COPY --from=builder /workspace/certd-server/ /app/
|
||||
#RUN cd /app/tools/linux/ && ls -lh && tar -zxvf lego_linux_amd64.tar.gz
|
||||
RUN chmod +x /app/tools/linux/*
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV NODE_ENV=production
|
||||
ENV MIDWAY_SERVER_ENV=production
|
||||
ENV LEGO_VERSION 4.19.2
|
||||
ENV LEGO_DOWNLOAD_DIR /app/tools/lego
|
||||
RUN mkdir -p $LEGO_DOWNLOAD_DIR
|
||||
|
||||
# 根据架构下载不同的文件
|
||||
RUN ARCH=$(uname -m) && \
|
||||
if [ "$ARCH" = "x86_64" ]; then \
|
||||
wget -O $LEGO_DOWNLOAD_DIR/lego_v${LEGO_VERSION}_linux_amd64.tar.gz https://github.com/go-acme/lego/releases/download/v${LEGO_VERSION}/lego_v${LEGO_VERSION}_linux_amd64.tar.gz; \
|
||||
elif [ "$ARCH" = "aarch64" ]; then \
|
||||
wget -O $LEGO_DOWNLOAD_DIR/lego_v${LEGO_VERSION}_linux_arm64.tar.gz https://github.com/go-acme/lego/releases/download/v${LEGO_VERSION}/lego_v${LEGO_VERSION}_linux_arm64.tar.gz; \
|
||||
else \
|
||||
echo "Unsupported architecture: $ARCH"; \
|
||||
fi
|
||||
|
||||
ENV TZ Asia/Shanghai
|
||||
ENV NODE_ENV production
|
||||
ENV MIDWAY_SERVER_ENV production
|
||||
CMD ["npm", "run","start"]
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,45 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
### 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
|
||||
|
||||
* 修复邮件配置,忽略证书校验设置不生效的bug ([66a9690](https://github.com/certd/certd/commit/66a9690dc958732e1b3c672d965db502296446f9))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修复站点个性化,浏览器标题没有生效的bug ([bcfac02](https://github.com/certd/certd/commit/bcfac02c96ceaf23d1a0b05b48d8047da933beaf))
|
||||
* 优化上传到主机插 路径选择,根据证书格式显示 ([8c3f86c](https://github.com/certd/certd/commit/8c3f86c6909ed91f48bb2880e78834e22f6f6a29))
|
||||
* ipv6支持 ([da6ac16](https://github.com/certd/certd/commit/da6ac1626b3574be2fabeeb18a1f10d60bdcbe49))
|
||||
|
||||
## [1.27.2](https://github.com/certd/certd/compare/v1.27.1...v1.27.2) (2024-11-08)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化流水线页面切换回来不丢失查询条件 ([4dcf6e8](https://github.com/certd/certd/commit/4dcf6e87bc5f7657ce8a56c5331e8723a0fee8ee))
|
||||
* 支持公共cname服务 ([3c919ee](https://github.com/certd/certd/commit/3c919ee5d1aef5d26cf3620a7c49d920786bc941))
|
||||
* 执行历史支持点击查看流水线详情 ([8968639](https://github.com/certd/certd/commit/89686399f90058835435b92872fc236fac990148))
|
||||
* 专业版7天试用 ([c58250e](https://github.com/certd/certd/commit/c58250e1f065a9bd8b4e82acc1df754504c0010c))
|
||||
|
||||
## [1.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复头像没有更新的bug ([9b4a31f](https://github.com/certd/certd/commit/9b4a31fa6a32b9cab2e22bd141cf96ca29120445))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 禁止页面缓存,点击tab页签可以刷新数据 ([7ad4b55](https://github.com/certd/certd/commit/7ad4b55ee000c1dd0747832b11107f32b0ffb889))
|
||||
* 优化时间选择器,自动填写分钟和秒钟 ([396dc34](https://github.com/certd/certd/commit/396dc34a841c7d016b033736afdba8366fb2d211))
|
||||
* cname 域名映射记录可读性优化 ([b1117ed](https://github.com/certd/certd/commit/b1117ed54a3ef015752999324ff72b821ef5e4b9))
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.27.0",
|
||||
"version": "1.27.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -26,10 +26,10 @@
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.0.2",
|
||||
"@ant-design/icons-vue": "^6.1.0",
|
||||
"@fast-crud/fast-crud": "^1.22.2",
|
||||
"@fast-crud/fast-extends": "^1.22.2",
|
||||
"@fast-crud/ui-antdv4": "^1.22.2",
|
||||
"@fast-crud/ui-interface": "^1.22.2",
|
||||
"@fast-crud/fast-crud": "^1.23.1",
|
||||
"@fast-crud/fast-extends": "^1.23.1",
|
||||
"@fast-crud/ui-antdv4": "^1.23.1",
|
||||
"@fast-crud/ui-interface": "^1.23.1",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@soerenmartius/vue3-clipboard": "^0.1.2",
|
||||
"@vue-js-cron/light": "^4.0.5",
|
||||
@@ -44,7 +44,7 @@
|
||||
"cos-js-sdk-v5": "^1.7.0",
|
||||
"cron-parser": "^4.9.0",
|
||||
"cropperjs": "^1.6.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"dayjs": "^1.11.7",
|
||||
"echarts": "^5.5.1",
|
||||
"highlight.js": "^11.9.0",
|
||||
"humanize-duration": "^3.27.3",
|
||||
@@ -65,8 +65,8 @@
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.27.0",
|
||||
"@certd/pipeline": "^1.27.0",
|
||||
"@certd/lib-iframe": "^1.27.4",
|
||||
"@certd/pipeline": "^1.27.4",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
@@ -94,13 +94,10 @@
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-vue": "^9.23.0",
|
||||
"esno": "^4.7.0",
|
||||
"husky": "^9.0.11",
|
||||
"less": "^4.2.0",
|
||||
"less-loader": "^12.2.0",
|
||||
"lint-staged": "^15.2.2",
|
||||
"postcss": "^8.4.35",
|
||||
"prettier": "3.2.5",
|
||||
"prettier": "3.3.3",
|
||||
"pretty-quick": "^4.0.0",
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^4.13.0",
|
||||
@@ -111,7 +108,7 @@
|
||||
"terser": "^5.29.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslint": "^6.1.3",
|
||||
"typescript": "5.4.2",
|
||||
"typescript": "^5.4.2",
|
||||
"unplugin-vue-define-options": "^1.4.2",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
|
||||
@@ -28,6 +28,7 @@ function createService() {
|
||||
// dataAxios 是 axios 返回数据中的 data
|
||||
const dataAxios = response.data;
|
||||
|
||||
// @ts-ignore
|
||||
if (response.config.unpack === false) {
|
||||
//如果不需要解包
|
||||
return dataAxios;
|
||||
|
||||
@@ -48,6 +48,15 @@ const onUpdate = (value: string) => {
|
||||
if (value === props.modelValue) {
|
||||
return;
|
||||
}
|
||||
const arr: string[] = value.split(" ");
|
||||
if (arr[0] === "*") {
|
||||
arr[0] = "0";
|
||||
}
|
||||
if (arr[1] === "*") {
|
||||
arr[1] = "0";
|
||||
}
|
||||
value = arr.join(" ");
|
||||
|
||||
emit("update:modelValue", value);
|
||||
errorMessage.value = undefined;
|
||||
};
|
||||
|
||||
+21
-3
@@ -15,8 +15,12 @@
|
||||
<fs-values-format v-model="cnameRecord.status" :dict="statusDict" />
|
||||
</td>
|
||||
<td class="center">
|
||||
<a-button v-if="cnameRecord.status !== 'valid'" type="primary" size="small" :loading="loading" @click="doVerify">点击验证</a-button>
|
||||
<div v-else class="helper">不要删除CNAME</div>
|
||||
<template v-if="cnameRecord.status !== 'valid'">
|
||||
<a-button type="primary" size="small" :loading="loading" @click="doVerify">点击验证</a-button>
|
||||
<cname-tip :record="cnameRecord"></cname-tip>
|
||||
</template>
|
||||
|
||||
<div v-else class="helper" title="后续自动申请证书需要">不要删除CNAME</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -27,12 +31,14 @@ import { CnameRecord, GetByDomain } from "/@/components/plugins/cert/domains-ver
|
||||
import { ref, watch } from "vue";
|
||||
import { dict } from "@fast-crud/fast-crud";
|
||||
import * as api from "./api.js";
|
||||
import CnameTip from "./cname-tip.vue";
|
||||
const statusDict = dict({
|
||||
data: [
|
||||
{ label: "待设置CNAME", value: "cname", color: "warning" },
|
||||
{ label: "验证中", value: "validating", color: "blue" },
|
||||
{ label: "验证成功", value: "valid", color: "green" },
|
||||
{ label: "验证失败", value: "failed", color: "red" }
|
||||
{ label: "验证失败", value: "failed", color: "red" },
|
||||
{ label: "验证超时", value: "timeout", color: "red" }
|
||||
]
|
||||
});
|
||||
|
||||
@@ -62,12 +68,24 @@ function onRecordChange() {
|
||||
});
|
||||
}
|
||||
|
||||
let refreshIntervalId: any = null;
|
||||
async function doRefresh() {
|
||||
if (!props.domain) {
|
||||
return;
|
||||
}
|
||||
cnameRecord.value = await GetByDomain(props.domain);
|
||||
onRecordChange();
|
||||
|
||||
if (cnameRecord.value.status === "validating") {
|
||||
if (!refreshIntervalId) {
|
||||
refreshIntervalId = setInterval(async () => {
|
||||
await doRefresh();
|
||||
}, 9000);
|
||||
}
|
||||
} else {
|
||||
clearInterval(refreshIntervalId);
|
||||
refreshIntervalId = null;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<a-tooltip :overlay-style="{ maxWidth: '400px' }">
|
||||
<template #title>
|
||||
<div>
|
||||
<div>多试几次,如果仍然无法验证通过,请按如下步骤排查问题:</div>
|
||||
<div>1. 解析记录应该添加在{{ record.domain }}域名下</div>
|
||||
<div>2. 要添加的是CNAME类型的记录,不是TXT</div>
|
||||
<div>3. 核对记录值是否是:{{ record.recordValue }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<fs-icon class="ml-5 pointer" icon="mingcute:question-line"></fs-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps<{
|
||||
record: any;
|
||||
}>();
|
||||
</script>
|
||||
@@ -64,18 +64,22 @@ const steps = ref<Step[]>([
|
||||
{
|
||||
image: "/static/doc/images/3-add-success.png",
|
||||
title: "流水线创建成功",
|
||||
descriptions: ["此时证书申请任务已经建好", "点击手动触发即可测试证书申请", "接下来演示如何添加部署任务"]
|
||||
descriptions: ["点击手动触发即可申请证书"]
|
||||
},
|
||||
{
|
||||
title: "接下来演示如何自动部署证书",
|
||||
descriptions: ["如果您只需要申请证书,那么到这一步就可以了"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "添加部署证书任务",
|
||||
description: "演示部署到主机上的Nginx",
|
||||
description: "这里演示部署证书到Nginx",
|
||||
items: [
|
||||
{
|
||||
image: "/static/doc/images/5-1-add-host.png",
|
||||
title: "添加nginx部署任务",
|
||||
descriptions: ["演示第一个部署任务,部署到nginx"]
|
||||
title: "添加证书部署任务",
|
||||
descriptions: ["这里演示自动部署证书到nginx", "Certd提供茫茫多的部署插件,满足您的各种部署需求"]
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/5-2-add-host.png",
|
||||
@@ -94,8 +98,8 @@ const steps = ref<Step[]>([
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/5-5-plugin-list.png",
|
||||
title: "还可以添加其他更多部署任务",
|
||||
descriptions: ["插件列表"]
|
||||
title: "本系统提供茫茫多的部署插件",
|
||||
descriptions: ["您可以根据自身需求将证书部署到各种应用和平台"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="tsx" setup>
|
||||
import { computed, reactive } from "vue";
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
@@ -91,24 +91,6 @@ const formState = reactive({
|
||||
code: ""
|
||||
});
|
||||
|
||||
const vipTypeDefine = {
|
||||
free: {
|
||||
title: "基础版",
|
||||
type: "free",
|
||||
privilege: ["证书申请功能无限制", "证书流水线数量10条", "常用的主机、cdn等部署插件"]
|
||||
},
|
||||
plus: {
|
||||
title: "专业版",
|
||||
type: "plus",
|
||||
privilege: ["可加VIP群,需求优先实现", "证书流水线数量无限制", "免配置发邮件功能", "支持宝塔、易盾、群晖、1Panel、cdnfly等部署插件"]
|
||||
},
|
||||
comm: {
|
||||
title: "商业版",
|
||||
type: "comm",
|
||||
privilege: ["拥有专业版所有特权", "允许商用,可修改logo、标题", "数据统计", "插件管理", "多用户无限制", "支持用户支付(敬请期待)"]
|
||||
}
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
async function doActive() {
|
||||
if (!formState.code) {
|
||||
@@ -141,6 +123,58 @@ async function doActive() {
|
||||
const computedSiteId = computed(() => settingStore.installInfo?.siteId);
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
const userStore = useUserStore();
|
||||
|
||||
function goAccount() {
|
||||
Modal.destroyAll();
|
||||
router.push("/sys/account");
|
||||
}
|
||||
|
||||
function openTrialModal() {
|
||||
Modal.destroyAll();
|
||||
|
||||
modal.confirm({
|
||||
title: "7天专业版试用获取",
|
||||
okText: "立即去绑定账号",
|
||||
onOk() {
|
||||
goAccount();
|
||||
},
|
||||
width: 600,
|
||||
content: () => {
|
||||
return (
|
||||
<div class="flex-col mt-10 mb-10">
|
||||
<div>感谢您对开源项目的支持</div>
|
||||
<div>绑定袖手账号后,即可获取7天专业版试用</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openStarModal() {
|
||||
Modal.destroyAll();
|
||||
const goGithub = () => {
|
||||
window.open("https://github.com/certd/certd/");
|
||||
};
|
||||
|
||||
modal.confirm({
|
||||
title: "7天专业版试用获取",
|
||||
okText: "立即去Star",
|
||||
onOk() {
|
||||
goGithub();
|
||||
openTrialModal();
|
||||
},
|
||||
width: 600,
|
||||
content: () => {
|
||||
return (
|
||||
<div class="flex mt-10 mb-10">
|
||||
<div>可以先请您帮忙点个star吗?感谢感谢</div>
|
||||
<img class="ml-5" src="https://img.shields.io/github/stars/certd/certd?logo=github" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openUpgrade() {
|
||||
if (!userStore.isAdmin) {
|
||||
message.info("仅限管理员操作");
|
||||
@@ -155,7 +189,31 @@ function openUpgrade() {
|
||||
title = "续期专业版/升级商业版";
|
||||
}
|
||||
|
||||
modal.confirm({
|
||||
const vipTypeDefine = {
|
||||
free: {
|
||||
title: "基础版",
|
||||
type: "free",
|
||||
privilege: ["证书申请功能无限制", "证书流水线数量10条", "常用的主机、cdn等部署插件"]
|
||||
},
|
||||
plus: {
|
||||
title: "专业版",
|
||||
type: "plus",
|
||||
privilege: ["可加VIP群,需求优先实现", "证书流水线数量无限制", "免配置发邮件功能", "支持宝塔、易盾、群晖、1Panel、cdnfly等部署插件"],
|
||||
trial: {
|
||||
title: "7天试用",
|
||||
click: () => {
|
||||
openStarModal();
|
||||
}
|
||||
}
|
||||
},
|
||||
comm: {
|
||||
title: "商业版",
|
||||
type: "comm",
|
||||
privilege: ["拥有专业版所有特权", "允许商用,可修改logo、标题", "数据统计", "插件管理", "多用户无限制", "支持用户支付(敬请期待)"]
|
||||
}
|
||||
};
|
||||
|
||||
const modalRef = modal.confirm({
|
||||
title,
|
||||
async onOk() {
|
||||
return await doActive();
|
||||
@@ -193,7 +251,16 @@ function openUpgrade() {
|
||||
slots.push(
|
||||
<a-col span={8}>
|
||||
<div class={vipBlockClass}>
|
||||
<h3 class="block-header">{item.title}</h3>
|
||||
<h3 class="block-header">
|
||||
<span>{item.title}</span>
|
||||
{item.trial && (
|
||||
<span class="trial">
|
||||
<a-tooltip title={item.trial.message}>
|
||||
<a onClick={item.trial.click}>{item.trial.title}</a>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
)}
|
||||
</h3>
|
||||
<ul>
|
||||
{item.privilege.map((p: string) => (
|
||||
<li>
|
||||
@@ -226,6 +293,9 @@ function openUpgrade() {
|
||||
没有激活码?
|
||||
{activationCodeGetWay}
|
||||
</div>
|
||||
<div class="mt-10">
|
||||
激活码使用过一次之后,不可再次使用,如果要更换站点,请<a onClick={goAccount}>绑定账号</a>,然后"转移VIP"即可
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -263,6 +333,12 @@ function openUpgrade() {
|
||||
}
|
||||
.block-header {
|
||||
padding: 0px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.trial {
|
||||
font-size: 12px;
|
||||
font-wight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<script lang="ts">
|
||||
import i18n from "../../../i18n";
|
||||
import { computed, inject } from "vue";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
export default {
|
||||
name: "FsLocale",
|
||||
setup() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { ref, watch, onMounted, onUnmounted, resolveComponent, nextTick, defineComponent } from "vue";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import BScroll from "better-scroll";
|
||||
import "./index.less";
|
||||
import { utils } from "@fast-crud/fast-crud";
|
||||
|
||||
@@ -165,7 +165,7 @@ onMounted(async () => {
|
||||
await settingStore.checkUrlBound();
|
||||
});
|
||||
|
||||
function menuClick(menu) {
|
||||
function menuClick(menu: any) {
|
||||
routerUtils.open(menu.path);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
function copyList(originList: any, newList: any, options: any, parentId?: any) {
|
||||
for (const item of originList) {
|
||||
const newItem: any = _.cloneDeep(item);
|
||||
|
||||
@@ -3,7 +3,7 @@ import cascaderData from "./cascader-data";
|
||||
import pcaDataLittle from "./pca-data-little";
|
||||
// @ts-ignore
|
||||
import { TreeNodesLazyLoader, getPcaData } from "./pcas-data";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
const openStatus = [
|
||||
{ value: "1", label: "打开", color: "success", icon: "ion:radio-button-on" },
|
||||
{ value: "2", label: "停止", color: "cyan" },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
export async function getPcasData() {
|
||||
// @ts-ignore
|
||||
const pcasData = () => import("china-division/dist/pcas-code.json");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mock } from "../api/service";
|
||||
import * as tools from "../api/tools";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { utils } from "@fast-crud/fast-crud";
|
||||
// @ts-ignore
|
||||
const commonMocks: any = import.meta.glob("./common/mock.*.[j|t]s", { eager: true });
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
import "@fast-crud/fast-extends/dist/style.css";
|
||||
import UiAntdv from "@fast-crud/ui-antdv4";
|
||||
import "@fast-crud/ui-antdv4/dist/style.css";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { useCrudPermission } from "../permission";
|
||||
import { App } from "vue";
|
||||
import { notification } from "ant-design-vue";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { usePermission } from "/@/plugin/permission";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
|
||||
export type UseCrudPermissionExtraProps = {
|
||||
hasActionPermission: (action: string) => boolean;
|
||||
|
||||
@@ -69,7 +69,8 @@ router.afterEach((to: any) => {
|
||||
// }
|
||||
pageStore.open(to);
|
||||
// 更改标题
|
||||
site.title(to.meta.title);
|
||||
const settingStore = useSettingStore();
|
||||
site.title(to.meta.title, settingStore.siteInfo.title);
|
||||
|
||||
//修改左侧边栏
|
||||
const matched = to.matched;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import LayoutPass from "/src/layout/layout-pass.vue";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { outsideResource } from "./source/outside";
|
||||
import { headerResource } from "./source/header";
|
||||
import { frameworkResource } from "./source/framework";
|
||||
@@ -40,11 +40,11 @@ function transformOneResource(resource: any, parent: any) {
|
||||
if (route.component == null) {
|
||||
route.component = LayoutPass;
|
||||
}
|
||||
if (route?.meta?.cache !== false) {
|
||||
if (route?.meta?.cache !== true) {
|
||||
if (route.meta == null) {
|
||||
route.meta = {};
|
||||
}
|
||||
route.meta.cache = true;
|
||||
route.meta.cache = false;
|
||||
}
|
||||
}
|
||||
if (resource.children) {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { sysResources } from "/@/router/source/modules/sys";
|
||||
|
||||
export const certdResources = [
|
||||
{
|
||||
title: "证书自动化",
|
||||
@@ -17,7 +15,8 @@ export const certdResources = [
|
||||
path: "/certd/pipeline",
|
||||
component: "/certd/pipeline/index.vue",
|
||||
meta: {
|
||||
icon: "ion:analytics-sharp"
|
||||
icon: "ion:analytics-sharp",
|
||||
cache: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -35,7 +34,8 @@ export const certdResources = [
|
||||
path: "/certd/history",
|
||||
component: "/certd/history/index.vue",
|
||||
meta: {
|
||||
icon: "ion:timer-outline"
|
||||
icon: "ion:timer-outline",
|
||||
cache: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -45,7 +45,8 @@ export const certdResources = [
|
||||
component: "/certd/access/index.vue",
|
||||
meta: {
|
||||
icon: "ion:disc-outline",
|
||||
auth: true
|
||||
auth: true,
|
||||
cache: true
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -27,16 +27,7 @@ export const sysResources = [
|
||||
permission: "sys:auth:user:view"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "用户管理",
|
||||
name: "UserManager",
|
||||
path: "/sys/authority/user",
|
||||
component: "/sys/authority/user/index.vue",
|
||||
meta: {
|
||||
icon: "ion:person-outline",
|
||||
permission: "sys:auth:user:view"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: "系统设置",
|
||||
name: "SysSettings",
|
||||
@@ -92,7 +83,7 @@ export const sysResources = [
|
||||
const settingStore = useSettingStore();
|
||||
return settingStore.isComm;
|
||||
},
|
||||
icon: "ion:document-text-outline",
|
||||
icon: "ion:menu",
|
||||
permission: "sys:settings:view"
|
||||
}
|
||||
},
|
||||
@@ -168,7 +159,17 @@ export const sysResources = [
|
||||
icon: "ion:people-outline",
|
||||
permission: "sys:auth:role:view"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "用户管理",
|
||||
name: "UserManager",
|
||||
path: "/sys/authority/user",
|
||||
component: "/sys/authority/user/index.vue",
|
||||
meta: {
|
||||
icon: "ion:person-outline",
|
||||
permission: "sys:auth:user:view"
|
||||
}
|
||||
},
|
||||
|
||||
// {
|
||||
// title: "商业版设置",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineStore } from "pinia";
|
||||
// @ts-ignore
|
||||
import { frameworkMenus, headerMenus, filterMenus, findMenus } from "/src/router/resolve";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { mitter } from "/src/utils/util.mitt";
|
||||
//监听注销事件
|
||||
mitter.on("app.logout", () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { Modal, notification, theme } from "ant-design-vue";
|
||||
import _, { cloneDeep } from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
// @ts-ignore
|
||||
import { LocalStorage } from "/src/utils/util.storage";
|
||||
|
||||
@@ -9,8 +9,6 @@ import { HeaderMenus, PlusInfo, SiteEnv, SiteInfo, SysInstallInfo, SysPublicSett
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import { mitter } from "/@/utils/util.mitt";
|
||||
import { env } from "/@/utils/util.env";
|
||||
import { toRef } from "vue";
|
||||
import { util } from "/@/utils";
|
||||
|
||||
export type ThemeToken = {
|
||||
token: {
|
||||
@@ -122,8 +120,10 @@ export const useSettingStore = defineStore({
|
||||
};
|
||||
return vipLabelMap[this.plusInfo?.vipType || "free"];
|
||||
},
|
||||
// @ts-ignore
|
||||
getHeaderMenus() {
|
||||
return this.headerMenus?.menus || [];
|
||||
// @ts-ignore
|
||||
return this.headerMenus?.menus || { menus: [] };
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
||||
@@ -82,6 +82,10 @@ export const useUserStore = defineStore({
|
||||
return userInfo;
|
||||
},
|
||||
|
||||
async loadUserInfo() {
|
||||
await this.getUserInfoAction();
|
||||
},
|
||||
|
||||
async onLoginSuccess(loginData: any) {
|
||||
await this.getUserInfoAction();
|
||||
const userInfo = await this.getUserInfoAction();
|
||||
|
||||
@@ -158,6 +158,9 @@ h1, h2, h3, h4, h5, h6 {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.p-20 {
|
||||
padding: 20px;
|
||||
}
|
||||
.ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { asyncCompute, compute } from "@fast-crud/fast-crud";
|
||||
import { computed } from "vue";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as sites from "./util.site";
|
||||
import * as storages from "./util.storage";
|
||||
import commons from "./util.common";
|
||||
import * as mitt from "./util.mitt";
|
||||
import router from "/util.router";
|
||||
import { routerUtils } from "./util.router";
|
||||
import { treeUtils } from "./util.tree";
|
||||
export const util = {
|
||||
...envs,
|
||||
@@ -11,6 +11,6 @@ export const util = {
|
||||
...storages,
|
||||
...commons,
|
||||
...mitt,
|
||||
...router,
|
||||
router: routerUtils,
|
||||
tree: treeUtils
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
export default {
|
||||
arrayToMap(array: any) {
|
||||
if (!array) {
|
||||
@@ -33,5 +33,12 @@ export default {
|
||||
|
||||
async sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
},
|
||||
|
||||
maxLength(str?: string, length = 100) {
|
||||
if (str) {
|
||||
return str.length > length ? str.slice(0, length) + "..." : str;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-ignore
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
|
||||
export class EnvConfig {
|
||||
MODE: string = import.meta.env.MODE;
|
||||
|
||||
@@ -4,8 +4,8 @@ export const site = {
|
||||
* @description 更新标题
|
||||
* @param titleText
|
||||
*/
|
||||
title: function (titleText: string) {
|
||||
const processTitle = env.TITLE || "FsAdmin";
|
||||
title: function (titleText: string, baseTitle?: string) {
|
||||
const processTitle = baseTitle || env.TITLE || "Certd";
|
||||
window.document.title = `${processTitle}${titleText ? ` | ${titleText}` : ""}`;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted } from "vue";
|
||||
import { defineComponent, onActivated, onMounted } from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { createAccessApi } from "/@/views/certd/access/api";
|
||||
@@ -26,6 +26,9 @@ export default defineComponent({
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
return {
|
||||
crudBinding,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, Edi
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import { message } from "ant-design-vue";
|
||||
|
||||
import CnameTip from "/@/components/plugins/cert/domains-verify-plan-editor/cname-tip.vue";
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
@@ -126,11 +126,24 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
component: {
|
||||
onDictChange: ({ form, dict }: any) => {
|
||||
if (!form.cnameProviderId) {
|
||||
const item = dict.data.find((item: any) => item.isDefault);
|
||||
const list = dict.data.filter((item: any) => {
|
||||
return !item.disabled;
|
||||
});
|
||||
let item = list.find((item: any) => item.isDefault);
|
||||
if (!item && list.length > 0) {
|
||||
item = list[0];
|
||||
}
|
||||
if (item) {
|
||||
form.cnameProviderId = item.id;
|
||||
}
|
||||
}
|
||||
},
|
||||
renderLabel(item: any) {
|
||||
if (item.title) {
|
||||
return `${item.domain}<${item.title}>`;
|
||||
} else {
|
||||
return item.domain;
|
||||
}
|
||||
}
|
||||
},
|
||||
helper: {
|
||||
@@ -139,15 +152,26 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
crudExpose.getFormWrapperRef().close();
|
||||
};
|
||||
return (
|
||||
<router-link to={"/sys/cname/provider"} onClick={closeForm}>
|
||||
前往设置CNAME服务
|
||||
</router-link>
|
||||
<div>
|
||||
默认提供公共CNAME服务,您还可以
|
||||
<router-link to={"/sys/cname/provider"} onClick={closeForm}>
|
||||
自定义CNAME服务
|
||||
</router-link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
column: {
|
||||
show: false
|
||||
width: 120,
|
||||
align: "center",
|
||||
cellRender({ value }) {
|
||||
if (value < 0) {
|
||||
return <a-tag color={"green"}>公共CNAME</a-tag>;
|
||||
} else {
|
||||
return <a-tag color={"blue"}>自定义CNAME</a-tag>;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
status: {
|
||||
@@ -158,7 +182,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
{ label: "待设置CNAME", value: "cname", color: "warning" },
|
||||
{ label: "验证中", value: "validating", color: "blue" },
|
||||
{ label: "验证成功", value: "valid", color: "green" },
|
||||
{ label: "验证失败", value: "failed", color: "red" }
|
||||
{ label: "验证失败", value: "failed", color: "red" },
|
||||
{ label: "验证超时", value: "timeout", color: "red" }
|
||||
]
|
||||
}),
|
||||
addForm: {
|
||||
@@ -183,6 +208,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
if (row.status === "valid") {
|
||||
return "-";
|
||||
}
|
||||
|
||||
async function doVerify() {
|
||||
row._validating_ = true;
|
||||
try {
|
||||
@@ -190,7 +216,13 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
if (res === true) {
|
||||
message.success("验证成功");
|
||||
row.status = "valid";
|
||||
} else if (res === false) {
|
||||
message.success("验证超时");
|
||||
row.status = "timeout";
|
||||
} else {
|
||||
message.success("开始验证,请耐心等待");
|
||||
}
|
||||
await crudExpose.doRefresh();
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
message.error(e.message);
|
||||
@@ -199,9 +231,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
}
|
||||
}
|
||||
return (
|
||||
<a-button onClick={doVerify} loading={row._validating_} size={"small"} type={"primary"}>
|
||||
点击验证
|
||||
</a-button>
|
||||
<div>
|
||||
<a-button onClick={doVerify} loading={row._validating_} size={"small"} type={"primary"}>
|
||||
点击验证
|
||||
</a-button>
|
||||
<CnameTip record={row} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
},
|
||||
pipelineTitle: {
|
||||
title: "流水线名称",
|
||||
type: "link",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
component: {
|
||||
@@ -136,7 +136,13 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
}
|
||||
},
|
||||
column: {
|
||||
width: 300
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
createTime: {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from "vue";
|
||||
import {onActivated, onMounted} from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
@@ -47,5 +47,8 @@ const handleBatchDelete = () => {
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
</script>
|
||||
<style lang="less"></style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { request } from "/src/api/service";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { PluginConfigBean, PluginSysSetting } from "/@/views/sys/plugin/api";
|
||||
const apiPrefix = "/pi/plugin";
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ export default function (certPluginGroup: PluginGroup, formWrapperRef: any): Cre
|
||||
vModel: "modelValue",
|
||||
placeholder: "0 0 4 * * *"
|
||||
},
|
||||
helper: "点击上面的按钮,选择每天几点几分定时执行,后面的分秒都要选择0。\n建议设置为每天触发一次,证书未到期之前任务会跳过,不会重复执行",
|
||||
helper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次,证书未到期之前任务会跳过,不会重复执行",
|
||||
order: 100
|
||||
}
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { useColumns, useExpose } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud.jsx";
|
||||
import { ref } from "vue";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import * as api from "../api.plugin";
|
||||
import { PluginGroup, PluginGroups } from "/@/views/certd/pipeline/pipeline/type";
|
||||
export default {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { env } from "/@/utils/util.env";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import dayjs from "dayjs";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { useModal } from "/@/use/use-modal";
|
||||
import CertView from "./cert-view.vue";
|
||||
import { eachStages } from "./utils";
|
||||
@@ -348,6 +348,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
type: "link",
|
||||
search: {
|
||||
show: true,
|
||||
title: "关键字",
|
||||
component: {
|
||||
name: "a-input"
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useRoute } from "vue-router";
|
||||
import { PipelineDetail, PipelineOptions, PluginGroups, RunHistory } from "./pipeline/type";
|
||||
import { TourProps } from "ant-design-vue";
|
||||
import { LocalStorage } from "/@/utils/util.storage";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
|
||||
defineOptions({
|
||||
name: "PipelineDetail"
|
||||
@@ -124,7 +125,11 @@ function useTour() {
|
||||
|
||||
const { tour, tourHandleOpen } = useTour();
|
||||
|
||||
const userStore = useUserStore();
|
||||
async function onLoaded(pipeline: PipelineDetail) {
|
||||
if (pipeline.pipeline?.userId !== userStore.getUserInfo?.id) {
|
||||
return;
|
||||
}
|
||||
const count = LocalStorage.get("pipeline-count") ?? 0;
|
||||
if (count > 1) {
|
||||
return;
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, onMounted } from "vue";
|
||||
import { defineComponent, ref, onMounted, onActivated } from "vue";
|
||||
import { useCrud, useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { useExpose } from "@fast-crud/fast-crud";
|
||||
import PiCertdForm from "./certd-form/index.vue";
|
||||
export default defineComponent({
|
||||
name: "PipelineManager1",
|
||||
name: "PipelineManager",
|
||||
components: { PiCertdForm },
|
||||
setup() {
|
||||
const certdFormRef = ref();
|
||||
@@ -34,6 +34,10 @@ export default defineComponent({
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
return {
|
||||
crudBinding,
|
||||
crudRef,
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@
|
||||
<script lang="ts">
|
||||
import { Modal } from "ant-design-vue";
|
||||
import { ref } from "vue";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { nanoid } from "nanoid";
|
||||
import PiNotificationFormEmail from "./pi-notification-form-email.vue";
|
||||
|
||||
|
||||
+2
-2
@@ -108,7 +108,7 @@
|
||||
<script lang="tsx">
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import { computed, inject, Ref, ref, watch, provide } from "vue";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { nanoid } from "nanoid";
|
||||
import { CopyOutlined } from "@ant-design/icons-vue";
|
||||
import { PluginGroups } from "/@/views/certd/pipeline/pipeline/type";
|
||||
@@ -230,7 +230,7 @@ export default {
|
||||
}
|
||||
const { doComputed } = useCompute();
|
||||
const currentPlugin = doComputed(() => {
|
||||
return currentPluginDefine.value;
|
||||
return currentPluginDefine.value || {};
|
||||
}, getContext);
|
||||
const changeCurrentPlugin = async (step: any) => {
|
||||
const stepType = step.type;
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { provide, Ref, ref } from "vue";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { nanoid } from "nanoid";
|
||||
import PiStepForm from "../step-form/index.vue";
|
||||
import { Modal } from "ant-design-vue";
|
||||
|
||||
+27
-2
@@ -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";
|
||||
|
||||
@@ -61,6 +61,7 @@ export default {
|
||||
if (currentHistory?.value?.logs != null) {
|
||||
node.logs = computed(() => {
|
||||
if (currentHistory?.value?.logs && currentHistory.value?.logs[node.node.id] != null) {
|
||||
console.log("log changed", node.node.id);
|
||||
const logs = currentHistory.value?.logs[node.node.id];
|
||||
const list = [];
|
||||
for (let log of logs) {
|
||||
@@ -78,6 +79,30 @@ export default {
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return node.logs.value.length;
|
||||
},
|
||||
async () => {
|
||||
let el = document.querySelector(`.pi-task-view-logs.${node.node.id}`);
|
||||
console.log("el", el);
|
||||
//判断当前是否在底部
|
||||
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
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -58,7 +58,7 @@
|
||||
name: 'cron-editor',
|
||||
vModel: 'modelValue'
|
||||
},
|
||||
helper: '点击上面的按钮,选择每天几点几分定时执行,后面的分秒都要选择0。\n建议设置为每天触发一次,证书未到期之前任务会跳过,不会重复执行',
|
||||
helper: '点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次,证书未到期之前任务会跳过,不会重复执行',
|
||||
rules: [{ required: true, message: '此项必填' }]
|
||||
}"
|
||||
/>
|
||||
@@ -77,7 +77,7 @@
|
||||
<script>
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import { inject, ref } from "vue";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { nanoid } from "nanoid";
|
||||
export default {
|
||||
name: "PiTriggerForm",
|
||||
|
||||
@@ -260,7 +260,7 @@ import PiNotificationForm from "./component/notification-form/index.vue";
|
||||
import PiTaskView from "./component/task-view/index.vue";
|
||||
import PiStatusShow from "./component/status-show.vue";
|
||||
import VDraggable from "vuedraggable";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { message, Modal, notification, TourProps } from "ant-design-vue";
|
||||
import { nanoid } from "nanoid";
|
||||
import { PipelineDetail, PipelineOptions, PluginGroups, RunHistory } from "./type";
|
||||
|
||||
@@ -5,6 +5,7 @@ export type StatusEnumItem = {
|
||||
icon: string;
|
||||
spin?: boolean;
|
||||
iconSpin?: boolean;
|
||||
iconColor?: string;
|
||||
};
|
||||
export type StatusEnumType = {
|
||||
[key: string]: StatusEnumItem;
|
||||
|
||||
@@ -205,6 +205,7 @@ async function loadPluginGroups() {
|
||||
|
||||
const pluginGroups = ref();
|
||||
onMounted(async () => {
|
||||
await userStore.loadUserInfo();
|
||||
await loadLatestVersion();
|
||||
await loadCount();
|
||||
await loadPluginGroups();
|
||||
@@ -265,6 +266,7 @@ onMounted(async () => {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: keep-all;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,9 @@ const iframeSrcRef = computed(() => {
|
||||
|
||||
type SubjectInfo = {
|
||||
subjectId: string;
|
||||
installTime?: number;
|
||||
installAt?: number;
|
||||
vipType?: string;
|
||||
expiresTime?: number;
|
||||
expiresAt?: number;
|
||||
};
|
||||
onMounted(() => {
|
||||
const iframeClient = new IframeClient(iframeRef.value, (e: any) => {
|
||||
@@ -47,17 +47,17 @@ onMounted(() => {
|
||||
description: e.message
|
||||
});
|
||||
});
|
||||
iframeClient.register("getSubjectInfo", async (req) => {
|
||||
iframeClient.register("getSubjectInfo", async (req: any) => {
|
||||
const subjectInfo: SubjectInfo = {
|
||||
subjectId: settingStore.installInfo.siteId,
|
||||
installTime: settingStore.installInfo.installTime,
|
||||
installAt: settingStore.installInfo.installTime,
|
||||
vipType: settingStore.plusInfo.vipType || "free",
|
||||
expiresTime: settingStore.plusInfo.expireTime
|
||||
expiresAt: settingStore.plusInfo.expireTime
|
||||
};
|
||||
return subjectInfo;
|
||||
});
|
||||
|
||||
let preBindUserId = null;
|
||||
let preBindUserId: any = null;
|
||||
iframeClient.register("preBindUser", async (req) => {
|
||||
const userId = req.data.userId;
|
||||
preBindUserId = userId;
|
||||
@@ -75,7 +75,7 @@ onMounted(() => {
|
||||
|
||||
iframeClient.register("updateLicense", async (req) => {
|
||||
await api.UpdateLicense(req.data);
|
||||
await userStore.reInit();
|
||||
await settingStore.init();
|
||||
notification.success({
|
||||
message: "更新成功",
|
||||
description: "专业版/商业版已激活"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { utils } from "@fast-crud/fast-crud";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
import { computed, defineComponent, ref } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
@@ -13,6 +13,8 @@ export type SysPublicSetting = {
|
||||
export type SysPrivateSetting = {
|
||||
httpProxy?: string;
|
||||
httpsProxy?: string;
|
||||
dnsResultOrder?: string;
|
||||
commonCnameEnabled?: boolean;
|
||||
};
|
||||
|
||||
export const SettingKeys = {
|
||||
@@ -52,6 +54,14 @@ export async function EmailSettingsGet() {
|
||||
});
|
||||
}
|
||||
|
||||
export async function EmailSettingsSave(setting: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/saveEmailSettings",
|
||||
method: "post",
|
||||
data: setting
|
||||
});
|
||||
}
|
||||
|
||||
export async function stopOtherUserTimer() {
|
||||
return await request({
|
||||
url: apiPrefix + "/stopOtherUserTimer",
|
||||
|
||||
@@ -8,16 +8,17 @@
|
||||
</template>
|
||||
|
||||
<div class="flex-o">
|
||||
<div v-if="!formState.usePlus" class="email-form">
|
||||
<a-form
|
||||
:model="formState"
|
||||
name="basic"
|
||||
:label-col="{ span: 8 }"
|
||||
:wrapper-col="{ span: 16 }"
|
||||
autocomplete="off"
|
||||
@finish="onFinish"
|
||||
@finish-failed="onFinishFailed"
|
||||
>
|
||||
<a-form
|
||||
:model="formState"
|
||||
name="basic"
|
||||
:label-col="{ span: 8 }"
|
||||
:wrapper-col="{ span: 16 }"
|
||||
autocomplete="off"
|
||||
class="email-form-box"
|
||||
@finish="onFinish"
|
||||
@finish-failed="onFinishFailed"
|
||||
>
|
||||
<div v-if="!formState.usePlus" class="email-form">
|
||||
<a-form-item label="使用自定义邮件服务器"> </a-form-item>
|
||||
<a-form-item label="SMTP域名" name="host" :rules="[{ required: true, message: '请输入smtp域名或ip' }]">
|
||||
<a-input v-model:value="formState.host" />
|
||||
@@ -41,32 +42,31 @@
|
||||
<a-switch v-model:checked="formState.secure" />
|
||||
<div class="helper">ssl和非ssl的smtp端口是不一样的,注意修改端口</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="忽略证书校验" name="tls.rejectUnauthorized">
|
||||
<a-form-item label="忽略证书校验" :name="['tls', 'rejectUnauthorized']">
|
||||
<a-switch v-model:checked="formState.tls.rejectUnauthorized" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
|
||||
<a-button type="primary" html-type="submit">保存</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<div class="email-form">
|
||||
<a-form :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
|
||||
<a-form-item label="使用官方邮件服务器">
|
||||
</div>
|
||||
<div class="email-form">
|
||||
<a-form-item label="使用官方邮件服务器" name="usePlus">
|
||||
<div class="flex-o">
|
||||
<a-switch v-model:checked="formState.usePlus" :disabled="!settingStore.isPlus" @change="onUsePlusChanged" />
|
||||
<vip-button class="ml-5" mode="button"></vip-button>
|
||||
</div>
|
||||
<div class="helper">使用官方邮箱服务器直接发邮件,免除繁琐的配置</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
</a-form>
|
||||
</div>
|
||||
<div class="email-form">
|
||||
<a-form :model="testFormState" name="basic" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onTestSend">
|
||||
<a-form-item label="测试收件邮箱" name="receiver" :rules="[{ required: true, message: '请输入测试收件邮箱' }]">
|
||||
<a-input v-model:value="testFormState.receiver" />
|
||||
<div class="helper">发送失败???可以试试使用官方邮件服务器↗↗↗↗↗↗↗↗</div>
|
||||
<div class="helper">发送失败???<a href="https://certd.docmirror.cn/guide/use/email/" target="_blank">邮件配置帮助文档</a></div>
|
||||
<div class="helper">您还可以试试使用官方邮件服务器↗↗↗↗↗↗↗↗</div>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
|
||||
<a-button type="primary" :loading="testFormState.loading" html-type="submit">测试</a-button>
|
||||
@@ -79,11 +79,11 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue";
|
||||
import * as api from "../api";
|
||||
import { SettingKeys } from "../api";
|
||||
import { EmailSettingsSave, SettingKeys } from "../api";
|
||||
import * as emailApi from "./api.email";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { useSettingStore } from "/src/store/modules/settings";
|
||||
import _ from "lodash-es";
|
||||
import * as _ from "lodash-es";
|
||||
defineOptions({
|
||||
name: "EmailSetting"
|
||||
});
|
||||
@@ -122,7 +122,7 @@ load();
|
||||
|
||||
const onFinish = async (form: any) => {
|
||||
console.log("Success:", form);
|
||||
await api.SettingsSave(SettingKeys.SysEmail, form);
|
||||
await api.EmailSettingsSave(form);
|
||||
notification.success({
|
||||
message: "保存成功"
|
||||
});
|
||||
@@ -133,7 +133,7 @@ const onFinishFailed = (errorInfo: any) => {
|
||||
};
|
||||
|
||||
async function onUsePlusChanged() {
|
||||
await api.SettingsSave(SettingKeys.SysEmail, formState);
|
||||
await api.EmailSettingsSave(formState);
|
||||
}
|
||||
|
||||
interface TestFormState {
|
||||
@@ -161,6 +161,9 @@ const settingStore = useSettingStore();
|
||||
|
||||
<style lang="less">
|
||||
.page-setting-email {
|
||||
.email-form-box {
|
||||
display: flex;
|
||||
}
|
||||
.email-form {
|
||||
width: 500px;
|
||||
margin: 20px;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<a-form-item label="管理其他用户流水线" :name="['public', 'managerOtherUserPipeline']">
|
||||
<a-switch v-model:checked="formState.public.managerOtherUserPipeline" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="ICP备案号" :name="['public', 'icpNo']">
|
||||
<a-input v-model:value="formState.public.icpNo" placeholder="粤ICP备xxxxxxx号" />
|
||||
</a-form-item>
|
||||
@@ -37,8 +38,22 @@
|
||||
<a-input v-model:value="formState.private.httpsProxy" placeholder="http://192.168.1.2:18010/" />
|
||||
<a-button class="ml-5" type="primary" :loading="testProxyLoading" title="保存后,再点击测试" @click="testProxy">测试</a-button>
|
||||
</div>
|
||||
<div class="helper">一般这两个代理填一样的</div>
|
||||
<div class="helper">一般这两个代理填一样的,保存后再测试</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="双栈网络" :name="['private', 'dnsResultOrder']">
|
||||
<a-select v-model:value="formState.private.dnsResultOrder">
|
||||
<a-select-option value="verbatim">默认</a-select-option>
|
||||
<a-select-option value="ipv4first">IPV4优先</a-select-option>
|
||||
<a-select-option value="ipv6first">IPV6优先</a-select-option>
|
||||
</a-select>
|
||||
<div class="helper">如果选择IPv6优先,需要在docker-compose.yaml中启用ipv6</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="启用公共CNAME服务" :name="['private', 'commonCnameEnabled']">
|
||||
<a-switch v-model:checked="formState.private.commonCnameEnabled" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
|
||||
<a-button :loading="saveLoading" type="primary" html-type="submit">保存</a-button>
|
||||
</a-form-item>
|
||||
@@ -47,13 +62,14 @@
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
<script setup lang="tsx">
|
||||
import { reactive, ref } from "vue";
|
||||
import * as api from "./api";
|
||||
import { SysSettings } from "./api";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import { merge } from "lodash-es";
|
||||
import { util } from "/@/utils";
|
||||
|
||||
defineOptions({
|
||||
name: "SysSettings"
|
||||
@@ -111,7 +127,25 @@ async function testProxy() {
|
||||
testProxyLoading.value = true;
|
||||
try {
|
||||
const res = await api.TestProxy();
|
||||
const content = `测试google:${res.google === true ? "成功" : "失败" + res.google},测试百度:${res.baidu === true ? "成功" : "失败:" + res.baidu}`;
|
||||
let success = true;
|
||||
if (res.google !== true || res.baidu !== true) {
|
||||
success = false;
|
||||
}
|
||||
const content = () => {
|
||||
return (
|
||||
<div>
|
||||
<div>Google: {res.google === true ? "成功" : util.maxLength(res.google)}</div>
|
||||
<div>Baidu: {res.baidu === true ? "成功" : util.maxLength(res.google)}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
if (!success) {
|
||||
notification.error({
|
||||
message: "测试失败",
|
||||
description: content
|
||||
});
|
||||
return;
|
||||
}
|
||||
notification.success({
|
||||
message: "测试完成",
|
||||
description: content
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
// 这样就可以对 `this` 上的数据属性进行更严格的推断`
|
||||
"noImplicitAny": true,
|
||||
|
||||
@@ -17,7 +17,6 @@ process.env.VITE_APP_BUILD_TIME = require("dayjs")().format("YYYY-M-D HH:mm:ss")
|
||||
|
||||
import { theme } from "ant-design-vue";
|
||||
import * as https from "node:https";
|
||||
|
||||
const { defaultAlgorithm, defaultSeed } = theme;
|
||||
|
||||
const mapToken = defaultAlgorithm(defaultSeed);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
LEGO_VERSION=4.19.2
|
||||
@@ -22,18 +22,11 @@ typeorm:
|
||||
default:
|
||||
database: './data/db-comm.sqlite'
|
||||
|
||||
#plus:
|
||||
# server:
|
||||
# baseUrls: ['https://api.ai.handsfree.work', 'https://api.ai.docmirror.cn']
|
||||
|
||||
#
|
||||
#account:
|
||||
# server:
|
||||
# baseUrl: 'https://ai.handsfree.work/subject'
|
||||
#PLUS_SERVER_BASE_URL=http://127.0.0.1:11007
|
||||
|
||||
|
||||
plus:
|
||||
server:
|
||||
baseUrls: ['http://127.0.0.1:11007']
|
||||
|
||||
account:
|
||||
server:
|
||||
|
||||
@@ -22,13 +22,6 @@ typeorm:
|
||||
default:
|
||||
database: './data/db-comm-pro.sqlite'
|
||||
|
||||
plus:
|
||||
server:
|
||||
baseUrls: ['https://api.ai.handsfree.work', 'https://api.ai.docmirror.cn']
|
||||
|
||||
account:
|
||||
server:
|
||||
baseUrl: 'https://ai.handsfree.work/subject'
|
||||
|
||||
#
|
||||
#plus:
|
||||
|
||||
@@ -9,19 +9,9 @@
|
||||
# dataSource:
|
||||
# default:
|
||||
# database: './data/db.sqlite'
|
||||
plus:
|
||||
server:
|
||||
baseUrls: ['https://api.ai.handsfree.work', 'https://api.ai.docmirror.cn']
|
||||
|
||||
account:
|
||||
server:
|
||||
baseUrl: 'https://ai.handsfree.work/subject'
|
||||
baseUrl: 'https://app.handfree.work/subject'
|
||||
|
||||
|
||||
#plus:
|
||||
# server:
|
||||
# baseUrls: ['http://127.0.0.1:11007']
|
||||
#
|
||||
#account:
|
||||
# server:
|
||||
# baseUrl: 'http://127.0.0.1:1017/subject'
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# key: ./data/ssl/cert.key
|
||||
# cert: ./data/ssl/cert.crt
|
||||
#plus:
|
||||
# server:
|
||||
# baseUrl: 'http://127.0.0.1:11007'
|
||||
|
||||
|
||||
typeorm:
|
||||
dataSource:
|
||||
default:
|
||||
database: './data/db-new.sqlite'
|
||||
|
||||
|
||||
#plus:
|
||||
# server:
|
||||
# baseUrls: ['http://127.0.0.1:11007']
|
||||
#
|
||||
#account:
|
||||
# server:
|
||||
# baseUrl: 'http://127.0.0.1:1017/subject'
|
||||
@@ -0,0 +1,29 @@
|
||||
# key: ./data/ssl/cert.key
|
||||
# cert: ./data/ssl/cert.crt
|
||||
#plus:
|
||||
# server:
|
||||
# baseUrl: 'http://127.0.0.1:11007'
|
||||
|
||||
#flyway:
|
||||
# scriptDir: './db/migration-pg'
|
||||
|
||||
#typeorm:
|
||||
# dataSource:
|
||||
# default:
|
||||
# type: postgres
|
||||
# host: localhost
|
||||
# port: 5433
|
||||
# username: postgres
|
||||
# password: root
|
||||
# database: postgres
|
||||
|
||||
typeorm:
|
||||
dataSource:
|
||||
default:
|
||||
database: './data/db-plus-dev-1.sqlite'
|
||||
|
||||
# plus server: 'http://127.0.0.1:11007'
|
||||
|
||||
account:
|
||||
server:
|
||||
baseUrl: 'http://127.0.0.1:1017/subject'
|
||||
@@ -7,9 +7,6 @@ typeorm:
|
||||
logging: false
|
||||
|
||||
|
||||
plus:
|
||||
server:
|
||||
baseUrls: ['https://api.ai.handsfree.work', 'https://api.ai.docmirror.cn']
|
||||
account:
|
||||
server:
|
||||
baseUrl: 'https://ai.handsfree.work/subject'
|
||||
baseUrl: 'https://app.handfree.work/subject'
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
// "no-unused-expressions": "off",
|
||||
"max-len": [0, 160, 2, { "ignoreUrls": true }]
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
tools/** filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,5 @@ run/
|
||||
.clinic
|
||||
|
||||
.env.pgpl.yaml
|
||||
|
||||
tools/windows/*
|
||||
!tools/windows/*.zip
|
||||
tools/lego/*
|
||||
!tools/lego/readme.md
|
||||
|
||||
@@ -3,6 +3,44 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.4](https://github.com/certd/certd/compare/v1.27.3...v1.27.4) (2024-11-14)
|
||||
|
||||
### 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
|
||||
|
||||
* 修复偶发性cname一直验证超时的bug ([d2ce72e](https://github.com/certd/certd/commit/d2ce72e4aaacdf726ba8b91fcd71db40a27714ba))
|
||||
* 修复邮件配置,忽略证书校验设置不生效的bug ([66a9690](https://github.com/certd/certd/commit/66a9690dc958732e1b3c672d965db502296446f9))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化上传到主机插 路径选择,根据证书格式显示 ([8c3f86c](https://github.com/certd/certd/commit/8c3f86c6909ed91f48bb2880e78834e22f6f6a29))
|
||||
|
||||
## [1.27.2](https://github.com/certd/certd/compare/v1.27.1...v1.27.2) (2024-11-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复删除腾讯云过期证书时间判断上的bug,导致已过期仍然没有删除证书 ([1ba1007](https://github.com/certd/certd/commit/1ba10072615015d91b81fc56a3b01dae6a2ae9d1))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化部署到阿里云CDN插件,支持多域名,更易用 ([80c500f](https://github.com/certd/certd/commit/80c500f618b169a1f64c57fe442242a4d0d9d833))
|
||||
* 优化流水线页面切换回来不丢失查询条件 ([4dcf6e8](https://github.com/certd/certd/commit/4dcf6e87bc5f7657ce8a56c5331e8723a0fee8ee))
|
||||
* 支持公共cname服务 ([3c919ee](https://github.com/certd/certd/commit/3c919ee5d1aef5d26cf3620a7c49d920786bc941))
|
||||
* 执行历史支持点击查看流水线详情 ([8968639](https://github.com/certd/certd/commit/89686399f90058835435b92872fc236fac990148))
|
||||
* 专业版7天试用 ([c58250e](https://github.com/certd/certd/commit/c58250e1f065a9bd8b4e82acc1df754504c0010c))
|
||||
|
||||
## [1.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化时间选择器,自动填写分钟和秒钟 ([396dc34](https://github.com/certd/certd/commit/396dc34a841c7d016b033736afdba8366fb2d211))
|
||||
* cname 域名映射记录可读性优化 ([b1117ed](https://github.com/certd/certd/commit/b1117ed54a3ef015752999324ff72b821ef5e4b9))
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.27.0",
|
||||
"version": "1.27.4",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -10,8 +10,9 @@
|
||||
"commdev": "cross-env NODE_ENV=commdev mwtsc --watch --run @midwayjs/mock/app",
|
||||
"commpro": "cross-env NODE_ENV=commpro mwtsc --watch --run @midwayjs/mock/app",
|
||||
"pgdev": "cross-env NODE_ENV=pgdev mwtsc --watch --run @midwayjs/mock/app",
|
||||
"local-plus": "cross-env NODE_ENV=localplus mwtsc --watch --run @midwayjs/mock/app",
|
||||
"pgpl": "cross-env NODE_ENV=pgpl mwtsc --watch --run @midwayjs/mock/app",
|
||||
"dev-new": "npm run rm-db-new && cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app",
|
||||
"dev-new": "cross-env NODE_ENV=devnew mwtsc --watch --run @midwayjs/mock/app",
|
||||
"rm-db-new": "rimraf ./data/db-new.sqlite",
|
||||
"test": "cross-env NODE_ENV=unittest mocha",
|
||||
"cov": "cross-env c8 --all --reporter=text --reporter=lcovonly npm run test",
|
||||
@@ -23,21 +24,22 @@
|
||||
"build-on-docker": "node ./before-build.js && npm run build",
|
||||
"up-mw-deps": "npx midway-version -u -w",
|
||||
"heap": "cross-env NODE_ENV=pgpl clinic heapprofiler -- node ./bootstrap.js",
|
||||
"flame": "clinic flame -- node ./bootstrap.js"
|
||||
"flame": "clinic flame -- node ./bootstrap.js",
|
||||
"tsc": "tsc --skipLibCheck"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/acme-client": "^1.27.0",
|
||||
"@certd/commercial-core": "^1.27.0",
|
||||
"@certd/lib-huawei": "^1.27.0",
|
||||
"@certd/lib-jdcloud": "^1.27.0",
|
||||
"@certd/lib-k8s": "^1.27.0",
|
||||
"@certd/lib-server": "^1.27.0",
|
||||
"@certd/midway-flyway-js": "^1.27.0",
|
||||
"@certd/pipeline": "^1.27.0",
|
||||
"@certd/plugin-cert": "^1.27.0",
|
||||
"@certd/plugin-plus": "^1.27.0",
|
||||
"@certd/plus-core": "^1.27.0",
|
||||
"@certd/acme-client": "^1.27.4",
|
||||
"@certd/basic": "^1.27.4",
|
||||
"@certd/commercial-core": "^1.27.4",
|
||||
"@certd/lib-huawei": "^1.27.4",
|
||||
"@certd/lib-k8s": "^1.27.4",
|
||||
"@certd/lib-server": "^1.27.4",
|
||||
"@certd/midway-flyway-js": "^1.27.4",
|
||||
"@certd/pipeline": "^1.27.4",
|
||||
"@certd/plugin-cert": "^1.27.4",
|
||||
"@certd/plugin-plus": "^1.27.4",
|
||||
"@certd/plus-core": "^1.27.4",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.120",
|
||||
"@koa/cors": "^5.0.0",
|
||||
@@ -84,7 +86,7 @@
|
||||
"qiniu": "^7.12.0",
|
||||
"querystring": "^0.2.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rimraf": "^6.0.1",
|
||||
"rimraf": "^5.0.5",
|
||||
"socks": "^2.8.3",
|
||||
"socks-proxy-agent": "^8.0.4",
|
||||
"ssh2": "^1.15.0",
|
||||
@@ -107,9 +109,9 @@
|
||||
"@types/ssh2": "^1.15.0",
|
||||
"c8": "^10.1.2",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier": "^2.8.8",
|
||||
"rimraf": "^5.0.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { UserEntity } from '../modules/sys/authority/entity/user.js';
|
||||
import { PipelineEntity } from '../modules/pipeline/entity/pipeline.js';
|
||||
//import { logger } from '../utils/logger';
|
||||
// load .env file in process.cwd
|
||||
import { mergeConfig } from './loader.js';
|
||||
import { loadDotEnv, mergeConfig } from './loader.js';
|
||||
import { libServerEntities } from '@certd/lib-server';
|
||||
import { commercialEntities } from '@certd/commercial-core';
|
||||
import { tmpdir } from 'node:os';
|
||||
@@ -123,6 +123,8 @@ const development = {
|
||||
contactLink: '',
|
||||
},
|
||||
} as MidwayConfig;
|
||||
loadDotEnv();
|
||||
|
||||
mergeConfig(development, 'development');
|
||||
|
||||
mergeConfig(development, env);
|
||||
|
||||
@@ -2,7 +2,7 @@ import path from 'path';
|
||||
import * as _ from 'lodash-es';
|
||||
import yaml from 'js-yaml';
|
||||
import fs from 'fs';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
|
||||
function parseEnv(defaultConfig: any) {
|
||||
const config = {};
|
||||
@@ -46,3 +46,14 @@ export function mergeConfig(config: any, envType: string) {
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
export function loadDotEnv() {
|
||||
const envStr = fs.readFileSync('.env').toString();
|
||||
envStr.split('\n').forEach(line => {
|
||||
const [key, value] = line.trim().split('=');
|
||||
const oldValue = process.env[key];
|
||||
if (!oldValue) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import cors from '@koa/cors';
|
||||
import { GlobalExceptionMiddleware } from './middleware/global-exception.js';
|
||||
import { PreviewMiddleware } from './middleware/preview.js';
|
||||
import { AuthorityMiddleware } from './middleware/authority.js';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
import { ResetPasswdMiddleware } from './middleware/reset-passwd/middleware.js';
|
||||
import DefaultConfig from './config/config.default.js';
|
||||
import * as libServer from '@certd/lib-server';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Controller, Get, Provide } from '@midwayjs/core';
|
||||
import { BaseController, Constants } from '@certd/lib-server';
|
||||
import { http, logger } from '@certd/pipeline';
|
||||
import { http, logger } from '@certd/basic';
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Controller, Fields, Files, Get, Inject, Post, Provide, Query } from '@m
|
||||
import { BaseController, Constants, FileService, UploadFileItem, uploadTmpFileCacheKey } from '@certd/lib-server';
|
||||
import send from 'koa-send';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { cache } from '@certd/pipeline';
|
||||
import { cache } from '@certd/basic';
|
||||
import { UploadFileInfo } from '@midwayjs/upload';
|
||||
|
||||
/**
|
||||
@@ -41,6 +41,7 @@ export class FileController extends BaseController {
|
||||
}
|
||||
const filePath = this.fileService.getFile(key, userId);
|
||||
this.ctx.response.attachment(filePath);
|
||||
this.ctx.response.set('Cache-Control', 'public,max-age=2592000');
|
||||
await send(this.ctx, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Controller, Get, Inject, MidwayEnvironmentService, Provide } from '@midwayjs/core';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
import { Constants } from '@certd/lib-server';
|
||||
|
||||
@Provide()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Config, Controller, Get, Inject, Provide } from '@midwayjs/core';
|
||||
import { BaseController, Constants, SysHeaderMenus, SysInstallInfo, SysPublicSettings, SysSettingsService, SysSiteEnv, SysSiteInfo } from '@certd/lib-server';
|
||||
import { AppKey, getPlusInfo } from '@certd/pipeline';
|
||||
import { AppKey, getPlusInfo } from '@certd/plus-core';
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
@@ -21,7 +21,7 @@ export class CnameProviderController extends BaseController {
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
body.userId = this.getUserId();
|
||||
const res = await this.providerService.find({});
|
||||
const res = await this.providerService.list({});
|
||||
return this.ok(res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
body.userId = this.getUserId();
|
||||
return super.list(body);
|
||||
const list = await this.getService().list(body);
|
||||
return this.ok(list);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: Constants.per.authOnly })
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { Constants } from '@certd/lib-server';
|
||||
import {
|
||||
AccessRequestHandleReq,
|
||||
http,
|
||||
ITaskPlugin,
|
||||
logger,
|
||||
mergeUtils,
|
||||
newAccess,
|
||||
pluginRegistry,
|
||||
PluginRequestHandleReq,
|
||||
TaskInstanceContext,
|
||||
utils,
|
||||
} from '@certd/pipeline';
|
||||
import { AccessRequestHandleReq, ITaskPlugin, newAccess, pluginRegistry, PluginRequestHandleReq, TaskInstanceContext } from '@certd/pipeline';
|
||||
import { BaseController } from '@certd/lib-server';
|
||||
import { AccessService } from '../../modules/pipeline/service/access-service.js';
|
||||
import { EmailService } from '../../modules/basic/service/email-service.js';
|
||||
import { AccessGetter } from '../../modules/pipeline/service/access-getter.js';
|
||||
import { http, HttpRequestConfig, logger, mergeUtils, utils } from '@certd/basic';
|
||||
|
||||
@Provide()
|
||||
@Controller('/api/pi/handle')
|
||||
@@ -64,12 +54,21 @@ export class HandleController extends BaseController {
|
||||
|
||||
const accessGetter = new AccessGetter(userId, this.accessService.getById.bind(this.accessService));
|
||||
|
||||
const download = async (config: HttpRequestConfig, savePath: string) => {
|
||||
await utils.download({
|
||||
http,
|
||||
logger,
|
||||
config,
|
||||
savePath,
|
||||
});
|
||||
};
|
||||
//@ts-ignore
|
||||
const taskCtx: TaskInstanceContext = {
|
||||
pipeline: undefined,
|
||||
step: undefined,
|
||||
lastStatus: undefined,
|
||||
http,
|
||||
download,
|
||||
logger: logger,
|
||||
inputChanged: true,
|
||||
accessService: accessGetter,
|
||||
|
||||
@@ -7,7 +7,7 @@ import { HistoryEntity } from '../../modules/pipeline/entity/history.js';
|
||||
import { HistoryLogEntity } from '../../modules/pipeline/entity/history-log.js';
|
||||
import { PipelineService } from '../../modules/pipeline/service/pipeline-service.js';
|
||||
import * as fs from 'fs';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
import { AuthService } from '../../modules/sys/authority/service/auth-service.js';
|
||||
import { SysSettingsService } from '@certd/lib-server';
|
||||
import { In } from 'typeorm';
|
||||
|
||||
@@ -37,7 +37,7 @@ export class PipelineController extends CrudController<PipelineService> {
|
||||
|
||||
const buildQuery = qb => {
|
||||
if (title) {
|
||||
qb.andWhere('title like :title', { title: `%${title}%` });
|
||||
qb.andWhere('title like :title', { title: `%${title}%` }).orWhere('content like :content', { content: `%${title}%` });
|
||||
}
|
||||
};
|
||||
if (!body.sort || !body.sort?.prop) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
|
||||
import { AccessService } from '../../../modules/pipeline/service/access-service.js';
|
||||
import { AccessController } from '../../pipeline/access-controller.js';
|
||||
import { checkComm } from '@certd/pipeline';
|
||||
import { checkComm } from '@certd/plus-core';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { BaseController, PlusService } from '@certd/lib-server';
|
||||
import { AppKey } from '@certd/pipeline';
|
||||
import { SysSettingsService } from '@certd/lib-server';
|
||||
import { SysInstallInfo } from '@certd/lib-server';
|
||||
import { BaseController, PlusService, SysInstallInfo, SysSettingsService } from '@certd/lib-server';
|
||||
|
||||
export type PreBindUserReq = {
|
||||
userId: number;
|
||||
@@ -23,18 +20,8 @@ export class BasicController extends BaseController {
|
||||
|
||||
@Post('/preBindUser', { summary: 'sys:settings:edit' })
|
||||
public async preBindUser(@Body(ALL) body: PreBindUserReq) {
|
||||
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
|
||||
// 设置缓存内容
|
||||
await this.plusService.requestWithoutSign({
|
||||
url: '/activation/subject/preBind',
|
||||
method: 'POST',
|
||||
data: {
|
||||
userId: body.userId,
|
||||
appKey: AppKey,
|
||||
subjectId: installInfo.siteId,
|
||||
},
|
||||
});
|
||||
|
||||
await this.plusService.userPreBind(body.userId);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { BaseController, PlusService, SysInstallInfo, SysSettingsService } from '@certd/lib-server';
|
||||
import { AppKey, logger } from '@certd/pipeline';
|
||||
|
||||
/**
|
||||
*/
|
||||
@@ -16,23 +15,8 @@ export class SysPlusController extends BaseController {
|
||||
@Post('/active', { summary: 'sys:settings:edit' })
|
||||
async active(@Body(ALL) body) {
|
||||
const { code } = body;
|
||||
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
|
||||
const siteId = installInfo.siteId;
|
||||
const formData = {
|
||||
appKey: AppKey,
|
||||
code,
|
||||
subjectId: siteId,
|
||||
};
|
||||
|
||||
const res: any = await this.plusService.active(formData);
|
||||
|
||||
if (res.code > 0) {
|
||||
logger.error('激活失败', res.message);
|
||||
return this.fail(res.message, 1);
|
||||
}
|
||||
const license = res.data.license;
|
||||
|
||||
await this.plusService.updateLicense(license);
|
||||
await this.plusService.active(code);
|
||||
|
||||
return this.ok(true);
|
||||
}
|
||||
@@ -41,7 +25,7 @@ export class SysPlusController extends BaseController {
|
||||
const { url } = body;
|
||||
|
||||
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
|
||||
await this.plusService.bindUrl(installInfo.siteId, url);
|
||||
await this.plusService.bindUrl(url);
|
||||
|
||||
installInfo.bindUrl = url;
|
||||
await this.sysSettingsService.saveSetting(installInfo);
|
||||
|
||||
@@ -4,7 +4,8 @@ import * as _ from 'lodash-es';
|
||||
import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
|
||||
import { UserSettingsService } from '../../../modules/mine/service/user-settings-service.js';
|
||||
import { getEmailSettings } from '../../../modules/sys/settings/fix.js';
|
||||
import { http, logger } from '@certd/pipeline';
|
||||
import { http, logger } from '@certd/basic';
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
/**
|
||||
*/
|
||||
@@ -77,6 +78,14 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
return this.ok(conf);
|
||||
}
|
||||
|
||||
@Post('/saveEmailSettings', { summary: 'sys:settings:edit' })
|
||||
async saveEmailSettings(@Body(ALL) body) {
|
||||
const conf = await getEmailSettings(this.service, this.userSettingsService);
|
||||
merge(conf, body);
|
||||
await this.service.saveSetting(conf);
|
||||
return this.ok(conf);
|
||||
}
|
||||
|
||||
@Post('/getSysSettings', { summary: 'sys:settings:edit' })
|
||||
async getSysSettings() {
|
||||
const publicSettings = await this.service.getPublicSettings();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Init, Inject, MidwayWebRouterService, Provide, Scope, ScopeEnum } from
|
||||
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { Constants } from '@certd/lib-server';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
import { AuthService } from '../modules/sys/authority/service/auth-service.js';
|
||||
import { SysSettingsService } from '@certd/lib-server';
|
||||
import { SysPrivateSettings } from '@certd/lib-server';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Provide } from '@midwayjs/core';
|
||||
import { IWebMiddleware, IMidwayKoaContext, NextFunction } from '@midwayjs/koa';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
import { Result } from '@certd/lib-server';
|
||||
|
||||
@Provide()
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Autoload, Config, Init, Inject, Provide, Scope, ScopeEnum } from '@midw
|
||||
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
||||
import { CommonException } from '@certd/lib-server';
|
||||
import { UserService } from '../../modules/sys/authority/service/user-service.js';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
|
||||
/**
|
||||
* 重置密码模式
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
import { UserService } from '../sys/authority/service/user-service.js';
|
||||
import { PlusService, SysInstallInfo, SysPrivateSettings, SysSettingsService } from '@certd/lib-server';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { PipelineService } from '../pipeline/service/pipeline-service.js';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
import { SysSettingsService } from '@certd/lib-server';
|
||||
|
||||
@Autoload()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { App, Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { getPlusInfo, isPlus, logger } from '@certd/pipeline';
|
||||
import { getPlusInfo, isPlus } from '@certd/plus-core';
|
||||
import { logger } from '@certd/basic';
|
||||
|
||||
import { SysInstallInfo, SysSettingsService } from '@certd/lib-server';
|
||||
import { getVersion } from '../../utils/version.js';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
import fs from 'fs';
|
||||
// @ts-ignore
|
||||
import forge from 'node-forge';
|
||||
|
||||
@@ -2,7 +2,7 @@ import https from 'node:https';
|
||||
import fs from 'fs';
|
||||
import { Application } from '@midwayjs/koa';
|
||||
import { createSelfCertificate } from './self-certificate.js';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
|
||||
export type HttpsServerOptions = {
|
||||
enabled: boolean;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import type { EmailSend } from '@certd/pipeline';
|
||||
import { IEmailService, isPlus, logger } from '@certd/pipeline';
|
||||
import { IEmailService } from '@certd/pipeline';
|
||||
|
||||
import { logger } from '@certd/basic';
|
||||
import { isPlus } from '@certd/plus-core';
|
||||
|
||||
import nodemailer from 'nodemailer';
|
||||
import type SMTPConnection from 'nodemailer/lib/smtp-connection';
|
||||
import { UserSettingsService } from '../../mine/service/user-settings-service.js';
|
||||
@@ -45,14 +49,7 @@ export class EmailService implements IEmailService {
|
||||
* receivers: string[];
|
||||
*/
|
||||
|
||||
await this.plusService.request({
|
||||
url: '/activation/emailSend',
|
||||
data: {
|
||||
subject: email.subject,
|
||||
text: email.content,
|
||||
to: email.receivers,
|
||||
},
|
||||
});
|
||||
await this.plusService.sendEmail(email);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
@@ -34,4 +34,6 @@ export class CnameProviderEntity {
|
||||
default: () => 'CURRENT_TIMESTAMP',
|
||||
})
|
||||
updateTime: Date;
|
||||
|
||||
title: string;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
export type CnameRecordStatusType = 'cname' | 'validating' | 'valid' | 'error';
|
||||
export type CnameRecordStatusType = 'cname' | 'validating' | 'valid' | 'error' | 'timeout';
|
||||
/**
|
||||
* cname record配置
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService, ValidateException } from '@certd/lib-server';
|
||||
import { CnameProviderEntity } from '../entity/cname_provider.js';
|
||||
import { BaseService, ListReq, SysPrivateSettings, SysSettingsService, ValidateException } from '@certd/lib-server';
|
||||
import { CnameProviderEntity } from '../entity/cname-provider.js';
|
||||
import { CommonProviders } from './common-provider.js';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
@@ -13,13 +14,16 @@ export class CnameProviderService extends BaseService<CnameProviderEntity> {
|
||||
@InjectEntityModel(CnameProviderEntity)
|
||||
repository: Repository<CnameProviderEntity>;
|
||||
|
||||
@Inject()
|
||||
settingsService: SysSettingsService;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
async getDefault() {
|
||||
return await this.repository.findOne({ where: { isDefault: true } });
|
||||
return await this.repository.findOne({ where: { isDefault: true, disabled: false } });
|
||||
}
|
||||
/**
|
||||
* 新增
|
||||
@@ -80,10 +84,34 @@ export class CnameProviderService extends BaseService<CnameProviderEntity> {
|
||||
if (def) {
|
||||
return def;
|
||||
}
|
||||
const founds = await this.repository.find({ take: 1, order: { createTime: 'DESC' } });
|
||||
const founds = await this.repository.find({ take: 1, order: { createTime: 'DESC' }, where: { disabled: false } });
|
||||
if (founds && founds.length > 0) {
|
||||
return founds[0];
|
||||
}
|
||||
|
||||
const sysPrivateSettings = await this.settingsService.getSetting<SysPrivateSettings>(SysPrivateSettings);
|
||||
|
||||
if (sysPrivateSettings.commonCnameEnabled !== false && CommonProviders.length > 0) {
|
||||
return CommonProviders[0] as CnameProviderEntity;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async list(req: ListReq): Promise<any[]> {
|
||||
const list = await super.list(req);
|
||||
const sysPrivateSettings = await this.settingsService.getSetting<SysPrivateSettings>(SysPrivateSettings);
|
||||
|
||||
if (sysPrivateSettings.commonCnameEnabled !== false) {
|
||||
return [...list, ...CommonProviders];
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
async info(id: any, infoIgnoreProperty?: any): Promise<any | null> {
|
||||
if (id < 0) {
|
||||
//使用公共provider
|
||||
return CommonProviders.find(p => p.id === id);
|
||||
}
|
||||
return await super.info(id, infoIgnoreProperty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService, ValidateException } from '@certd/lib-server';
|
||||
import { BaseService, PlusService, ValidateException } from '@certd/lib-server';
|
||||
import { CnameRecordEntity, CnameRecordStatusType } from '../entity/cname-record.js';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { createDnsProvider, IDnsProvider, parseDomain } from '@certd/plugin-cert';
|
||||
import { cache, CnameProvider, http, logger, utils } from '@certd/pipeline';
|
||||
import { CnameProvider, CnameRecord } from '@certd/pipeline';
|
||||
import { cache, http, logger, utils } from '@certd/basic';
|
||||
|
||||
import { AccessService } from '../../pipeline/service/access-service.js';
|
||||
import { isDev } from '../../../utils/env.js';
|
||||
import { isDev } from '@certd/basic';
|
||||
import { walkTxtRecord } from '@certd/acme-client';
|
||||
import { CnameProviderService } from './cname-provider-service.js';
|
||||
import { CnameProviderEntity } from '../entity/cname_provider.js';
|
||||
import { CnameProviderEntity } from '../entity/cname-provider.js';
|
||||
import { CommonDnsProvider } from './common-provider.js';
|
||||
|
||||
type CnameCheckCacheValue = {
|
||||
validating: boolean;
|
||||
@@ -34,6 +36,10 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
|
||||
@Inject()
|
||||
accessService: AccessService;
|
||||
|
||||
@Inject()
|
||||
plusService: PlusService;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
@@ -85,8 +91,8 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
}
|
||||
param.hostRecord = hostRecord;
|
||||
|
||||
const cnameKey = uuidv4().replaceAll('-', '');
|
||||
param.recordValue = `${cnameKey}.${cnameProvider.domain}`;
|
||||
const cnameKey = utils.id.simpleNanoId();
|
||||
param.recordValue = `${param.domain}.${cnameKey}.${cnameProvider.domain}`;
|
||||
}
|
||||
|
||||
async update(param: any) {
|
||||
@@ -122,8 +128,17 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
// }
|
||||
|
||||
async getWithAccessByDomain(domain: string, userId: number) {
|
||||
const record = await this.getByDomain(domain, userId);
|
||||
record.cnameProvider.access = await this.accessService.getAccessById(record.cnameProvider.accessId, false);
|
||||
const record: CnameRecord = await this.getByDomain(domain, userId);
|
||||
if (record.cnameProvider.id > 0) {
|
||||
//自定义cname服务
|
||||
record.cnameProvider.access = await this.accessService.getAccessById(record.cnameProvider.accessId, false);
|
||||
} else {
|
||||
record.commonDnsProvider = new CommonDnsProvider({
|
||||
config: record.cnameProvider,
|
||||
plusService: this.plusService,
|
||||
});
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
@@ -152,7 +167,7 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
cnameProvider: {
|
||||
...provider,
|
||||
} as CnameProvider,
|
||||
};
|
||||
} as CnameRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,17 +193,29 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
startTime: new Date().getTime(),
|
||||
};
|
||||
}
|
||||
let ttl = 60 * 60 * 15 * 1000;
|
||||
let ttl = 5 * 60 * 1000;
|
||||
if (isDev()) {
|
||||
ttl = 30 * 1000;
|
||||
}
|
||||
const recordValue = bean.recordValue.substring(0, bean.recordValue.indexOf('.'));
|
||||
const testRecordValue = 'certd-cname-verify';
|
||||
|
||||
const buildDnsProvider = async () => {
|
||||
const cnameProvider = await this.cnameProviderService.info(bean.cnameProviderId);
|
||||
if (cnameProvider == null) {
|
||||
throw new ValidateException(`CNAME服务:${bean.cnameProviderId} 已被删除,请修改CNAME记录,重新选择CNAME服务`);
|
||||
}
|
||||
if (cnameProvider.disabled === true) {
|
||||
throw new Error(`CNAME服务:${bean.cnameProviderId} 已被禁用`);
|
||||
}
|
||||
|
||||
if (cnameProvider.id < 0) {
|
||||
//公共CNAME
|
||||
return new CommonDnsProvider({
|
||||
config: cnameProvider,
|
||||
plusService: this.plusService,
|
||||
});
|
||||
}
|
||||
|
||||
const access = await this.accessService.getById(cnameProvider.accessId, cnameProvider.userId);
|
||||
const context = { access, logger, http, utils };
|
||||
const dnsProvider: IDnsProvider = await createDnsProvider({
|
||||
@@ -203,16 +230,17 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
return true;
|
||||
}
|
||||
if (value.startTime + ttl < new Date().getTime()) {
|
||||
logger.warn(`cname验证超时,停止检查,${bean.domain} ${recordValue}`);
|
||||
logger.warn(`cname验证超时,停止检查,${bean.domain} ${testRecordValue}`);
|
||||
clearInterval(value.intervalId);
|
||||
await this.updateStatus(bean.id, 'cname');
|
||||
await this.updateStatus(bean.id, 'timeout');
|
||||
cache.delete(cacheKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
const originDomain = parseDomain(bean.domain);
|
||||
const fullDomain = `${bean.hostRecord}.${originDomain}`;
|
||||
|
||||
logger.info(`检查CNAME配置 ${fullDomain} ${recordValue}`);
|
||||
logger.info(`检查CNAME配置 ${fullDomain} ${testRecordValue}`);
|
||||
|
||||
// const txtRecords = await dns.promises.resolveTxt(fullDomain);
|
||||
// if (txtRecords.length) {
|
||||
@@ -225,10 +253,10 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
logger.error(`获取TXT记录失败,${e.message}`);
|
||||
}
|
||||
logger.info(`检查到TXT记录 ${JSON.stringify(records)}`);
|
||||
const success = records.includes(recordValue);
|
||||
const success = records.includes(testRecordValue);
|
||||
if (success) {
|
||||
clearInterval(value.intervalId);
|
||||
logger.info(`检测到CNAME配置,修改状态 ${fullDomain} ${recordValue}`);
|
||||
logger.info(`检测到CNAME配置,修改状态 ${fullDomain} ${testRecordValue}`);
|
||||
await this.updateStatus(bean.id, 'valid');
|
||||
value.pass = true;
|
||||
cache.delete(cacheKey);
|
||||
@@ -242,8 +270,8 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
} catch (e) {
|
||||
logger.error(`删除CNAME的校验DNS记录失败, ${e.message},req:${JSON.stringify(value.recordReq)},recordRes:${JSON.stringify(value.recordRes)}`, e);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
return success;
|
||||
};
|
||||
|
||||
if (value.validating) {
|
||||
@@ -263,7 +291,7 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||
fullRecord: fullRecord,
|
||||
hostRecord: hostRecord,
|
||||
type: 'TXT',
|
||||
value: recordValue,
|
||||
value: testRecordValue,
|
||||
};
|
||||
const dnsProvider = await buildDnsProvider();
|
||||
const recordRes = await dnsProvider.createRecord(req);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user