Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zone: make settings more flexible #1251

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changelog/1251.txt
Original file line number Diff line number Diff line change
@@ -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`
```
2 changes: 2 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -43,6 +44,7 @@ var (
ErrMissingResourceIdentifier = errors.New(errMissingResourceIdentifier)

ErrRequiredAccountLevelResourceContainer = errors.New(errRequiredAccountLevelResourceContainer)
ErrRequiredZoneLevelResourceContainer = errors.New(errRequiredZoneLevelResourceContainer)
)

type ErrorType string
Expand Down
63 changes: 53 additions & 10 deletions zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
100 changes: 100 additions & 0 deletions zone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}