From 46f02331fd8392c96a543d5e4c1996517f33f7ac Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Tue, 18 Feb 2025 11:45:41 +0800 Subject: [PATCH] feat: add cachefly deployer --- README.md | 1 + README_EN.md | 1 + internal/deployer/providers.go | 14 +++ internal/domain/access.go | 6 +- internal/domain/provider.go | 5 +- .../baotapanel-site/baotapanel_site.go | 2 +- .../deployer/providers/cachefly/cachefly.go | 71 +++++++++++++ .../providers/cachefly/cachefly_test.go | 65 ++++++++++++ internal/pkg/vendors/baishan-sdk/client.go | 30 ++---- internal/pkg/vendors/baishan-sdk/models.go | 18 ++-- internal/pkg/vendors/btpanel-sdk/client.go | 14 +-- internal/pkg/vendors/cachefly-sdk/api.go | 19 ++++ internal/pkg/vendors/cachefly-sdk/client.go | 72 +++++++++++++ internal/pkg/vendors/cachefly-sdk/models.go | 35 +++++++ internal/pkg/vendors/gname-sdk/client.go | 12 +-- internal/pkg/vendors/safeline-sdk/client.go | 16 ++- ui/public/imgs/acme/letsencrypt.svg | 2 +- ui/public/imgs/providers/acmehttpreq.svg | 2 +- ui/public/imgs/providers/aliyun.svg | 2 +- ui/public/imgs/providers/aws.svg | 2 +- ui/public/imgs/providers/azure.svg | 2 +- ui/public/imgs/providers/baiducloud.svg | 2 +- ui/public/imgs/providers/cachefly.png | Bin 0 -> 11406 bytes ui/public/imgs/providers/cloudflare.svg | 2 +- ui/public/imgs/providers/cloudns.png | Bin 0 -> 5314 bytes ui/public/imgs/providers/cloudns.svg | 99 ------------------ ui/public/imgs/providers/dogecloud.png | Bin 0 -> 8929 bytes ui/public/imgs/providers/dogecloud.svg | 1 - ui/public/imgs/providers/gname.png | Bin 0 -> 4480 bytes ui/public/imgs/providers/gname.svg | 1 - ui/public/imgs/providers/godaddy.svg | 2 +- ui/public/imgs/providers/huaweicloud.svg | 2 +- ui/public/imgs/providers/kubernetes.svg | 2 +- ui/public/imgs/providers/local.svg | 2 +- ui/public/imgs/providers/namesilo.svg | 2 +- ui/public/imgs/providers/powerdns.svg | 2 +- ui/public/imgs/providers/qiniu.svg | 2 +- ui/public/imgs/providers/safeline.svg | 2 +- ui/public/imgs/providers/ssh.svg | 2 +- ui/public/imgs/providers/tencentcloud.svg | 2 +- ui/public/imgs/providers/ucloud.svg | 2 +- ui/public/imgs/providers/webhook.svg | 2 +- ui/public/imgs/providers/westcn.svg | 2 +- ui/src/components/access/AccessForm.tsx | 3 + .../access/AccessFormCacheFlyConfig.tsx | 56 ++++++++++ .../workflow/node/DeployNodeConfigForm.tsx | 17 ++- ui/src/domain/access.ts | 5 + ui/src/domain/provider.ts | 12 ++- ui/src/i18n/locales/en/nls.access.json | 3 + ui/src/i18n/locales/en/nls.provider.json | 2 +- ui/src/i18n/locales/zh/nls.access.json | 3 + ui/src/i18n/locales/zh/nls.provider.json | 2 +- 52 files changed, 433 insertions(+), 192 deletions(-) create mode 100644 internal/pkg/core/deployer/providers/cachefly/cachefly.go create mode 100644 internal/pkg/core/deployer/providers/cachefly/cachefly_test.go create mode 100644 internal/pkg/vendors/cachefly-sdk/api.go create mode 100644 internal/pkg/vendors/cachefly-sdk/client.go create mode 100644 internal/pkg/vendors/cachefly-sdk/models.go create mode 100644 ui/public/imgs/providers/cachefly.png create mode 100644 ui/public/imgs/providers/cloudns.png delete mode 100644 ui/public/imgs/providers/cloudns.svg create mode 100644 ui/public/imgs/providers/dogecloud.png delete mode 100644 ui/public/imgs/providers/dogecloud.svg create mode 100644 ui/public/imgs/providers/gname.png delete mode 100644 ui/public/imgs/providers/gname.svg create mode 100644 ui/src/components/access/AccessFormCacheFlyConfig.tsx diff --git a/README.md b/README.md index 95180539..ab7d553c 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ make local.run | [宝塔面板](https://www.bt.cn/) | 可部署到宝塔面板 | | [AWS](https://aws.amazon.com/) | 可部署到 AWS CloudFront | | [BytePlus](https://www.byteplus.com/) | 可部署到 BytePlus CDN | +| [CacheFly](https://www.cachefly.com/) | 可部署到 CacheFly CDN | | [Edgio](https://edg.io/) | 可部署到 Edgio Applications | | [Gcore](https://gcore.com/) | 可部署到 Gcore CDN | diff --git a/README_EN.md b/README_EN.md index c47de082..1320f3ea 100644 --- a/README_EN.md +++ b/README_EN.md @@ -135,6 +135,7 @@ The following hosting providers are supported: | [BaoTa Panel](https://www.bt.cn/) | Supports deployment to BaoTa Panel sites | | [AWS](https://aws.amazon.com/) | Supports deployment to AWS CloudFront | | [BytePlus](https://www.byteplus.com/) | Supports deployment to BytePlus CDN | +| [CacheFly](https://www.cachefly.com/) | Supports deployment to CacheFly CDN | | [Edgio](https://edg.io/) | Supports deployment to Edgio Applications | | [Gcore](https://gcore.com/) | Supports deployment to Gcore CDN | diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 8903f96b..5c3c53ed 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -22,6 +22,7 @@ import ( pBaotaPanelConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-console" pBaotaPanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-site" pBytePlusCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/byteplus-cdn" + pCacheFly "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cachefly" pDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn" pEdgioApplications "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/edgio-applications" pGcoreCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/gcore-cdn" @@ -288,6 +289,19 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, } } + case domain.DeployProviderTypeCacheFly: + { + access := domain.AccessConfigForCacheFly{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + deployer, err := pCacheFly.NewWithLogger(&pCacheFly.CacheFlyDeployerConfig{ + ApiToken: access.ApiToken, + }, logger) + return deployer, logger, err + } + case domain.DeployProviderTypeDogeCloudCDN: { access := domain.AccessConfigForDogeCloud{} diff --git a/internal/domain/access.go b/internal/domain/access.go index 4136a276..b21b5a3f 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -67,6 +67,10 @@ type AccessConfigForBytePlus struct { SecretKey string `json:"secretKey"` } +type AccessConfigForCacheFly struct { + ApiToken string `json:"apiToken"` +} + type AccessConfigForCloudflare struct { DnsApiToken string `json:"dnsApiToken"` } @@ -87,7 +91,7 @@ type AccessConfigForEdgio struct { } type AccessConfigForGcore struct { - ApiToken string `json:"apiToken"` + ApiToken string `json:"apiToken"` } type AccessConfigForGname struct { diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 8d2fd046..94e8c7ae 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -19,8 +19,8 @@ const ( AccessProviderTypeBaishan = AccessProviderType("baishan") AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel") AccessProviderTypeBytePlus = AccessProviderType("byteplus") - AccessProviderTypeCacheFly = AccessProviderType("cachefly") // CacheFly(预留) - AccessProviderTypeCdnfly = AccessProviderType("cdnfly") // Cdnly(预留) + AccessProviderTypeCacheFly = AccessProviderType("cachefly") + AccessProviderTypeCdnfly = AccessProviderType("cdnfly") // Cdnly(预留) AccessProviderTypeCloudflare = AccessProviderType("cloudflare") AccessProviderTypeClouDNS = AccessProviderType("cloudns") AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud") // 移动云(预留) @@ -112,6 +112,7 @@ const ( DeployProviderTypeBaotaPanelConsole = DeployProviderType("baotapanel-console") DeployProviderTypeBaotaPanelSite = DeployProviderType("baotapanel-site") DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn") + DeployProviderTypeCacheFly = DeployProviderType("cachefly") DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn") DeployProviderTypeEdgioApplications = DeployProviderType("edgio-applications") DeployProviderTypeGcoreCDN = DeployProviderType("gcore-cdn") diff --git a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go index d2d8622f..14261968 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go +++ b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go @@ -61,7 +61,7 @@ func (d *BaotaPanelSiteDeployer) Deploy(ctx context.Context, certPem string, pri // 设置站点 SSL 证书 siteSetSSLReq := &btsdk.SiteSetSSLRequest{ SiteName: d.config.SiteName, - Type: "1", + Type: "0", PrivateKey: privkeyPem, Certificate: certPem, } diff --git a/internal/pkg/core/deployer/providers/cachefly/cachefly.go b/internal/pkg/core/deployer/providers/cachefly/cachefly.go new file mode 100644 index 00000000..fe3fb3e4 --- /dev/null +++ b/internal/pkg/core/deployer/providers/cachefly/cachefly.go @@ -0,0 +1,71 @@ +package cachefly + +import ( + "context" + "errors" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + cfsdk "github.com/usual2970/certimate/internal/pkg/vendors/cachefly-sdk" +) + +type CacheFlyDeployerConfig struct { + // CacheFly API Token。 + ApiToken string `json:"apiToken"` +} + +type CacheFlyDeployer struct { + config *CacheFlyDeployerConfig + logger logger.Logger + sdkClient *cfsdk.Client +} + +var _ deployer.Deployer = (*CacheFlyDeployer)(nil) + +func New(config *CacheFlyDeployerConfig) (*CacheFlyDeployer, error) { + return NewWithLogger(config, logger.NewNilLogger()) +} + +func NewWithLogger(config *CacheFlyDeployerConfig, logger logger.Logger) (*CacheFlyDeployer, error) { + if config == nil { + return nil, errors.New("config is nil") + } + + if logger == nil { + return nil, errors.New("logger is nil") + } + + client, err := createSdkClient(config.ApiToken) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &CacheFlyDeployer{ + logger: logger, + config: config, + sdkClient: client, + }, nil +} + +func (d *CacheFlyDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 上传证书 + createCertificateReq := &cfsdk.CreateCertificateRequest{ + Certificate: certPem, + CertificateKey: privkeyPem, + } + createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cachefly.CreateCertificate'") + } else { + d.logger.Logt("已上传证书", createCertificateResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiToken string) (*cfsdk.Client, error) { + client := cfsdk.NewClient(apiToken) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/cachefly/cachefly_test.go b/internal/pkg/core/deployer/providers/cachefly/cachefly_test.go new file mode 100644 index 00000000..fcef1172 --- /dev/null +++ b/internal/pkg/core/deployer/providers/cachefly/cachefly_test.go @@ -0,0 +1,65 @@ +package cachefly_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cachefly" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiToken string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_CACHEFLY_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./cachefly_test.go -args \ + --CERTIMATE_DEPLOYER_CACHEFLY_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_CACHEFLY_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_CACHEFLY_APITOKEN="your-baota-panel-key" +*/ +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("APITOKEN: %v", fApiToken), + }, "\n")) + + deployer, err := provider.New(&provider.CacheFlyDeployerConfig{ + ApiToken: fApiToken, + }) + 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/internal/pkg/vendors/baishan-sdk/client.go b/internal/pkg/vendors/baishan-sdk/client.go index 28cb0bc3..c49698ea 100644 --- a/internal/pkg/vendors/baishan-sdk/client.go +++ b/internal/pkg/vendors/baishan-sdk/client.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "time" "github.com/go-resty/resty/v2" @@ -32,7 +33,9 @@ func (c *Client) sendRequest(method string, path string, params map[string]any) url := "https://cdn.api.baishan.com" + path req := c.client.R() - if method == http.MethodGet { + req.Method = method + req.URL = url + if strings.EqualFold(method, http.MethodGet) { data := make(map[string]string) for k, v := range params { data[k] = fmt.Sprintf("%v", v) @@ -40,27 +43,18 @@ func (c *Client) sendRequest(method string, path string, params map[string]any) req = req. SetQueryParams(data). SetQueryParam("token", c.apiToken) - } else if method == http.MethodPost { + } else { req = req. SetHeader("Content-Type", "application/json"). SetQueryParam("token", c.apiToken). SetBody(params) } - var resp *resty.Response - var err error - if method == http.MethodGet { - resp, err = req.Get(url) - } else if method == http.MethodPost { - resp, err = req.Post(url) - } else { - return nil, fmt.Errorf("baishan: unsupported method: %s", method) - } - + resp, err := req.Send() if err != nil { - return nil, fmt.Errorf("baishan: failed to send request: %w", err) + return nil, fmt.Errorf("baishan api error: failed to send request: %w", err) } else if resp.IsError() { - return nil, fmt.Errorf("baishan: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + return nil, fmt.Errorf("baishan api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) } return resp, nil @@ -73,11 +67,9 @@ func (c *Client) sendRequestWithResult(method string, path string, params map[st } if err := json.Unmarshal(resp.Body(), &result); err != nil { - return fmt.Errorf("baishan: failed to parse response: %w", err) - } - - if result.GetCode() != 0 { - return fmt.Errorf("baishan api error: %d, %s", result.GetCode(), result.GetMessage()) + return fmt.Errorf("baishan api error: failed to parse response: %w", err) + } else if result.GetCode() != 0 { + return fmt.Errorf("baishan api error: %d - %s", result.GetCode(), result.GetMessage()) } return nil diff --git a/internal/pkg/vendors/baishan-sdk/models.go b/internal/pkg/vendors/baishan-sdk/models.go index 4cf1a918..78685571 100644 --- a/internal/pkg/vendors/baishan-sdk/models.go +++ b/internal/pkg/vendors/baishan-sdk/models.go @@ -36,12 +36,10 @@ type GetDomainConfigRequest struct { type GetDomainConfigResponse struct { baseResponse - Data []*GetDomainConfigResponseData `json:"data"` -} - -type GetDomainConfigResponseData struct { - Domain string `json:"domain"` - Config *DomainConfig `json:"config"` + Data []*struct { + Domain string `json:"domain"` + Config *DomainConfig `json:"config"` + } `json:"data"` } type SetDomainConfigRequest struct { @@ -51,11 +49,9 @@ type SetDomainConfigRequest struct { type SetDomainConfigResponse struct { baseResponse - Data *SetDomainConfigResponseData `json:"data"` -} - -type SetDomainConfigResponseData struct { - Config *DomainConfig `json:"config"` + Data *struct { + Config *DomainConfig `json:"config"` + } `json:"data"` } type DomainCertificate struct { diff --git a/internal/pkg/vendors/btpanel-sdk/client.go b/internal/pkg/vendors/btpanel-sdk/client.go index 513a9eb3..0620a80f 100644 --- a/internal/pkg/vendors/btpanel-sdk/client.go +++ b/internal/pkg/vendors/btpanel-sdk/client.go @@ -56,11 +56,9 @@ func (c *Client) sendRequest(path string, params map[string]any) (*resty.Respons SetBody(params) resp, err := req.Post(url) if err != nil { - return nil, fmt.Errorf("baota: failed to send request: %w", err) - } - - if resp.IsError() { - return nil, fmt.Errorf("baota: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + return nil, fmt.Errorf("baota api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("baota api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) } return resp, nil @@ -73,10 +71,8 @@ func (c *Client) sendRequestWithResult(path string, params map[string]any, resul } if err := json.Unmarshal(resp.Body(), &result); err != nil { - return fmt.Errorf("baota: failed to parse response: %w", err) - } - - if result.GetStatus() != nil && !*result.GetStatus() { + return fmt.Errorf("baota api error: failed to parse response: %w", err) + } else if result.GetStatus() != nil && !*result.GetStatus() { if result.GetMsg() == nil { return fmt.Errorf("baota api error: unknown error") } else { diff --git a/internal/pkg/vendors/cachefly-sdk/api.go b/internal/pkg/vendors/cachefly-sdk/api.go new file mode 100644 index 00000000..16a3411a --- /dev/null +++ b/internal/pkg/vendors/cachefly-sdk/api.go @@ -0,0 +1,19 @@ +package cacheflysdk + +import ( + "encoding/json" + "net/http" +) + +func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := CreateCertificateResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/certificates", params, &result) + if err != nil { + return nil, err + } + return &result, nil +} diff --git a/internal/pkg/vendors/cachefly-sdk/client.go b/internal/pkg/vendors/cachefly-sdk/client.go new file mode 100644 index 00000000..2516a388 --- /dev/null +++ b/internal/pkg/vendors/cachefly-sdk/client.go @@ -0,0 +1,72 @@ +package cacheflysdk + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + apiToken string + client *resty.Client +} + +func NewClient(apiToken string) *Client { + client := resty.New() + + return &Client{ + apiToken: apiToken, + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) sendRequest(method string, path string, params map[string]any) (*resty.Response, error) { + url := "https://api.cachefly.com/api/2.5" + path + + req := c.client.R() + req.Method = method + req.URL = url + req = req.SetHeader("x-cf-authorization", "Bearer "+c.apiToken) + if strings.EqualFold(method, http.MethodGet) { + data := make(map[string]string) + for k, v := range params { + data[k] = fmt.Sprintf("%v", v) + } + req = req.SetQueryParams(data) + } else { + req = req. + SetHeader("Content-Type", "application/json"). + SetBody(params) + } + + resp, err := req.Send() + if err != nil { + return nil, fmt.Errorf("cachefly api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("cachefly api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(method string, path string, params map[string]any, result BaseResponse) error { + resp, err := c.sendRequest(method, path, params) + if err != nil { + return err + } + + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("cachefly api error: failed to parse response: %w", err) + } + + return nil +} diff --git a/internal/pkg/vendors/cachefly-sdk/models.go b/internal/pkg/vendors/cachefly-sdk/models.go new file mode 100644 index 00000000..aaca7723 --- /dev/null +++ b/internal/pkg/vendors/cachefly-sdk/models.go @@ -0,0 +1,35 @@ +package cacheflysdk + +type BaseResponse interface { + GetMessage() *string +} + +type baseResponse struct { + Message *string `json:"message,omitempty"` +} + +func (r *baseResponse) GetMessage() *string { + return r.Message +} + +type CreateCertificateRequest struct { + Certificate string `json:"certificate"` + CertificateKey string `json:"certificateKey"` + Password *string `json:"password"` +} + +type CreateCertificateResponse struct { + baseResponse + Id string `json:"_id"` + SubjectCommonName string `json:"subjectCommonName"` + SubjectNames []string `json:"subjectNames"` + Expired bool `json:"expired"` + Expiring bool `json:"expiring"` + InUse bool `json:"inUse"` + Managed bool `json:"managed"` + Services []string `json:"services"` + Domains []string `json:"domains"` + NotBefore string `json:"notBefore"` + NotAfter string `json:"notAfter"` + CreatedAt string `json:"createdAt"` +} diff --git a/internal/pkg/vendors/gname-sdk/client.go b/internal/pkg/vendors/gname-sdk/client.go index d73782e4..5d9ffa3f 100644 --- a/internal/pkg/vendors/gname-sdk/client.go +++ b/internal/pkg/vendors/gname-sdk/client.go @@ -76,9 +76,9 @@ func (c *Client) sendRequest(path string, params map[string]any) (*resty.Respons SetFormData(data) resp, err := req.Post(url) if err != nil { - return nil, fmt.Errorf("gname: failed to send request: %w", err) + return nil, fmt.Errorf("gname api error: failed to send request: %w", err) } else if resp.IsError() { - return nil, fmt.Errorf("gname: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + return nil, fmt.Errorf("gname api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) } return resp, nil @@ -91,11 +91,9 @@ func (c *Client) sendRequestWithResult(path string, params map[string]any, resul } if err := json.Unmarshal(resp.Body(), &result); err != nil { - return fmt.Errorf("gname: failed to parse response: %w", err) - } - - if result.GetCode() != 1 { - return fmt.Errorf("gname api error: %s", result.GetMsg()) + return fmt.Errorf("gname api error: failed to parse response: %w", err) + } else if result.GetCode() != 1 { + return fmt.Errorf("gname api error: %d - %s", result.GetCode(), result.GetMsg()) } return nil diff --git a/internal/pkg/vendors/safeline-sdk/client.go b/internal/pkg/vendors/safeline-sdk/client.go index be04cb94..dbf54f66 100644 --- a/internal/pkg/vendors/safeline-sdk/client.go +++ b/internal/pkg/vendors/safeline-sdk/client.go @@ -42,11 +42,9 @@ func (c *Client) sendRequest(path string, params map[string]any) (*resty.Respons SetBody(params) resp, err := req.Post(url) if err != nil { - return nil, fmt.Errorf("safeline: failed to send request: %w", err) - } - - if resp.IsError() { - return nil, fmt.Errorf("safeline: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + return nil, fmt.Errorf("safeline api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("safeline api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) } return resp, nil @@ -59,14 +57,12 @@ func (c *Client) sendRequestWithResult(path string, params map[string]any, resul } if err := json.Unmarshal(resp.Body(), &result); err != nil { - return fmt.Errorf("safeline: failed to parse response: %w", err) - } - - if result.GetErrCode() != nil && *result.GetErrCode() != "" { + return fmt.Errorf("safeline api error: failed to parse response: %w", err) + } else if result.GetErrCode() != nil && *result.GetErrCode() != "" { if result.GetErrMsg() == nil { return fmt.Errorf("safeline api error: %s", *result.GetErrCode()) } else { - return fmt.Errorf("safeline api error: %s, %s", *result.GetErrCode(), *result.GetErrMsg()) + return fmt.Errorf("safeline api error: %s - %s", *result.GetErrCode(), *result.GetErrMsg()) } } diff --git a/ui/public/imgs/acme/letsencrypt.svg b/ui/public/imgs/acme/letsencrypt.svg index 3a6c2312..b13df853 100644 --- a/ui/public/imgs/acme/letsencrypt.svg +++ b/ui/public/imgs/acme/letsencrypt.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/acmehttpreq.svg b/ui/public/imgs/providers/acmehttpreq.svg index 88f2d6b2..936ca077 100644 --- a/ui/public/imgs/providers/acmehttpreq.svg +++ b/ui/public/imgs/providers/acmehttpreq.svg @@ -1,2 +1,2 @@ - + diff --git a/ui/public/imgs/providers/aliyun.svg b/ui/public/imgs/providers/aliyun.svg index 7d0b70e0..05bfc6fe 100644 --- a/ui/public/imgs/providers/aliyun.svg +++ b/ui/public/imgs/providers/aliyun.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/aws.svg b/ui/public/imgs/providers/aws.svg index 9f211f19..3b771872 100644 --- a/ui/public/imgs/providers/aws.svg +++ b/ui/public/imgs/providers/aws.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/azure.svg b/ui/public/imgs/providers/azure.svg index 01b62bc9..014647a3 100644 --- a/ui/public/imgs/providers/azure.svg +++ b/ui/public/imgs/providers/azure.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/baiducloud.svg b/ui/public/imgs/providers/baiducloud.svg index 25ab747a..e448fd3e 100644 --- a/ui/public/imgs/providers/baiducloud.svg +++ b/ui/public/imgs/providers/baiducloud.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/cachefly.png b/ui/public/imgs/providers/cachefly.png new file mode 100644 index 0000000000000000000000000000000000000000..86a13db55caf1c438794cb5ecbef7d48ba5fa3fd GIT binary patch literal 11406 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 + diff --git a/ui/public/imgs/providers/cloudns.png b/ui/public/imgs/providers/cloudns.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad3068d3ae2e6158e5474da51217b513a94ee85 GIT binary patch literal 5314 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 Qxc)L3>YM1%be!(~AIoNnr~m)} literal 0 HcmV?d00001 diff --git a/ui/public/imgs/providers/cloudns.svg b/ui/public/imgs/providers/cloudns.svg deleted file mode 100644 index 44cf1ed2..00000000 --- a/ui/public/imgs/providers/cloudns.svg +++ /dev/null @@ -1,99 +0,0 @@ - - diff --git a/ui/public/imgs/providers/dogecloud.png b/ui/public/imgs/providers/dogecloud.png new file mode 100644 index 0000000000000000000000000000000000000000..1897bc88f716cb9bfd59ecea1f3c79a2fa8034bf GIT binary patch literal 8929 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 QzkWKAl~j@_6EpVzFXDrcY5)KL literal 0 HcmV?d00001 diff --git a/ui/public/imgs/providers/dogecloud.svg b/ui/public/imgs/providers/dogecloud.svg deleted file mode 100644 index 253f9ae7..00000000 --- a/ui/public/imgs/providers/dogecloud.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ui/public/imgs/providers/gname.png b/ui/public/imgs/providers/gname.png new file mode 100644 index 0000000000000000000000000000000000000000..ef3772f5631e28272529e9d9908dad6ffa154644 GIT binary patch literal 4480 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 literal 0 HcmV?d00001 diff --git a/ui/public/imgs/providers/gname.svg b/ui/public/imgs/providers/gname.svg deleted file mode 100644 index ec409ca5..00000000 --- a/ui/public/imgs/providers/gname.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ui/public/imgs/providers/godaddy.svg b/ui/public/imgs/providers/godaddy.svg index a859a7ae..f9471283 100644 --- a/ui/public/imgs/providers/godaddy.svg +++ b/ui/public/imgs/providers/godaddy.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/huaweicloud.svg b/ui/public/imgs/providers/huaweicloud.svg index 552e59e7..45a42dd2 100644 --- a/ui/public/imgs/providers/huaweicloud.svg +++ b/ui/public/imgs/providers/huaweicloud.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/kubernetes.svg b/ui/public/imgs/providers/kubernetes.svg index b7f555f7..88125935 100644 --- a/ui/public/imgs/providers/kubernetes.svg +++ b/ui/public/imgs/providers/kubernetes.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/local.svg b/ui/public/imgs/providers/local.svg index 2f59af07..46974fa7 100644 --- a/ui/public/imgs/providers/local.svg +++ b/ui/public/imgs/providers/local.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/namesilo.svg b/ui/public/imgs/providers/namesilo.svg index e0cc8da4..4284796d 100644 --- a/ui/public/imgs/providers/namesilo.svg +++ b/ui/public/imgs/providers/namesilo.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/powerdns.svg b/ui/public/imgs/providers/powerdns.svg index 192466ed..768bbacf 100644 --- a/ui/public/imgs/providers/powerdns.svg +++ b/ui/public/imgs/providers/powerdns.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/qiniu.svg b/ui/public/imgs/providers/qiniu.svg index d3b98877..20a88367 100644 --- a/ui/public/imgs/providers/qiniu.svg +++ b/ui/public/imgs/providers/qiniu.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/safeline.svg b/ui/public/imgs/providers/safeline.svg index b5490ac7..9a0db247 100644 --- a/ui/public/imgs/providers/safeline.svg +++ b/ui/public/imgs/providers/safeline.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/ssh.svg b/ui/public/imgs/providers/ssh.svg index 8dea9e89..d673cafa 100644 --- a/ui/public/imgs/providers/ssh.svg +++ b/ui/public/imgs/providers/ssh.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/tencentcloud.svg b/ui/public/imgs/providers/tencentcloud.svg index 76e54dbb..1fb8f4b6 100644 --- a/ui/public/imgs/providers/tencentcloud.svg +++ b/ui/public/imgs/providers/tencentcloud.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/ucloud.svg b/ui/public/imgs/providers/ucloud.svg index 9e246c65..3000023f 100644 --- a/ui/public/imgs/providers/ucloud.svg +++ b/ui/public/imgs/providers/ucloud.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/webhook.svg b/ui/public/imgs/providers/webhook.svg index 2ca5bff3..6c5eaee1 100644 --- a/ui/public/imgs/providers/webhook.svg +++ b/ui/public/imgs/providers/webhook.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/westcn.svg b/ui/public/imgs/providers/westcn.svg index 9ea5a83c..2ad4fa58 100644 --- a/ui/public/imgs/providers/westcn.svg +++ b/ui/public/imgs/providers/westcn.svg @@ -1 +1 @@ - + diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 0b5632c3..fd3c4536 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -17,6 +17,7 @@ import AccessFormBaiduCloudConfig from "./AccessFormBaiduCloudConfig"; import AccessFormBaishanConfig from "./AccessFormBaishanConfig"; import AccessFormBaotaPanelConfig from "./AccessFormBaotaPanelConfig"; import AccessFormBytePlusConfig from "./AccessFormBytePlusConfig"; +import AccessFormCacheFlyConfig from "./AccessFormCacheFlyConfig"; import AccessFormCloudflareConfig from "./AccessFormCloudflareConfig"; import AccessFormClouDNSConfig from "./AccessFormClouDNSConfig"; import AccessFormDogeCloudConfig from "./AccessFormDogeCloudConfig"; @@ -109,6 +110,8 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.BYTEPLUS: return ; + case ACCESS_PROVIDERS.CACHEFLY: + return ; case ACCESS_PROVIDERS.CLOUDFLARE: return ; case ACCESS_PROVIDERS.CLOUDNS: diff --git a/ui/src/components/access/AccessFormCacheFlyConfig.tsx b/ui/src/components/access/AccessFormCacheFlyConfig.tsx new file mode 100644 index 00000000..b3172785 --- /dev/null +++ b/ui/src/components/access/AccessFormCacheFlyConfig.tsx @@ -0,0 +1,56 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForCacheFly } from "@/domain/access"; + +type AccessFormCacheFlyConfigFieldValues = Nullish; + +export type AccessFormCacheFlyConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormCacheFlyConfigFieldValues; + onValuesChange?: (values: AccessFormCacheFlyConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormCacheFlyConfigFieldValues => { + return { + apiToken: "", + }; +}; + +const AccessFormCacheFlyConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormCacheFlyConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiToken: z + .string() + .min(1, t("access.form.cachefly_api_token.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 AccessFormCacheFlyConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx index b0586aae..9b992914 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -104,8 +104,7 @@ const DeployNodeConfigForm = forwardRef !!formInst.getFieldValue("provider"), t("workflow_node.deploy.form.provider.placeholder")), + .nonempty(t("workflow_node.deploy.form.provider_access.placeholder")), providerConfig: z.any(), skipOnLastSucceeded: z.boolean().nullish(), }); @@ -246,7 +245,7 @@ const DeployNodeConfigForm = forwardRef} > - + @@ -378,7 +383,7 @@ const DeployNodeConfigForm = forwardRef - + {t("workflow_node.deploy.form.params_config.label")} @@ -386,7 +391,9 @@ const DeployNodeConfigForm = forwardRef {nestedFormEl} + + {t("workflow_node.deploy.form.strategy_config.label")} diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index 1779c64c..c4132f60 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -14,6 +14,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForBaishan | AccessConfigForBaotaPanel | AccessConfigForBytePlus + | AccessConfigForCacheFly | AccessConfigForCloudflare | AccessConfigForClouDNS | AccessConfigForDogeCloud @@ -83,6 +84,10 @@ export type AccessConfigForBytePlus = { secretKey: string; }; +export type AccessConfigForCacheFly = { + apiToken: string; +}; + export type AccessConfigForCloudflare = { dnsApiToken: string; }; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 53eb7898..f58299da 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -12,6 +12,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ BAISHAN: "baishan", BAOTAPANEL: "baotapanel", BYTEPLUS: "byteplus", + CACHEFLY: "cachefly", CLOUDFLARE: "cloudflare", CLOUDNS: "cloudns", DOGECLOUD: "dogecloud", @@ -72,16 +73,17 @@ export const accessProvidersMap: Maphttps://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys", + "access.form.cachefly_api_token.label": "CacheFly API token", + "access.form.cachefly_api_token.placeholder": "Please enter CacheFly API token", + "access.form.cachefly_api_token.tooltip": "For more information, see https://kb.cachefly.com/kb/guide/en/generating-tokens-and-keys-Oll9Irt5TI/Steps/2460228", "access.form.cloudflare_dns_api_token.label": "Cloudflare API token", "access.form.cloudflare_dns_api_token.placeholder": "Please enter Cloudflare API token", "access.form.cloudflare_dns_api_token.tooltip": "For more information, see https://developers.cloudflare.com/fundamentals/api/get-started/create-token/", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index dcd555c3..e53e5efe 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -29,7 +29,7 @@ "provider.baotapanel.site": "BaoTa Panel - Site", "provider.byteplus": "BytePlus", "provider.byteplus.cdn": "BytePlus - CDN (Content Delivery Network)", - "provider.cachefly": "Cachefly", + "provider.cachefly": "CacheFly", "provider.cdnfly": "Cdnfly", "provider.cloudflare": "Cloudflare", "provider.cloudns": "ClouDNS", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index e3ae142c..bb366764 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -79,6 +79,9 @@ "access.form.byteplus_secret_key.label": "BytePlus SecretKey", "access.form.byteplus_secret_key.placeholder": "请输入 BytePlus SecretKey", "access.form.byteplus_secret_key.tooltip": "这是什么?请参阅 https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys", + "access.form.cachefly_api_token.label": "CacheFly API Token", + "access.form.cachefly_api_token.placeholder": "请输入 CacheFly API Token", + "access.form.cachefly_api_token.tooltip": "这是什么?请参阅 https://kb.cachefly.com/kb/guide/en/generating-tokens-and-keys-Oll9Irt5TI/Steps/2460228", "access.form.cloudflare_dns_api_token.label": "Cloudflare API Token", "access.form.cloudflare_dns_api_token.placeholder": "请输入 Cloudflare API Token", "access.form.cloudflare_dns_api_token.tooltip": "这是什么?请参阅 https://developers.cloudflare.com/fundamentals/api/get-started/create-token/", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 95cbeef7..8bc10b25 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -29,7 +29,7 @@ "provider.baotapanel.site": "宝塔面板 - 网站", "provider.byteplus": "BytePlus", "provider.byteplus.cdn": "BytePlus - 内容分发网络 CDN", - "provider.cachefly": "Cachefly", + "provider.cachefly": "CacheFly", "provider.cdnfly": "Cdnfly", "provider.cloudflare": "Cloudflare", "provider.cloudns": "ClouDNS",