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

Handle case where ZoneRecord name can be not present #92

Merged
merged 3 commits into from
May 2, 2020
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# CHANGELOG


#### master

- FIXED: A zone record can be updated without the risk of overridig the name by mistake (dnsimple/dnsimple-go#33, dnsimple/dnsimple-go#92)

Incompatible changes:

- CHANGED: CreateZoneRecord and UpdateZoneRecord now requires to use ZoneRecordAttributes instead of ZoneRecord. This is required to avoid conflicts caused by blank record names (dnsimple/dnsimple-go#92)


#### Release 0.50.0

- NEW: Added Client.SetUserAgent() as a convenient helper to set a custom user agent.
Expand Down
8 changes: 8 additions & 0 deletions dnsimple/dnsimple.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,11 @@ func addURLQueryOptions(path string, options interface{}) (string, error) {

return u.String(), nil
}

// Int64P is a helper routine that allocates a new int64 value
// to store v and returns a pointer to it.
func Int64P(v int64) *int64 { return &v }

// StringP is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func StringP(v string) *string { return &v }
aeden marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 2 additions & 1 deletion dnsimple/live_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ func TestLive_Zones(t *testing.T) {
}

zoneName := domainResponse.Data.Name
recordResponse, err := dnsimpleClient.Zones.CreateRecord(context.Background(), accountID, zoneName, ZoneRecord{Name: fmt.Sprintf("%v", time.Now().Unix()), Type: "TXT", Content: "Test"})
recordName := fmt.Sprintf("%v", time.Now().Unix())
recordResponse, err := dnsimpleClient.Zones.CreateRecord(context.Background(), accountID, zoneName, ZoneRecordAttributes{Name: &recordName, Type: "TXT", Content: "Test"})
if err != nil {
t.Fatalf("Live Zones/CreateRecord() returned error: %v", err)
}
Expand Down
21 changes: 18 additions & 3 deletions dnsimple/zones_records.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
)

// ZoneRecord represents a DNS record in DNSimple.
// ZoneRecord represents a zone record in DNSimple.
type ZoneRecord struct {
ID int64 `json:"id,omitempty"`
ZoneID string `json:"zone_id,omitempty"`
Expand All @@ -21,6 +21,21 @@ type ZoneRecord struct {
UpdatedAt string `json:"updated_at,omitempty"`
}

// ZoneRecordAttributes represents the attributes you can send to create/update a zone record.
//
// Compared to most other calls in this library, you should not use ZoneRecord as payload for record calls.
// This is because it can lead to side effects due to the inability of go to distinguish between a non-present string
// and an empty string. Name can be both, therefore a specific struct is required.
type ZoneRecordAttributes struct {
ZoneID string `json:"zone_id,omitempty"`
Type string `json:"type,omitempty"`
Name *string `json:"name,omitempty"`
Content string `json:"content,omitempty"`
TTL int `json:"ttl,omitempty"`
Priority int `json:"priority,omitempty"`
Regions []string `json:"regions,omitempty"`
}

func zoneRecordPath(accountID string, zoneName string, recordID int64) (path string) {
path = fmt.Sprintf("/%v/zones/%v/records", accountID, zoneName)
if recordID != 0 {
Expand Down Expand Up @@ -81,7 +96,7 @@ func (s *ZonesService) ListRecords(ctx context.Context, accountID string, zoneNa
// CreateRecord creates a zone record.
//
// See https://developer.dnsimple.com/v2/zones/records/#createZoneRecord
func (s *ZonesService) CreateRecord(ctx context.Context, accountID string, zoneName string, recordAttributes ZoneRecord) (*ZoneRecordResponse, error) {
func (s *ZonesService) CreateRecord(ctx context.Context, accountID string, zoneName string, recordAttributes ZoneRecordAttributes) (*ZoneRecordResponse, error) {
path := versioned(zoneRecordPath(accountID, zoneName, 0))
recordResponse := &ZoneRecordResponse{}

Expand Down Expand Up @@ -113,7 +128,7 @@ func (s *ZonesService) GetRecord(ctx context.Context, accountID string, zoneName
// UpdateRecord updates a zone record.
//
// See https://developer.dnsimple.com/v2/zones/records/#updateZoneRecord
func (s *ZonesService) UpdateRecord(ctx context.Context, accountID string, zoneName string, recordID int64, recordAttributes ZoneRecord) (*ZoneRecordResponse, error) {
func (s *ZonesService) UpdateRecord(ctx context.Context, accountID string, zoneName string, recordID int64, recordAttributes ZoneRecordAttributes) (*ZoneRecordResponse, error) {
path := versioned(zoneRecordPath(accountID, zoneName, recordID))
recordResponse := &ZoneRecordResponse{}
resp, err := s.client.patch(ctx, path, recordAttributes, recordResponse)
Expand Down
50 changes: 39 additions & 11 deletions dnsimple/zones_records_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func TestZonesService_CreateRecord(t *testing.T) {
})

accountID := "1010"
recordValues := ZoneRecord{Name: "foo", Content: "mxa.example.com", Type: "MX"}
recordValues := ZoneRecordAttributes{Name: StringP("foo"), Content: "mxa.example.com", Type: "MX"}

recordResponse, err := client.Zones.CreateRecord(context.Background(), accountID, "example.com", recordValues)
if err != nil {
Expand Down Expand Up @@ -141,7 +141,7 @@ func TestZonesService_CreateRecord_BlankName(t *testing.T) {
io.Copy(w, httpResponse.Body)
})

recordValues := ZoneRecord{Name: "", Content: "127.0.0.1", Type: "A"}
recordValues := ZoneRecordAttributes{Name: StringP(""), Content: "127.0.0.1", Type: "A"}

recordResponse, err := client.Zones.CreateRecord(context.Background(), "1010", "example.com", recordValues)
if err != nil {
Expand All @@ -161,7 +161,7 @@ func TestZonesService_CreateRecord_Regions(t *testing.T) {
setupMockServer()
defer teardownMockServer()

var recordValues ZoneRecord
var recordValues ZoneRecordAttributes

mux.HandleFunc("/v2/1/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) {
httpResponse := httpResponseFixture(t, "/api/createZoneRecord/created.http")
Expand All @@ -173,7 +173,8 @@ func TestZonesService_CreateRecord_Regions(t *testing.T) {
io.Copy(w, httpResponse.Body)
})

recordValues = ZoneRecord{Name: "foo", Regions: []string{}}
recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{}}

if _, err := client.Zones.CreateRecord(context.Background(), "1", "example.com", recordValues); err != nil {
t.Fatalf("Zones.CreateRecord() returned error: %v", err)
}
Expand All @@ -188,7 +189,8 @@ func TestZonesService_CreateRecord_Regions(t *testing.T) {
io.Copy(w, httpResponse.Body)
})

recordValues = ZoneRecord{Name: "foo", Regions: []string{"global"}}
recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{"global"}}

if _, err := client.Zones.CreateRecord(context.Background(), "2", "example.com", recordValues); err != nil {
t.Fatalf("Zones.CreateRecord() returned error: %v", err)
}
Expand All @@ -203,7 +205,8 @@ func TestZonesService_CreateRecord_Regions(t *testing.T) {
io.Copy(w, httpResponse.Body)
})

recordValues = ZoneRecord{Name: "foo", Regions: []string{"global"}}
recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{"global"}}

if _, err := client.Zones.CreateRecord(context.Background(), "2", "example.com", recordValues); err != nil {
t.Fatalf("Zones.CreateRecord() returned error: %v", err)
}
Expand Down Expand Up @@ -268,7 +271,7 @@ func TestZonesService_UpdateRecord(t *testing.T) {
})

accountID := "1010"
recordValues := ZoneRecord{Name: "foo", Content: "127.0.0.1"}
recordValues := ZoneRecordAttributes{Name: StringP("foo"), Content: "127.0.0.1"}

recordResponse, err := client.Zones.UpdateRecord(context.Background(), accountID, "example.com", 5, recordValues)
if err != nil {
Expand All @@ -284,11 +287,33 @@ func TestZonesService_UpdateRecord(t *testing.T) {
}
}

func TestZonesService_UpdateRecord_NameNotProvided(t *testing.T) {
setupMockServer()
defer teardownMockServer()

mux.HandleFunc("/v2/1010/zones/example.com/records/5", func(w http.ResponseWriter, r *http.Request) {
httpResponse := httpResponseFixture(t, "/api/updateZoneRecord/success.http")

want := map[string]interface{}{"content": "127.0.0.1"}
testRequestJSON(t, r, want)

w.WriteHeader(httpResponse.StatusCode)
io.Copy(w, httpResponse.Body)
})

recordValues := ZoneRecordAttributes{Content: "127.0.0.1"}

_, err := client.Zones.UpdateRecord(context.Background(), "1010", "example.com", 5, recordValues)
if err != nil {
t.Fatalf("Zones.UpdateRecord() returned error: %v", err)
}
}

func TestZonesService_UpdateRecord_Regions(t *testing.T) {
setupMockServer()
defer teardownMockServer()

var recordValues ZoneRecord
var recordValues ZoneRecordAttributes

mux.HandleFunc("/v2/1/zones/example.com/records/1", func(w http.ResponseWriter, r *http.Request) {
httpResponse := httpResponseFixture(t, "/api/updateZoneRecord/success.http")
Expand All @@ -300,7 +325,8 @@ func TestZonesService_UpdateRecord_Regions(t *testing.T) {
io.Copy(w, httpResponse.Body)
})

recordValues = ZoneRecord{Name: "foo", Regions: []string{}}
recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{}}

if _, err := client.Zones.UpdateRecord(context.Background(), "1", "example.com", 1, recordValues); err != nil {
t.Fatalf("Zones.UpdateRecord() returned error: %v", err)
}
Expand All @@ -315,7 +341,8 @@ func TestZonesService_UpdateRecord_Regions(t *testing.T) {
io.Copy(w, httpResponse.Body)
})

recordValues = ZoneRecord{Name: "foo", Regions: []string{"global"}}
recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{"global"}}

if _, err := client.Zones.UpdateRecord(context.Background(), "2", "example.com", 1, recordValues); err != nil {
t.Fatalf("Zones.UpdateRecord() returned error: %v", err)
}
Expand All @@ -330,7 +357,8 @@ func TestZonesService_UpdateRecord_Regions(t *testing.T) {
io.Copy(w, httpResponse.Body)
})

recordValues = ZoneRecord{Name: "foo", Regions: []string{"global"}}
recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{"global"}}

if _, err := client.Zones.UpdateRecord(context.Background(), "2", "example.com", 1, recordValues); err != nil {
t.Fatalf("Zones.UpdateRecord() returned error: %v", err)
}
Expand Down