diff --git a/.changelog/1264.txt b/.changelog/1264.txt new file mode 100644 index 00000000000..55ed0957708 --- /dev/null +++ b/.changelog/1264.txt @@ -0,0 +1,19 @@ +```release-note:breaking-change +pages_deployment: add support for auto pagination +``` + +```release-note:enchancement +pages_deployment: add Force to DeletePagesDeploymentParams +``` + +```release-note:breaking-change +pages_deployment: change DeletePagesDeploymentParams to contain all parameters +``` + +```release-note:breaking-change +pages_project: rename PagesProject to GetPagesProject +``` + +```release-note:breaking-change +pages_project: change to use ResourceContainer for account ID +``` \ No newline at end of file diff --git a/.changelog/1328.txt b/.changelog/1328.txt new file mode 100644 index 00000000000..51d73f83089 --- /dev/null +++ b/.changelog/1328.txt @@ -0,0 +1,3 @@ +```release-note:dependency +deps: bumps golang.org/x/net from 0.11.0 to 0.12.0 +``` diff --git a/.changelog/1329.txt b/.changelog/1329.txt new file mode 100644 index 00000000000..da19ca1536a --- /dev/null +++ b/.changelog/1329.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +certificate_packs: Add Delegation Records +``` \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d6dffc9b32..009fdce14a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ ## 0.73.0 (Unreleased) +BREAKING CHANGES: + +* pages_deployment: add support for auto pagination ([#1264](https://github.com/cloudflare/cloudflare-go/issues/1264)) +* pages_deployment: change DeletePagesDeploymentParams to contain all parameters ([#1264](https://github.com/cloudflare/cloudflare-go/issues/1264)) +* pages_project: change to use ResourceContainer for account ID ([#1264](https://github.com/cloudflare/cloudflare-go/issues/1264)) +* pages_project: rename PagesProject to GetPagesProject ([#1264](https://github.com/cloudflare/cloudflare-go/issues/1264)) + +DEPENDENCIES: + +* deps: bumps golang.org/x/net from 0.11.0 to 0.12.0 ([#1328](https://github.com/cloudflare/cloudflare-go/issues/1328)) + ## 0.72.0 (July 5th, 2023) BREAKING CHANGES: diff --git a/certificate_packs.go b/certificate_packs.go index 802ed5dfe30..7c862b72f4f 100644 --- a/certificate_packs.go +++ b/certificate_packs.go @@ -45,6 +45,7 @@ type CertificatePack struct { ValidityDays int `json:"validity_days"` CertificateAuthority string `json:"certificate_authority"` CloudflareBranding bool `json:"cloudflare_branding"` + DelegationRecords []SSLDelegationRecord `json:"dcv_delegation_records,omitempty"` } // CertificatePackRequest is used for requesting a new certificate. diff --git a/certificate_packs_test.go b/certificate_packs_test.go index 6dc97582470..ca5f8b1d15e 100644 --- a/certificate_packs_test.go +++ b/certificate_packs_test.go @@ -47,6 +47,22 @@ var ( ValidityDays: 90, CertificateAuthority: "lets_encrypt", } + + pendingCertificatePackRecords = CertificatePack{ + ID: "64289572-8b22-4cd4-af3c-3fef28ef5dae", + Type: "advanced", + Hosts: []string{"example.com"}, + Certificates: []CertificatePackCertificate{}, + PrimaryCertificate: "0", + Status: "pending_validation", + ValidationRecords: []SSLValidationRecord{SSLValidationRecord{CnameTarget: "", CnameName: "", TxtName: "_acme-challenge.example.com", TxtValue: "QkyhZpLUAD4r3Fn9urywnXzeIeZ_ZG68MxJgBY32NmU", HTTPUrl: "", HTTPBody: "", Emails: []string(nil)}}, + ValidationErrors: []SSLValidationError(nil), + ValidationMethod: "txt", + ValidityDays: 90, + CertificateAuthority: "lets_encrypt", + CloudflareBranding: false, + DelegationRecords: []SSLDelegationRecord{SSLDelegationRecord{CnameTarget: "example.com.0f461ad6a17edc91.dcv.cloudflare.com", CnameName: "_acme-challenge.example.com"}}, + } ) func TestListCertificatePacks(t *testing.T) { @@ -267,14 +283,14 @@ func TestDeleteCertificatePack(t *testing.T) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/json") fmt.Fprintf(w, `{ - "success": true, - "errors": [], - "messages": [], - "result": { - "id": "3822ff90-ea29-44df-9e55-21300bb9419b" - } -} - `) + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "3822ff90-ea29-44df-9e55-21300bb9419b" + } + } + `) } mux.HandleFunc("/zones/"+testZoneID+"/ssl/certificate_packs/3822ff90-ea29-44df-9e55-21300bb9419b", handler) @@ -283,3 +299,53 @@ func TestDeleteCertificatePack(t *testing.T) { assert.NoError(t, err) } + +func TestListCertificatePackPending(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "64289572-8b22-4cd4-af3c-3fef28ef5dae", + "type": "advanced", + "hosts": [ + "example.com" + ], + "primary_certificate": "0", + "status": "pending_validation", + "certificates": [], + "created_on": "2023-06-21T13:48:39.114782Z", + "validity_days": 90, + "validation_method": "txt", + "validation_records": [ + { + "status": "pending", + "txt_name": "_acme-challenge.example.com", + "txt_value": "QkyhZpLUAD4r3Fn9urywnXzeIeZ_ZG68MxJgBY32NmU" + } + ], + "dcv_delegation_records": [ + { + "cname": "_acme-challenge.example.com", + "cname_target": "example.com.0f461ad6a17edc91.dcv.cloudflare.com" + } + ], + "certificate_authority": "lets_encrypt" + } + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/ssl/certificate_packs/3822ff90-ea29-44df-9e55-21300bb9419a", handler) + + actual, err := client.CertificatePack(context.Background(), testZoneID, "3822ff90-ea29-44df-9e55-21300bb9419a") + + if assert.NoError(t, err) { + assert.Equal(t, pendingCertificatePackRecords, actual) + } +} diff --git a/go.mod b/go.mod index 856fd9cb6c7..ccc0c45d487 100644 --- a/go.mod +++ b/go.mod @@ -32,4 +32,4 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/text v0.10.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect -) +) \ No newline at end of file diff --git a/go.sum b/go.sum index a528bd1062b..19fd962612c 100644 --- a/go.sum +++ b/go.sum @@ -77,4 +77,4 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= \ No newline at end of file diff --git a/pages_deployment.go b/pages_deployment.go index 4eb5c8f2ab1..899e89100e0 100644 --- a/pages_deployment.go +++ b/pages_deployment.go @@ -62,12 +62,6 @@ type pagesDeploymentResponse struct { Result PagesProjectDeployment `json:"result"` } -type pagesDeploymentStageLogsResponse struct { - Response - Result PagesDeploymentStageLogs `json:"result"` - ResultInfo `json:"result_info"` -} - type pagesDeploymentLogsResponse struct { Response Result PagesDeploymentLogs `json:"result"` @@ -75,9 +69,9 @@ type pagesDeploymentLogsResponse struct { } type ListPagesDeploymentsParams struct { - ProjectName string + ProjectName string `url:"-"` - PaginationOptions + ResultInfo } type GetPagesDeploymentInfoParams struct { @@ -101,12 +95,14 @@ type GetPagesDeploymentLogsParams struct { } type DeletePagesDeploymentParams struct { - ProjectName string - DeploymentID string + ProjectName string `url:"-"` + DeploymentID string `url:"-"` + Force bool `url:"force,omitempty"` } type CreatePagesDeploymentParams struct { - ProjectName string + ProjectName string `json:"-"` + Branch string `json:"branch,omitempty"` } type RetryPagesDeploymentParams struct { @@ -122,33 +118,53 @@ type RollbackPagesDeploymentParams struct { var ( ErrMissingProjectName = errors.New("required missing project name") ErrMissingDeploymentID = errors.New("required missing deployment ID") - ErrMissingStageName = errors.New("required missing stage name") ) // ListPagesDeployments returns all deployments for a Pages project. // // API reference: https://api.cloudflare.com/#pages-deployment-get-deployments -func (api *API) ListPagesDeployments(ctx context.Context, rc *ResourceContainer, params ListPagesDeploymentsParams) ([]PagesProjectDeployment, ResultInfo, error) { +func (api *API) ListPagesDeployments(ctx context.Context, rc *ResourceContainer, params ListPagesDeploymentsParams) ([]PagesProjectDeployment, *ResultInfo, error) { if rc.Identifier == "" { - return []PagesProjectDeployment{}, ResultInfo{}, ErrMissingAccountID + return []PagesProjectDeployment{}, &ResultInfo{}, ErrMissingAccountID } if params.ProjectName == "" { - return []PagesProjectDeployment{}, ResultInfo{}, ErrMissingProjectName + return []PagesProjectDeployment{}, &ResultInfo{}, ErrMissingProjectName } - uri := buildURI(fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments", rc.Identifier, params.ProjectName), params.PaginationOptions) + autoPaginate := true + if params.PerPage >= 1 || params.Page >= 1 { + autoPaginate = false + } - res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) - if err != nil { - return []PagesProjectDeployment{}, ResultInfo{}, err + if params.PerPage < 1 { + params.PerPage = 25 } - var r pagesDeploymentListResponse - err = json.Unmarshal(res, &r) - if err != nil { - return []PagesProjectDeployment{}, ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + + if params.Page < 1 { + params.Page = 1 } - return r.Result, r.ResultInfo, nil + + var deployments []PagesProjectDeployment + var r pagesDeploymentListResponse + + for { + uri := buildURI(fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments", rc.Identifier, params.ProjectName), params) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return []PagesProjectDeployment{}, &ResultInfo{}, err + } + err = json.Unmarshal(res, &r) + if err != nil { + return []PagesProjectDeployment{}, &ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + deployments = append(deployments, r.Result...) + params.ResultInfo = r.ResultInfo.Next() + if params.Done() || !autoPaginate { + break + } + } + return deployments, &r.ResultInfo, nil } // GetPagesDeploymentInfo returns a deployment for a Pages project. @@ -217,20 +233,20 @@ func (api *API) GetPagesDeploymentLogs(ctx context.Context, rc *ResourceContaine // DeletePagesDeployment deletes a Pages deployment. // // API reference: https://api.cloudflare.com/#pages-deployment-delete-deployment -func (api *API) DeletePagesDeployment(ctx context.Context, rc *ResourceContainer, projectName, deploymentID string) error { +func (api *API) DeletePagesDeployment(ctx context.Context, rc *ResourceContainer, params DeletePagesDeploymentParams) error { if rc.Identifier == "" { return ErrMissingAccountID } - if projectName == "" { + if params.ProjectName == "" { return ErrMissingProjectName } - if deploymentID == "" { + if params.DeploymentID == "" { return ErrMissingDeploymentID } - uri := fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments/%s", rc.Identifier, projectName, deploymentID) + uri := buildURI(fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments/%s", rc.Identifier, params.ProjectName, params.DeploymentID), params) _, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) if err != nil { @@ -253,7 +269,7 @@ func (api *API) CreatePagesDeployment(ctx context.Context, rc *ResourceContainer uri := fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments", rc.Identifier, params.ProjectName) - res, err := api.makeRequestContext(ctx, http.MethodPost, uri, nil) + res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) if err != nil { return PagesProjectDeployment{}, err } diff --git a/pages_deployment_test.go b/pages_deployment_test.go index 282710a0cf8..48ec89abb6d 100644 --- a/pages_deployment_test.go +++ b/pages_deployment_test.go @@ -11,7 +11,7 @@ import ( ) const ( - testPagesDeplyomentResponse = ` + testPagesDeploymentResponse = ` { "id": "0012e50b-fa5d-44db-8cb5-1f372785dcbe", "short_id": "0012e50b", @@ -207,44 +207,6 @@ var ( Status: "success", } - expectedPagesDeploymentStageLogEntries = []PagesDeploymentStageLogEntry{ - { - ID: 0, - Timestamp: &pagesDeploymentDummyTime, - Message: "Installing dependencies", - }, - { - ID: 1, - Timestamp: &pagesDeploymentDummyTime, - Message: "Verify run directory", - }, - { - ID: 2, - Timestamp: &pagesDeploymentDummyTime, - Message: "Executing user command: bash test.sh", - }, - { - ID: 3, - Timestamp: &pagesDeploymentDummyTime, - Message: "Finished", - }, - { - ID: 4, - Timestamp: &pagesDeploymentDummyTime, - Message: "Building functions...", - }, - { - ID: 5, - Timestamp: &pagesDeploymentDummyTime, - Message: "Validating asset output directory", - }, - { - ID: 6, - Timestamp: &pagesDeploymentDummyTime, - Message: "Parsed 2 valid header rules.", - }, - } - expectedPagesDeploymentLogs = &PagesDeploymentLogs{ Total: 6, IncludesContainerLogs: true, @@ -289,6 +251,8 @@ func TestListPagesDeployments(t *testing.T) { handler := func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + assert.Equal(t, "25", r.URL.Query().Get("per_page")) + assert.Equal(t, "1", r.URL.Query().Get("page")) w.Header().Set("content-type", "application/json") fmt.Fprintf(w, `{ @@ -304,7 +268,7 @@ func TestListPagesDeployments(t *testing.T) { "count": 1, "total_count": 1 } - }`, testPagesDeplyomentResponse) + }`, testPagesDeploymentResponse) } mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/test/deployments", handler) @@ -319,12 +283,70 @@ func TestListPagesDeployments(t *testing.T) { Total: 1, } actual, resultInfo, err := client.ListPagesDeployments(context.Background(), AccountIdentifier(testAccountID), ListPagesDeploymentsParams{ - ProjectName: "test", - PaginationOptions: PaginationOptions{}, + ProjectName: "test", + ResultInfo: ResultInfo{}, }) if assert.NoError(t, err) { assert.Equal(t, expectedPagesDeployments, actual) - assert.Equal(t, expectedResultInfo, resultInfo) + assert.Equal(t, &expectedResultInfo, resultInfo) + } +} + +func TestListPagesDeploymentsPagination(t *testing.T) { + setup() + defer teardown() + var page1Called, page2Called bool + handler := func(w http.ResponseWriter, r *http.Request) { + page := r.URL.Query().Get("page") + w.Header().Set("content-type", "application/json") + switch page { + case "1": + page1Called = true + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": [ + %s + ], + "result_info": { + "page": 1, + "per_page": 25, + "total_count": 26, + "total_pages": 2 + } + }`, testPagesDeploymentResponse) + case "2": + page2Called = true + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": [ + %s + ], + "result_info": { + "page": 2, + "per_page": 25, + "total_count": 26, + "total_pages": 2 + } + }`, testPagesDeploymentResponse) + default: + assert.Failf(t, "Unexpected page number", "Expected page 1 or 2, got %s", page) + return + } + } + mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/test/deployments", handler) + actual, resultInfo, err := client.ListPagesDeployments(context.Background(), AccountIdentifier(testAccountID), ListPagesDeploymentsParams{ + ProjectName: "test", + ResultInfo: ResultInfo{}, + }) + if assert.NoError(t, err) { + assert.True(t, page1Called) + assert.True(t, page2Called) + assert.Equal(t, 2, len(actual)) + assert.Equal(t, 26, resultInfo.Total) } } @@ -341,7 +363,7 @@ func TestGetPagesDeploymentInfo(t *testing.T) { "errors": [], "messages": [], "result": %s - }`, testPagesDeplyomentResponse) + }`, testPagesDeploymentResponse) } mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/test/deployments/0012e50b-fa5d-44db-8cb5-1f372785dcbe", handler) @@ -386,7 +408,7 @@ func TestDeletePagesDeployment(t *testing.T) { handler := func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) - + assert.Equal(t, "true", r.URL.Query().Get("force")) w.Header().Set("content-type", "application/json") fmt.Fprintf(w, `{ "success": true, @@ -398,7 +420,7 @@ func TestDeletePagesDeployment(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/test/deployments/0012e50b-fa5d-44db-8cb5-1f372785dcbe", handler) - err := client.DeletePagesDeployment(context.Background(), AccountIdentifier(testAccountID), "test", "0012e50b-fa5d-44db-8cb5-1f372785dcbe") + err := client.DeletePagesDeployment(context.Background(), AccountIdentifier(testAccountID), DeletePagesDeploymentParams{ProjectName: "test", DeploymentID: "0012e50b-fa5d-44db-8cb5-1f372785dcbe", Force: true}) assert.NoError(t, err) } @@ -415,7 +437,7 @@ func TestCreatePagesDeployment(t *testing.T) { "errors": [], "messages": [], "result": %s - }`, testPagesDeplyomentResponse) + }`, testPagesDeploymentResponse) } mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/test/deployments", handler) @@ -442,7 +464,7 @@ func TestRetryPagesDeployment(t *testing.T) { "errors": [], "messages": [], "result": %s - }`, testPagesDeplyomentResponse) + }`, testPagesDeploymentResponse) } mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/test/deployments/0012e50b-fa5d-44db-8cb5-1f372785dcbe/retry", handler) @@ -466,7 +488,7 @@ func TestRollbackPagesDeployment(t *testing.T) { "errors": [], "messages": [], "result": %s - }`, testPagesDeplyomentResponse) + }`, testPagesDeploymentResponse) } mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/test/deployments/0012e50b-fa5d-44db-8cb5-1f372785dcbe/rollback", handler) diff --git a/pages_project.go b/pages_project.go index 4cbbb46497d..94c67b242ed 100644 --- a/pages_project.go +++ b/pages_project.go @@ -190,11 +190,46 @@ const ( Unbound UsageModel = "unbound" ) +type ListPagesProjectsParams struct { + PaginationOptions +} + +type CreatePagesProjectParams struct { + Name string `json:"name,omitempty"` + SubDomain string `json:"subdomain"` + Domains []string `json:"domains,omitempty"` + Source *PagesProjectSource `json:"source,omitempty"` + BuildConfig PagesProjectBuildConfig `json:"build_config"` + DeploymentConfigs PagesProjectDeploymentConfigs `json:"deployment_configs"` + LatestDeployment PagesProjectDeployment `json:"latest_deployment"` + CanonicalDeployment PagesProjectDeployment `json:"canonical_deployment"` + ProductionBranch string `json:"production_branch,omitempty"` +} + +type UpdatePagesProjectParams struct { + // `ID` is used for addressing the resource via the UI or a stable + // anchor whereas `Name` is used for updating the value. + ID string `json:"-"` + Name string `json:"name,omitempty"` + SubDomain string `json:"subdomain"` + Domains []string `json:"domains,omitempty"` + Source *PagesProjectSource `json:"source,omitempty"` + BuildConfig PagesProjectBuildConfig `json:"build_config"` + DeploymentConfigs PagesProjectDeploymentConfigs `json:"deployment_configs"` + LatestDeployment PagesProjectDeployment `json:"latest_deployment"` + CanonicalDeployment PagesProjectDeployment `json:"canonical_deployment"` + ProductionBranch string `json:"production_branch,omitempty"` +} + // ListPagesProjects returns all Pages projects for an account. // // API reference: https://api.cloudflare.com/#pages-project-get-projects -func (api *API) ListPagesProjects(ctx context.Context, accountID string, pageOpts PaginationOptions) ([]PagesProject, ResultInfo, error) { - uri := buildURI(fmt.Sprintf("/accounts/%s/pages/projects", accountID), pageOpts) +func (api *API) ListPagesProjects(ctx context.Context, rc *ResourceContainer, params ListPagesProjectsParams) ([]PagesProject, ResultInfo, error) { + if rc.Identifier == "" { + return []PagesProject{}, ResultInfo{}, ErrMissingAccountID + } + + uri := buildURI(fmt.Sprintf("/accounts/%s/pages/projects", rc.Identifier), params) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { @@ -208,11 +243,15 @@ func (api *API) ListPagesProjects(ctx context.Context, accountID string, pageOpt return r.Result, r.ResultInfo, nil } -// PagesProject returns a single Pages project by name. +// GetPagesProject returns a single Pages project by name. // // API reference: https://api.cloudflare.com/#pages-project-get-project -func (api *API) PagesProject(ctx context.Context, accountID, projectName string) (PagesProject, error) { - uri := fmt.Sprintf("/accounts/%s/pages/projects/%s", accountID, projectName) +func (api *API) GetPagesProject(ctx context.Context, rc *ResourceContainer, projectName string) (PagesProject, error) { + if rc.Identifier == "" { + return PagesProject{}, ErrMissingAccountID + } + + uri := fmt.Sprintf("/accounts/%s/pages/projects/%s", rc.Identifier, projectName) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { return PagesProject{}, err @@ -228,9 +267,12 @@ func (api *API) PagesProject(ctx context.Context, accountID, projectName string) // CreatePagesProject creates a new Pages project in an account. // // API reference: https://api.cloudflare.com/#pages-project-create-project -func (api *API) CreatePagesProject(ctx context.Context, accountID string, pagesProject PagesProject) (PagesProject, error) { - uri := fmt.Sprintf("/accounts/%s/pages/projects", accountID) - res, err := api.makeRequestContext(ctx, http.MethodPost, uri, pagesProject) +func (api *API) CreatePagesProject(ctx context.Context, rc *ResourceContainer, params CreatePagesProjectParams) (PagesProject, error) { + if rc.Identifier == "" { + return PagesProject{}, ErrMissingAccountID + } + uri := fmt.Sprintf("/accounts/%s/pages/projects", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) if err != nil { return PagesProject{}, err } @@ -245,9 +287,17 @@ func (api *API) CreatePagesProject(ctx context.Context, accountID string, pagesP // UpdatePagesProject updates an existing Pages project. // // API reference: https://api.cloudflare.com/#pages-project-update-project -func (api *API) UpdatePagesProject(ctx context.Context, accountID, projectName string, pagesProject PagesProject) (PagesProject, error) { - uri := fmt.Sprintf("/accounts/%s/pages/projects/%s", accountID, projectName) - res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, pagesProject) +func (api *API) UpdatePagesProject(ctx context.Context, rc *ResourceContainer, params UpdatePagesProjectParams) (PagesProject, error) { + if rc.Identifier == "" { + return PagesProject{}, ErrMissingAccountID + } + + if params.ID == "" { + return PagesProject{}, ErrMissingIdentifier + } + + uri := fmt.Sprintf("/accounts/%s/pages/projects/%s", rc.Identifier, params.ID) + res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, params) if err != nil { return PagesProject{}, err } @@ -262,8 +312,11 @@ func (api *API) UpdatePagesProject(ctx context.Context, accountID, projectName s // DeletePagesProject deletes a Pages project by name. // // API reference: https://api.cloudflare.com/#pages-project-delete-project -func (api *API) DeletePagesProject(ctx context.Context, accountID, projectName string) error { - uri := fmt.Sprintf("/accounts/%s/pages/projects/%s", accountID, projectName) +func (api *API) DeletePagesProject(ctx context.Context, rc *ResourceContainer, projectName string) error { + if rc.Identifier == "" { + return ErrMissingAccountID + } + uri := fmt.Sprintf("/accounts/%s/pages/projects/%s", rc.Identifier, projectName) res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) if err != nil { return err diff --git a/pages_project_test.go b/pages_project_test.go index 32d09ab570e..3c4b7ecc049 100644 --- a/pages_project_test.go +++ b/pages_project_test.go @@ -81,8 +81,8 @@ const ( } }, "d1_databases": { - "D1_BINDING": { - "id": "a94509c6-0757-43f3-b053-474b0ab10935" + "D1_BINDING": { + "id": "a94509c6-0757-43f3-b053-474b0ab10935" } }, "kv_namespaces": { @@ -521,7 +521,13 @@ func TestListPagesProjects(t *testing.T) { Count: 1, Total: 1, } - actual, resultInfo, err := client.ListPagesProjects(context.Background(), testAccountID, PaginationOptions{}) + + _, _, err := client.ListPagesProjects(context.Background(), AccountIdentifier(""), ListPagesProjectsParams{}) + if assert.Error(t, err) { + assert.Equal(t, err.Error(), errMissingAccountID) + } + + actual, resultInfo, err := client.ListPagesProjects(context.Background(), AccountIdentifier(testAccountID), ListPagesProjectsParams{}) if assert.NoError(t, err) { assert.Equal(t, expectedPagesProjects, actual) assert.Equal(t, expectedResultInfo, resultInfo) @@ -546,7 +552,12 @@ func TestPagesProject(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/Test Pages Project", handler) - actual, err := client.PagesProject(context.Background(), testAccountID, "Test Pages Project") + _, err := client.GetPagesProject(context.Background(), AccountIdentifier(""), "Test Pages Project") + if assert.Error(t, err) { + assert.Equal(t, err.Error(), errMissingAccountID) + } + + actual, err := client.GetPagesProject(context.Background(), AccountIdentifier(testAccountID), "Test Pages Project") if assert.NoError(t, err) { assert.Equal(t, *expectedPagesProject, actual) } @@ -570,7 +581,26 @@ func TestCreatePagesProject(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects", handler) - actual, err := client.CreatePagesProject(context.Background(), testAccountID, *expectedPagesProject) + params := &CreatePagesProjectParams{ + SubDomain: "test.pages.dev", + Name: "Test Pages Project", + Domains: []string{ + "testdomain.com", + "testdomain.org", + }, + CanonicalDeployment: *expectedPagesProjectDeployment, + BuildConfig: *expectedPagesProjectBuildConfig, + DeploymentConfigs: *expectedPagesProjectDeploymentConfigs, + Source: expectedPagesProjectSource, + LatestDeployment: *expectedPagesProjectDeployment, + ProductionBranch: "main", + } + _, err := client.CreatePagesProject(context.Background(), AccountIdentifier(""), *params) + if assert.Error(t, err) { + assert.Equal(t, err.Error(), errMissingAccountID) + } + + actual, err := client.CreatePagesProject(context.Background(), AccountIdentifier(testAccountID), *params) if assert.NoError(t, err) { assert.Equal(t, *expectedPagesProject, actual) } @@ -580,7 +610,8 @@ func TestUpdatePagesProject(t *testing.T) { setup() defer teardown() - updateAttributes := &PagesProject{ + updateAttributes := &UpdatePagesProjectParams{ + ID: "Test Pages Project", Name: "updated-project-name", } @@ -598,9 +629,12 @@ func TestUpdatePagesProject(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/Test Pages Project", handler) - _, err := client.UpdatePagesProject(context.Background(), testAccountID, "Test Pages Project", *updateAttributes) + _, err := client.UpdatePagesProject(context.Background(), AccountIdentifier(""), *updateAttributes) + if assert.Error(t, err) { + assert.Equal(t, err.Error(), errMissingAccountID) + } - t.Log(err) + _, err = client.UpdatePagesProject(context.Background(), AccountIdentifier(testAccountID), *updateAttributes) assert.NoError(t, err) } @@ -623,6 +657,11 @@ func TestDeletePagesProject(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/pages/projects/Test Pages Project", handler) - err := client.DeletePagesProject(context.Background(), testAccountID, "Test Pages Project") + err := client.DeletePagesProject(context.Background(), AccountIdentifier(""), "Test Pages Project") + if assert.Error(t, err) { + assert.Equal(t, err.Error(), errMissingAccountID) + } + + err = client.DeletePagesProject(context.Background(), AccountIdentifier(testAccountID), "Test Pages Project") assert.NoError(t, err) } diff --git a/ssl.go b/ssl.go index 178e98c6caf..53c6adb17f7 100644 --- a/ssl.go +++ b/ssl.go @@ -170,3 +170,9 @@ type SSLValidationRecord struct { Emails []string `json:"emails,omitempty"` } + +// SSLDelegationRecord displays Domain Control Delegation tokens. +type SSLDelegationRecord struct { + CnameTarget string `json:"cname_target,omitempty"` + CnameName string `json:"cname,omitempty"` +} diff --git a/zone.go b/zone.go index 59489f50c92..3a7ebb7b06d 100644 --- a/zone.go +++ b/zone.go @@ -19,6 +19,11 @@ var ( ErrMissingSettingName = errors.New("zone setting name required but missing") ) +const ( + // ZoneDCVDelegationHostname is the DCV delegation hostname. + ZoneDCVDelegationHostname = ".dcv.cloudflare.com" +) + // Owner describes the resource owner. type Owner struct { ID string `json:"id"` @@ -110,6 +115,17 @@ type ZoneResponse struct { Result Zone `json:"result"` } +// ZoneDCVDelegationResponse represents the response from the Zone DCV Delegation. +type ZoneDCVDelegationResponse struct { + Response + Result ZoneDCVDelegation `json:"result"` +} + +// ZoneDCVDelegation contains only the DCV delegation UUID. +type ZoneDCVDelegation struct { + UUID string `json:"uuid"` +} + // ZonesResponse represents the response from the Zone endpoint containing an array of zones. type ZonesResponse struct { Response @@ -840,6 +856,22 @@ func (api *API) ZoneSSLSettings(ctx context.Context, zoneID string) (ZoneSSLSett return r.Result, nil } +// ZoneDCVDelegation returns information about DCV Delegation to the specified zone. +func (api *API) ZoneDCVDelegation(ctx context.Context, zoneID string) (ZoneDCVDelegation, error) { + uri := fmt.Sprintf("/zones/%s/dcv_delegation/uuid", zoneID) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + + if err != nil { + return ZoneDCVDelegation{}, err + } + var r ZoneDCVDelegationResponse + err = json.Unmarshal(res, &r) + if err != nil { + return ZoneDCVDelegation{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r.Result, nil +} + // UpdateZoneSSLSettings update information about SSL setting to the specified zone. // // API reference: https://api.cloudflare.com/#zone-settings-change-ssl-setting