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 00000000..86a13db5 Binary files /dev/null and b/ui/public/imgs/providers/cachefly.png differ diff --git a/ui/public/imgs/providers/cloudflare.svg b/ui/public/imgs/providers/cloudflare.svg index b6f07b50..5a6d858b 100644 --- a/ui/public/imgs/providers/cloudflare.svg +++ b/ui/public/imgs/providers/cloudflare.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/cloudns.png b/ui/public/imgs/providers/cloudns.png new file mode 100644 index 00000000..1ad3068d Binary files /dev/null and b/ui/public/imgs/providers/cloudns.png differ 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 00000000..1897bc88 Binary files /dev/null and b/ui/public/imgs/providers/dogecloud.png differ 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 00000000..ef3772f5 Binary files /dev/null and b/ui/public/imgs/providers/gname.png differ 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",