Skip to content

Commit

Permalink
Merge pull request #926 from orium/redirect-lists
Browse files Browse the repository at this point in the history
Added support for redirect lists.
  • Loading branch information
jacobbednarz committed Jun 13, 2022
2 parents 270cf73 + eb7df79 commit 5c7e96e
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 10 deletions.
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

0 comments on commit 5c7e96e

Please sign in to comment.