Repository: cloudflare/cloudflare-go
Pull request #1114 (2022-10-20 01:01:47)

teams_list: update method signatures and add List iterator
Moves the `team_list` methods to the experimental method signature format and adds in  automatic pagination for `ListItems`.


Patch:
diff --git a/.changelog/1114.txt b/.changelog/1114.txt
new file mode 100644
index 000000000..afef66673
--- /dev/null
+++ b/.changelog/1114.txt
@@ -0,0 +1,7 @@
+```release-note:breaking-change
+teams_list: updated methods to match the experimental client format
+```
+
+```release-note:enhancement
+teams_list: `List` operations now automatically paginate
+```
diff --git a/teams_list.go b/teams_list.go
index ec1f18bc4..b4699a051 100644
--- a/teams_list.go
+++ b/teams_list.go
@@ -60,18 +60,47 @@ type TeamsListDetailResponse struct {
 	Result TeamsList `json:"result"`
 }
 
-type TeamsListItemsParams struct {
-	AccountID string `url:"-"`
-	ListID    string `url:"-"`
+type ListTeamsListItemsParams struct {
+	ListID string `url:"-"`
 
-	PaginationOptions
+	ResultInfo
 }
 
-// TeamsLists returns all lists within an account.
+type ListTeamListsParams struct{}
+
+type CreateTeamsListParams struct {
+	ID          string          `json:"id,omitempty"`
+	Name        string          `json:"name"`
+	Type        string          `json:"type"`
+	Description string          `json:"description,omitempty"`
+	Items       []TeamsListItem `json:"items,omitempty"`
+	Count       uint64          `json:"count,omitempty"`
+	CreatedAt   *time.Time      `json:"created_at,omitempty"`
+	UpdatedAt   *time.Time      `json:"updated_at,omitempty"`
+}
+
+type UpdateTeamsListParams struct {
+	ID          string          `json:"id,omitempty"`
+	Name        string          `json:"name"`
+	Type        string          `json:"type"`
+	Description string          `json:"description,omitempty"`
+	Items       []TeamsListItem `json:"items,omitempty"`
+	Count       uint64          `json:"count,omitempty"`
+	CreatedAt   *time.Time      `json:"created_at,omitempty"`
+	UpdatedAt   *time.Time      `json:"updated_at,omitempty"`
+}
+
+type PatchTeamsListParams struct {
+	ID     string          `json:"id"`
+	Append []TeamsListItem `json:"append"`
+	Remove []string        `json:"remove"`
+}
+
+// ListTeamsLists returns all lists within an account.
 //
 // API reference: https://api.cloudflare.com/#teams-lists-list-teams-lists
-func (api *API) TeamsLists(ctx context.Context, accountID string) ([]TeamsList, ResultInfo, error) {
-	uri := fmt.Sprintf("/%s/%s/gateway/lists", AccountRouteRoot, accountID)
+func (api *API) ListTeamsLists(ctx context.Context, rc *ResourceContainer, params ListTeamListsParams) ([]TeamsList, ResultInfo, error) {
+	uri := fmt.Sprintf("/%s/%s/gateway/lists", AccountRouteRoot, rc.Identifier)
 
 	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
 	if err != nil {
@@ -87,14 +116,14 @@ func (api *API) TeamsLists(ctx context.Context, accountID string) ([]TeamsList,
 	return teamsListListResponse.Result, teamsListListResponse.ResultInfo, nil
 }
 
-// TeamsList returns a single list based on the list ID.
+// GetTeamsList returns a single list based on the list ID.
 //
 // API reference: https://api.cloudflare.com/#teams-lists-teams-list-details
-func (api *API) TeamsList(ctx context.Context, accountID, listID string) (TeamsList, error) {
+func (api *API) GetTeamsList(ctx context.Context, rc *ResourceContainer, listID string) (TeamsList, error) {
 	uri := fmt.Sprintf(
 		"/%s/%s/gateway/lists/%s",
-		AccountRouteRoot,
-		accountID,
+		rc.Level,
+		rc.Identifier,
 		listID,
 	)
 
@@ -112,11 +141,15 @@ func (api *API) TeamsList(ctx context.Context, accountID, listID string) (TeamsL
 	return teamsListDetailResponse.Result, nil
 }
 
-// TeamsListItems returns all list items for a list.
+// ListTeamsListItems returns all list items for a list.
 //
 // API reference: https://api.cloudflare.com/#teams-lists-teams-list-items
-func (api *API) TeamsListItems(ctx context.Context, params TeamsListItemsParams) ([]TeamsListItem, ResultInfo, error) {
-	if params.AccountID == "" {
+func (api *API) ListTeamsListItems(ctx context.Context, rc *ResourceContainer, params ListTeamsListItemsParams) ([]TeamsListItem, ResultInfo, error) {
+	if rc.Level != AccountRouteLevel {
+		return []TeamsListItem{}, ResultInfo{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
+	}
+
+	if rc.Identifier == "" {
 		return []TeamsListItem{}, ResultInfo{}, ErrMissingAccountID
 	}
 
@@ -124,32 +157,63 @@ func (api *API) TeamsListItems(ctx context.Context, params TeamsListItemsParams)
 		return []TeamsListItem{}, ResultInfo{}, ErrMissingListID
 	}
 
-	uri := buildURI(
-		fmt.Sprintf("/%s/%s/gateway/lists/%s/items", AccountRouteRoot, params.AccountID, params.ListID),
-		params,
-	)
+	autoPaginate := true
+	if params.PerPage >= 1 || params.Page >= 1 {
+		autoPaginate = false
+	}
 
-	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return []TeamsListItem{}, ResultInfo{}, err
+	if params.PerPage < 1 {
+		params.PerPage = 50
 	}
 
-	var teamsListItemsListResponse TeamsListItemsListResponse
-	err = json.Unmarshal(res, &teamsListItemsListResponse)
-	if err != nil {
-		return []TeamsListItem{}, ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+	if params.Page < 1 {
+		params.Page = 1
 	}
 
-	return teamsListItemsListResponse.Result, teamsListItemsListResponse.ResultInfo, nil
+	var teamListItems []TeamsListItem
+	var lResponse TeamsListItemsListResponse
+	for {
+		uri := buildURI(
+			fmt.Sprintf("/%s/%s/gateway/lists/%s/items", rc.Level, rc.Identifier, params.ListID),
+			params,
+		)
+
+		res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
+		if err != nil {
+			return []TeamsListItem{}, ResultInfo{}, err
+		}
+
+		err = json.Unmarshal(res, &lResponse)
+		if err != nil {
+			return []TeamsListItem{}, ResultInfo{}, fmt.Errorf("failed to unmarshal teams list JSON data: %w", err)
+		}
+
+		teamListItems = append(teamListItems, lResponse.Result...)
+		params.ResultInfo = lResponse.ResultInfo.Next()
+
+		if params.ResultInfo.Done() || !autoPaginate {
+			break
+		}
+	}
+
+	return teamListItems, lResponse.ResultInfo, nil
 }
 
 // CreateTeamsList creates a new teams list.
 //
 // API reference: https://api.cloudflare.com/#teams-lists-create-teams-list
-func (api *API) CreateTeamsList(ctx context.Context, accountID string, teamsList TeamsList) (TeamsList, error) {
-	uri := fmt.Sprintf("/%s/%s/gateway/lists", AccountRouteRoot, accountID)
+func (api *API) CreateTeamsList(ctx context.Context, rc *ResourceContainer, params CreateTeamsListParams) (TeamsList, error) {
+	if rc.Level != AccountRouteLevel {
+		return TeamsList{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
+	}
+
+	if rc.Identifier == "" {
+		return TeamsList{}, ErrMissingAccountID
+	}
+
+	uri := fmt.Sprintf("/%s/%s/gateway/lists", rc.Level, rc.Identifier)
 
-	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, teamsList)
+	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
 	if err != nil {
 		return TeamsList{}, err
 	}
@@ -166,19 +230,27 @@ func (api *API) CreateTeamsList(ctx context.Context, accountID string, teamsList
 // UpdateTeamsList updates an existing teams list.
 //
 // API reference: https://api.cloudflare.com/#teams-lists-update-teams-list
-func (api *API) UpdateTeamsList(ctx context.Context, accountID string, teamsList TeamsList) (TeamsList, error) {
-	if teamsList.ID == "" {
+func (api *API) UpdateTeamsList(ctx context.Context, rc *ResourceContainer, params UpdateTeamsListParams) (TeamsList, error) {
+	if rc.Level != AccountRouteLevel {
+		return TeamsList{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
+	}
+
+	if rc.Identifier == "" {
+		return TeamsList{}, ErrMissingAccountID
+	}
+
+	if params.ID == "" {
 		return TeamsList{}, fmt.Errorf("teams list ID cannot be empty")
 	}
 
 	uri := fmt.Sprintf(
 		"/%s/%s/gateway/lists/%s",
-		AccountRouteRoot,
-		accountID,
-		teamsList.ID,
+		rc.Level,
+		rc.Identifier,
+		params.ID,
 	)
 
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, teamsList)
+	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
 	if err != nil {
 		return TeamsList{}, err
 	}
@@ -195,7 +267,15 @@ func (api *API) UpdateTeamsList(ctx context.Context, accountID string, teamsList
 // PatchTeamsList updates the items in an existing teams list.
 //
 // API reference: https://api.cloudflare.com/#teams-lists-patch-teams-list
-func (api *API) PatchTeamsList(ctx context.Context, accountID string, listPatch PatchTeamsList) (TeamsList, error) {
+func (api *API) PatchTeamsList(ctx context.Context, rc *ResourceContainer, listPatch PatchTeamsListParams) (TeamsList, error) {
+	if rc.Level != AccountRouteLevel {
+		return TeamsList{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
+	}
+
+	if rc.Identifier == "" {
+		return TeamsList{}, ErrMissingAccountID
+	}
+
 	if listPatch.ID == "" {
 		return TeamsList{}, fmt.Errorf("teams list ID cannot be empty")
 	}
@@ -203,7 +283,7 @@ func (api *API) PatchTeamsList(ctx context.Context, accountID string, listPatch
 	uri := fmt.Sprintf(
 		"/%s/%s/gateway/lists/%s",
 		AccountRouteRoot,
-		accountID,
+		rc.Identifier,
 		listPatch.ID,
 	)
 
@@ -224,11 +304,19 @@ func (api *API) PatchTeamsList(ctx context.Context, accountID string, listPatch
 // DeleteTeamsList deletes a teams list.
 //
 // API reference: https://api.cloudflare.com/#teams-lists-delete-teams-list
-func (api *API) DeleteTeamsList(ctx context.Context, accountID, teamsListID string) error {
+func (api *API) DeleteTeamsList(ctx context.Context, rc *ResourceContainer, teamsListID string) error {
+	if rc.Level != AccountRouteLevel {
+		return fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
+	}
+
+	if rc.Identifier == "" {
+		return ErrMissingAccountID
+	}
+
 	uri := fmt.Sprintf(
 		"/%s/%s/gateway/lists/%s",
 		AccountRouteRoot,
-		accountID,
+		rc.Identifier,
 		teamsListID,
 	)
 


Test patch:
diff --git a/dlp_profile_test.go b/dlp_profile_test.go
index 692db6f25..d7c88f571 100644
--- a/dlp_profile_test.go
+++ b/dlp_profile_test.go
@@ -291,7 +291,7 @@ func TestCreateDLPCustomProfiles(t *testing.T) {
 			},
 		},
 	}
-	actual, err := client.CreateDLPProfiles(context.Background(), AccountIdentifier(testAccountID), CreateDLPProfilesParams{Profiles: profiles})
+	actual, err := client.CreateDLPProfiles(context.Background(), AccountIdentifier(testAccountID), CreateDLPProfilesParams{Profiles: profiles, Type: "custom"})
 	require.NoError(t, err)
 	require.Equal(t, want, actual)
 }
@@ -386,6 +386,7 @@ func TestCreateDLPCustomProfile(t *testing.T) {
 
 	actual, err := client.CreateDLPProfiles(context.Background(), AccountIdentifier(testAccountID), CreateDLPProfilesParams{
 		Profiles: profiles,
+		Type:     "custom",
 	})
 	require.NoError(t, err)
 	require.Equal(t, want, actual)
diff --git a/teams_list_test.go b/teams_list_test.go
index 0129fd7d1..f9d991a00 100644
--- a/teams_list_test.go
+++ b/teams_list_test.go
@@ -36,7 +36,8 @@ func TestTeamsLists(t *testing.T) {
 				"page": 1,
 				"per_page": 20,
 				"count": 1,
-				"total_count": 2000
+				"total_count": 2000,
+				"total_pages": 1
 			}
 		}
 		`)
@@ -57,7 +58,7 @@ func TestTeamsLists(t *testing.T) {
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/lists", handler)
 
-	actual, _, err := client.TeamsLists(context.Background(), testAccountID)
+	actual, _, err := client.ListTeamsLists(context.Background(), AccountIdentifier(testAccountID), ListTeamListsParams{})
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
@@ -83,6 +84,13 @@ func TestTeamsList(t *testing.T) {
 				"count": 1,
 				"created_at": "2014-01-01T05:20:00.12345Z",
 				"updated_at": "2014-01-01T05:20:00.12345Z"
+			},
+			"result_info": {
+				"page": 1,
+				"per_page": 20,
+				"count": 1,
+				"total_count": 2000,
+				"total_pages": 1
 			}
 		}
 		`)
@@ -103,7 +111,7 @@ func TestTeamsList(t *testing.T) {
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/lists/480f4f69-1a28-4fdd-9240-1ed29f0ac1db", handler)
 
-	actual, err := client.TeamsList(context.Background(), testAccountID, "480f4f69-1a28-4fdd-9240-1ed29f0ac1db")
+	actual, err := client.GetTeamsList(context.Background(), AccountIdentifier(testAccountID), "480f4f69-1a28-4fdd-9240-1ed29f0ac1db")
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
@@ -130,7 +138,14 @@ func TestTeamsListItems(t *testing.T) {
 					"value": "val2",
 					"created_at": "2014-01-01T05:20:00.12345Z"
 				}
-			]
+			],
+			"result_info": {
+				"page": 1,
+				"per_page": 20,
+				"count": 1,
+				"total_count": 2000,
+				"total_pages": 1
+			}
 		}
 		`)
 	}
@@ -150,7 +165,7 @@ func TestTeamsListItems(t *testing.T) {
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/lists/480f4f69-1a28-4fdd-9240-1ed29f0ac1db/items", handler)
 
-	actual, _, err := client.TeamsListItems(context.Background(), TeamsListItemsParams{AccountID: testAccountID, ListID: "480f4f69-1a28-4fdd-9240-1ed29f0ac1db"})
+	actual, _, err := client.ListTeamsListItems(context.Background(), AccountIdentifier(testAccountID), ListTeamsListItemsParams{ListID: "480f4f69-1a28-4fdd-9240-1ed29f0ac1db"})
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
 	}
@@ -194,7 +209,7 @@ func TestCreateTeamsList(t *testing.T) {
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/lists", handler)
 
-	actual, err := client.CreateTeamsList(context.Background(), testAccountID, TeamsList{
+	actual, err := client.CreateTeamsList(context.Background(), AccountIdentifier(testAccountID), CreateTeamsListParams{
 		Name:        "My Serial List",
 		Description: "My Description",
 		Type:        "SERIAL",
@@ -244,7 +259,15 @@ func TestUpdateTeamsList(t *testing.T) {
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/lists/480f4f69-1a28-4fdd-9240-1ed29f0ac1db", handler)
 
-	actual, err := client.UpdateTeamsList(context.Background(), testAccountID, teamsList)
+	actual, err := client.UpdateTeamsList(context.Background(), AccountIdentifier(testAccountID), UpdateTeamsListParams{
+		ID:          "480f4f69-1a28-4fdd-9240-1ed29f0ac1db",
+		Name:        "My Serial List",
+		Description: "My Updated Description",
+		Type:        "SERIAL",
+		Count:       1,
+		CreatedAt:   &createdAt,
+		UpdatedAt:   &updatedAt,
+	})
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, teamsList, actual)
@@ -255,7 +278,7 @@ func TestUpdateTeamsListWithMissingID(t *testing.T) {
 	setup()
 	defer teardown()
 
-	_, err := client.UpdateTeamsList(context.Background(), testZoneID, TeamsList{})
+	_, err := client.UpdateTeamsList(context.Background(), AccountIdentifier(testAccountID), UpdateTeamsListParams{})
 	assert.EqualError(t, err, "teams list ID cannot be empty")
 }
 
@@ -297,7 +320,7 @@ func TestPatchTeamsList(t *testing.T) {
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/lists/480f4f69-1a28-4fdd-9240-1ed29f0ac1db", handler)
 
-	actual, err := client.PatchTeamsList(context.Background(), testAccountID, PatchTeamsList{
+	actual, err := client.PatchTeamsList(context.Background(), AccountIdentifier(testAccountID), PatchTeamsListParams{
 		ID:     "480f4f69-1a28-4fdd-9240-1ed29f0ac1db",
 		Append: []TeamsListItem{{Value: "abcd-1234"}},
 		Remove: []string{"def-5678"},
@@ -327,7 +350,7 @@ func TestDeleteTeamsList(t *testing.T) {
 	}
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/lists/480f4f69-1a28-4fdd-9240-1ed29f0ac1db", handler)
-	err := client.DeleteTeamsList(context.Background(), testAccountID, "480f4f69-1a28-4fdd-9240-1ed29f0ac1db")
+	err := client.DeleteTeamsList(context.Background(), AccountIdentifier(testAccountID), "480f4f69-1a28-4fdd-9240-1ed29f0ac1db")
 
 	assert.NoError(t, err)
 }