mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-15 08:59:51 +00:00
feat: support removing certificates
This commit is contained in:
parent
831f0ee5d9
commit
3a2baba746
@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultExpireSubject = "您有 ${COUNT} 张证书即将过期"
|
||||
defaultExpireSubject = "有 ${COUNT} 张证书即将过期"
|
||||
defaultExpireMessage = "有 ${COUNT} 张证书即将过期,域名分别为 ${DOMAINS},请保持关注!"
|
||||
)
|
||||
|
||||
@ -36,7 +36,7 @@ func (s *CertificateService) InitSchedule(ctx context.Context) error {
|
||||
err := scheduler.Add("certificate", "0 0 * * *", func() {
|
||||
certs, err := s.repo.ListExpireSoon(context.Background())
|
||||
if err != nil {
|
||||
app.GetLogger().Error("failed to get expire soon certificate", "err", err)
|
||||
app.GetLogger().Error("failed to get certificates which expire soon", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ func (s *CertificateService) InitSchedule(ctx context.Context) error {
|
||||
}
|
||||
|
||||
if err := notify.SendToAllChannels(notification.Subject, notification.Message); err != nil {
|
||||
app.GetLogger().Error("failed to send expire soon certificate", "err", err)
|
||||
app.GetLogger().Error("failed to send notification", "err", err)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/types"
|
||||
)
|
||||
|
||||
type AccessRepository struct{}
|
||||
@ -27,7 +26,7 @@ func (r *AccessRepository) GetById(ctx context.Context, id string) (*domain.Acce
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !types.IsNil(record.Get("deleted")) {
|
||||
if !record.GetDateTime("deleted").Time().IsZero() {
|
||||
return nil, domain.ErrRecordNotFound
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"github.com/usual2970/certimate/internal/app"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/pkg/utils/types"
|
||||
)
|
||||
|
||||
type CertificateRepository struct{}
|
||||
@ -52,7 +51,7 @@ func (r *CertificateRepository) GetById(ctx context.Context, id string) (*domain
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !types.IsNil(record.Get("deleted")) {
|
||||
if !record.GetDateTime("deleted").Time().IsZero() {
|
||||
return nil, domain.ErrRecordNotFound
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ export type NotifyTemplate = {
|
||||
};
|
||||
|
||||
export const defaultNotifyTemplate: NotifyTemplate = {
|
||||
subject: "您有 ${COUNT} 张证书即将过期",
|
||||
subject: "有 ${COUNT} 张证书即将过期",
|
||||
message: "有 ${COUNT} 张证书即将过期,域名分别为 ${DOMAINS},请保持关注!",
|
||||
};
|
||||
// #endregion
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
"certificate.action.view": "View certificate",
|
||||
"certificate.action.delete": "Delete certificate",
|
||||
"certificate.action.delete.confirm": "Are you sure to delete this certificate?",
|
||||
"certificate.action.download": "Download certificate",
|
||||
|
||||
"certificate.props.subject_alt_names": "Name",
|
||||
|
@ -13,6 +13,6 @@
|
||||
"dashboard.quick_actions": "Quick actions",
|
||||
"dashboard.quick_actions.create_workflow": "Create workflow",
|
||||
"dashboard.quick_actions.change_login_password": "Change login password",
|
||||
"dashboard.quick_actions.notification_settings": "Notification settings",
|
||||
"dashboard.quick_actions.certificate_authority_configuration": "Certificate authority configuration"
|
||||
"dashboard.quick_actions.cofigure_notification": "Configure notificaion",
|
||||
"dashboard.quick_actions.configure_ca": "Configure certificate authority"
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
"access.form.name.placeholder": "请输入授权名称",
|
||||
"access.form.provider.label": "提供商",
|
||||
"access.form.provider.placeholder": "请选择提供商",
|
||||
"access.form.provider.tooltip": "提供商分为两种类型:<br>【DNS 提供商】您的 DNS 托管方,通常等同于域名注册商,用于在申请证书时管理您的域名解析记录。<br>【主机提供商】您的服务器或云服务的托管方,用于部署签发的证书。<br><br>该字段保存后不可修改。",
|
||||
"access.form.provider.tooltip": "提供商分为两种类型:<br>【DNS 提供商】你的 DNS 托管方,通常等同于域名注册商,用于在申请证书时管理您的域名解析记录。<br>【主机提供商】你的服务器或云服务的托管方,用于部署签发的证书。<br><br>该字段保存后不可修改。",
|
||||
"access.form.acmehttpreq_endpoint.label": "服务端点",
|
||||
"access.form.acmehttpreq_endpoint.placeholder": "请输入服务端点",
|
||||
"access.form.acmehttpreq_endpoint.tooltip": "这是什么?请参阅 <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
"certificate.action.view": "查看证书",
|
||||
"certificate.action.delete": "删除证书",
|
||||
"certificate.action.delete.confirm": "确定要删除此证书吗?",
|
||||
"certificate.action.download": "下载证书",
|
||||
|
||||
"certificate.props.subject_alt_names": "名称",
|
||||
|
@ -49,7 +49,7 @@
|
||||
"workflow.detail.orchestration.action.release.confirm": "确定要发布更改吗?",
|
||||
"workflow.detail.orchestration.action.release.failed.uncompleted": "流程编排未完成,请检查是否有节点未配置",
|
||||
"workflow.detail.orchestration.action.run": "执行",
|
||||
"workflow.detail.orchestration.action.run.confirm": "你有尚未发布的更改。你确定要以最近一次发布的版本继续执行吗?",
|
||||
"workflow.detail.orchestration.action.run.confirm": "你有尚未发布的更改。确定要以最近一次发布的版本继续执行吗?",
|
||||
"workflow.detail.orchestration.action.run.prompt": "执行中……请稍后查看执行历史",
|
||||
"workflow.detail.runs.tab": "执行历史"
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
"workflow_node.action.rename_branch": "重命名",
|
||||
"workflow_node.action.remove_branch": "删除分支",
|
||||
|
||||
"workflow_node.unsaved_changes.confirm": "你有尚未保存的更改。你确定要关闭面板吗?",
|
||||
"workflow_node.unsaved_changes.confirm": "你有尚未保存的更改。确定要关闭面板吗?",
|
||||
|
||||
"workflow_node.start.label": "开始",
|
||||
"workflow_node.start.form.trigger.label": "触发方式",
|
||||
|
@ -130,7 +130,7 @@ const AccessList = () => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const { loading } = useRequest(
|
||||
const { loading, run: refreshTableData } = useRequest(
|
||||
() => {
|
||||
const startIndex = (page - 1) * pageSize;
|
||||
const endIndex = startIndex + pageSize;
|
||||
@ -157,6 +157,7 @@ const AccessList = () => {
|
||||
// TODO: 有关联数据的不允许被删除
|
||||
try {
|
||||
await deleteAccess(data);
|
||||
refreshTableData();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
|
||||
|
@ -4,13 +4,13 @@ import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { DeleteOutlined as DeleteOutlinedIcon, SelectOutlined as SelectOutlinedIcon } from "@ant-design/icons";
|
||||
import { PageHeader } from "@ant-design/pro-components";
|
||||
import { useRequest } from "ahooks";
|
||||
import { Button, Divider, Empty, Menu, type MenuProps, Radio, Space, Table, type TableProps, Tooltip, Typography, notification, theme } from "antd";
|
||||
import { Button, Divider, Empty, Menu, type MenuProps, Modal, Radio, Space, Table, type TableProps, Tooltip, Typography, notification, theme } from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
|
||||
import CertificateDetailDrawer from "@/components/certificate/CertificateDetailDrawer";
|
||||
import { CERTIFICATE_SOURCES, type CertificateModel } from "@/domain/certificate";
|
||||
import { type ListCertificateRequest, list as listCertificate } from "@/repository/certificate";
|
||||
import { type ListCertificateRequest, list as listCertificate, remove as removeCertificate } from "@/repository/certificate";
|
||||
import { getErrMsg } from "@/utils/error";
|
||||
|
||||
const CertificateList = () => {
|
||||
@ -21,6 +21,7 @@ const CertificateList = () => {
|
||||
|
||||
const { token: themeToken } = theme.useToken();
|
||||
|
||||
const [modalApi, ModalContextHolder] = Modal.useModal();
|
||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||
|
||||
const tableColumns: TableProps<CertificateModel>["columns"] = [
|
||||
@ -169,14 +170,7 @@ const CertificateList = () => {
|
||||
/>
|
||||
|
||||
<Tooltip title={t("certificate.action.delete")}>
|
||||
<Button
|
||||
color="danger"
|
||||
icon={<DeleteOutlinedIcon />}
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
alert("TODO: 暂时不支持删除证书");
|
||||
}}
|
||||
/>
|
||||
<Button color="danger" icon={<DeleteOutlinedIcon />} variant="text" onClick={() => handleDeleteClick(record)} />
|
||||
</Tooltip>
|
||||
</Button.Group>
|
||||
),
|
||||
@ -194,7 +188,7 @@ const CertificateList = () => {
|
||||
const [page, setPage] = useState<number>(() => parseInt(+searchParams.get("page")! + "") || 1);
|
||||
const [pageSize, setPageSize] = useState<number>(() => parseInt(+searchParams.get("perPage")! + "") || 10);
|
||||
|
||||
const { loading } = useRequest(
|
||||
const { loading, run: refreshTableData } = useRequest(
|
||||
() => {
|
||||
return listCertificate({
|
||||
page: page,
|
||||
@ -219,8 +213,28 @@ const CertificateList = () => {
|
||||
}
|
||||
);
|
||||
|
||||
const handleDeleteClick = (certificate: CertificateModel) => {
|
||||
modalApi.confirm({
|
||||
title: t("certificate.action.delete"),
|
||||
content: t("certificate.action.delete.confirm"),
|
||||
onOk: async () => {
|
||||
try {
|
||||
const resp = await removeCertificate(certificate);
|
||||
if (resp) {
|
||||
setTableData((prev) => prev.filter((item) => item.id !== certificate.id));
|
||||
refreshTableData();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
{ModalContextHolder}
|
||||
{NotificationContextHolder}
|
||||
|
||||
<PageHeader title={t("certificate.page.title")} />
|
||||
|
@ -251,10 +251,10 @@ const Dashboard = () => {
|
||||
{t("dashboard.quick_actions.change_login_password")}
|
||||
</Button>
|
||||
<Button block size="large" icon={<SendOutlined />} onClick={() => navigate("/settings/notification")}>
|
||||
{t("dashboard.quick_actions.notification_settings")}
|
||||
{t("dashboard.quick_actions.cofigure_notification")}
|
||||
</Button>
|
||||
<Button block size="large" icon={<ApiOutlined />} onClick={() => navigate("/settings/ssl-provider")}>
|
||||
{t("dashboard.quick_actions.certificate_authority_configuration")}
|
||||
{t("dashboard.quick_actions.configure_ca")}
|
||||
</Button>
|
||||
</Space>
|
||||
</Card>
|
||||
|
@ -109,7 +109,7 @@ const WorkflowDetail = () => {
|
||||
content: t("workflow.action.delete.confirm"),
|
||||
onOk: async () => {
|
||||
try {
|
||||
const resp: boolean = await removeWorkflow(workflow);
|
||||
const resp = await removeWorkflow(workflow);
|
||||
if (resp) {
|
||||
navigate("/workflows", { replace: true });
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ const WorkflowList = () => {
|
||||
const [page, setPage] = useState<number>(() => parseInt(+searchParams.get("page")! + "") || 1);
|
||||
const [pageSize, setPageSize] = useState<number>(() => parseInt(+searchParams.get("perPage")! + "") || 10);
|
||||
|
||||
const { loading } = useRequest(
|
||||
const { loading, run: refreshTableData } = useRequest(
|
||||
() => {
|
||||
return listWorkflow({
|
||||
page: page,
|
||||
@ -302,9 +302,10 @@ const WorkflowList = () => {
|
||||
content: t("workflow.action.delete.confirm"),
|
||||
onOk: async () => {
|
||||
try {
|
||||
const resp: boolean = await removeWorkflow(workflow);
|
||||
const resp = await removeWorkflow(workflow);
|
||||
if (resp) {
|
||||
setTableData((prev) => prev.filter((item) => item.id !== workflow.id));
|
||||
refreshTableData();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
@ -30,4 +30,5 @@ export const remove = async (record: MaybeModelRecordWithId<AccessModel>) => {
|
||||
if ("provider" in record && record.provider === "pdns") record.provider = "powerdns";
|
||||
|
||||
await getPocketBase().collection(COLLECTION_NAME).update<AccessModel>(record.id!, record);
|
||||
return true;
|
||||
};
|
||||
|
@ -42,4 +42,5 @@ export const remove = async (record: MaybeModelRecordWithId<CertificateModel>) =
|
||||
record = { ...record, deleted: dayjs.utc().format("YYYY-MM-DD HH:mm:ss") };
|
||||
|
||||
await getPocketBase().collection(COLLECTION_NAME).update<CertificateModel>(record.id!, record);
|
||||
return true;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user