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

Added support for redirect lists. #926

Merged
merged 1 commit into from Jun 13, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 18 additions & 3 deletions list.go
Expand Up @@ -13,6 +13,8 @@ import (
const (
// ListTypeIP specifies a list containing IP addresses.
ListTypeIP = "ip"
// ListTypeRedirect specifies a list containing redirects.
ListTypeRedirect = "redirect"
)

// ListBulkOperation contains information about a Bulk Operation.
Expand All @@ -35,10 +37,22 @@ type List struct {
ModifiedOn *time.Time `json:"modified_on"`
}

// Redirect represents a redirect item in a List.
type Redirect struct {
SourceUrl string `json:"source_url"`
IncludeSubdomains *bool `json:"include_subdomains,omitempty"`
TargetUrl string `json:"target_url"`
StatusCode *int `json:"status_code,omitempty"`
PreserveQueryString *bool `json:"preserve_query_string,omitempty"`
SubpathMatching *bool `json:"subpath_matching,omitempty"`
PreservePathSuffix *bool `json:"preserve_path_suffix,omitempty"`
}

// ListItem contains information about a single List Item.
type ListItem struct {
ID string `json:"id"`
IP string `json:"ip"`
IP *string `json:"ip,omitempty"`
Redirect *Redirect `json:"redirect,omitempty"`
Comment string `json:"comment"`
CreatedOn *time.Time `json:"created_on"`
ModifiedOn *time.Time `json:"modified_on"`
Expand All @@ -53,8 +67,9 @@ type ListCreateRequest struct {

// ListItemCreateRequest contains data for a new List Item.
type ListItemCreateRequest struct {
IP string `json:"ip"`
Comment string `json:"comment"`
IP *string `json:"ip,omitempty"`
Redirect *Redirect `json:"redirect,omitempty"`
Comment string `json:"comment"`
}

// ListItemDeleteRequest wraps List Items that shall be deleted.
Expand Down
211 changes: 204 additions & 7 deletions list_test.go
Expand Up @@ -301,14 +301,14 @@ func TestListsItemsIP(t *testing.T) {
want := []ListItem{
{
ID: "2c0fc9fa937b11eaa1b71c4d701ab86e",
IP: "192.0.2.1",
IP: StringPtr("192.0.2.1"),
Comment: "Private IP address",
CreatedOn: &createdOn,
ModifiedOn: &modifiedOn,
},
{
ID: "2c0fc9fa937b11eaa1b71c4d701ab86e",
IP: "192.0.2.2",
IP: StringPtr("192.0.2.2"),
Comment: "Another Private IP address",
CreatedOn: &createdOn,
ModifiedOn: &modifiedOn,
Expand All @@ -323,6 +323,111 @@ func TestListsItemsIP(t *testing.T) {
}
}

func TestListsItemsRedirect(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")

if len(r.URL.Query().Get("cursor")) > 0 && r.URL.Query().Get("cursor") == "yyy" {
fmt.Fprint(w, `{
"result": [
{
"id": "1c0fc9fa937b11eaa1b71c4d701ab86e",
"redirect": {
"source_url": "www.3fonteinen.be",
"target_url": "https://shop.3fonteinen.be"
},
"comment": "3F redirect",
"created_on": "2020-01-01T08:00:00Z",
"modified_on": "2020-01-10T14:00:00Z"
}
],
"result_info": {
"cursors": {
"before": "xxx"
}
},
"success": true,
"errors": [],
"messages": []
}`)
} else {
fmt.Fprint(w, `{
"result": [
{
"id": "0c0fc9fa937b11eaa1b71c4d701ab86e",
"redirect": {
"source_url": "http://cloudflare.com",
"include_subdomains": true,
"target_url": "https://cloudflare.com",
"status_code": 302,
"preserve_query_string": true,
"subpath_matching": true,
"preserve_path_suffix": false
},
"comment": "Cloudflare http redirect",
"created_on": "2020-01-01T08:00:00Z",
"modified_on": "2020-01-10T14:00:00Z"
}
],
"result_info": {
"cursors": {
"before": "xxx",
"after": "yyy"
}
},
"success": true,
"errors": [],
"messages": []
}`)
}
}

mux.HandleFunc("/accounts/"+testAccountID+"/rules/lists/0c0fc9fa937b11eaa1b71c4d701ab86e/items", handler)

createdOn, _ := time.Parse(time.RFC3339, "2020-01-01T08:00:00Z")
modifiedOn, _ := time.Parse(time.RFC3339, "2020-01-10T14:00:00Z")

want := []ListItem{
{
ID: "0c0fc9fa937b11eaa1b71c4d701ab86e",
Redirect: &Redirect{
SourceUrl: "http://cloudflare.com",
IncludeSubdomains: BoolPtr(true),
TargetUrl: "https://cloudflare.com",
StatusCode: IntPtr(302),
PreserveQueryString: BoolPtr(true),
SubpathMatching: BoolPtr(true),
PreservePathSuffix: BoolPtr(false),
},
Comment: "Cloudflare http redirect",
CreatedOn: &createdOn,
ModifiedOn: &modifiedOn,
},
{
ID: "1c0fc9fa937b11eaa1b71c4d701ab86e",
Redirect: &Redirect{
SourceUrl: "www.3fonteinen.be",
TargetUrl: "https://shop.3fonteinen.be",
},
Comment: "3F redirect",
CreatedOn: &createdOn,
ModifiedOn: &modifiedOn,
},
}

actual, err := client.ListListItems(
context.Background(),
ListListItemsParams{AccountID: testAccountID, ID: "0c0fc9fa937b11eaa1b71c4d701ab86e"},
)
if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}

func TestCreateListItemsIP(t *testing.T) {
setup()
defer teardown()
Expand Down Expand Up @@ -352,17 +457,63 @@ func TestCreateListItemsIP(t *testing.T) {
AccountID: testAccountID,
ID: "2c0fc9fa937b11eaa1b71c4d701ab86e",
Items: []ListItemCreateRequest{{
IP: "192.0.2.1",
IP: StringPtr("192.0.2.1"),
Comment: "Private IP",
}, {
IP: "192.0.2.2",
IP: StringPtr("192.0.2.2"),
Comment: "Another Private IP",
}}})
if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}

func TestCreateListItemsRedirect(t *testing.T) {
setup()
defer teardown()

handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
w.Header().Set("content-type", "application/json")
fmt.Fprint(w, `{
"result": {
"operation_id": "4da8780eeb215e6cb7f48dd981c4ea02"
},
"success": true,
"errors": [],
"messages": []
}`)
}

mux.HandleFunc("/accounts/"+testAccountID+"/rules/lists/0c0fc9fa937b11eaa1b71c4d701ab86e/items", handler)

want := ListItemCreateResponse{}
want.Success = true
want.Errors = []ResponseInfo{}
want.Messages = []ResponseInfo{}
want.Result.OperationID = "4da8780eeb215e6cb7f48dd981c4ea02"

actual, err := client.CreateListItemsAsync(context.Background(), ListCreateItemsParams{
AccountID: testAccountID,
ID: "0c0fc9fa937b11eaa1b71c4d701ab86e",
Items: []ListItemCreateRequest{{
Redirect: &Redirect{
SourceUrl: "www.3fonteinen.be",
TargetUrl: "https://shop.3fonteinen.be",
},
Comment: "redirect 3F",
}, {
Redirect: &Redirect{
SourceUrl: "www.cf.com",
TargetUrl: "https://cloudflare.com",
},
Comment: "Redirect cf",
}}})
if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}

func TestReplaceListItemsIP(t *testing.T) {
setup()
defer teardown()
Expand Down Expand Up @@ -392,17 +543,63 @@ func TestReplaceListItemsIP(t *testing.T) {
AccountID: testAccountID,
ID: "2c0fc9fa937b11eaa1b71c4d701ab86e",
Items: []ListItemCreateRequest{{
IP: "192.0.2.1",
IP: StringPtr("192.0.2.1"),
Comment: "Private IP",
}, {
IP: "192.0.2.2",
IP: StringPtr("192.0.2.2"),
Comment: "Another Private IP",
}}})
if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}

func TestReplaceListItemsRedirect(t *testing.T) {
setup()
defer teardown()

handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
w.Header().Set("content-type", "application/json")
fmt.Fprint(w, `{
"result": {
"operation_id": "4da8780eeb215e6cb7f48dd981c4ea02"
},
"success": true,
"errors": [],
"messages": []
}`)
}

mux.HandleFunc("/accounts/"+testAccountID+"/rules/lists/2c0fc9fa937b11eaa1b71c4d701ab86e/items", handler)

want := ListItemCreateResponse{}
want.Success = true
want.Errors = []ResponseInfo{}
want.Messages = []ResponseInfo{}
want.Result.OperationID = "4da8780eeb215e6cb7f48dd981c4ea02"

actual, err := client.ReplaceListItemsAsync(context.Background(), ListReplaceItemsParams{
AccountID: testAccountID,
ID: "2c0fc9fa937b11eaa1b71c4d701ab86e",
Items: []ListItemCreateRequest{{
Redirect: &Redirect{
SourceUrl: "www.3fonteinen.be",
TargetUrl: "https://shop.3fonteinen.be",
},
Comment: "redirect 3F",
}, {
Redirect: &Redirect{
SourceUrl: "www.cf.com",
TargetUrl: "https://cloudflare.com",
},
Comment: "Redirect cf",
}}})
if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}

func TestDeleteListItems(t *testing.T) {
setup()
defer teardown()
Expand Down Expand Up @@ -468,7 +665,7 @@ func TestGetListItemIP(t *testing.T) {

want := ListItem{
ID: "2c0fc9fa937b11eaa1b71c4d701ab86e",
IP: "192.0.2.1",
IP: StringPtr("192.0.2.1"),
Comment: "Private IP address",
CreatedOn: &createdOn,
ModifiedOn: &modifiedOn,
Expand Down