diff --git a/.changelog/1251.txt b/.changelog/1251.txt new file mode 100644 index 00000000000..b750d6ebf68 --- /dev/null +++ b/.changelog/1251.txt @@ -0,0 +1,11 @@ +```release-note:breaking-change +zone: `ZoneSingleSetting` has been renamed to `GetZoneSetting` and updated method signature inline with our expected conventions +``` + +```release-note:breaking-change +zone: `UpdateZoneSingleSetting` has been renamed to `UpdateZoneSetting` and updated method signature inline with our expected conventions +``` + +```release-note:enhancement +zone: `GetZoneSetting` and `UpdateZoneSetting` now allow configuring the path for where a setting resides instead of assuming `settings` +``` diff --git a/errors.go b/errors.go index 723c18bae3a..85fdc3efacb 100644 --- a/errors.go +++ b/errors.go @@ -31,6 +31,7 @@ const ( errInvalidResourceContainerAccess = "requested resource container (%q) is not supported for this endpoint" errRequiredAccountLevelResourceContainer = "this endpoint requires using an account level resource container and identifiers" + errRequiredZoneLevelResourceContainer = "this endpoint requires using a zone level resource container and identifiers" ) var ( @@ -43,6 +44,7 @@ var ( ErrMissingResourceIdentifier = errors.New(errMissingResourceIdentifier) ErrRequiredAccountLevelResourceContainer = errors.New(errRequiredAccountLevelResourceContainer) + ErrRequiredZoneLevelResourceContainer = errors.New(errRequiredZoneLevelResourceContainer) ) type ErrorType string diff --git a/zone.go b/zone.go index ba544c78966..59489f50c92 100644 --- a/zone.go +++ b/zone.go @@ -14,6 +14,11 @@ import ( "golang.org/x/net/idna" ) +var ( + // ErrMissingSettingName is for when setting name is required but missing. + ErrMissingSettingName = errors.New("zone setting name required but missing") +) + // Owner describes the resource owner. type Owner struct { ID string `json:"id"` @@ -300,6 +305,17 @@ type zoneSubscriptionRatePlanPayload struct { } `json:"rate_plan"` } +type GetZoneSettingParams struct { + Name string `json:"-"` + PathPrefix string `json:"-"` +} + +type UpdateZoneSettingParams struct { + Name string `json:"-"` + PathPrefix string `json:"-"` + Value interface{} `json:"value"` +} + // CreateZone creates a zone on an account. // // Setting jumpstart to true will attempt to automatically scan for existing @@ -897,11 +913,25 @@ func normalizeZoneName(name string) string { return name } -// ZoneSingleSetting returns information about specified setting to the specified zone. +// GetZoneSetting returns information about specified setting to the specified +// zone. // // API reference: https://api.cloudflare.com/#zone-settings-get-all-zone-settings -func (api *API) ZoneSingleSetting(ctx context.Context, zoneID, settingName string) (ZoneSetting, error) { - uri := fmt.Sprintf("/zones/%s/settings/%s", zoneID, settingName) +func (api *API) GetZoneSetting(ctx context.Context, rc *ResourceContainer, params GetZoneSettingParams) (ZoneSetting, error) { + if rc.Level != ZoneRouteLevel { + return ZoneSetting{}, ErrRequiredZoneLevelResourceContainer + } + + if rc.Identifier == "" { + return ZoneSetting{}, ErrMissingName + } + + pathPrefix := "settings" + if params.PathPrefix != "" { + pathPrefix = params.PathPrefix + } + + uri := fmt.Sprintf("/zones/%s/%s/%s", rc.Identifier, pathPrefix, params.Name) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { return ZoneSetting{}, err @@ -914,23 +944,36 @@ func (api *API) ZoneSingleSetting(ctx context.Context, zoneID, settingName strin return r.Result, nil } -// UpdateZoneSingleSetting updates the specified setting for a given zone. +// UpdateZoneSetting updates the specified setting for a given zone. // // API reference: https://api.cloudflare.com/#zone-settings-edit-zone-settings-info -func (api *API) UpdateZoneSingleSetting(ctx context.Context, zoneID, settingName string, setting ZoneSetting) (*ZoneSettingSingleResponse, error) { - uri := fmt.Sprintf("/zones/%s/settings/%s", zoneID, settingName) - res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, setting) +func (api *API) UpdateZoneSetting(ctx context.Context, rc *ResourceContainer, params UpdateZoneSettingParams) (ZoneSetting, error) { + if rc.Level != ZoneRouteLevel { + return ZoneSetting{}, ErrRequiredZoneLevelResourceContainer + } + + if rc.Identifier == "" { + return ZoneSetting{}, ErrMissingName + } + + pathPrefix := "settings" + if params.PathPrefix != "" { + pathPrefix = params.PathPrefix + } + + uri := fmt.Sprintf("/zones/%s/%s/%s", rc.Identifier, pathPrefix, params.Name) + res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, params) if err != nil { - return nil, err + return ZoneSetting{}, err } response := &ZoneSettingSingleResponse{} err = json.Unmarshal(res, &response) if err != nil { - return nil, fmt.Errorf("%s: %w", errUnmarshalError, err) + return ZoneSetting{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } - return response, nil + return response.Result, nil } // ZoneExport returns the text BIND config for the given zone diff --git a/zone_test.go b/zone_test.go index 93a2bb6fd5b..6dd5bc4fccd 100644 --- a/zone_test.go +++ b/zone_test.go @@ -1510,3 +1510,103 @@ func TestUpdateZoneSSLSettings(t *testing.T) { assert.Equal(t, s.ModifiedOn, "2014-01-01T05:20:00.12345Z") } } + +func TestGetZoneSetting(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, `{ + "result": { + "id": "ssl", + "value": "off", + "editable": true, + "modified_on": "2014-01-01T05:20:00.12345Z" + } + }`) + } + mux.HandleFunc("/zones/foo/settings/ssl", handler) + s, err := client.GetZoneSetting(context.Background(), ZoneIdentifier("foo"), GetZoneSettingParams{Name: "ssl"}) + if assert.NoError(t, err) { + assert.Equal(t, s.ID, "ssl") + assert.Equal(t, s.Value, "off") + assert.Equal(t, s.Editable, true) + assert.Equal(t, s.ModifiedOn, "2014-01-01T05:20:00.12345Z") + } +} + +func TestGetZoneSettingWithCustomPathPrefix(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, `{ + "result": { + "id": "ssl", + "value": "off", + "editable": true, + "modified_on": "2014-01-01T05:20:00.12345Z" + } + }`) + } + mux.HandleFunc("/zones/foo/my_custom_path/ssl", handler) + s, err := client.GetZoneSetting(context.Background(), ZoneIdentifier("foo"), GetZoneSettingParams{Name: "ssl", PathPrefix: "my_custom_path"}) + if assert.NoError(t, err) { + assert.Equal(t, s.ID, "ssl") + assert.Equal(t, s.Value, "off") + assert.Equal(t, s.Editable, true) + assert.Equal(t, s.ModifiedOn, "2014-01-01T05:20:00.12345Z") + } +} + +func TestUpdateZoneSetting(t *testing.T) { + setup() + defer teardown() + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method) + w.Header().Set("content-type", "application/json") + _, _ = fmt.Fprintf(w, `{ + "result": { + "id": "ssl", + "value": "off", + "editable": true, + "modified_on": "2014-01-01T05:20:00.12345Z" + } + }`) + } + mux.HandleFunc("/zones/foo/settings/ssl", handler) + s, err := client.UpdateZoneSetting(context.Background(), ZoneIdentifier("foo"), UpdateZoneSettingParams{Name: "ssl", Value: "off"}) + if assert.NoError(t, err) { + assert.Equal(t, s.ID, "ssl") + assert.Equal(t, s.Value, "off") + assert.Equal(t, s.Editable, true) + assert.Equal(t, s.ModifiedOn, "2014-01-01T05:20:00.12345Z") + } +} + +func TestUpdateZoneSettingWithCustomPathPrefix(t *testing.T) { + setup() + defer teardown() + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method) + w.Header().Set("content-type", "application/json") + _, _ = fmt.Fprintf(w, `{ + "result": { + "id": "ssl", + "value": "off", + "editable": true, + "modified_on": "2014-01-01T05:20:00.12345Z" + } + }`) + } + mux.HandleFunc("/zones/foo/my_custom_path/ssl", handler) + s, err := client.UpdateZoneSetting(context.Background(), ZoneIdentifier("foo"), UpdateZoneSettingParams{Name: "ssl", PathPrefix: "my_custom_path", Value: "off"}) + if assert.NoError(t, err) { + assert.Equal(t, s.ID, "ssl") + assert.Equal(t, s.Value, "off") + assert.Equal(t, s.Editable, true) + assert.Equal(t, s.ModifiedOn, "2014-01-01T05:20:00.12345Z") + } +}