mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-23 12:49:56 +00:00
feat: reserve accesses for ca or notification
This commit is contained in:
parent
193a19b79c
commit
e533f9407f
@ -1098,7 +1098,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
|||||||
|
|
||||||
deployer, err := pWebhook.NewDeployer(&pWebhook.DeployerConfig{
|
deployer, err := pWebhook.NewDeployer(&pWebhook.DeployerConfig{
|
||||||
WebhookUrl: access.Url,
|
WebhookUrl: access.Url,
|
||||||
WebhookData: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", access.TemplateDataForDeployment),
|
WebhookData: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", access.DefaultDataForDeployment),
|
||||||
Method: access.Method,
|
Method: access.Method,
|
||||||
Headers: mergedHeaders,
|
Headers: mergedHeaders,
|
||||||
AllowInsecureConnections: access.AllowInsecureConnections,
|
AllowInsecureConnections: access.AllowInsecureConnections,
|
||||||
|
@ -11,6 +11,7 @@ type Access struct {
|
|||||||
Name string `json:"name" db:"name"`
|
Name string `json:"name" db:"name"`
|
||||||
Provider string `json:"provider" db:"provider"`
|
Provider string `json:"provider" db:"provider"`
|
||||||
Config map[string]any `json:"config" db:"config"`
|
Config map[string]any `json:"config" db:"config"`
|
||||||
|
Reserve string `json:"reserve,omitempty" db:"reserve"`
|
||||||
DeletedAt *time.Time `json:"deleted" db:"deleted"`
|
DeletedAt *time.Time `json:"deleted" db:"deleted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,8 +266,8 @@ type AccessConfigForWebhook struct {
|
|||||||
Method string `json:"method,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
HeadersString string `json:"headers,omitempty"`
|
HeadersString string `json:"headers,omitempty"`
|
||||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
TemplateDataForDeployment string `json:"templateDataForDeployment,omitempty"` // TODO:
|
DefaultDataForDeployment string `json:"defaultDataForDeployment,omitempty"`
|
||||||
TemplateDataForNotification string `json:"templateDataForNotification,omitempty"` // TODO:
|
DefaultDataForNotification string `json:"defaultDataForNotification,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessConfigForWestcn struct {
|
type AccessConfigForWestcn struct {
|
||||||
|
@ -101,7 +101,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
|||||||
|
|
||||||
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
|
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
|
||||||
WebhookUrl: access.Url,
|
WebhookUrl: access.Url,
|
||||||
WebhookData: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", access.TemplateDataForNotification),
|
WebhookData: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", access.DefaultDataForNotification),
|
||||||
Method: access.Method,
|
Method: access.Method,
|
||||||
Headers: mergedHeaders,
|
Headers: mergedHeaders,
|
||||||
AllowInsecureConnections: access.AllowInsecureConnections,
|
AllowInsecureConnections: access.AllowInsecureConnections,
|
||||||
|
@ -80,7 +80,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse webhook url: %w", err)
|
return nil, fmt.Errorf("failed to parse webhook url: %w", err)
|
||||||
} else if webhookUrl.Scheme != "http" && webhookUrl.Scheme != "https" {
|
} else if webhookUrl.Scheme != "http" && webhookUrl.Scheme != "https" {
|
||||||
return nil, fmt.Errorf("unsupported webhook url scheme: %s", webhookUrl.Scheme)
|
return nil, fmt.Errorf("unsupported webhook url scheme '%s'", webhookUrl.Scheme)
|
||||||
} else {
|
} else {
|
||||||
webhookUrl.Path = strings.ReplaceAll(webhookUrl.Path, "${DOMAIN}", url.PathEscape(certX509.Subject.CommonName))
|
webhookUrl.Path = strings.ReplaceAll(webhookUrl.Path, "${DOMAIN}", url.PathEscape(certX509.Subject.CommonName))
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
webhookMethod != http.MethodPut &&
|
webhookMethod != http.MethodPut &&
|
||||||
webhookMethod != http.MethodPatch &&
|
webhookMethod != http.MethodPatch &&
|
||||||
webhookMethod != http.MethodDelete {
|
webhookMethod != http.MethodDelete {
|
||||||
return nil, fmt.Errorf("unsupported webhook request method: %s", webhookMethod)
|
return nil, fmt.Errorf("unsupported webhook request method '%s'", webhookMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理 Webhook 请求标头
|
// 处理 Webhook 请求标头
|
||||||
@ -114,7 +114,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
|||||||
} else if strings.HasPrefix(webhookContentType, CONTENT_TYPE_JSON) &&
|
} else if strings.HasPrefix(webhookContentType, CONTENT_TYPE_JSON) &&
|
||||||
strings.HasPrefix(webhookContentType, CONTENT_TYPE_FORM) &&
|
strings.HasPrefix(webhookContentType, CONTENT_TYPE_FORM) &&
|
||||||
strings.HasPrefix(webhookContentType, CONTENT_TYPE_MULTIPART) {
|
strings.HasPrefix(webhookContentType, CONTENT_TYPE_MULTIPART) {
|
||||||
return nil, fmt.Errorf("unsupported webhook content type: %s", webhookContentType)
|
return nil, fmt.Errorf("unsupported webhook content type '%s'", webhookContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理 Webhook 请求数据
|
// 处理 Webhook 请求数据
|
||||||
|
@ -73,7 +73,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse webhook url: %w", err)
|
return nil, fmt.Errorf("failed to parse webhook url: %w", err)
|
||||||
} else if webhookUrl.Scheme != "http" && webhookUrl.Scheme != "https" {
|
} else if webhookUrl.Scheme != "http" && webhookUrl.Scheme != "https" {
|
||||||
return nil, fmt.Errorf("unsupported webhook url scheme: %s", webhookUrl.Scheme)
|
return nil, fmt.Errorf("unsupported webhook url scheme '%s'", webhookUrl.Scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理 Webhook 请求谓词
|
// 处理 Webhook 请求谓词
|
||||||
@ -85,7 +85,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
|||||||
webhookMethod != http.MethodPut &&
|
webhookMethod != http.MethodPut &&
|
||||||
webhookMethod != http.MethodPatch &&
|
webhookMethod != http.MethodPatch &&
|
||||||
webhookMethod != http.MethodDelete {
|
webhookMethod != http.MethodDelete {
|
||||||
return nil, fmt.Errorf("unsupported webhook request method: %s", webhookMethod)
|
return nil, fmt.Errorf("unsupported webhook request method '%s'", webhookMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理 Webhook 请求标头
|
// 处理 Webhook 请求标头
|
||||||
@ -105,7 +105,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
|||||||
} else if strings.HasPrefix(webhookContentType, CONTENT_TYPE_JSON) &&
|
} else if strings.HasPrefix(webhookContentType, CONTENT_TYPE_JSON) &&
|
||||||
strings.HasPrefix(webhookContentType, CONTENT_TYPE_FORM) &&
|
strings.HasPrefix(webhookContentType, CONTENT_TYPE_FORM) &&
|
||||||
strings.HasPrefix(webhookContentType, CONTENT_TYPE_MULTIPART) {
|
strings.HasPrefix(webhookContentType, CONTENT_TYPE_MULTIPART) {
|
||||||
return nil, fmt.Errorf("unsupported webhook content type: %s", webhookContentType)
|
return nil, fmt.Errorf("unsupported webhook content type '%s'", webhookContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理 Webhook 请求数据
|
// 处理 Webhook 请求数据
|
||||||
|
@ -53,6 +53,7 @@ func (r *AccessRepository) castRecordToModel(record *core.Record) (*domain.Acces
|
|||||||
Name: record.GetString("name"),
|
Name: record.GetString("name"),
|
||||||
Provider: record.GetString("provider"),
|
Provider: record.GetString("provider"),
|
||||||
Config: config,
|
Config: config,
|
||||||
|
Reserve: record.GetString("reserve"),
|
||||||
}
|
}
|
||||||
return access, nil
|
return access, nil
|
||||||
}
|
}
|
||||||
|
88
migrations/1745726400_upgrade.go
Normal file
88
migrations/1745726400_upgrade.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
// update collection `access`
|
||||||
|
{
|
||||||
|
collection, err := app.FindCollectionByNameOrId("4yzbv8urny5ja1e")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(4, []byte(`{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text2859962647",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "reserve",
|
||||||
|
"pattern": "",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Save(collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// migrate data
|
||||||
|
{
|
||||||
|
accesses, err := app.FindAllRecords("access")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, access := range accesses {
|
||||||
|
changed := false
|
||||||
|
|
||||||
|
if access.GetString("provider") == "buypass" {
|
||||||
|
access.Set("reserve", "ca")
|
||||||
|
changed = true
|
||||||
|
} else if access.GetString("provider") == "googletrustservices" {
|
||||||
|
access.Set("reserve", "ca")
|
||||||
|
changed = true
|
||||||
|
} else if access.GetString("provider") == "sslcom" {
|
||||||
|
access.Set("reserve", "ca")
|
||||||
|
changed = true
|
||||||
|
} else if access.GetString("provider") == "zerossl" {
|
||||||
|
access.Set("reserve", "ca")
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if access.GetString("provider") == "webhook" {
|
||||||
|
config := make(map[string]any)
|
||||||
|
if err := access.UnmarshalJSONField("config", &config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
config["method"] = "POST"
|
||||||
|
config["headers"] = "Content-Type: application/json"
|
||||||
|
access.Set("config", config)
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if changed {
|
||||||
|
err = app.Save(access)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
@ -14,14 +14,14 @@ export type AccessEditDrawerProps = {
|
|||||||
data?: AccessFormProps["initialValues"];
|
data?: AccessFormProps["initialValues"];
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
range?: AccessFormProps["range"];
|
|
||||||
scene: AccessFormProps["scene"];
|
scene: AccessFormProps["scene"];
|
||||||
trigger?: React.ReactNode;
|
trigger?: React.ReactNode;
|
||||||
|
usage?: AccessFormProps["usage"];
|
||||||
onOpenChange?: (open: boolean) => void;
|
onOpenChange?: (open: boolean) => void;
|
||||||
afterSubmit?: (record: AccessModel) => void;
|
afterSubmit?: (record: AccessModel) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AccessEditDrawer = ({ data, loading, trigger, scene, range, afterSubmit, ...props }: AccessEditDrawerProps) => {
|
const AccessEditDrawer = ({ data, loading, trigger, scene, usage, afterSubmit, ...props }: AccessEditDrawerProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||||
@ -109,7 +109,7 @@ const AccessEditDrawer = ({ data, loading, trigger, scene, range, afterSubmit, .
|
|||||||
width={720}
|
width={720}
|
||||||
onClose={() => setOpen(false)}
|
onClose={() => setOpen(false)}
|
||||||
>
|
>
|
||||||
<AccessForm ref={formRef} initialValues={data} range={range} scene={scene === "add" ? "add" : "edit"} />
|
<AccessForm ref={formRef} initialValues={data} scene={scene === "add" ? "add" : "edit"} usage={usage} />
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -14,14 +14,14 @@ export type AccessEditModalProps = {
|
|||||||
data?: AccessFormProps["initialValues"];
|
data?: AccessFormProps["initialValues"];
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
range?: AccessFormProps["range"];
|
usage?: AccessFormProps["usage"];
|
||||||
scene: AccessFormProps["scene"];
|
scene: AccessFormProps["scene"];
|
||||||
trigger?: React.ReactNode;
|
trigger?: React.ReactNode;
|
||||||
onOpenChange?: (open: boolean) => void;
|
onOpenChange?: (open: boolean) => void;
|
||||||
afterSubmit?: (record: AccessModel) => void;
|
afterSubmit?: (record: AccessModel) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AccessEditModal = ({ data, loading, trigger, scene, range, afterSubmit, ...props }: AccessEditModalProps) => {
|
const AccessEditModal = ({ data, loading, trigger, scene, usage, afterSubmit, ...props }: AccessEditModalProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||||
@ -105,7 +105,7 @@ const AccessEditModal = ({ data, loading, trigger, scene, range, afterSubmit, ..
|
|||||||
onCancel={handleCancelClick}
|
onCancel={handleCancelClick}
|
||||||
>
|
>
|
||||||
<div className="pb-2 pt-4">
|
<div className="pb-2 pt-4">
|
||||||
<AccessForm ref={formRef} initialValues={data} range={range} scene={scene === "add" ? "add" : "edit"} />
|
<AccessForm ref={formRef} initialValues={data} scene={scene === "add" ? "add" : "edit"} usage={usage} />
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
|
@ -61,16 +61,16 @@ import AccessFormWestcnConfig from "./AccessFormWestcnConfig";
|
|||||||
import AccessFormZeroSSLConfig from "./AccessFormZeroSSLConfig";
|
import AccessFormZeroSSLConfig from "./AccessFormZeroSSLConfig";
|
||||||
|
|
||||||
type AccessFormFieldValues = Partial<MaybeModelRecord<AccessModel>>;
|
type AccessFormFieldValues = Partial<MaybeModelRecord<AccessModel>>;
|
||||||
type AccessFormRanges = "both-dns-hosting" | "ca-only" | "notify-only";
|
|
||||||
type AccessFormScenes = "add" | "edit";
|
type AccessFormScenes = "add" | "edit";
|
||||||
|
type AccessFormUsages = "both-dns-hosting" | "ca-only" | "notification-only";
|
||||||
|
|
||||||
export type AccessFormProps = {
|
export type AccessFormProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
initialValues?: AccessFormFieldValues;
|
initialValues?: AccessFormFieldValues;
|
||||||
range?: AccessFormRanges;
|
|
||||||
scene: AccessFormScenes;
|
scene: AccessFormScenes;
|
||||||
|
usage?: AccessFormUsages;
|
||||||
onValuesChange?: (values: AccessFormFieldValues) => void;
|
onValuesChange?: (values: AccessFormFieldValues) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ export type AccessFormInstance = {
|
|||||||
validateFields: FormInstance<AccessFormFieldValues>["validateFields"];
|
validateFields: FormInstance<AccessFormFieldValues>["validateFields"];
|
||||||
};
|
};
|
||||||
|
|
||||||
const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className, style, disabled, initialValues, range, scene, onValuesChange }, ref) => {
|
const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className, style, disabled, initialValues, usage, scene, onValuesChange }, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
@ -91,13 +91,14 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
|||||||
.trim(),
|
.trim(),
|
||||||
provider: z.nativeEnum(ACCESS_PROVIDERS, {
|
provider: z.nativeEnum(ACCESS_PROVIDERS, {
|
||||||
message:
|
message:
|
||||||
range === "ca-only"
|
usage === "ca-only"
|
||||||
? t("access.form.certificate_authority.placeholder")
|
? t("access.form.certificate_authority.placeholder")
|
||||||
: range === "notify-only"
|
: usage === "notification-only"
|
||||||
? t("access.form.notification_channel.placeholder")
|
? t("access.form.notification_channel.placeholder")
|
||||||
: t("access.form.provider.placeholder"),
|
: t("access.form.provider.placeholder"),
|
||||||
}),
|
}),
|
||||||
config: z.any(),
|
config: z.any(),
|
||||||
|
reserve: z.string().nullish(),
|
||||||
});
|
});
|
||||||
const formRule = createSchemaFieldRule(formSchema);
|
const formRule = createSchemaFieldRule(formSchema);
|
||||||
const { form: formInst, formProps } = useAntdForm({
|
const { form: formInst, formProps } = useAntdForm({
|
||||||
@ -105,33 +106,33 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
|||||||
});
|
});
|
||||||
|
|
||||||
const providerLabel = useMemo(() => {
|
const providerLabel = useMemo(() => {
|
||||||
switch (range) {
|
switch (usage) {
|
||||||
case "ca-only":
|
case "ca-only":
|
||||||
return t("access.form.certificate_authority.label");
|
return t("access.form.certificate_authority.label");
|
||||||
case "notify-only":
|
case "notification-only":
|
||||||
return t("access.form.notification_channel.label");
|
return t("access.form.notification_channel.label");
|
||||||
}
|
}
|
||||||
|
|
||||||
return t("access.form.provider.label");
|
return t("access.form.provider.label");
|
||||||
}, [range]);
|
}, [usage]);
|
||||||
const providerPlaceholder = useMemo(() => {
|
const providerPlaceholder = useMemo(() => {
|
||||||
switch (range) {
|
switch (usage) {
|
||||||
case "ca-only":
|
case "ca-only":
|
||||||
return t("access.form.certificate_authority.placeholder");
|
return t("access.form.certificate_authority.placeholder");
|
||||||
case "notify-only":
|
case "notification-only":
|
||||||
return t("access.form.notification_channel.placeholder");
|
return t("access.form.notification_channel.placeholder");
|
||||||
}
|
}
|
||||||
|
|
||||||
return t("access.form.provider.placeholder");
|
return t("access.form.provider.placeholder");
|
||||||
}, [range]);
|
}, [usage]);
|
||||||
const providerTooltip = useMemo(() => {
|
const providerTooltip = useMemo(() => {
|
||||||
switch (range) {
|
switch (usage) {
|
||||||
case "both-dns-hosting":
|
case "both-dns-hosting":
|
||||||
return <span dangerouslySetInnerHTML={{ __html: t("access.form.provider.tooltip") }}></span>;
|
return <span dangerouslySetInnerHTML={{ __html: t("access.form.provider.tooltip") }}></span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}, [range]);
|
}, [usage]);
|
||||||
|
|
||||||
const fieldProvider = Form.useWatch("provider", formInst);
|
const fieldProvider = Form.useWatch("provider", formInst);
|
||||||
|
|
||||||
@ -269,6 +270,7 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
|||||||
getFieldsValue: () => {
|
getFieldsValue: () => {
|
||||||
const values = formInst.getFieldsValue(true);
|
const values = formInst.getFieldsValue(true);
|
||||||
values.config = nestedFormInst.getFieldsValue();
|
values.config = nestedFormInst.getFieldsValue();
|
||||||
|
values.reserve = usage === "ca-only" ? "ca" : usage === "notification-only" ? "notification" : undefined;
|
||||||
return values;
|
return values;
|
||||||
},
|
},
|
||||||
resetFields: (fields) => {
|
resetFields: (fields) => {
|
||||||
@ -297,20 +299,20 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
|||||||
<Form.Item name="provider" label={providerLabel} rules={[formRule]} tooltip={providerTooltip}>
|
<Form.Item name="provider" label={providerLabel} rules={[formRule]} tooltip={providerTooltip}>
|
||||||
<AccessProviderSelect
|
<AccessProviderSelect
|
||||||
filter={(record) => {
|
filter={(record) => {
|
||||||
if (range == null) return true;
|
if (usage == null) return true;
|
||||||
|
|
||||||
switch (range) {
|
switch (usage) {
|
||||||
case "both-dns-hosting":
|
case "both-dns-hosting":
|
||||||
return record.usages.includes(ACCESS_USAGES.DNS) || record.usages.includes(ACCESS_USAGES.HOSTING);
|
return record.usages.includes(ACCESS_USAGES.DNS) || record.usages.includes(ACCESS_USAGES.HOSTING);
|
||||||
case "ca-only":
|
case "ca-only":
|
||||||
return record.usages.includes(ACCESS_USAGES.CA);
|
return record.usages.includes(ACCESS_USAGES.CA);
|
||||||
case "notify-only":
|
case "notification-only":
|
||||||
return record.usages.includes(ACCESS_USAGES.NOTIFICATION);
|
return record.usages.includes(ACCESS_USAGES.NOTIFICATION);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={scene !== "add"}
|
disabled={scene !== "add"}
|
||||||
placeholder={providerPlaceholder}
|
placeholder={providerPlaceholder}
|
||||||
showOptionTags={range == null || (range === "both-dns-hosting" ? { [ACCESS_USAGES.DNS]: true, [ACCESS_USAGES.HOSTING]: true } : false)}
|
showOptionTags={usage == null || (usage === "both-dns-hosting" ? { [ACCESS_USAGES.DNS]: true, [ACCESS_USAGES.HOSTING]: true } : false)}
|
||||||
showSearch={!disabled}
|
showSearch={!disabled}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
@ -352,7 +352,6 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<AccessEditModal
|
<AccessEditModal
|
||||||
range="both-dns-hosting"
|
|
||||||
scene="add"
|
scene="add"
|
||||||
trigger={
|
trigger={
|
||||||
<Button size="small" type="link">
|
<Button size="small" type="link">
|
||||||
@ -360,6 +359,7 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
|||||||
<PlusOutlinedIcon className="text-xs" />
|
<PlusOutlinedIcon className="text-xs" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
usage="both-dns-hosting"
|
||||||
afterSubmit={(record) => {
|
afterSubmit={(record) => {
|
||||||
const provider = accessProvidersMap.get(record.provider);
|
const provider = accessProvidersMap.get(record.provider);
|
||||||
if (provider?.usages?.includes(ACCESS_USAGES.DNS)) {
|
if (provider?.usages?.includes(ACCESS_USAGES.DNS)) {
|
||||||
@ -374,6 +374,8 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
|||||||
<Form.Item name="providerAccessId" rules={[formRule]}>
|
<Form.Item name="providerAccessId" rules={[formRule]}>
|
||||||
<AccessSelect
|
<AccessSelect
|
||||||
filter={(record) => {
|
filter={(record) => {
|
||||||
|
if (record.reserve) return false;
|
||||||
|
|
||||||
const provider = accessProvidersMap.get(record.provider);
|
const provider = accessProvidersMap.get(record.provider);
|
||||||
return !!provider?.usages?.includes(ACCESS_USAGES.DNS);
|
return !!provider?.usages?.includes(ACCESS_USAGES.DNS);
|
||||||
}}
|
}}
|
||||||
@ -429,7 +431,6 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
|||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<AccessEditModal
|
<AccessEditModal
|
||||||
data={{ provider: caProvidersMap.get(fieldCAProvider!)?.provider }}
|
data={{ provider: caProvidersMap.get(fieldCAProvider!)?.provider }}
|
||||||
range="ca-only"
|
|
||||||
scene="add"
|
scene="add"
|
||||||
trigger={
|
trigger={
|
||||||
<Button size="small" type="link">
|
<Button size="small" type="link">
|
||||||
@ -437,6 +438,7 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
|||||||
<PlusOutlinedIcon className="text-xs" />
|
<PlusOutlinedIcon className="text-xs" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
usage="ca-only"
|
||||||
afterSubmit={(record) => {
|
afterSubmit={(record) => {
|
||||||
const provider = accessProvidersMap.get(record.provider);
|
const provider = accessProvidersMap.get(record.provider);
|
||||||
if (provider?.usages?.includes(ACCESS_USAGES.CA)) {
|
if (provider?.usages?.includes(ACCESS_USAGES.CA)) {
|
||||||
@ -450,9 +452,8 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
|||||||
<Form.Item name="caProviderAccessId" rules={[formRule]}>
|
<Form.Item name="caProviderAccessId" rules={[formRule]}>
|
||||||
<AccessSelect
|
<AccessSelect
|
||||||
filter={(record) => {
|
filter={(record) => {
|
||||||
if (fieldCAProvider) {
|
if (!!record.reserve && record.reserve !== "ca") return false;
|
||||||
return caProvidersMap.get(fieldCAProvider)?.provider === record.provider;
|
if (fieldCAProvider) return caProvidersMap.get(fieldCAProvider)?.provider === record.provider;
|
||||||
}
|
|
||||||
|
|
||||||
const provider = accessProvidersMap.get(record.provider);
|
const provider = accessProvidersMap.get(record.provider);
|
||||||
return !!provider?.usages?.includes(ACCESS_USAGES.CA);
|
return !!provider?.usages?.includes(ACCESS_USAGES.CA);
|
||||||
|
@ -409,7 +409,6 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
|||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<AccessEditModal
|
<AccessEditModal
|
||||||
data={{ provider: deploymentProvidersMap.get(fieldProvider!)?.provider }}
|
data={{ provider: deploymentProvidersMap.get(fieldProvider!)?.provider }}
|
||||||
range="both-dns-hosting"
|
|
||||||
scene="add"
|
scene="add"
|
||||||
trigger={
|
trigger={
|
||||||
<Button size="small" type="link">
|
<Button size="small" type="link">
|
||||||
@ -417,6 +416,7 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
|||||||
<PlusOutlinedIcon className="text-xs" />
|
<PlusOutlinedIcon className="text-xs" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
usage="both-dns-hosting"
|
||||||
afterSubmit={(record) => {
|
afterSubmit={(record) => {
|
||||||
const provider = accessProvidersMap.get(record.provider);
|
const provider = accessProvidersMap.get(record.provider);
|
||||||
if (provider?.usages?.includes(ACCESS_USAGES.HOSTING)) {
|
if (provider?.usages?.includes(ACCESS_USAGES.HOSTING)) {
|
||||||
@ -430,9 +430,8 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
|||||||
<Form.Item name="providerAccessId" rules={[formRule]}>
|
<Form.Item name="providerAccessId" rules={[formRule]}>
|
||||||
<AccessSelect
|
<AccessSelect
|
||||||
filter={(record) => {
|
filter={(record) => {
|
||||||
if (fieldProvider) {
|
if (record.reserve) return false;
|
||||||
return deploymentProvidersMap.get(fieldProvider)?.provider === record.provider;
|
if (fieldProvider) return deploymentProvidersMap.get(fieldProvider)?.provider === record.provider;
|
||||||
}
|
|
||||||
|
|
||||||
const provider = accessProvidersMap.get(record.provider);
|
const provider = accessProvidersMap.get(record.provider);
|
||||||
return !!provider?.usages?.includes(ACCESS_USAGES.HOSTING);
|
return !!provider?.usages?.includes(ACCESS_USAGES.HOSTING);
|
||||||
|
@ -228,7 +228,6 @@ const NotifyNodeConfigForm = forwardRef<NotifyNodeConfigFormInstance, NotifyNode
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<AccessEditModal
|
<AccessEditModal
|
||||||
range="notify-only"
|
|
||||||
scene="add"
|
scene="add"
|
||||||
trigger={
|
trigger={
|
||||||
<Button size="small" type="link">
|
<Button size="small" type="link">
|
||||||
@ -236,6 +235,7 @@ const NotifyNodeConfigForm = forwardRef<NotifyNodeConfigFormInstance, NotifyNode
|
|||||||
<PlusOutlinedIcon className="text-xs" />
|
<PlusOutlinedIcon className="text-xs" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
usage="notification-only"
|
||||||
afterSubmit={(record) => {
|
afterSubmit={(record) => {
|
||||||
const provider = accessProvidersMap.get(record.provider);
|
const provider = accessProvidersMap.get(record.provider);
|
||||||
if (provider?.usages?.includes(ACCESS_USAGES.NOTIFICATION)) {
|
if (provider?.usages?.includes(ACCESS_USAGES.NOTIFICATION)) {
|
||||||
@ -250,6 +250,8 @@ const NotifyNodeConfigForm = forwardRef<NotifyNodeConfigFormInstance, NotifyNode
|
|||||||
<Form.Item name="providerAccessId" rules={[formRule]}>
|
<Form.Item name="providerAccessId" rules={[formRule]}>
|
||||||
<AccessSelect
|
<AccessSelect
|
||||||
filter={(record) => {
|
filter={(record) => {
|
||||||
|
if (!!record.reserve && record.reserve !== "notification") return false;
|
||||||
|
|
||||||
const provider = accessProvidersMap.get(record.provider);
|
const provider = accessProvidersMap.get(record.provider);
|
||||||
return !!provider?.usages?.includes(ACCESS_USAGES.NOTIFICATION);
|
return !!provider?.usages?.includes(ACCESS_USAGES.NOTIFICATION);
|
||||||
}}
|
}}
|
||||||
|
@ -56,6 +56,7 @@ export interface AccessModel extends BaseModel {
|
|||||||
| AccessConfigForWestcn
|
| AccessConfigForWestcn
|
||||||
| AccessConfigForZeroSSL
|
| AccessConfigForZeroSSL
|
||||||
);
|
);
|
||||||
|
reserve?: "ca" | "notification";
|
||||||
}
|
}
|
||||||
|
|
||||||
// #region AccessConfig
|
// #region AccessConfig
|
||||||
@ -310,8 +311,8 @@ export type AccessConfigForWebhook = {
|
|||||||
method: string;
|
method: string;
|
||||||
headers?: string;
|
headers?: string;
|
||||||
allowInsecureConnections?: boolean;
|
allowInsecureConnections?: boolean;
|
||||||
templateDataForDeployment?: string;
|
defaultDataForDeployment?: string;
|
||||||
templateDataForNotification?: string;
|
defaultDataForNotification?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AccessConfigForWestcn = {
|
export type AccessConfigForWestcn = {
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
"access.props.provider.usage.ca": "Certificate authority",
|
"access.props.provider.usage.ca": "Certificate authority",
|
||||||
"access.props.provider.usage.notification": "Notification channel",
|
"access.props.provider.usage.notification": "Notification channel",
|
||||||
"access.props.provider.builtin": "Built-in",
|
"access.props.provider.builtin": "Built-in",
|
||||||
"access.props.range.both_dns_hosting": "Provider",
|
"access.props.usage.both_dns_hosting": "Provider",
|
||||||
"access.props.range.ca_only": "Certificate authority",
|
"access.props.usage.ca_only": "Certificate authority",
|
||||||
"access.props.range.notify_only": "Notification channel",
|
"access.props.usage.notification_only": "Notification channel",
|
||||||
"access.props.created_at": "Created at",
|
"access.props.created_at": "Created at",
|
||||||
"access.props.updated_at": "Updated at",
|
"access.props.updated_at": "Updated at",
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
"access.props.provider.usage.ca": "证书颁发机构",
|
"access.props.provider.usage.ca": "证书颁发机构",
|
||||||
"access.props.provider.usage.notification": "通知渠道",
|
"access.props.provider.usage.notification": "通知渠道",
|
||||||
"access.props.provider.builtin": "内置",
|
"access.props.provider.builtin": "内置",
|
||||||
"access.props.range.both_dns_hosting": "提供商",
|
"access.props.usage.both_dns_hosting": "提供商",
|
||||||
"access.props.range.ca_only": "证书颁发机构",
|
"access.props.usage.ca_only": "证书颁发机构",
|
||||||
"access.props.range.notify_only": "通知渠道",
|
"access.props.usage.notification_only": "通知渠道",
|
||||||
"access.props.created_at": "创建时间",
|
"access.props.created_at": "创建时间",
|
||||||
"access.props.updated_at": "更新时间",
|
"access.props.updated_at": "更新时间",
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import { useZustandShallowSelector } from "@/hooks";
|
|||||||
import { useAccessesStore } from "@/stores/access";
|
import { useAccessesStore } from "@/stores/access";
|
||||||
import { getErrMsg } from "@/utils/error";
|
import { getErrMsg } from "@/utils/error";
|
||||||
|
|
||||||
type AccessRanges = AccessEditDrawerProps["range"];
|
type AccessUsageProp = AccessEditDrawerProps["usage"];
|
||||||
|
|
||||||
const AccessList = () => {
|
const AccessList = () => {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
@ -87,7 +87,7 @@ const AccessList = () => {
|
|||||||
<Space.Compact>
|
<Space.Compact>
|
||||||
<AccessEditDrawer
|
<AccessEditDrawer
|
||||||
data={record}
|
data={record}
|
||||||
range={filters["range"] as AccessRanges}
|
usage={filters["usage"] as AccessUsageProp}
|
||||||
scene="edit"
|
scene="edit"
|
||||||
trigger={
|
trigger={
|
||||||
<Tooltip title={t("access.action.edit")}>
|
<Tooltip title={t("access.action.edit")}>
|
||||||
@ -98,7 +98,7 @@ const AccessList = () => {
|
|||||||
|
|
||||||
<AccessEditDrawer
|
<AccessEditDrawer
|
||||||
data={{ ...record, id: undefined, name: `${record.name}-copy` }}
|
data={{ ...record, id: undefined, name: `${record.name}-copy` }}
|
||||||
range={filters["range"] as AccessRanges}
|
usage={filters["usage"] as AccessUsageProp}
|
||||||
scene="add"
|
scene="add"
|
||||||
trigger={
|
trigger={
|
||||||
<Tooltip title={t("access.action.duplicate")}>
|
<Tooltip title={t("access.action.duplicate")}>
|
||||||
@ -126,7 +126,7 @@ const AccessList = () => {
|
|||||||
|
|
||||||
const [filters, setFilters] = useState<Record<string, unknown>>(() => {
|
const [filters, setFilters] = useState<Record<string, unknown>>(() => {
|
||||||
return {
|
return {
|
||||||
range: "both-dns-hosting" satisfies AccessRanges,
|
usage: "both-dns-hosting" satisfies AccessUsageProp,
|
||||||
keyword: searchParams.get("keyword"),
|
keyword: searchParams.get("keyword"),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -160,13 +160,13 @@ const AccessList = () => {
|
|||||||
})
|
})
|
||||||
.filter((e) => {
|
.filter((e) => {
|
||||||
const provider = accessProvidersMap.get(e.provider);
|
const provider = accessProvidersMap.get(e.provider);
|
||||||
switch (filters["range"] as AccessRanges) {
|
switch (filters["usage"] as AccessUsageProp) {
|
||||||
case "both-dns-hosting":
|
case "both-dns-hosting":
|
||||||
return provider?.usages?.includes(ACCESS_USAGES.DNS) || provider?.usages?.includes(ACCESS_USAGES.HOSTING);
|
return !e.reserve && (provider?.usages?.includes(ACCESS_USAGES.DNS) || provider?.usages?.includes(ACCESS_USAGES.HOSTING));
|
||||||
case "ca-only":
|
case "ca-only":
|
||||||
return provider?.usages?.includes(ACCESS_USAGES.CA);
|
return e.reserve === "ca" && provider?.usages?.includes(ACCESS_USAGES.CA);
|
||||||
case "notify-only":
|
case "notification-only":
|
||||||
return provider?.usages?.includes(ACCESS_USAGES.NOTIFICATION);
|
return e.reserve === "notification" && provider?.usages?.includes(ACCESS_USAGES.NOTIFICATION);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
@ -184,7 +184,7 @@ const AccessList = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleTabChange = (key: string) => {
|
const handleTabChange = (key: string) => {
|
||||||
setFilters((prev) => ({ ...prev, range: key }));
|
setFilters((prev) => ({ ...prev, usage: key }));
|
||||||
setPage(1);
|
setPage(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ const AccessList = () => {
|
|||||||
extra={[
|
extra={[
|
||||||
<AccessEditDrawer
|
<AccessEditDrawer
|
||||||
key="create"
|
key="create"
|
||||||
range={filters["range"] as AccessRanges}
|
usage={filters["usage"] as AccessUsageProp}
|
||||||
scene="add"
|
scene="add"
|
||||||
trigger={
|
trigger={
|
||||||
<Button type="primary" icon={<PlusOutlinedIcon />}>
|
<Button type="primary" icon={<PlusOutlinedIcon />}>
|
||||||
@ -247,18 +247,18 @@ const AccessList = () => {
|
|||||||
tabList={[
|
tabList={[
|
||||||
{
|
{
|
||||||
key: "both-dns-hosting",
|
key: "both-dns-hosting",
|
||||||
label: t("access.props.range.both_dns_hosting"),
|
label: t("access.props.usage.both_dns_hosting"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "ca-only",
|
key: "ca-only",
|
||||||
label: t("access.props.range.ca_only"),
|
label: t("access.props.usage.ca_only"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "notify-only",
|
key: "notification-only",
|
||||||
label: t("access.props.range.notify_only"),
|
label: t("access.props.usage.notification_only"),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
activeTabKey={filters["range"] as string}
|
activeTabKey={filters["usage"] as string}
|
||||||
onTabChange={(key) => handleTabChange(key)}
|
onTabChange={(key) => handleTabChange(key)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user