mirror of
https://github.com/certd/certd.git
synced 2026-05-13 19:47:55 +08:00
perf: 支持域名到期时间监控通知
This commit is contained in:
@@ -7,6 +7,7 @@ import { IEmailService } from "../service/index.js";
|
|||||||
|
|
||||||
export type NotificationBody = {
|
export type NotificationBody = {
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
projectId?: number;
|
||||||
title: string;
|
title: string;
|
||||||
content: string;
|
content: string;
|
||||||
pipeline?: Pipeline;
|
pipeline?: Pipeline;
|
||||||
@@ -20,6 +21,7 @@ export type NotificationBody = {
|
|||||||
pipelineResult?: string;
|
pipelineResult?: string;
|
||||||
pipelineTitle?: string;
|
pipelineTitle?: string;
|
||||||
errors?: string;
|
errors?: string;
|
||||||
|
[key: string]: any; // 其他templateData
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NotificationRequestHandleReqInput<T = any> = {
|
export type NotificationRequestHandleReqInput<T = any> = {
|
||||||
|
|||||||
@@ -221,6 +221,7 @@ export default {
|
|||||||
projectJoin: "Join Project",
|
projectJoin: "Join Project",
|
||||||
currentProject: "Current Project",
|
currentProject: "Current Project",
|
||||||
projectMemberManager: "Project Member",
|
projectMemberManager: "Project Member",
|
||||||
|
domainMonitorSetting: "Domain Monitor Settings",
|
||||||
},
|
},
|
||||||
certificateRepo: {
|
certificateRepo: {
|
||||||
title: "Certificate Repository",
|
title: "Certificate Repository",
|
||||||
|
|||||||
@@ -64,6 +64,18 @@ export default {
|
|||||||
dnsServerHelper: "Use a custom domain name resolution server, such as: 1.1.1.1 , support multiple",
|
dnsServerHelper: "Use a custom domain name resolution server, such as: 1.1.1.1 , support multiple",
|
||||||
certValidDays: "Certificate Valid Days",
|
certValidDays: "Certificate Valid Days",
|
||||||
certValidDaysHelper: "Number of days before expiration to send a notification",
|
certValidDaysHelper: "Number of days before expiration to send a notification",
|
||||||
|
|
||||||
|
domain: {
|
||||||
|
monitorSettings: "Domain Monitor Settings",
|
||||||
|
enabled: "Enable Domain Monitor",
|
||||||
|
enabledHelper: "Enable to monitor all domain registration expiration time",
|
||||||
|
notificationChannel: "Notification Channel",
|
||||||
|
setNotificationChannel: "Set the notification channel",
|
||||||
|
willExpireDays: "Will Expire Days",
|
||||||
|
willExpireDaysHelper: "Number of days before expiration to send a notification",
|
||||||
|
monitorCronSetting: "Monitoring Schedule",
|
||||||
|
cronTrigger: "Scheduled trigger for monitoring",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
cert: {
|
cert: {
|
||||||
expired: "Expired",
|
expired: "Expired",
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ export default {
|
|||||||
projectJoin: "加入项目",
|
projectJoin: "加入项目",
|
||||||
currentProject: "当前项目",
|
currentProject: "当前项目",
|
||||||
projectMemberManager: "项目成员管理",
|
projectMemberManager: "项目成员管理",
|
||||||
|
domainMonitorSetting: "域名监控设置",
|
||||||
},
|
},
|
||||||
certificateRepo: {
|
certificateRepo: {
|
||||||
title: "证书仓库",
|
title: "证书仓库",
|
||||||
|
|||||||
@@ -68,6 +68,17 @@ export default {
|
|||||||
dnsServerHelper: "使用自定义的域名解析服务器,如:1.1.1.1 , 支持多个",
|
dnsServerHelper: "使用自定义的域名解析服务器,如:1.1.1.1 , 支持多个",
|
||||||
certValidDays: "证书到期前天数",
|
certValidDays: "证书到期前天数",
|
||||||
certValidDaysHelper: "证书到期前多少天发送通知",
|
certValidDaysHelper: "证书到期前多少天发送通知",
|
||||||
|
domain: {
|
||||||
|
monitorSettings: "域名监控设置",
|
||||||
|
enabled: "启用域名监控",
|
||||||
|
enabledHelper: "启用后,将监控域名管理中的域名的过期时间",
|
||||||
|
notificationChannel: "通知渠道",
|
||||||
|
setNotificationChannel: "设置通知渠道",
|
||||||
|
willExpireDays: "到期前天数",
|
||||||
|
willExpireDaysHelper: "域名有效期到期前多少天发送通知",
|
||||||
|
monitorCronSetting: "监控定时设置",
|
||||||
|
cronTrigger: "定时触发监控",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
cert: {
|
cert: {
|
||||||
expired: "已过期",
|
expired: "已过期",
|
||||||
|
|||||||
@@ -241,6 +241,17 @@ export const certdResources = [
|
|||||||
isMenu: true,
|
isMenu: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "certd.sysResources.domainMonitorSetting",
|
||||||
|
name: "DomainMonitorSetting",
|
||||||
|
path: "/certd/cert/domain/setting",
|
||||||
|
component: "/certd/cert/domain/setting/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:videocam-outline",
|
||||||
|
auth: true,
|
||||||
|
isMenu: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "certd.userSecurity",
|
title: "certd.userSecurity",
|
||||||
name: "UserSecurity",
|
name: "UserSecurity",
|
||||||
|
|||||||
@@ -128,6 +128,18 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||||||
}, 2000);
|
}, 2000);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
monitorSettingSave: {
|
||||||
|
show: hasActionPermission("write"),
|
||||||
|
title: "域名过期监控设置",
|
||||||
|
type: "primary",
|
||||||
|
icon: "ion:save-outline",
|
||||||
|
text: "域名过期监控设置",
|
||||||
|
click: async () => {
|
||||||
|
router.push({
|
||||||
|
path: "/certd/cert/domain/setting",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import { request } from "/src/api/service";
|
||||||
|
const apiPrefix = "/cert/domain/setting";
|
||||||
|
export type UserDomainMonitorSetting = {
|
||||||
|
enabled?: boolean;
|
||||||
|
notificationId?: number;
|
||||||
|
cron?: string;
|
||||||
|
willExpireDays?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function DomainMonitorSettingsGet() {
|
||||||
|
const res = await request({
|
||||||
|
url: apiPrefix + "/get",
|
||||||
|
method: "post",
|
||||||
|
});
|
||||||
|
if (!res) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return res as UserDomainMonitorSetting;
|
||||||
|
}
|
||||||
|
export async function DomainMonitorSettingsSave(data: UserDomainMonitorSetting) {
|
||||||
|
await request({
|
||||||
|
url: apiPrefix + "/save",
|
||||||
|
method: "post",
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<fs-page class="page-user-settings page-domain-monitor-setting">
|
||||||
|
<template #header>
|
||||||
|
<div class="title">{{ t("monitor.setting.domain.monitorSettings") }}</div>
|
||||||
|
</template>
|
||||||
|
<div class="user-settings-form settings-form">
|
||||||
|
<a-form :model="formState" name="basic" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off">
|
||||||
|
<a-form-item :label="t('monitor.setting.domain.enabled')" :name="['enabled']">
|
||||||
|
<div class="flex flex-baseline">
|
||||||
|
<a-switch v-model:checked="formState.enabled" :disabled="!settingsStore.isPlus" />
|
||||||
|
<vip-button class="ml-5" mode="button"></vip-button>
|
||||||
|
</div>
|
||||||
|
<div class="helper">{{ t("monitor.setting.domain.enabledHelper") }}</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="formState.enabled" :label="t('monitor.setting.domain.notificationChannel')" :name="['notificationId']">
|
||||||
|
<div class="flex">
|
||||||
|
<NotificationSelector v-model="formState.notificationId" />
|
||||||
|
</div>
|
||||||
|
<div class="helper">{{ t("monitor.setting.domain.setNotificationChannel") }}</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="formState.enabled" :label="t('monitor.setting.domain.willExpireDays')" :name="['willExpireDays']">
|
||||||
|
<div class="flex">
|
||||||
|
<a-input-number v-model:value="formState.willExpireDays" />
|
||||||
|
</div>
|
||||||
|
<div class="helper">{{ t("monitor.setting.domain.willExpireDaysHelper") }}</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="formState.enabled" :label="t('monitor.setting.domain.monitorCronSetting')" :name="['cron']">
|
||||||
|
<div class="flex flex-baseline">
|
||||||
|
<cron-editor v-model="formState.cron" :disabled="!settingsStore.isPlus" :allow-every-min="userStore.isAdmin" />
|
||||||
|
<vip-button class="ml-5" mode="button"></vip-button>
|
||||||
|
</div>
|
||||||
|
<div class="helper">{{ t("monitor.setting.domain.cronTrigger") }}</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 16 }">
|
||||||
|
<loading-button type="primary" html-type="button" :click="doSave" :disabled="!hasActionPermission('write')">{{ t("certd.save") }}</loading-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</fs-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import { notification } from "ant-design-vue";
|
||||||
|
import { merge } from "lodash-es";
|
||||||
|
import { reactive } from "vue";
|
||||||
|
import * as api from "./api";
|
||||||
|
import { UserDomainMonitorSetting } from "./api";
|
||||||
|
import { useUserStore } from "/@/store/user";
|
||||||
|
import { utils } from "/@/utils";
|
||||||
|
import NotificationSelector from "/@/views/certd/notification/notification-selector/index.vue";
|
||||||
|
import { useI18n } from "/src/locales";
|
||||||
|
import { useSettingStore } from "/src/store/settings";
|
||||||
|
import { useCrudPermission } from "/@/plugin/permission";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const settingsStore = useSettingStore();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
defineOptions({
|
||||||
|
name: "DomainMonitorSetting",
|
||||||
|
});
|
||||||
|
|
||||||
|
const randomHour = Math.floor(Math.random() * 9);
|
||||||
|
const randomMin = Math.floor(Math.random() * 59);
|
||||||
|
const randomCron = `0 ${randomMin} ${randomHour} * * *`;
|
||||||
|
|
||||||
|
const formState = reactive<Partial<UserDomainMonitorSetting>>({
|
||||||
|
enabled: false,
|
||||||
|
notificationId: 0,
|
||||||
|
cron: randomCron,
|
||||||
|
willExpireDays: 30,
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadUserSettings() {
|
||||||
|
const data: any = await api.DomainMonitorSettingsGet();
|
||||||
|
merge(formState, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { hasActionPermission } = useCrudPermission({ permission: { isProjectPermission: true } });
|
||||||
|
|
||||||
|
loadUserSettings();
|
||||||
|
const doSave = async (form: any) => {
|
||||||
|
await utils.sleep(300);
|
||||||
|
await api.DomainMonitorSettingsSave({
|
||||||
|
...formState,
|
||||||
|
});
|
||||||
|
notification.success({
|
||||||
|
message: t("certd.saveSuccess"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.page-domain-monitor-setting {
|
||||||
|
.settings-form {
|
||||||
|
width: 700px;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
CREATE TABLE "cd_job_history"
|
||||||
|
(
|
||||||
|
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
"user_id" integer NOT NULL,
|
||||||
|
"project_id" integer NOT NULL,
|
||||||
|
"type" varchar(100) NOT NULL,
|
||||||
|
"title" varchar(512) NOT NULL,
|
||||||
|
"related_id" varchar(100),
|
||||||
|
"result" varchar(100) NOT NULL,
|
||||||
|
"content" text ,
|
||||||
|
"start_at" integer NOT NULL,
|
||||||
|
"end_at" integer ,
|
||||||
|
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||||
|
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CREATE INDEX "index_job_history_user_id" ON "cd_job_history" ("user_id");
|
||||||
|
CREATE INDEX "index_job_history_project_id" ON "cd_job_history" ("project_id");
|
||||||
|
CREATE INDEX "index_job_history_type" ON "cd_job_history" ("type");
|
||||||
@@ -141,6 +141,7 @@
|
|||||||
"typeorm": "^0.3.20",
|
"typeorm": "^0.3.20",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"wechatpay-node-v3": "^2.2.1",
|
"wechatpay-node-v3": "^2.2.1",
|
||||||
|
"whoiser": "2.0.0-beta.10",
|
||||||
"xml2js": "^0.6.2"
|
"xml2js": "^0.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
|
|
||||||
@Post('/page', { description: Constants.per.authOnly, summary: "查询域名分页列表" })
|
@Post('/page', { description: Constants.per.authOnly, summary: "查询域名分页列表" })
|
||||||
async page(@Body(ALL) body: any) {
|
async page(@Body(ALL) body: any) {
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
body.query = body.query ?? {};
|
body.query = body.query ?? {};
|
||||||
body.query.projectId = projectId;
|
body.query.projectId = projectId;
|
||||||
body.query.userId = userId;
|
body.query.userId = userId;
|
||||||
@@ -44,7 +44,7 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
|
|
||||||
@Post('/list', { description: Constants.per.authOnly, summary: "查询域名列表" })
|
@Post('/list', { description: Constants.per.authOnly, summary: "查询域名列表" })
|
||||||
async list(@Body(ALL) body: any) {
|
async list(@Body(ALL) body: any) {
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
body.query = body.query ?? {};
|
body.query = body.query ?? {};
|
||||||
body.query.projectId = projectId;
|
body.query.projectId = projectId;
|
||||||
body.query.userId = userId;
|
body.query.userId = userId;
|
||||||
@@ -54,7 +54,7 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
|
|
||||||
@Post('/add', { description: Constants.per.authOnly, summary: "添加域名" })
|
@Post('/add', { description: Constants.per.authOnly, summary: "添加域名" })
|
||||||
async add(@Body(ALL) bean: any) {
|
async add(@Body(ALL) bean: any) {
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
bean.projectId = projectId;
|
bean.projectId = projectId;
|
||||||
bean.userId = userId;
|
bean.userId = userId;
|
||||||
return super.add(bean);
|
return super.add(bean);
|
||||||
@@ -82,7 +82,7 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
|
|
||||||
@Post('/deleteByIds', { description: Constants.per.authOnly, summary: "批量删除域名" })
|
@Post('/deleteByIds', { description: Constants.per.authOnly, summary: "批量删除域名" })
|
||||||
async deleteByIds(@Body(ALL) body: any) {
|
async deleteByIds(@Body(ALL) body: any) {
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
await this.service.delete(body.ids, {
|
await this.service.delete(body.ids, {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
@@ -94,10 +94,10 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
@Post('/import/start', { description: Constants.per.authOnly, summary: "开始域名导入任务" })
|
@Post('/import/start', { description: Constants.per.authOnly, summary: "开始域名导入任务" })
|
||||||
async importStart(@Body(ALL) body: any) {
|
async importStart(@Body(ALL) body: any) {
|
||||||
checkPlus();
|
checkPlus();
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
const { key } = body;
|
const { key } = body;
|
||||||
const req = {
|
const req = {
|
||||||
key,
|
key,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
|
|
||||||
@Post('/import/status', { description: Constants.per.authOnly, summary: "查询域名导入任务状态" })
|
@Post('/import/status', { description: Constants.per.authOnly, summary: "查询域名导入任务状态" })
|
||||||
async importStatus() {
|
async importStatus() {
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
const req = {
|
const req = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
@@ -119,7 +119,7 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
|
|
||||||
@Post('/import/delete', { description: Constants.per.authOnly, summary: "删除域名导入任务" })
|
@Post('/import/delete', { description: Constants.per.authOnly, summary: "删除域名导入任务" })
|
||||||
async importDelete(@Body(ALL) body: any) {
|
async importDelete(@Body(ALL) body: any) {
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
const { key } = body;
|
const { key } = body;
|
||||||
const req = {
|
const req = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
@@ -133,12 +133,12 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
@Post('/import/save', { description: Constants.per.authOnly, summary: "保存域名导入任务" })
|
@Post('/import/save', { description: Constants.per.authOnly, summary: "保存域名导入任务" })
|
||||||
async importSave(@Body(ALL) body: any) {
|
async importSave(@Body(ALL) body: any) {
|
||||||
checkPlus();
|
checkPlus();
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
const { dnsProviderType, dnsProviderAccessId, key } = body;
|
const { dnsProviderType, dnsProviderAccessId, key } = body;
|
||||||
const req = {
|
const req = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
dnsProviderType, dnsProviderAccessId, key
|
dnsProviderType, dnsProviderAccessId, key
|
||||||
}
|
}
|
||||||
const item = await this.service.saveDomainImportTask(req);
|
const item = await this.service.saveDomainImportTask(req);
|
||||||
return this.ok(item);
|
return this.ok(item);
|
||||||
@@ -147,7 +147,7 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
|
|
||||||
@Post('/sync/expiration/start', { description: Constants.per.authOnly, summary: "开始同步域名过期时间任务" })
|
@Post('/sync/expiration/start', { description: Constants.per.authOnly, summary: "开始同步域名过期时间任务" })
|
||||||
async syncExpirationStart(@Body(ALL) body: any) {
|
async syncExpirationStart(@Body(ALL) body: any) {
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
await this.service.startSyncExpirationTask({
|
await this.service.startSyncExpirationTask({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
@@ -156,7 +156,7 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
}
|
}
|
||||||
@Post('/sync/expiration/status', { description: Constants.per.authOnly, summary: "查询同步域名过期时间任务状态" })
|
@Post('/sync/expiration/status', { description: Constants.per.authOnly, summary: "查询同步域名过期时间任务状态" })
|
||||||
async syncExpirationStatus(@Body(ALL) body: any) {
|
async syncExpirationStatus(@Body(ALL) body: any) {
|
||||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
const status = await this.service.getSyncExpirationTaskStatus({
|
const status = await this.service.getSyncExpirationTaskStatus({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
@@ -165,4 +165,26 @@ export class DomainController extends CrudController<DomainService> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Post('/setting/save', { description: Constants.per.authOnly, summary: "保存域名监控设置" })
|
||||||
|
async settingSave(@Body(ALL) body: any) {
|
||||||
|
const { projectId, userId } = await this.getProjectUserIdWrite();
|
||||||
|
await this.service.monitorSettingSave({
|
||||||
|
userId: userId,
|
||||||
|
projectId: projectId,
|
||||||
|
setting: {...body},
|
||||||
|
})
|
||||||
|
return this.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/setting/get', { description: Constants.per.authOnly, summary: "查询域名监控设置" })
|
||||||
|
async settingGet() {
|
||||||
|
const { projectId, userId } = await this.getProjectUserIdRead();
|
||||||
|
const setting = await this.service.monitorSettingGet({
|
||||||
|
userId: userId,
|
||||||
|
projectId: projectId,
|
||||||
|
})
|
||||||
|
return this.ok(setting);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { Constants, CrudController } from "@certd/lib-server";
|
||||||
|
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||||
|
import { ApiTags } from "@midwayjs/swagger";
|
||||||
|
import { SiteInfoService } from "../../../modules/monitor/index.js";
|
||||||
|
import { JobHistoryService } from "../../../modules/monitor/service/job-history-service.js";
|
||||||
|
import { AuthService } from "../../../modules/sys/authority/service/auth-service.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
@Controller('/api/monitor/job-history')
|
||||||
|
@ApiTags(['monitor'])
|
||||||
|
export class JobHistoryController extends CrudController<JobHistoryService> {
|
||||||
|
@Inject()
|
||||||
|
service: JobHistoryService;
|
||||||
|
@Inject()
|
||||||
|
authService: AuthService;
|
||||||
|
@Inject()
|
||||||
|
siteInfoService: SiteInfoService;
|
||||||
|
|
||||||
|
getService(): JobHistoryService {
|
||||||
|
return this.service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/page', { description: Constants.per.authOnly, summary: "查询监控运行历史分页列表" })
|
||||||
|
async page(@Body(ALL) body: any) {
|
||||||
|
const { projectId, userId } = await this.getProjectUserIdRead()
|
||||||
|
body.query = body.query ?? {};
|
||||||
|
body.query.userId = userId;
|
||||||
|
body.query.projectId = projectId
|
||||||
|
const res = await this.service.page({
|
||||||
|
query: body.query,
|
||||||
|
page: body.page,
|
||||||
|
sort: body.sort,
|
||||||
|
});
|
||||||
|
return this.ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/list', { description: Constants.per.authOnly, summary: "查询监控运行历史列表" })
|
||||||
|
async list(@Body(ALL) body: any) {
|
||||||
|
body.query = body.query ?? {};
|
||||||
|
const { projectId, userId } = await this.getProjectUserIdRead()
|
||||||
|
body.query.userId = userId;
|
||||||
|
body.query.projectId = projectId
|
||||||
|
return await super.list(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Post('/info', { description: Constants.per.authOnly, summary: "查询监控运行历史详情" })
|
||||||
|
async info(@Query('id') id: number) {
|
||||||
|
await this.checkOwner(this.service,id,"read");
|
||||||
|
return await super.info(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/delete', { description: Constants.per.authOnly, summary: "删除监控运行历史" })
|
||||||
|
async delete(@Query('id') id: number) {
|
||||||
|
await this.checkOwner(this.service,id,"write");
|
||||||
|
const res = await super.delete(id);
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -67,6 +67,7 @@ export class AutoCRegisterCron {
|
|||||||
await this.registerUserExpireCheckCron();
|
await this.registerUserExpireCheckCron();
|
||||||
|
|
||||||
await this.registerDomainExpireCheckCron();
|
await this.registerDomainExpireCheckCron();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerSiteMonitorCron() {
|
async registerSiteMonitorCron() {
|
||||||
@@ -211,11 +212,11 @@ export class AutoCRegisterCron {
|
|||||||
if (!isPlus()){
|
if (!isPlus()){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 添加域名即将到期检查任务
|
// 添加域名即将到期同步任务
|
||||||
const randomWeek = Math.floor(Math.random() * 7) + 1
|
const randomWeek = Math.floor(Math.random() * 7) + 1
|
||||||
const randomHour = Math.floor(Math.random() * 24)
|
const randomHour = Math.floor(Math.random() * 24)
|
||||||
const randomMinute = Math.floor(Math.random() * 60)
|
const randomMinute = Math.floor(Math.random() * 60)
|
||||||
logger.info(`注册域名注册过期时间检查任务,每周${randomWeek} ${randomHour}:${randomMinute}检查一次`)
|
logger.info(`注册域名注册过期时间同步任务,每周${randomWeek} ${randomHour}:${randomMinute}检查一次`)
|
||||||
this.cron.register({
|
this.cron.register({
|
||||||
name: 'domain-expire-check',
|
name: 'domain-expire-check',
|
||||||
cron: `0 ${randomMinute} ${randomHour} ? * ${randomWeek}`, // 每周随机一天检查一次
|
cron: `0 ${randomMinute} ${randomHour} ? * ${randomWeek}`, // 每周随机一天检查一次
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
import { http, logger, utils } from '@certd/basic';
|
import { http, logger, utils } from '@certd/basic';
|
||||||
import { AccessService, BaseService } from '@certd/lib-server';
|
import { AccessService, BaseService, isEnterprise } from '@certd/lib-server';
|
||||||
import { doPageTurn, Pager, PageRes } from '@certd/pipeline';
|
import { doPageTurn, Pager, PageRes } from '@certd/pipeline';
|
||||||
import { DomainVerifiers } from "@certd/plugin-cert";
|
import { DomainVerifiers } from "@certd/plugin-cert";
|
||||||
import { createDnsProvider, dnsProviderRegistry, DomainParser, parseDomainByPsl } from "@certd/plugin-lib";
|
import { createDnsProvider, dnsProviderRegistry, DomainParser, parseDomainByPsl } from "@certd/plugin-lib";
|
||||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { In, Not, Repository } from 'typeorm';
|
import { merge } from 'lodash-es';
|
||||||
|
import { In, LessThan, Not, Repository } from 'typeorm';
|
||||||
import { BackTask, taskExecutor } from '../../basic/service/task-executor.js';
|
import { BackTask, taskExecutor } from '../../basic/service/task-executor.js';
|
||||||
import { CnameRecordEntity } from "../../cname/entity/cname-record.js";
|
import { CnameRecordEntity } from "../../cname/entity/cname-record.js";
|
||||||
import { CnameRecordService } from '../../cname/service/cname-record-service.js';
|
import { CnameRecordService } from '../../cname/service/cname-record-service.js';
|
||||||
import { UserDomainImportSetting } from '../../mine/service/models.js';
|
import { UserDomainImportSetting, UserDomainMonitorSetting } from '../../mine/service/models.js';
|
||||||
import { UserSettingsService } from '../../mine/service/user-settings-service.js';
|
import { UserSettingsService } from '../../mine/service/user-settings-service.js';
|
||||||
|
import { JobHistoryService } from '../../monitor/service/job-history-service.js';
|
||||||
import { TaskServiceBuilder } from '../../pipeline/service/getter/task-service-getter.js';
|
import { TaskServiceBuilder } from '../../pipeline/service/getter/task-service-getter.js';
|
||||||
import { SubDomainService } from "../../pipeline/service/sub-domain-service.js";
|
import { SubDomainService } from "../../pipeline/service/sub-domain-service.js";
|
||||||
import { DomainEntity } from '../entity/domain.js';
|
import { DomainEntity } from '../entity/domain.js';
|
||||||
|
import { Cron } from '../../cron/cron.js';
|
||||||
|
|
||||||
export interface SyncFromProviderReq {
|
export interface SyncFromProviderReq {
|
||||||
userId: number;
|
userId: number;
|
||||||
@@ -27,6 +30,8 @@ export interface SyncFromProviderReq {
|
|||||||
const DOMAIN_IMPORT_TASK_TYPE = 'domainImportTask'
|
const DOMAIN_IMPORT_TASK_TYPE = 'domainImportTask'
|
||||||
const DOMAIN_EXPIRE_TASK_TYPE = 'domainExpirationSyncTask'
|
const DOMAIN_EXPIRE_TASK_TYPE = 'domainExpirationSyncTask'
|
||||||
|
|
||||||
|
const DOMAIN_EXPIRE_CHECK_TYPE = 'domainExpirationCheck'
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -51,6 +56,14 @@ export class DomainService extends BaseService<DomainEntity> {
|
|||||||
@Inject()
|
@Inject()
|
||||||
userSettingService: UserSettingsService;
|
userSettingService: UserSettingsService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
jobHistoryService: JobHistoryService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
cron: Cron;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
getRepository() {
|
getRepository() {
|
||||||
return this.repository;
|
return this.repository;
|
||||||
@@ -320,9 +333,9 @@ export class DomainService extends BaseService<DomainEntity> {
|
|||||||
logger.info(`从域名提供商${dnsProviderType}导入域名完成(${key}),共导入${task.total}个域名,跳过${task.getSkipCount()}个域名,成功${task.getSuccessCount()}个域名,失败${task.getErrorCount()}个域名`)
|
logger.info(`从域名提供商${dnsProviderType}导入域名完成(${key}),共导入${task.total}个域名,跳过${task.getSkipCount()}个域名,成功${task.getSuccessCount()}个域名,失败${task.getErrorCount()}个域名`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDomainImportTaskStatus(req: { userId?: number ,projectId?: number}) {
|
async getDomainImportTaskStatus(req: { userId?: number, projectId?: number }) {
|
||||||
const userId = req.userId || 0
|
const userId = req.userId || 0
|
||||||
const projectId = req.projectId
|
const projectId = req.projectId
|
||||||
|
|
||||||
const setting = await this.userSettingService.getSetting<UserDomainImportSetting>(userId, projectId, UserDomainImportSetting)
|
const setting = await this.userSettingService.getSetting<UserDomainImportSetting>(userId, projectId, UserDomainImportSetting)
|
||||||
const list = setting?.domainImportList || []
|
const list = setting?.domainImportList || []
|
||||||
@@ -429,8 +442,6 @@ export class DomainService extends BaseService<DomainEntity> {
|
|||||||
await this.deleteDomainImportTask({ userId, projectId, key })
|
await this.deleteDomainImportTask({ userId, projectId, key })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return await this.addDomainImportTask({ userId, projectId, dnsProviderType, dnsProviderAccessId, index })
|
return await this.addDomainImportTask({ userId, projectId, dnsProviderType, dnsProviderAccessId, index })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,7 +452,7 @@ export class DomainService extends BaseService<DomainEntity> {
|
|||||||
const userId = req.userId ?? 'all'
|
const userId = req.userId ?? 'all'
|
||||||
const projectId = req.projectId
|
const projectId = req.projectId
|
||||||
let key = `user_${userId}`
|
let key = `user_${userId}`
|
||||||
if (projectId!=null) {
|
if (projectId != null) {
|
||||||
key += `_${projectId}`
|
key += `_${projectId}`
|
||||||
}
|
}
|
||||||
const task = taskExecutor.get(DOMAIN_EXPIRE_TASK_TYPE, key)
|
const task = taskExecutor.get(DOMAIN_EXPIRE_TASK_TYPE, key)
|
||||||
@@ -452,7 +463,7 @@ export class DomainService extends BaseService<DomainEntity> {
|
|||||||
const userId = req.userId
|
const userId = req.userId
|
||||||
const projectId = req.projectId
|
const projectId = req.projectId
|
||||||
let key = `user_${userId ?? 'all'}`
|
let key = `user_${userId ?? 'all'}`
|
||||||
if (projectId!=null) {
|
if (projectId != null) {
|
||||||
key += `_${projectId}`
|
key += `_${projectId}`
|
||||||
}
|
}
|
||||||
taskExecutor.start(new BackTask({
|
taskExecutor.start(new BackTask({
|
||||||
@@ -461,11 +472,15 @@ export class DomainService extends BaseService<DomainEntity> {
|
|||||||
title: `同步注册域名过期时间(${key}))`,
|
title: `同步注册域名过期时间(${key}))`,
|
||||||
run: async (task: BackTask) => {
|
run: async (task: BackTask) => {
|
||||||
await this._syncDomainsExpirationDate({ userId, projectId, task })
|
await this._syncDomainsExpirationDate({ userId, projectId, task })
|
||||||
|
if (userId != null) {
|
||||||
|
await this.startCheckDomainExpiration({ userId, projectId })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _syncDomainsExpirationDate(req: { userId?: number, projectId?: number, task: BackTask }) {
|
private async _syncDomainsExpirationDate(req: { userId?: number, projectId?: number, task: BackTask }) {
|
||||||
|
|
||||||
//同步所有域名的过期时间
|
//同步所有域名的过期时间
|
||||||
const pager = new Pager({
|
const pager = new Pager({
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
@@ -573,7 +588,138 @@ export class DomainService extends BaseService<DomainEntity> {
|
|||||||
|
|
||||||
await doPageTurn({ pager, getPage: getDomainPage, itemHandle: itemHandle })
|
await doPageTurn({ pager, getPage: getDomainPage, itemHandle: itemHandle })
|
||||||
const key = `user_${req.userId || 'all'}`
|
const key = `user_${req.userId || 'all'}`
|
||||||
logger.info(`同步用户(${key})注册域名过期时间完成(${req.task.getSuccessCount()}个成功,${req.task.getErrorCount()}个失败)`)
|
const log = `同步用户(${key})注册域名过期时间完成(${req.task.getSuccessCount()}个成功,${req.task.getErrorCount()}个失败)`
|
||||||
|
logger.info(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async startCheckDomainExpiration(req: { userId?: number, projectId?: number }) {
|
||||||
|
const { userId, projectId } = req
|
||||||
|
if (userId == null) {
|
||||||
|
throw new Error('userId is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectId && !isEnterprise()) {
|
||||||
|
logger.warn(`当前未开启企业模式,跳过检查项目(${projectId})的域名过期时间`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const setting = await this.monitorSettingGet({ userId, projectId })
|
||||||
|
if (!setting || !setting.enabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const jobHistory: any = {
|
||||||
|
userId,
|
||||||
|
projectId,
|
||||||
|
type: DOMAIN_EXPIRE_CHECK_TYPE,
|
||||||
|
title: `检查注册域名过期时间`,
|
||||||
|
startAt: dayjs().valueOf(),
|
||||||
|
result: "start",
|
||||||
|
}
|
||||||
|
await this.jobHistoryService.add(jobHistory)
|
||||||
|
|
||||||
|
const expireDays = setting.willExpireDays || 30
|
||||||
|
const ltTime = dayjs().add(expireDays, 'day').valueOf()
|
||||||
|
|
||||||
|
const total = await this.repository.count({
|
||||||
|
where:{
|
||||||
|
userId,
|
||||||
|
projectId,
|
||||||
|
disabled: false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//开始检查域名过期时间
|
||||||
|
const list = await this.repository.find({
|
||||||
|
where: {
|
||||||
|
userId,
|
||||||
|
projectId,
|
||||||
|
disabled: false,
|
||||||
|
expirationDate: LessThan(ltTime)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const now = dayjs().valueOf()
|
||||||
|
let willExpireDomains = []
|
||||||
|
let hasExpireDomains = []
|
||||||
|
|
||||||
|
for (const item of list) {
|
||||||
|
const { expirationDate } = item
|
||||||
|
if (expirationDate < now) {
|
||||||
|
hasExpireDomains.push(item.domain)
|
||||||
|
} else {
|
||||||
|
willExpireDomains.push(item.domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = `域名过期检查:共${total}个域名,即将过期${willExpireDomains.length}个域名,已过期${hasExpireDomains.length}个域名`
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.jobHistoryService.update({
|
||||||
|
id: jobHistory.id,
|
||||||
|
content: title,
|
||||||
|
result: "done",
|
||||||
|
endAt: dayjs().valueOf(),
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`更新域名过期检查任务状态失败:${error.message ?? error}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.length == 0) {
|
||||||
|
//没有过期域名 不发通知
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送通知
|
||||||
|
const content = `即将过期域名【${willExpireDomains.length}】:${willExpireDomains.join(',')}
|
||||||
|
\n已过期域名【${hasExpireDomains.length}】:${hasExpireDomains.join(',')}`
|
||||||
|
const taskService = this.taskServiceBuilder.create({ userId: userId, projectId: projectId });
|
||||||
|
|
||||||
|
const notificationService = await taskService.getNotificationService()
|
||||||
|
const url = await notificationService.getBindUrl("#/certd/cert/domain");
|
||||||
|
await notificationService.send({
|
||||||
|
id: setting.notificationId,
|
||||||
|
useDefault: true,
|
||||||
|
logger: logger,
|
||||||
|
body: {
|
||||||
|
title: title,
|
||||||
|
content: content,
|
||||||
|
url: url,
|
||||||
|
notificationType: DOMAIN_EXPIRE_CHECK_TYPE
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async monitorSettingGet(req: { userId?: number, projectId?: number }) {
|
||||||
|
const { userId, projectId } = req
|
||||||
|
const setting = await this.userSettingService.getSetting<UserDomainMonitorSetting>(userId, projectId, UserDomainMonitorSetting)
|
||||||
|
return setting || {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async monitorSettingSave(req: { userId?: number, projectId?: number, setting?: any }) {
|
||||||
|
const { userId, projectId, setting } = req
|
||||||
|
const bean: UserDomainMonitorSetting = new UserDomainMonitorSetting()
|
||||||
|
merge(bean, setting)
|
||||||
|
await this.userSettingService.saveSetting<UserDomainMonitorSetting>(userId, projectId, bean)
|
||||||
|
await this.registerMonitorCron({ userId, projectId })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async registerMonitorCron(req: { userId?: number, projectId?: number }) {
|
||||||
|
const { userId, projectId } = req
|
||||||
|
const setting = await this.monitorSettingGet(req)
|
||||||
|
const key = `${DOMAIN_EXPIRE_CHECK_TYPE}:${userId}_${projectId || ''}`
|
||||||
|
this.cron.remove(key)
|
||||||
|
if (setting.enabled) {
|
||||||
|
this.cron.register({
|
||||||
|
cron: setting.cron,
|
||||||
|
name: key,
|
||||||
|
job: async () => {
|
||||||
|
await this.startCheckDomainExpiration({ userId, projectId })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Config, Configuration, Logger } from '@midwayjs/core';
|
import { logger } from '@certd/basic';
|
||||||
import { ILogger } from '@midwayjs/logger';
|
import { Config, Configuration, IMidwayContainer } from '@midwayjs/core';
|
||||||
import { IMidwayContainer } from '@midwayjs/core';
|
|
||||||
import { Cron } from './cron.js';
|
import { Cron } from './cron.js';
|
||||||
|
|
||||||
// ... (see below) ...
|
// ... (see below) ...
|
||||||
@@ -11,18 +10,15 @@ import { Cron } from './cron.js';
|
|||||||
export class CronConfiguration {
|
export class CronConfiguration {
|
||||||
@Config()
|
@Config()
|
||||||
config;
|
config;
|
||||||
@Logger()
|
|
||||||
logger: ILogger;
|
|
||||||
|
|
||||||
cron: Cron;
|
cron: Cron;
|
||||||
async onReady(container: IMidwayContainer) {
|
async onReady(container: IMidwayContainer) {
|
||||||
this.logger.info('cron start');
|
logger.info('cron start');
|
||||||
this.cron = new Cron({
|
this.cron = new Cron({
|
||||||
logger: this.logger,
|
logger: logger,
|
||||||
...this.config,
|
...this.config,
|
||||||
});
|
});
|
||||||
container.registerObject('cron', this.cron);
|
container.registerObject('cron', this.cron);
|
||||||
this.cron.start();
|
this.cron.start();
|
||||||
this.logger.info('cron started');
|
logger.info('cron started');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,18 @@ export class UserSiteMonitorSetting extends BaseSettings {
|
|||||||
certValidDays?:number = 14;
|
certValidDays?:number = 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class UserDomainMonitorSetting extends BaseSettings {
|
||||||
|
static __title__ = "域名到期监控设置";
|
||||||
|
static __key__ = "user.domain.monitor";
|
||||||
|
|
||||||
|
enabled?:boolean = false;
|
||||||
|
notificationId?:number= 0;
|
||||||
|
cron?:string = undefined;
|
||||||
|
willExpireDays?:number = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class UserEmailSetting extends BaseSettings {
|
export class UserEmailSetting extends BaseSettings {
|
||||||
static __title__ = "用户邮箱设置";
|
static __title__ = "用户邮箱设置";
|
||||||
static __key__ = "user.email";
|
static __key__ = "user.email";
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
import { PipelineEntity } from '../../pipeline/entity/pipeline.js';
|
||||||
|
|
||||||
|
@Entity('cd_job_history')
|
||||||
|
export class JobHistoryEntity {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ name: 'user_id', comment: '用户id' })
|
||||||
|
userId: number;
|
||||||
|
|
||||||
|
@Column({ name: 'project_id', comment: '项目id' })
|
||||||
|
projectId: number;
|
||||||
|
|
||||||
|
|
||||||
|
@Column({ name: 'type', comment: '类型' })
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@Column({ name: 'title', comment: '标题' })
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@Column({ name: 'content', comment: '内容' })
|
||||||
|
content: string;
|
||||||
|
|
||||||
|
@Column({ name: 'related_id', comment: '关联id' })
|
||||||
|
relatedId: string;
|
||||||
|
|
||||||
|
@Column({ name: 'result', comment: '结果' })
|
||||||
|
result: string;
|
||||||
|
|
||||||
|
@Column({ name: 'start_at', comment: '开始时间' })
|
||||||
|
startAt: number;
|
||||||
|
|
||||||
|
@Column({ name: 'end_at', comment: '结束时间' })
|
||||||
|
endAt: number;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
name: 'create_time',
|
||||||
|
comment: '创建时间',
|
||||||
|
default: () => 'CURRENT_TIMESTAMP',
|
||||||
|
})
|
||||||
|
createTime: Date;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
name: 'update_time',
|
||||||
|
comment: '修改时间',
|
||||||
|
default: () => 'CURRENT_TIMESTAMP',
|
||||||
|
})
|
||||||
|
updateTime: Date;
|
||||||
|
|
||||||
|
pipeline?: PipelineEntity;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { BaseService } from "@certd/lib-server";
|
||||||
|
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||||
|
import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||||
|
import { Repository } from "typeorm";
|
||||||
|
import { UserSettingsService } from "../../mine/service/user-settings-service.js";
|
||||||
|
import { JobHistoryEntity } from "../entity/job-history.js";
|
||||||
|
|
||||||
|
|
||||||
|
@Provide()
|
||||||
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
|
export class JobHistoryService extends BaseService<JobHistoryEntity> {
|
||||||
|
@InjectEntityModel(JobHistoryEntity)
|
||||||
|
repository: Repository<JobHistoryEntity>;
|
||||||
|
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
userSettingsService: UserSettingsService;
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
getRepository() {
|
||||||
|
return this.repository;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,8 @@ import {SiteIpEntity} from "../entity/site-ip.js";
|
|||||||
import {Cron} from "../../cron/cron.js";
|
import {Cron} from "../../cron/cron.js";
|
||||||
import { dnsContainer } from "./dns-custom.js";
|
import { dnsContainer } from "./dns-custom.js";
|
||||||
import { merge } from "lodash-es";
|
import { merge } from "lodash-es";
|
||||||
|
import { JobHistoryService } from "./job-history-service.js";
|
||||||
|
import { JobHistoryEntity } from "../entity/job-history.js";
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
||||||
@@ -39,6 +41,9 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
@Inject()
|
@Inject()
|
||||||
siteIpService: SiteIpService;
|
siteIpService: SiteIpService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
jobHistoryService: JobHistoryService;
|
||||||
|
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
cron: Cron;
|
cron: Cron;
|
||||||
@@ -516,6 +521,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
async triggerJobOnce(userId?:number,projectId?:number) {
|
async triggerJobOnce(userId?:number,projectId?:number) {
|
||||||
logger.info(`站点证书检查开始执行[${userId??'所有用户'}_${projectId??'所有项目'}]`);
|
logger.info(`站点证书检查开始执行[${userId??'所有用户'}_${projectId??'所有项目'}]`);
|
||||||
const query:any = { disabled: false };
|
const query:any = { disabled: false };
|
||||||
|
let jobEntity :Partial<JobHistoryEntity> = null;
|
||||||
if(userId!=null){
|
if(userId!=null){
|
||||||
query.userId = userId;
|
query.userId = userId;
|
||||||
if(projectId){
|
if(projectId){
|
||||||
@@ -526,9 +532,19 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
if (!setting.cron) {
|
if (!setting.cron) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
jobEntity = {
|
||||||
|
userId,
|
||||||
|
projectId,
|
||||||
|
type:"siteCertMonitor",
|
||||||
|
title: '站点证书检查',
|
||||||
|
result:"start",
|
||||||
|
startAt:new Date().getTime(),
|
||||||
|
}
|
||||||
|
await this.jobHistoryService.add(jobEntity);
|
||||||
}
|
}
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
const limit = 50;
|
const limit = 50;
|
||||||
|
let count = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
const res = await this.page({
|
const res = await this.page({
|
||||||
query: query,
|
query: query,
|
||||||
@@ -541,10 +557,20 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
}
|
}
|
||||||
offset += records.length;
|
offset += records.length;
|
||||||
const isCommon = !userId;
|
const isCommon = !userId;
|
||||||
|
count += records.length;
|
||||||
await this.checkList(records,isCommon);
|
await this.checkList(records,isCommon);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`站点证书检查完成[${userId??'所有用户'}_${projectId??'所有项目'}]`);
|
logger.info(`站点证书检查完成[${userId??'所有用户'}_${projectId??'所有项目'}]`);
|
||||||
|
if(jobEntity){
|
||||||
|
await this.jobHistoryService.update({
|
||||||
|
id: jobEntity.id,
|
||||||
|
result: "done",
|
||||||
|
content:`共检查${count}个站点`,
|
||||||
|
endAt:new Date().getTime(),
|
||||||
|
updateTime:new Date(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async batchDelete(ids: number[], userId: number,projectId?:number): Promise<void> {
|
async batchDelete(ids: number[], userId: number,projectId?:number): Promise<void> {
|
||||||
|
|||||||
@@ -23,4 +23,8 @@ export class NotificationGetter implements INotificationService {
|
|||||||
async send(req: NotificationSendReq): Promise<void> {
|
async send(req: NotificationSendReq): Promise<void> {
|
||||||
return await this.notificationService.send(req, this.userId, this.projectId);
|
return await this.notificationService.send(req, this.userId, this.projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getBindUrl(url: string) {
|
||||||
|
return await this.notificationService.getBindUrl(url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+60
-44
@@ -49,7 +49,7 @@ importers:
|
|||||||
packages/core/acme-client:
|
packages/core/acme-client:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../basic
|
version: link:../basic
|
||||||
'@peculiar/x509':
|
'@peculiar/x509':
|
||||||
specifier: ^1.11.0
|
specifier: ^1.11.0
|
||||||
@@ -213,10 +213,10 @@ importers:
|
|||||||
packages/core/pipeline:
|
packages/core/pipeline:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../basic
|
version: link:../basic
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
@@ -412,7 +412,7 @@ importers:
|
|||||||
packages/libs/lib-k8s:
|
packages/libs/lib-k8s:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@kubernetes/client-node':
|
'@kubernetes/client-node':
|
||||||
specifier: 0.21.0
|
specifier: 0.21.0
|
||||||
@@ -452,19 +452,19 @@ importers:
|
|||||||
packages/libs/lib-server:
|
packages/libs/lib-server:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../plugins/plugin-lib
|
version: link:../../plugins/plugin-lib
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
'@midwayjs/cache':
|
'@midwayjs/cache':
|
||||||
specifier: 3.14.0
|
specifier: 3.14.0
|
||||||
@@ -610,16 +610,16 @@ importers:
|
|||||||
packages/plugins/plugin-cert:
|
packages/plugins/plugin-cert:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../plugin-lib
|
version: link:../plugin-lib
|
||||||
psl:
|
psl:
|
||||||
specifier: ^1.9.0
|
specifier: ^1.9.0
|
||||||
@@ -683,16 +683,16 @@ importers:
|
|||||||
specifier: ^3.964.0
|
specifier: ^3.964.0
|
||||||
version: 3.964.0(aws-crt@1.26.2)
|
version: 3.964.0(aws-crt@1.26.2)
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
'@kubernetes/client-node':
|
'@kubernetes/client-node':
|
||||||
specifier: 0.21.0
|
specifier: 0.21.0
|
||||||
@@ -783,16 +783,16 @@ importers:
|
|||||||
packages/pro/commercial-core:
|
packages/pro/commercial-core:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/lib-server':
|
'@certd/lib-server':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../libs/lib-server
|
version: link:../../libs/lib-server
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../plus-core
|
version: link:../plus-core
|
||||||
'@midwayjs/core':
|
'@midwayjs/core':
|
||||||
specifier: 3.20.11
|
specifier: 3.20.11
|
||||||
@@ -868,16 +868,16 @@ importers:
|
|||||||
packages/pro/plugin-plus:
|
packages/pro/plugin-plus:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../plugins/plugin-lib
|
version: link:../../plugins/plugin-lib
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../plus-core
|
version: link:../plus-core
|
||||||
crypto-js:
|
crypto-js:
|
||||||
specifier: ^4.2.0
|
specifier: ^4.2.0
|
||||||
@@ -953,7 +953,7 @@ importers:
|
|||||||
packages/pro/plus-core:
|
packages/pro/plus-core:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
@@ -1249,10 +1249,10 @@ importers:
|
|||||||
version: 0.1.3(zod@3.24.4)
|
version: 0.1.3(zod@3.24.4)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@certd/lib-iframe':
|
'@certd/lib-iframe':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../libs/lib-iframe
|
version: link:../../libs/lib-iframe
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@rollup/plugin-commonjs':
|
'@rollup/plugin-commonjs':
|
||||||
specifier: ^25.0.7
|
specifier: ^25.0.7
|
||||||
@@ -1447,46 +1447,46 @@ importers:
|
|||||||
specifier: ^3.990.0
|
specifier: ^3.990.0
|
||||||
version: 3.990.0(aws-crt@1.26.2)
|
version: 3.990.0(aws-crt@1.26.2)
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/commercial-core':
|
'@certd/commercial-core':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../pro/commercial-core
|
version: link:../../pro/commercial-core
|
||||||
'@certd/cv4pve-api-javascript':
|
'@certd/cv4pve-api-javascript':
|
||||||
specifier: ^8.4.2
|
specifier: ^8.4.2
|
||||||
version: 8.4.2
|
version: 8.4.2
|
||||||
'@certd/jdcloud':
|
'@certd/jdcloud':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../libs/lib-jdcloud
|
version: link:../../libs/lib-jdcloud
|
||||||
'@certd/lib-huawei':
|
'@certd/lib-huawei':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../libs/lib-huawei
|
version: link:../../libs/lib-huawei
|
||||||
'@certd/lib-k8s':
|
'@certd/lib-k8s':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../libs/lib-k8s
|
version: link:../../libs/lib-k8s
|
||||||
'@certd/lib-server':
|
'@certd/lib-server':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../libs/lib-server
|
version: link:../../libs/lib-server
|
||||||
'@certd/midway-flyway-js':
|
'@certd/midway-flyway-js':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../libs/midway-flyway-js
|
version: link:../../libs/midway-flyway-js
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-cert':
|
'@certd/plugin-cert':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../plugins/plugin-cert
|
version: link:../../plugins/plugin-cert
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../plugins/plugin-lib
|
version: link:../../plugins/plugin-lib
|
||||||
'@certd/plugin-plus':
|
'@certd/plugin-plus':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../pro/plugin-plus
|
version: link:../../pro/plugin-plus
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.39.7
|
specifier: ^1.39.8
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
'@google-cloud/publicca':
|
'@google-cloud/publicca':
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
@@ -1719,6 +1719,9 @@ importers:
|
|||||||
wechatpay-node-v3:
|
wechatpay-node-v3:
|
||||||
specifier: ^2.2.1
|
specifier: ^2.2.1
|
||||||
version: 2.2.1
|
version: 2.2.1
|
||||||
|
whoiser:
|
||||||
|
specifier: 2.0.0-beta.10
|
||||||
|
version: 2.0.0-beta.10
|
||||||
xml2js:
|
xml2js:
|
||||||
specifier: ^0.6.2
|
specifier: ^0.6.2
|
||||||
version: 0.6.2
|
version: 0.6.2
|
||||||
@@ -10743,6 +10746,10 @@ packages:
|
|||||||
pump@3.0.2:
|
pump@3.0.2:
|
||||||
resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
|
resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
|
||||||
|
|
||||||
|
punycode-esm@1.0.15:
|
||||||
|
resolution: {integrity: sha512-pR7pzaunGU4g3v3vMIXD9WnrGUiEBs2ezcVYr9piTC/HVem9F+MJ+JNdSeYD9pK7EumLMUMO9F3Gsa3RS+o7pA==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
punycode.js@2.3.1:
|
punycode.js@2.3.1:
|
||||||
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
|
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -12737,6 +12744,9 @@ packages:
|
|||||||
engines: {node: ^16.13.0 || >=18.0.0}
|
engines: {node: ^16.13.0 || >=18.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
whoiser@2.0.0-beta.10:
|
||||||
|
resolution: {integrity: sha512-Y1uyLNR6zQnKj/mZPYtofs6u/9ZAnBzAuiTgU1aEMKjlnknrQdLyOKv9ErmIeF2mySMjGFj0tCam+DpxotBXHw==}
|
||||||
|
|
||||||
why-is-node-running@2.3.0:
|
why-is-node-running@2.3.0:
|
||||||
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
|
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -20854,13 +20864,13 @@ snapshots:
|
|||||||
resolve: 1.22.10
|
resolve: 1.22.10
|
||||||
semver: 6.3.1
|
semver: 6.3.1
|
||||||
|
|
||||||
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8):
|
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
prettier: 2.8.8
|
prettier: 2.8.8
|
||||||
prettier-linter-helpers: 1.0.0
|
prettier-linter-helpers: 1.0.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint-config-prettier: 8.10.0(eslint@8.57.0)
|
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||||
|
|
||||||
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
|
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -23286,7 +23296,7 @@ snapshots:
|
|||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||||
eslint-plugin-node: 11.1.0(eslint@7.32.0)
|
eslint-plugin-node: 11.1.0(eslint@7.32.0)
|
||||||
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8)
|
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8)
|
||||||
execa: 5.1.1
|
execa: 5.1.1
|
||||||
inquirer: 7.3.3
|
inquirer: 7.3.3
|
||||||
json5: 2.2.3
|
json5: 2.2.3
|
||||||
@@ -24561,6 +24571,8 @@ snapshots:
|
|||||||
end-of-stream: 1.4.4
|
end-of-stream: 1.4.4
|
||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
|
|
||||||
|
punycode-esm@1.0.15: {}
|
||||||
|
|
||||||
punycode.js@2.3.1: {}
|
punycode.js@2.3.1: {}
|
||||||
|
|
||||||
punycode@1.4.1: {}
|
punycode@1.4.1: {}
|
||||||
@@ -26843,6 +26855,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
isexe: 3.1.1
|
isexe: 3.1.1
|
||||||
|
|
||||||
|
whoiser@2.0.0-beta.10:
|
||||||
|
dependencies:
|
||||||
|
punycode-esm: 1.0.15
|
||||||
|
|
||||||
why-is-node-running@2.3.0:
|
why-is-node-running@2.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
siginfo: 2.0.0
|
siginfo: 2.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user