diff --git a/README.md b/README.md
index 13eee2ba..3bec4e90 100644
--- a/README.md
+++ b/README.md
@@ -168,7 +168,11 @@ https://afdian.com/a/greper
1. 可以调整开源协议以使其更严格或更宽松。
2. 可以用于商业用途。
+感谢以下贡献者做出的贡献。
+
+
+
## 九、 开源许可
* 本项目遵循 GNU Affero General Public License(AGPL)开源协议。
diff --git a/packages/ui/certd-client/public/template-import.csv b/packages/ui/certd-client/public/site-import-template.csv
similarity index 100%
rename from packages/ui/certd-client/public/template-import.csv
rename to packages/ui/certd-client/public/site-import-template.csv
diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/api.ts b/packages/ui/certd-client/src/views/certd/monitor/site/api.ts
index 8121be30..4e85d98f 100644
--- a/packages/ui/certd-client/src/views/certd/monitor/site/api.ts
+++ b/packages/ui/certd-client/src/views/certd/monitor/site/api.ts
@@ -56,6 +56,14 @@ export const siteInfoApi = {
});
},
+ async Import(form: any) {
+ return await request({
+ url: apiPrefix + "/import",
+ method: "post",
+ data: form,
+ });
+ },
+
async DisabledChange(id: number, disabled: boolean) {
return await request({
url: apiPrefix + "/disabledChange",
diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx
index c3b3e5b1..abba9c88 100644
--- a/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx
+++ b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx
@@ -8,6 +8,7 @@ import { useSettingStore } from "/@/store/settings";
import { mySuiteApi } from "/@/views/certd/suite/mine/api";
import { mitter } from "/@/utils/util.mitt";
import { useSiteIpMonitor } from "./ip/use";
+import { useSiteImport } from "/@/views/certd/monitor/site/use";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
@@ -44,6 +45,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
});
const { openSiteIpMonitorDialog } = useSiteIpMonitor();
+ const { openSiteImportDialog } = useSiteImport();
return {
crudOptions: {
request: {
@@ -97,6 +99,19 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
await crudExpose.openAdd({});
},
},
+ //导入按钮
+ import: {
+ show: true,
+ text: "批量导入",
+ type: "primary",
+ async click() {
+ openSiteImportDialog({
+ afterSubmit() {
+ crudExpose.doRefresh();
+ },
+ });
+ },
+ },
},
},
rowHandle: {
@@ -235,7 +250,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
};
return (
-
+
{row.certDomains}
);
diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/ip/api.ts b/packages/ui/certd-client/src/views/certd/monitor/site/ip/api.ts
index 2cc40972..15c83e5a 100644
--- a/packages/ui/certd-client/src/views/certd/monitor/site/ip/api.ts
+++ b/packages/ui/certd-client/src/views/certd/monitor/site/ip/api.ts
@@ -68,4 +68,11 @@ export const siteIpApi = {
},
});
},
+ async Import(form: any) {
+ return await request({
+ url: apiPrefix + "/import",
+ method: "post",
+ data: form,
+ });
+ },
};
diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/ip/crud.tsx b/packages/ui/certd-client/src/views/certd/monitor/site/ip/crud.tsx
index 3715863e..1f7efe97 100644
--- a/packages/ui/certd-client/src/views/certd/monitor/site/ip/crud.tsx
+++ b/packages/ui/certd-client/src/views/certd/monitor/site/ip/crud.tsx
@@ -4,13 +4,11 @@ import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, Edi
import { siteIpApi } from "./api";
import dayjs from "dayjs";
import { Modal, notification } from "ant-design-vue";
-import { useSettingStore } from "/@/store/settings";
+import { useSiteIpMonitor } from "/@/views/certd/monitor/site/ip/use";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
- const { t } = useI18n();
const api = siteIpApi;
- const { crudBinding } = crudExpose;
const pageRequest = async (query: UserPageQuery): Promise => {
if (!query.query) {
query.query = {};
@@ -36,8 +34,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
return res;
};
- const settingsStore = useSettingStore();
-
const checkStatusDict = dict({
data: [
{ label: "成功", value: "ok", color: "green" },
@@ -45,6 +41,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
{ label: "异常", value: "error", color: "red" },
],
});
+ const { openSiteIpImportDialog } = useSiteIpMonitor();
return {
crudOptions: {
request: {
@@ -75,6 +72,19 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
await crudExpose.openAdd({});
},
},
+ import: {
+ show: true,
+ text: "批量导入",
+ type: "primary",
+ async click() {
+ openSiteIpImportDialog({
+ siteId: context.props.siteId,
+ afterSubmit() {
+ crudExpose.doRefresh();
+ },
+ });
+ },
+ },
load: {
text: "同步IP",
type: "primary",
@@ -295,6 +305,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
data: [
{ label: "同步", value: "sync", color: "green" },
{ label: "手动", value: "manual", color: "blue" },
+ { label: "导入", value: "import", color: "blue" },
],
}),
form: {
diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/ip/use.tsx b/packages/ui/certd-client/src/views/certd/monitor/site/ip/use.tsx
index 764cdd51..2a00d4d3 100644
--- a/packages/ui/certd-client/src/views/certd/monitor/site/ip/use.tsx
+++ b/packages/ui/certd-client/src/views/certd/monitor/site/ip/use.tsx
@@ -1,11 +1,10 @@
import { useFormWrapper } from "@fast-crud/fast-crud";
-import { useRouter } from "vue-router";
import SiteIpCertMonitor from "./index.vue";
+import { siteIpApi } from "/@/views/certd/monitor/site/ip/api";
export function useSiteIpMonitor() {
- const { openDialog } = useFormWrapper();
- const router = useRouter();
+ const { openDialog, openCrudFormDialog } = useFormWrapper();
async function openSiteIpMonitorDialog(opts: { siteId: number }) {
await openDialog({
@@ -34,7 +33,42 @@ export function useSiteIpMonitor() {
});
}
+ async function openSiteIpImportDialog(opts: { afterSubmit: any; siteId: any }) {
+ const { afterSubmit } = opts;
+ await openCrudFormDialog({
+ crudOptions: {
+ columns: {
+ text: {
+ type: "textarea",
+ title: "IP列表",
+ form: {
+ helper: "IP或者CNAME域名,一行一个",
+ rules: [{ required: true, message: "请输入要导入的IP或域名" }],
+ component: {
+ placeholder: "192.168.1.2\ncname.foo.com",
+ rows: 8,
+ },
+ col: {
+ span: 24,
+ },
+ },
+ },
+ },
+ form: {
+ async doSubmit({ form }) {
+ return siteIpApi.Import({
+ ...form,
+ siteId: opts.siteId,
+ });
+ },
+ afterSubmit,
+ },
+ },
+ });
+ }
+
return {
openSiteIpMonitorDialog,
+ openSiteIpImportDialog,
};
}
diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/use.tsx b/packages/ui/certd-client/src/views/certd/monitor/site/use.tsx
new file mode 100644
index 00000000..a4b913b7
--- /dev/null
+++ b/packages/ui/certd-client/src/views/certd/monitor/site/use.tsx
@@ -0,0 +1,41 @@
+import { useFormWrapper } from "@fast-crud/fast-crud";
+import { siteInfoApi } from "./api";
+
+export function useSiteImport() {
+ const { openCrudFormDialog } = useFormWrapper();
+
+ async function openSiteImportDialog(opts: { afterSubmit: any }) {
+ const { afterSubmit } = opts;
+ await openCrudFormDialog({
+ crudOptions: {
+ columns: {
+ text: {
+ type: "textarea",
+ title: "域名列表",
+ form: {
+ helper: "格式【域名:端口:名称】,一行一个,其中端口、名称可以省略\n比如:\nwww.baidu.com:443:百度\nwww.taobao.com::淘宝\nwww.google.com",
+ rules: [{ required: true, message: "请输入要导入的域名" }],
+ component: {
+ placeholder: "www.baidu.com:443:百度\nwww.taobao.com::淘宝\nwww.google.com\n",
+ rows: 8,
+ },
+ col: {
+ span: 24,
+ },
+ },
+ },
+ },
+ form: {
+ async doSubmit({ form }) {
+ return siteInfoApi.Import(form);
+ },
+ afterSubmit,
+ },
+ },
+ });
+ }
+
+ return {
+ openSiteImportDialog,
+ };
+}
diff --git a/packages/ui/certd-server/src/controller/user/monitor/site-info-controller.ts b/packages/ui/certd-server/src/controller/user/monitor/site-info-controller.ts
index ae56f156..1d686c0c 100644
--- a/packages/ui/certd-server/src/controller/user/monitor/site-info-controller.ts
+++ b/packages/ui/certd-server/src/controller/user/monitor/site-info-controller.ts
@@ -105,6 +105,17 @@ export class SiteInfoController extends CrudController {
await this.service.checkAllByUsers(userId);
return this.ok();
}
+
+ @Post('/import', { summary: Constants.per.authOnly })
+ async doImport(@Body(ALL) body: any) {
+ const userId = this.getUserId();
+ await this.service.doImport({
+ text:body.text,
+ userId
+ })
+ return this.ok();
+ }
+
@Post('/ipCheckChange', { summary: Constants.per.authOnly })
async ipCheckChange(@Body(ALL) bean: any) {
const userId = this.getUserId();
diff --git a/packages/ui/certd-server/src/controller/user/monitor/site-ip-controller.ts b/packages/ui/certd-server/src/controller/user/monitor/site-ip-controller.ts
index 0bd175c8..713928cb 100644
--- a/packages/ui/certd-server/src/controller/user/monitor/site-ip-controller.ts
+++ b/packages/ui/certd-server/src/controller/user/monitor/site-ip-controller.ts
@@ -111,5 +111,16 @@ export class SiteInfoController extends CrudController {
return this.ok();
}
+ @Post('/import', { summary: Constants.per.authOnly })
+ async doImport(@Body(ALL) body: any) {
+ const userId = this.getUserId();
+ await this.service.doImport({
+ text:body.text,
+ userId,
+ siteId:body.siteId
+ })
+ return this.ok();
+ }
+
}
diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts b/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts
index 183dc359..8886481f 100644
--- a/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts
+++ b/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts
@@ -1,19 +1,19 @@
-import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
-import { BaseService, NeedSuiteException, NeedVIPException, SysSettingsService } from '@certd/lib-server';
-import { InjectEntityModel } from '@midwayjs/typeorm';
-import { Repository } from 'typeorm';
-import { SiteInfoEntity } from '../entity/site-info.js';
-import { siteTester } from './site-tester.js';
-import dayjs from 'dayjs';
-import { logger, utils } from '@certd/basic';
-import { PeerCertificate } from 'tls';
-import { NotificationService } from '../../pipeline/service/notification-service.js';
-import { isComm, isPlus } from '@certd/plus-core';
-import { UserSuiteService } from '@certd/commercial-core';
+import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
+import { BaseService, NeedSuiteException, NeedVIPException, SysSettingsService } from "@certd/lib-server";
+import { InjectEntityModel } from "@midwayjs/typeorm";
+import { Repository } from "typeorm";
+import { SiteInfoEntity } from "../entity/site-info.js";
+import { siteTester } from "./site-tester.js";
+import dayjs from "dayjs";
+import { logger, utils } from "@certd/basic";
+import { PeerCertificate } from "tls";
+import { NotificationService } from "../../pipeline/service/notification-service.js";
+import { isComm, isPlus } from "@certd/plus-core";
+import { UserSuiteService } from "@certd/commercial-core";
import { UserSettingsService } from "../../mine/service/user-settings-service.js";
-import { UserSiteMonitorSetting } from "../../mine/service/models.js";
-import {SiteIpService} from "./site-ip-service.js";
-import {SiteIpEntity} from "../entity/site-ip.js";
+import { UserSiteMonitorSetting } from "../../mine/service/models.js";
+import { SiteIpService } from "./site-ip-service.js";
+import { SiteIpEntity } from "../entity/site-ip.js";
@Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
@@ -43,7 +43,7 @@ export class SiteInfoService extends BaseService {
async add(data: SiteInfoEntity) {
if (!data.userId) {
- throw new Error('userId is required');
+ throw new Error("userId is required");
}
if (isComm()) {
@@ -51,25 +51,34 @@ export class SiteInfoService extends BaseService {
if (suiteSetting.enabled) {
const userSuite = await this.userSuiteService.getMySuiteDetail(data.userId);
if (userSuite.monitorCount.max != -1 && userSuite.monitorCount.max <= userSuite.monitorCount.used) {
- throw new NeedSuiteException('站点监控数量已达上限,请购买或升级套餐');
+ throw new NeedSuiteException("站点监控数量已达上限,请购买或升级套餐");
}
}
- }else if (!isPlus()) {
- const count = await this.getUserMonitorCount(data.userId);
- if (count >= 1) {
- throw new NeedVIPException('站点监控数量已达上限,请升级专业版');
- }
+ } else if (!isPlus()) {
+ const count = await this.getUserMonitorCount(data.userId);
+ if (count >= 1) {
+ throw new NeedVIPException("站点监控数量已达上限,请升级专业版");
+ }
+ }
+ data.disabled = false;
+
+ const found = await this.repository.findOne({
+ where: {
+ domain: data.domain,
+ userId: data.userId,
+ httpsPort: data.httpsPort || 443
+ }
+ });
+ if (found) {
+ return { id: found.id };
}
-
-
- data.disabled = false;
return await super.add(data);
}
async update(data: any) {
if (!data.id) {
- throw new Error('id is required');
+ throw new Error("id is required");
}
delete data.userId;
await super.update(data);
@@ -77,10 +86,10 @@ export class SiteInfoService extends BaseService {
async getUserMonitorCount(userId: number) {
if (!userId) {
- throw new Error('userId is required');
+ throw new Error("userId is required");
}
return await this.repository.count({
- where: { userId },
+ where: { userId }
});
}
@@ -92,26 +101,26 @@ export class SiteInfoService extends BaseService {
*/
async doCheck(site: SiteInfoEntity, notify = true, retryTimes = 3) {
if (!site?.domain) {
- throw new Error('站点域名不能为空');
+ throw new Error("站点域名不能为空");
}
try {
await this.update({
id: site.id,
- checkStatus: 'checking',
- lastCheckTime: dayjs().valueOf(),
+ checkStatus: "checking",
+ lastCheckTime: dayjs().valueOf()
});
const res = await siteTester.test({
host: site.domain,
port: site.httpsPort,
- retryTimes,
+ retryTimes
});
const certi: PeerCertificate = res.certificate;
if (!certi) {
- throw new Error('没有发现证书');
+ throw new Error("没有发现证书");
}
const expires = certi.valid_to;
- const allDomains = certi.subjectaltname?.replaceAll('DNS:', '').split(',') ||[];
+ const allDomains = certi.subjectaltname?.replaceAll("DNS:", "").split(",") || [];
const mainDomain = certi.subject?.CN;
let domains = allDomains;
if (!allDomains.includes(mainDomain)) {
@@ -119,23 +128,26 @@ export class SiteInfoService extends BaseService {
}
const issuer = `${certi.issuer.O}<${certi.issuer.CN}>`;
const isExpired = dayjs().valueOf() > dayjs(expires).valueOf();
- const status = isExpired ? 'expired' : 'ok';
+ const status = isExpired ? "expired" : "ok";
const updateData = {
id: site.id,
- certDomains: domains.join(','),
+ certDomains: domains.join(","),
certStatus: status,
certProvider: issuer,
certExpiresTime: dayjs(expires).valueOf(),
lastCheckTime: dayjs().valueOf(),
error: null,
- checkStatus: 'ok',
+ checkStatus: "ok"
};
+ if (site.ipCheck) {
+ delete updateData.checkStatus
+ }
await this.update(updateData);
//检查ip
- await this.checkAllIp(site)
+ await this.checkAllIp(site);
if (!notify) {
return;
@@ -143,15 +155,15 @@ export class SiteInfoService extends BaseService {
try {
await this.sendExpiresNotify(site);
} catch (e) {
- logger.error('send notify error', e);
+ logger.error("send notify error", e);
}
} catch (e) {
- logger.error('check site error', e);
+ logger.error("check site error", e);
await this.update({
id: site.id,
- checkStatus: 'error',
+ checkStatus: "error",
lastCheckTime: dayjs().valueOf(),
- error: e.message,
+ error: e.message
});
if (!notify) {
return;
@@ -159,49 +171,56 @@ export class SiteInfoService extends BaseService {
try {
await this.sendCheckErrorNotify(site);
} catch (e) {
- logger.error('send notify error', e);
+ logger.error("send notify error", e);
}
}
}
- async checkAllIp(site:SiteInfoEntity){
- if( !site.ipCheck){
+ async checkAllIp(site: SiteInfoEntity) {
+ if (!site.ipCheck) {
return;
}
const certExpiresTime = site.certExpiresTime;
- const onFinished = async (list:SiteIpEntity[])=>{
- let errorCount = 0
- let errorMessage = ""
+ const onFinished = async (list: SiteIpEntity[]) => {
+ let errorCount = 0;
+ let errorMessage = "";
for (const item of list) {
if (!item) {
continue;
}
- errorCount++
- if(item.error){
- errorMessage += `${item.ipAddress}:${item.error}; \n`
- }else if(item.certExpiresTime!==certExpiresTime){
- errorMessage += `${item.ipAddress}:与主站证书过期时间不一致; \n`
- }else{
- errorCount--
+ errorCount++;
+ if (item.error) {
+ errorMessage += `${item.ipAddress}:${item.error}; \n`;
+ } else if (item.certExpiresTime !== certExpiresTime) {
+ errorMessage += `${item.ipAddress}:与主站证书过期时间不一致; \n`;
+ } else {
+ errorCount--;
}
}
- if (errorCount<=0){
- return
+ if (errorCount <= 0) {
+ //检查正常
+ await this.update({
+ id: site.id,
+ checkStatus: "ok",
+ error: "",
+ ipErrorCount: 0
+ });
+ return;
}
await this.update({
id: site.id,
- checkStatus: 'error',
+ checkStatus: "error",
error: errorMessage,
- ipErrorCount: errorCount,
- })
+ ipErrorCount: errorCount
+ });
try {
- site = await this.info(site.id)
- await this.sendCheckErrorNotify(site,true);
+ site = await this.info(site.id);
+ await this.sendCheckErrorNotify(site, true);
} catch (e) {
- logger.error('send notify error', e);
+ logger.error("send notify error", e);
}
- }
- await this.siteIpService.checkAll(site,onFinished)
+ };
+ await this.siteIpService.checkAll(site, onFinished);
}
/**
@@ -213,13 +232,13 @@ export class SiteInfoService extends BaseService {
async check(id: number, notify = false, retryTimes = 3) {
const site = await this.info(id);
if (!site) {
- throw new Error('站点不存在');
+ throw new Error("站点不存在");
}
return await this.doCheck(site, notify, retryTimes);
}
- async sendCheckErrorNotify(site: SiteInfoEntity,fromIpCheck=false) {
- const url = await this.notificationService.getBindUrl('#/certd/monitor/site');
+ async sendCheckErrorNotify(site: SiteInfoEntity, fromIpCheck = false) {
+ const url = await this.notificationService.getBindUrl("#/certd/monitor/site");
// 发邮件
await this.notificationService.send(
{
@@ -227,22 +246,23 @@ export class SiteInfoService extends BaseService {
logger: logger,
body: {
url,
- title: `站点证书${fromIpCheck?"(IP)":""}检查出错<${site.name}>`,
+ title: `站点证书${fromIpCheck ? "(IP)" : ""}检查出错<${site.name}>`,
content: `站点名称: ${site.name} \n站点域名: ${site.domain} \n错误信息:${site.error}`,
- errorMessage: site.error,
- },
+ errorMessage: site.error
+ }
},
site.userId
);
}
+
async sendExpiresNotify(site: SiteInfoEntity) {
- const tipDays = 10
+ const tipDays = 10;
const expires = site.certExpiresTime;
- const validDays = dayjs(expires).diff(dayjs(), 'day');
- const url = await this.notificationService.getBindUrl('#/certd/monitor/site');
- const content = `站点名称: ${site.name} \n站点域名: ${site.domain} \n证书域名: ${site.certDomains} \n颁发机构: ${site.certProvider} \n过期时间: ${dayjs(site.certExpiresTime).format('YYYY-MM-DD')} \n`;
+ const validDays = dayjs(expires).diff(dayjs(), "day");
+ const url = await this.notificationService.getBindUrl("#/certd/monitor/site");
+ const content = `站点名称: ${site.name} \n站点域名: ${site.domain} \n证书域名: ${site.certDomains} \n颁发机构: ${site.certProvider} \n过期时间: ${dayjs(site.certExpiresTime).format("YYYY-MM-DD")} \n`;
if (validDays >= 0 && validDays < tipDays) {
// 发通知
await this.notificationService.send(
@@ -252,8 +272,8 @@ export class SiteInfoService extends BaseService {
body: {
title: `站点证书即将过期,剩余${validDays}天,<${site.name}>`,
content,
- url,
- },
+ url
+ }
},
site.userId
);
@@ -268,7 +288,7 @@ export class SiteInfoService extends BaseService {
content,
url,
errorMessage: "站点证书已过期"
- },
+ }
},
site.userId
);
@@ -277,10 +297,10 @@ export class SiteInfoService extends BaseService {
async checkAllByUsers(userId: any) {
if (!userId) {
- throw new Error('userId is required');
+ throw new Error("userId is required");
}
const sites = await this.repository.find({
- where: { userId },
+ where: { userId }
});
this.checkList(sites);
}
@@ -294,7 +314,7 @@ export class SiteInfoService extends BaseService {
}
}
- async getSetting(userId: number){
+ async getSetting(userId: number) {
return await this.userSettingsService.getSetting(userId, UserSiteMonitorSetting);
}
@@ -302,26 +322,78 @@ export class SiteInfoService extends BaseService {
await this.userSettingsService.saveSetting(userId, bean);
}
- async ipCheckChange(req: {id: any; ipCheck: any}) {
+ async ipCheckChange(req: { id: any; ipCheck: any }) {
await this.update({
id: req.id,
- ipCheck: req.ipCheck,
+ ipCheck: req.ipCheck
});
- if(req.ipCheck){
+ if (req.ipCheck) {
const site = await this.info(req.id);
- await this.siteIpService.sync(site)
+ await this.siteIpService.sync(site);
}
}
async disabledChange(req: { disabled: any; id: any }) {
await this.update({
id: req.id,
- disabled: req.disabled,
+ disabled: req.disabled
});
- if(!req.disabled){
+ if (!req.disabled) {
const site = await this.info(req.id);
- await this.doCheck(site)
+ await this.doCheck(site);
}
}
+
+ async doImport(req: { text: string; userId: number }) {
+ if (!req.text) {
+ throw new Error("text is required");
+ }
+ if (!req.userId) {
+ throw new Error("userId is required");
+ }
+
+ const rows = req.text.split("\n");
+
+ const list = [];
+ for (const item of rows) {
+ if (!item) {
+ continue;
+ }
+ const arr = item.trim().split(":");
+ if (arr.length === 0) {
+ continue;
+ }
+ const domain = arr[0];
+ let port = 443;
+ let name = domain;
+ if (arr.length > 1) {
+ try {
+ port = parseInt(arr[1] || "443");
+ } catch (e) {
+ throw new Error(`${item}格式错误`);
+ }
+
+ }
+ if (arr.length > 2) {
+ name = arr[2] || domain;
+ }
+
+ list.push({
+ domain,
+ name,
+ httpsPort: port,
+ userId: req.userId
+ });
+ }
+
+ const batchAdd = async (list: any[]) => {
+ for (const item of list) {
+ await this.add(item);
+ }
+
+ // await this.checkAllByUsers(req.userId);
+ };
+ await batchAdd(list);
+ }
}
diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts b/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts
index 6c89975f..bf7ba7e8 100644
--- a/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts
+++ b/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts
@@ -182,7 +182,7 @@ export class SiteIpService extends BaseService {
const finished = res.filter(item=>{
return item!=null
})
- if (finished.length > 0) {
+ if (onFinish) {
onFinish && onFinish(finished)
}
})
@@ -232,4 +232,50 @@ export class SiteIpService extends BaseService {
ipCount:count
})
}
+
+ async doImport(req: { text: string; userId:number, siteId:number }) {
+ if (!req.text) {
+ throw new Error("text is required");
+ }
+ if (!req.siteId) {
+ throw new Error("siteId is required");
+ }
+
+ const siteEntity = await this.siteInfoRepository.findOne({
+ where: {
+ id: req.siteId,
+ userId:req.userId
+ }
+ });
+ if (!siteEntity) {
+ throw new Error(`站点${req.siteId}不存在`);
+ }
+
+ const userId = siteEntity.userId;
+
+ const rows = req.text.split("\n");
+
+ const list = [];
+ for (const item of rows) {
+ if (!item) {
+ continue;
+ }
+ list.push({
+ ipAddress:item,
+ userId: userId,
+ siteId: req.siteId,
+ from: "import",
+ disabled:false,
+ });
+ }
+
+ const batchAdd = async (list: any[]) => {
+ for (const item of list) {
+ await this.add(item);
+ }
+
+ // await this.checkAllByUsers(req.userId);
+ };
+ await batchAdd(list);
+ }
}