diff --git a/internal/app/scheduler.go b/internal/app/scheduler.go
index 1b16ac32..c5e93c9f 100644
--- a/internal/app/scheduler.go
+++ b/internal/app/scheduler.go
@@ -3,6 +3,7 @@ package app
import (
"sync"
"time"
+ _ "time/tzdata"
"github.com/pocketbase/pocketbase/tools/cron"
)
diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go
index 4e03ad2e..7d62ac41 100644
--- a/internal/deployer/providers.go
+++ b/internal/deployer/providers.go
@@ -56,6 +56,7 @@ import (
pTencentCloudWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-waf"
pUCloudUCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-ucdn"
pUCloudUS3 "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-us3"
+ pUpyunCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/upyun-cdn"
pVolcEngineCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-cdn"
pVolcEngineCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-clb"
pVolcEngineDCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-dcdn"
@@ -225,6 +226,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
Region: maputil.GetString(options.ProviderDeployConfig, "region"),
+ ServiceVersion: maputil.GetOrDefaultString(options.ProviderDeployConfig, "serviceVersion", "3.0"),
InstanceId: maputil.GetString(options.ProviderDeployConfig, "instanceId"),
Domain: maputil.GetString(options.ProviderDeployConfig, "domain"),
})
@@ -775,6 +777,27 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) {
}
}
+ case domain.DeployProviderTypeUpyunCDN:
+ {
+ access := domain.AccessConfigForUpyun{}
+ if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
+ return nil, fmt.Errorf("failed to populate provider access config: %w", err)
+ }
+
+ switch options.Provider {
+ case domain.DeployProviderTypeUpyunCDN:
+ deployer, err := pUpyunCDN.NewDeployer(&pUpyunCDN.DeployerConfig{
+ Username: access.Username,
+ Password: access.Password,
+ Domain: maputil.GetString(options.ProviderDeployConfig, "domain"),
+ })
+ return deployer, err
+
+ default:
+ break
+ }
+ }
+
case domain.DeployProviderTypeVolcEngineCDN, domain.DeployProviderTypeVolcEngineCLB, domain.DeployProviderTypeVolcEngineDCDN, domain.DeployProviderTypeVolcEngineImageX, domain.DeployProviderTypeVolcEngineLive, domain.DeployProviderTypeVolcEngineTOS:
{
access := domain.AccessConfigForVolcEngine{}
diff --git a/internal/domain/access.go b/internal/domain/access.go
index fc6a7eb1..963d4083 100644
--- a/internal/domain/access.go
+++ b/internal/domain/access.go
@@ -201,6 +201,11 @@ type AccessConfigForUCloud struct {
ProjectId string `json:"projectId,omitempty"`
}
+type AccessConfigForUpyun struct {
+ Username string `json:"username"`
+ Password string `json:"password"`
+}
+
type AccessConfigForVolcEngine struct {
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
diff --git a/internal/domain/provider.go b/internal/domain/provider.go
index 78c79d4a..cbc034fa 100644
--- a/internal/domain/provider.go
+++ b/internal/domain/provider.go
@@ -28,6 +28,7 @@ const (
AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 天翼云(预留)
AccessProviderTypeDNSLA = AccessProviderType("dnsla")
AccessProviderTypeDogeCloud = AccessProviderType("dogecloud")
+ AccessProviderTypeDynv6 = AccessProviderType("dynv6") // dynv6(预留)
AccessProviderTypeEdgio = AccessProviderType("edgio")
AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留)
AccessProviderTypeGname = AccessProviderType("gname")
@@ -50,6 +51,7 @@ const (
AccessProviderTypeSSH = AccessProviderType("ssh")
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
AccessProviderTypeUCloud = AccessProviderType("ucloud")
+ AccessProviderTypeUpyun = AccessProviderType("upyun")
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
AccessProviderTypeWebhook = AccessProviderType("webhook")
AccessProviderTypeWestcn = AccessProviderType("westcn")
@@ -158,6 +160,7 @@ const (
DeployProviderTypeTencentCloudWAF = DeployProviderType("tencentcloud-waf")
DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn")
DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3")
+ DeployProviderTypeUpyunCDN = DeployProviderType("upyun-cdn")
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn")
DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb")
DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn")
diff --git a/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go b/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go
index 02dac427..e8166afd 100644
--- a/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go
+++ b/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go
@@ -87,18 +87,18 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
// 判断域名是否已启用 HTTPS。如果已启用,修改域名证书;否则,启用 HTTPS
// REF: https://developer.qiniu.com/fusion/4246/the-domain-name
- if getDomainInfoResp.Https != nil && getDomainInfoResp.Https.CertID != "" {
- modifyDomainHttpsConfResp, err := d.sdkClient.ModifyDomainHttpsConf(context.TODO(), domain, upres.CertId, getDomainInfoResp.Https.ForceHttps, getDomainInfoResp.Https.Http2Enable)
- d.logger.Debug("sdk request 'cdn.ModifyDomainHttpsConf'", slog.String("request.domain", domain), slog.String("request.certId", upres.CertId), slog.Any("response", modifyDomainHttpsConfResp))
- if err != nil {
- return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.ModifyDomainHttpsConf'")
- }
- } else {
+ if getDomainInfoResp.Https == nil || getDomainInfoResp.Https.CertID == "" {
enableDomainHttpsResp, err := d.sdkClient.EnableDomainHttps(context.TODO(), domain, upres.CertId, true, true)
d.logger.Debug("sdk request 'cdn.EnableDomainHttps'", slog.String("request.domain", domain), slog.String("request.certId", upres.CertId), slog.Any("response", enableDomainHttpsResp))
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.EnableDomainHttps'")
}
+ } else if getDomainInfoResp.Https.CertID != upres.CertId {
+ modifyDomainHttpsConfResp, err := d.sdkClient.ModifyDomainHttpsConf(context.TODO(), domain, upres.CertId, getDomainInfoResp.Https.ForceHttps, getDomainInfoResp.Https.Http2Enable)
+ d.logger.Debug("sdk request 'cdn.ModifyDomainHttpsConf'", slog.String("request.domain", domain), slog.String("request.certId", upres.CertId), slog.Any("response", modifyDomainHttpsConfResp))
+ if err != nil {
+ return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.ModifyDomainHttpsConf'")
+ }
}
return &deployer.DeployResult{}, nil
diff --git a/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn.go b/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn.go
new file mode 100644
index 00000000..84d6cafb
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn.go
@@ -0,0 +1,129 @@
+package upyuncdn
+
+import (
+ "context"
+ "errors"
+ "log/slog"
+
+ xerrors "github.com/pkg/errors"
+ "golang.org/x/exp/slices"
+
+ "github.com/usual2970/certimate/internal/pkg/core/deployer"
+ "github.com/usual2970/certimate/internal/pkg/core/uploader"
+ uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/upyun-ssl"
+ upyunsdk "github.com/usual2970/certimate/internal/pkg/vendors/upyun-sdk/console"
+)
+
+type DeployerConfig struct {
+ // 又拍云账号用户名。
+ Username string `json:"username"`
+ // 又拍云账号密码。
+ Password string `json:"password"`
+ // 加速域名(支持泛域名)。
+ Domain string `json:"domain"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sdkClient *upyunsdk.Client
+ sslUploader uploader.Uploader
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.Username, config.Password)
+ if err != nil {
+ return nil, xerrors.Wrap(err, "failed to create sdk client")
+ }
+
+ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
+ Username: config.Username,
+ Password: config.Password,
+ })
+ if err != nil {
+ return nil, xerrors.Wrap(err, "failed to create ssl uploader")
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ sslUploader: uploader,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.Default()
+ } else {
+ d.logger = logger
+ }
+ d.sslUploader.WithLogger(logger)
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
+ // 上传证书到 SSL
+ upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
+ if err != nil {
+ return nil, xerrors.Wrap(err, "failed to upload certificate file")
+ } else {
+ d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
+ }
+
+ // 获取域名证书配置
+ getHttpsServiceManagerResp, err := d.sdkClient.GetHttpsServiceManager(d.config.Domain)
+ d.logger.Debug("sdk request 'console.GetHttpsServiceManager'", slog.String("request.domain", d.config.Domain), slog.Any("response", getHttpsServiceManagerResp))
+ if err != nil {
+ return nil, xerrors.Wrap(err, "failed to execute sdk request 'console.GetHttpsServiceManager'")
+ }
+
+ // 判断域名是否已启用 HTTPS。如果已启用,迁移域名证书;否则,设置新证书
+ lastCertIndex := slices.IndexFunc(getHttpsServiceManagerResp.Data.Domains, func(item upyunsdk.HttpsServiceManagerDomain) bool {
+ return item.Https
+ })
+ if lastCertIndex == -1 {
+ updateHttpsCertificateManagerReq := &upyunsdk.UpdateHttpsCertificateManagerRequest{
+ CertificateId: upres.CertId,
+ Domain: d.config.Domain,
+ Https: true,
+ ForceHttps: true,
+ }
+ updateHttpsCertificateManagerResp, err := d.sdkClient.UpdateHttpsCertificateManager(updateHttpsCertificateManagerReq)
+ d.logger.Debug("sdk request 'console.EnableDomainHttps'", slog.Any("request", updateHttpsCertificateManagerReq), slog.Any("response", updateHttpsCertificateManagerResp))
+ if err != nil {
+ return nil, xerrors.Wrap(err, "failed to execute sdk request 'console.UpdateHttpsCertificateManager'")
+ }
+ } else if getHttpsServiceManagerResp.Data.Domains[lastCertIndex].CertificateId != upres.CertId {
+ migrateHttpsDomainReq := &upyunsdk.MigrateHttpsDomainRequest{
+ CertificateId: upres.CertId,
+ Domain: d.config.Domain,
+ }
+ migrateHttpsDomainResp, err := d.sdkClient.MigrateHttpsDomain(migrateHttpsDomainReq)
+ d.logger.Debug("sdk request 'console.MigrateHttpsDomain'", slog.Any("request", migrateHttpsDomainReq), slog.Any("response", migrateHttpsDomainResp))
+ if err != nil {
+ return nil, xerrors.Wrap(err, "failed to execute sdk request 'console.MigrateHttpsDomain'")
+ }
+ }
+
+ return &deployer.DeployResult{}, nil
+}
+
+func createSdkClient(username, password string) (*upyunsdk.Client, error) {
+ if username == "" {
+ return nil, errors.New("invalid upyun username")
+ }
+
+ if password == "" {
+ return nil, errors.New("invalid upyun password")
+ }
+
+ client := upyunsdk.NewClient(username, password)
+ return client, nil
+}
diff --git a/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn_test.go b/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn_test.go
new file mode 100644
index 00000000..8a7b4485
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn_test.go
@@ -0,0 +1,75 @@
+package upyuncdn_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/upyun-cdn"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fUsername string
+ fPassword string
+ fDomain string
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_DEPLOYER_UPYUNCDN_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fUsername, argsPrefix+"USERNAME", "", "")
+ flag.StringVar(&fPassword, argsPrefix+"PASSWORD", "", "")
+ flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./upyun_cdn_test.go -args \
+ --CERTIMATE_DEPLOYER_UPYUNCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_DEPLOYER_UPYUNCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_UPYUNCDN_USERNAME="your-username" \
+ --CERTIMATE_DEPLOYER_UPYUNCDN_PASSWORD="your-password" \
+ --CERTIMATE_DEPLOYER_UPYUNCDN_DOMAIN="example.com" \
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("USERNAME: %v", fUsername),
+ fmt.Sprintf("PASSWORD: %v", fPassword),
+ fmt.Sprintf("DOMAIN: %v", fDomain),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ Username: fUsername,
+ Password: fPassword,
+ Domain: fDomain,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/migrations/1742392800_upgrade.go b/migrations/1742392800_upgrade.go
new file mode 100644
index 00000000..a06bdc75
--- /dev/null
+++ b/migrations/1742392800_upgrade.go
@@ -0,0 +1,81 @@
+package migrations
+
+import (
+ "github.com/pocketbase/pocketbase/core"
+ m "github.com/pocketbase/pocketbase/migrations"
+)
+
+func init() {
+ m.Register(func(app core.App) error {
+ collection, err := app.FindCollectionByNameOrId("4yzbv8urny5ja1e")
+ if err != nil {
+ return err
+ }
+
+ // update field
+ if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
+ "hidden": false,
+ "id": "hwy7m03o",
+ "maxSelect": 1,
+ "name": "provider",
+ "presentable": false,
+ "required": false,
+ "system": false,
+ "type": "select",
+ "values": [
+ "1panel",
+ "acmehttpreq",
+ "akamai",
+ "aliyun",
+ "aws",
+ "azure",
+ "baiducloud",
+ "baishan",
+ "baotapanel",
+ "byteplus",
+ "cachefly",
+ "cdnfly",
+ "cloudflare",
+ "cloudns",
+ "cmcccloud",
+ "ctcccloud",
+ "cucccloud",
+ "dnsla",
+ "dogecloud",
+ "dynv6",
+ "edgio",
+ "fastly",
+ "gname",
+ "gcore",
+ "godaddy",
+ "goedge",
+ "huaweicloud",
+ "jdcloud",
+ "k8s",
+ "local",
+ "namecheap",
+ "namedotcom",
+ "namesilo",
+ "ns1",
+ "powerdns",
+ "qiniu",
+ "qingcloud",
+ "rainyun",
+ "safeline",
+ "ssh",
+ "tencentcloud",
+ "ucloud",
+ "upyun",
+ "volcengine",
+ "webhook",
+ "westcn"
+ ]
+ }`)); err != nil {
+ return err
+ }
+
+ return app.Save(collection)
+ }, func(app core.App) error {
+ return nil
+ })
+}
diff --git a/ui/public/imgs/providers/upyun.svg b/ui/public/imgs/providers/upyun.svg
new file mode 100644
index 00000000..cc13793d
--- /dev/null
+++ b/ui/public/imgs/providers/upyun.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx
index 7f2143ac..caf5c605 100644
--- a/ui/src/components/access/AccessForm.tsx
+++ b/ui/src/components/access/AccessForm.tsx
@@ -44,6 +44,7 @@ import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig";
import AccessFormSSHConfig from "./AccessFormSSHConfig";
import AccessFormTencentCloudConfig from "./AccessFormTencentCloudConfig";
import AccessFormUCloudConfig from "./AccessFormUCloudConfig";
+import AccessFormUpyunConfig from "./AccessFormUpyunConfig";
import AccessFormVolcEngineConfig from "./AccessFormVolcEngineConfig";
import AccessFormWebhookConfig from "./AccessFormWebhookConfig";
import AccessFormWestcnConfig from "./AccessFormWestcnConfig";
@@ -170,6 +171,8 @@ const AccessForm = forwardRef(({ className,
return ;
case ACCESS_PROVIDERS.UCLOUD:
return ;
+ case ACCESS_PROVIDERS.UPYUN:
+ return ;
case ACCESS_PROVIDERS.VOLCENGINE:
return ;
case ACCESS_PROVIDERS.WEBHOOK:
diff --git a/ui/src/components/access/AccessFormUpyunConfig.tsx b/ui/src/components/access/AccessFormUpyunConfig.tsx
new file mode 100644
index 00000000..8cc06d97
--- /dev/null
+++ b/ui/src/components/access/AccessFormUpyunConfig.tsx
@@ -0,0 +1,76 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { type AccessConfigForUpyun } from "@/domain/access";
+
+type AccessFormUpyunConfigFieldValues = Nullish;
+
+export type AccessFormUpyunConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: AccessFormUpyunConfigFieldValues;
+ onValuesChange?: (values: AccessFormUpyunConfigFieldValues) => void;
+};
+
+const initFormModel = (): AccessFormUpyunConfigFieldValues => {
+ return {
+ username: "",
+ password: "",
+ };
+};
+
+const AccessFormUpyunConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormUpyunConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ username: z
+ .string()
+ .trim()
+ .min(1, t("access.form.upyun_username.placeholder"))
+ .max(64, t("common.errmsg.string_max", { max: 64 })),
+ password: z
+ .string()
+ .min(1, t("access.form.upyun_password.placeholder"))
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+ );
+};
+
+export default AccessFormUpyunConfig;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormUpyunCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormUpyunCDNConfig.tsx
new file mode 100644
index 00000000..e09f5266
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormUpyunCDNConfig.tsx
@@ -0,0 +1,59 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+type DeployNodeConfigFormUpyunCDNConfigFieldValues = Nullish<{
+ domain: string;
+}>;
+
+export type DeployNodeConfigFormUpyunCDNConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: DeployNodeConfigFormUpyunCDNConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormUpyunCDNConfigFieldValues) => void;
+};
+
+const initFormModel = (): DeployNodeConfigFormUpyunCDNConfigFieldValues => {
+ return {};
+};
+
+const DeployNodeConfigFormUpyunCDNConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormUpyunCDNConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.upyun_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+ }
+ >
+
+
+
+ );
+};
+
+export default DeployNodeConfigFormUpyunCDNConfig;
diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts
index 1b5adf45..59a41cc6 100644
--- a/ui/src/domain/access.ts
+++ b/ui/src/domain/access.ts
@@ -40,6 +40,7 @@ export interface AccessModel extends BaseModel {
| AccessConfigForSSH
| AccessConfigForTencentCloud
| AccessConfigForUCloud
+ | AccessConfigForUpyun
| AccessConfigForVolcEngine
| AccessConfigForWebhook
| AccessConfigForWestcn
@@ -224,6 +225,11 @@ export type AccessConfigForUCloud = {
projectId?: string;
};
+export type AccessConfigForUpyun = {
+ username: string;
+ password: string;
+};
+
export type AccessConfigForVolcEngine = {
accessKeyId: string;
secretAccessKey: string;
diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts
index f3d6deb3..998ec718 100644
--- a/ui/src/domain/provider.ts
+++ b/ui/src/domain/provider.ts
@@ -39,6 +39,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
SSH: "ssh",
TENCENTCLOUD: "tencentcloud",
UCLOUD: "ucloud",
+ UPYUN: "upyun",
VOLCENGINE: "volcengine",
WEBHOOK: "webhook",
WESTCN: "westcn",
@@ -80,6 +81,7 @@ export const accessProvidersMap: Maphttps://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en",
+ "access.form.upyun_username.label": "UPYUN subaccount username",
+ "access.form.upyun_username.placeholder": "Please enter UPYUN subaccount username",
+ "access.form.upyun_username.tooltip": "For more information, see https://console.upyun.com/account/subaccount/",
+ "access.form.upyun_password.label": "UPYUN subaccount password",
+ "access.form.upyun_password.placeholder": "Please enter UPYUN subaccount password",
+ "access.form.upyun_password.tooltip": "For more information, see https://console.upyun.com/account/subaccount/",
"access.form.baishan_api_token.label": "Baishan Cloud API token",
"access.form.baishan_api_token.placeholder": "Please enter Baishan Cloud API token",
"access.form.baotapanel_api_url.label": "aaPanel URL",
diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json
index 4c6091e1..9034aeea 100644
--- a/ui/src/i18n/locales/en/nls.provider.json
+++ b/ui/src/i18n/locales/en/nls.provider.json
@@ -93,6 +93,8 @@
"provider.ucloud": "UCloud",
"provider.ucloud.ucdn": "UCloud - UCDN (UCloud Content Delivery Network)",
"provider.ucloud.us3": "UCloud - US3 (UCloud Object-based Storage)",
+ "provider.upyun": "UPYUN",
+ "provider.upyun.cdn": "UPYUN - CDN (Content Delivery Network)",
"provider.volcengine": "Volcengine",
"provider.volcengine.cdn": "Volcengine - CDN (Content Delivery Network)",
"provider.volcengine.clb": "Volcengine - CLB (Cloud Load Balancer)",
diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json
index 6d4b0f97..666ef424 100644
--- a/ui/src/i18n/locales/en/nls.workflow.nodes.json
+++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json
@@ -508,6 +508,9 @@
"workflow_node.deploy.form.ucloud_us3_domain.label": "UCloud US3 domain",
"workflow_node.deploy.form.ucloud_us3_domain.placeholder": "Please enter UCloud US3 domain name",
"workflow_node.deploy.form.ucloud_us3_domain.tooltip": "For more information, see https://console.ucloud-global.com/ufile",
+ "workflow_node.deploy.form.upyun_cdn_domain.label": "UPYUN CDN domain",
+ "workflow_node.deploy.form.upyun_cdn_domain.placeholder": "Please enter UPYUN CDN domain name",
+ "workflow_node.deploy.form.upyun_cdn_domain.tooltip": "For more information, see https://console.upyun.com/services/cdn/",
"workflow_node.deploy.form.volcengine_cdn_domain.label": "VolcEngine CDN domain",
"workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "Please enter VolcEngine CDN domain name",
"workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "For more information, see https://console.volcengine.com/cdn/homepage",
diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json
index d72cd259..bb2f829a 100644
--- a/ui/src/i18n/locales/zh/nls.access.json
+++ b/ui/src/i18n/locales/zh/nls.access.json
@@ -243,6 +243,12 @@
"access.form.ucloud_project_id.label": "优刻得项目 ID(可选)",
"access.form.ucloud_project_id.placeholder": "请输入优刻得项目 ID",
"access.form.ucloud_project_id.tooltip": "这是什么?请参阅 https://console.ucloud.cn/uaccount/iam/project_manage",
+ "access.form.upyun_username.label": "又拍云子账号用户名",
+ "access.form.upyun_username.placeholder": "请输入又拍云子账号用户名",
+ "access.form.upyun_username.tooltip": "这是什么?请参阅 https://console.upyun.com/account/subaccount/
请关闭该账号的二次登录验证。",
+ "access.form.upyun_password.label": "又拍云子账号密码",
+ "access.form.upyun_password.placeholder": "请输入又拍云子账号密码",
+ "access.form.upyun_password.tooltip": "这是什么?请参阅 https://console.upyun.com/account/subaccount/
请关闭该账号的二次登录验证。",
"access.form.volcengine_access_key_id.label": "火山引擎 AccessKeyId",
"access.form.volcengine_access_key_id.placeholder": "请输入火山引擎 AccessKeyId",
"access.form.volcengine_access_key_id.tooltip": "这是什么?请参阅 https://www.volcengine.com/docs/6291/216571",
diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json
index e8580e41..2e830cf3 100644
--- a/ui/src/i18n/locales/zh/nls.provider.json
+++ b/ui/src/i18n/locales/zh/nls.provider.json
@@ -93,6 +93,8 @@
"provider.ucloud": "优刻得",
"provider.ucloud.ucdn": "优刻得 - 内容分发 UCDN",
"provider.ucloud.us3": "优刻得 - 对象存储 US3",
+ "provider.upyun": "又拍云",
+ "provider.upyun.cdn": "又拍云 - 云分发 CDN",
"provider.volcengine": "火山引擎",
"provider.volcengine.cdn": "火山引擎 - 内容分发网络 CDN",
"provider.volcengine.clb": "火山引擎 - 负载均衡 CLB",
diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json
index 3144bfa8..63d881f8 100644
--- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json
+++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json
@@ -508,6 +508,9 @@
"workflow_node.deploy.form.ucloud_us3_domain.label": "优刻得 US3 自定义域名",
"workflow_node.deploy.form.ucloud_us3_domain.placeholder": "请输入优刻得 US3 自定义域名",
"workflow_node.deploy.form.ucloud_us3_domain.tooltip": "这是什么?请参阅 https://console.ucloud.cn/ufile",
+ "workflow_node.deploy.form.upyun_cdn_domain.label": "又拍云 CDN 加速域名",
+ "workflow_node.deploy.form.upyun_cdn_domain.placeholder": "请输入又拍云 CDN 加速域名(支持泛域名)",
+ "workflow_node.deploy.form.upyun_cdn_domain.tooltip": "这是什么?请参阅 https://console.upyun.com/services/cdn/",
"workflow_node.deploy.form.volcengine_cdn_domain.label": "火山引擎 CDN 加速域名",
"workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "请输入火山引擎 CDN 加速域名(支持泛域名)",
"workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/cdn/homepage",