From 83c77693e654a05fbeb7338cdff8da474fe38fc9 Mon Sep 17 00:00:00 2001 From: auyer Date: Wed, 17 Jan 2024 11:56:10 -0300 Subject: [PATCH 1/6] fixes parameters for UpdateAccessUserSeat --- access_seats.go | 5 +++-- access_seats_test.go | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/access_seats.go b/access_seats.go index c1d6bf21304..2204fe4dcdf 100644 --- a/access_seats.go +++ b/access_seats.go @@ -35,7 +35,7 @@ type UpdateAccessUserSeatResponse struct { ResultInfo `json:"result_info"` } -// UpdateAccessUserSeat updates a Access User Seat. +// UpdateAccessUserSeat updates a single Access User Seat. // // API documentation: https://developers.cloudflare.com/api/operations/zero-trust-seats-update-a-user-seat func (api *API) UpdateAccessUserSeat(ctx context.Context, rc *ResourceContainer, params UpdateAccessUserSeatParams) ([]AccessUpdateAccessUserSeatResult, error) { @@ -53,7 +53,8 @@ func (api *API) UpdateAccessUserSeat(ctx context.Context, rc *ResourceContainer, rc.Identifier, ) - res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, params) + // this requests expects an array of params, but this method only accepts a single param + res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, []UpdateAccessUserSeatParams{params}) if err != nil { return []AccessUpdateAccessUserSeatResult{}, fmt.Errorf("%s: %w", errMakeRequestError, err) } diff --git a/access_seats_test.go b/access_seats_test.go index 9b52235f6dc..9a08f81c370 100644 --- a/access_seats_test.go +++ b/access_seats_test.go @@ -2,6 +2,7 @@ package cloudflare import ( "context" + "encoding/json" "fmt" "net/http" "testing" @@ -34,6 +35,14 @@ func TestUpdateAccessUserSeat(t *testing.T) { handler := func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method) + + req := []UpdateAccessUserSeatParams{} + + // Try to decode the request body into the struct. + err := json.NewDecoder(r.Body).Decode(&req) + assert.NoError(t, err, "Failed to decode request body into UpdateAccessUserSeatParams") + assert.Equal(t, len(req), 1, "Expected 1 seat to be updated, got %d", len(req)) + w.Header().Set("content-type", "application/json") fmt.Fprintf(w, `{ "errors": [], From 6d516a000d2eb8e3e5d41fb00ec6e1d3be971715 Mon Sep 17 00:00:00 2001 From: auyer Date: Wed, 17 Jan 2024 11:56:57 -0300 Subject: [PATCH 2/6] Adds TestUpdateAccessUsersSeats for multiple Seats Update --- access_seats.go | 35 +++++++++++++++++ access_seats_test.go | 91 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/access_seats.go b/access_seats.go index 2204fe4dcdf..7c7d0f06f87 100644 --- a/access_seats.go +++ b/access_seats.go @@ -67,3 +67,38 @@ func (api *API) UpdateAccessUserSeat(ctx context.Context, rc *ResourceContainer, return updateAccessUserSeatResponse.Result, nil } + +// UpdateAccessUsersSeats updates many Access User Seats. +// +// API documentation: https://developers.cloudflare.com/api/operations/zero-trust-seats-update-a-user-seat +func (api *API) UpdateAccessUsersSeats(ctx context.Context, rc *ResourceContainer, params []UpdateAccessUserSeatParams) ([]AccessUpdateAccessUserSeatResult, error) { + if rc.Level != AccountRouteLevel { + return []AccessUpdateAccessUserSeatResult{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level) + } + + for _, param := range params { + if param.SeatUID == "" { + return []AccessUpdateAccessUserSeatResult{}, errMissingAccessSeatUID + } + } + + uri := fmt.Sprintf( + "/%s/%s/access/seats", + rc.Level, + rc.Identifier, + ) + + // this requests expects an array of params, but this method only accepts a single param + res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, params) + if err != nil { + return []AccessUpdateAccessUserSeatResult{}, fmt.Errorf("%s: %w", errMakeRequestError, err) + } + + var updateAccessUserSeatResponse UpdateAccessUserSeatResponse + err = json.Unmarshal(res, &updateAccessUserSeatResponse) + if err != nil { + return []AccessUpdateAccessUserSeatResult{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return updateAccessUserSeatResponse.Result, nil +} diff --git a/access_seats_test.go b/access_seats_test.go index 9a08f81c370..d54dbd4ec1b 100644 --- a/access_seats_test.go +++ b/access_seats_test.go @@ -12,6 +12,7 @@ import ( ) var testAccessGroupSeatUID = "access-group-seat-uid" +var testAccessGroupSeatUID2 = "access-group-seat-uid2" func TestUpdateAccessUserSeat_ZoneIsNotSupported(t *testing.T) { setup() @@ -29,6 +30,14 @@ func TestUpdateAccessUserSeat_MissingUID(t *testing.T) { assert.EqualError(t, err, "missing required access seat UID") } +func TestUpdateAccessUsersSeats_MissingUID(t *testing.T) { + setup() + defer teardown() + + _, err := client.UpdateAccessUsersSeats(context.Background(), testAccountRC, []UpdateAccessUserSeatParams{{GatewaySeat: BoolPtr(false), SeatUID: "seat_id"}, {SeatUID: "", AccessSeat: BoolPtr(true)}}) + assert.EqualError(t, err, "missing required access seat UID") +} + func TestUpdateAccessUserSeat(t *testing.T) { setup() defer teardown() @@ -89,3 +98,85 @@ func TestUpdateAccessUserSeat(t *testing.T) { assert.Equal(t, want, actual) } } + +func TestUpdateAccessUsersSeats(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) + + req := []UpdateAccessUserSeatParams{} + + // Try to decode the request body into the struct. + err := json.NewDecoder(r.Body).Decode(&req) + assert.NoError(t, err, "Failed to decode request body into UpdateAccessUserSeatParams") + assert.Equal(t, len(req), 2, "Expected 2 seat to be updated, got %d", len(req)) + + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "errors": [], + "messages": [], + "result": [ + { + "access_seat": false, + "created_at": "2014-01-01T05:20:00.12345Z", + "gateway_seat": false, + "seat_uid": "%s", + "updated_at": "2014-01-01T05:20:00.12345Z" + }, + { + "access_seat": false, + "created_at": "2014-01-01T05:20:00.12345Z", + "gateway_seat": false, + "seat_uid": "%s", + "updated_at": "2014-01-01T05:20:00.12345Z" + } + ], + "success": true, + "result_info": { + "count": 1, + "page": 1, + "per_page": 20, + "total_count": 2000 + } + } + `, testAccessGroupSeatUID, testAccessGroupSeatUID2) + } + + mux.HandleFunc("/accounts/"+testAccountID+"/access/seats", handler) + createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + want := []AccessUpdateAccessUserSeatResult{ + { + AccessSeat: BoolPtr(false), + CreatedAt: &createdAt, + GatewaySeat: BoolPtr(false), + SeatUID: testAccessGroupSeatUID, + UpdatedAt: &updatedAt, + }, + { + AccessSeat: BoolPtr(false), + CreatedAt: &createdAt, + GatewaySeat: BoolPtr(false), + SeatUID: testAccessGroupSeatUID2, + UpdatedAt: &updatedAt, + }, + } + + actual, err := client.UpdateAccessUsersSeats(context.Background(), testAccountRC, []UpdateAccessUserSeatParams{ + { + SeatUID: testAccessGroupSeatUID, + AccessSeat: BoolPtr(false), + GatewaySeat: BoolPtr(false), + }, + { + SeatUID: testAccessGroupSeatUID2, + AccessSeat: BoolPtr(false), + GatewaySeat: BoolPtr(false), + }, + }) + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} From 45ff0105aca48c7804f23048745adcb48e2b35cc Mon Sep 17 00:00:00 2001 From: auyer Date: Wed, 17 Jan 2024 13:38:15 -0300 Subject: [PATCH 3/6] add release note: bug 1478 --- .changelog/1478.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/1478.txt diff --git a/.changelog/1478.txt b/.changelog/1478.txt new file mode 100644 index 00000000000..339a76d7548 --- /dev/null +++ b/.changelog/1478.txt @@ -0,0 +1,3 @@ +```release-note:bug +UpdateAccessUserSeat: fix parameters not being an array. This caused an error when updating a user's seat +``` From 265d39c451ada9e5a45cddff6e24f86e8e6c6915 Mon Sep 17 00:00:00 2001 From: auyer Date: Wed, 17 Jan 2024 13:47:19 -0300 Subject: [PATCH 4/6] fixes file name, adds enhancement changelog --- .changelog/1478.txt | 3 --- .changelog/1479.txt | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) delete mode 100644 .changelog/1478.txt create mode 100644 .changelog/1479.txt diff --git a/.changelog/1478.txt b/.changelog/1478.txt deleted file mode 100644 index 339a76d7548..00000000000 --- a/.changelog/1478.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -UpdateAccessUserSeat: fix parameters not being an array. This caused an error when updating a user's seat -``` diff --git a/.changelog/1479.txt b/.changelog/1479.txt new file mode 100644 index 00000000000..0fdf1bfecb4 --- /dev/null +++ b/.changelog/1479.txt @@ -0,0 +1,7 @@ +```release-note:bug +access_seats: UpdateAccessUserSeat: fix parameters not being an array when sending to the api. This caused an error when updating a user's seat +``` + +```release-note:enhancement +access_seats: Add `UpdateAccessUsersSeats` with an array as input for multiple operations +``` From c6e0851f55dbc023c4d48cc11b9864d32b6b9649 Mon Sep 17 00:00:00 2001 From: auyer Date: Wed, 17 Jan 2024 14:40:25 -0300 Subject: [PATCH 5/6] rename file to match pr number --- .changelog/{1479.txt => 1480.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{1479.txt => 1480.txt} (100%) diff --git a/.changelog/1479.txt b/.changelog/1480.txt similarity index 100% rename from .changelog/1479.txt rename to .changelog/1480.txt From 6c9c526e2cd0ada09132feb91d4fadbe545b6d82 Mon Sep 17 00:00:00 2001 From: auyer Date: Tue, 30 Jan 2024 13:57:30 -0300 Subject: [PATCH 6/6] Adds separate struct for UpdateAccessUsersSeats This was done to abide by convention --- access_seats.go | 9 ++++++++- access_seats_test.go | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/access_seats.go b/access_seats.go index 7c7d0f06f87..ea44eebc7b1 100644 --- a/access_seats.go +++ b/access_seats.go @@ -28,6 +28,13 @@ type UpdateAccessUserSeatParams struct { GatewaySeat *bool `json:"gateway_seat"` } +// UpdateAccessUsersSeatsParams represents the update payload for multiple access seats. +type UpdateAccessUsersSeatsParams []struct { + SeatUID string `json:"seat_uid,omitempty"` + AccessSeat *bool `json:"access_seat"` + GatewaySeat *bool `json:"gateway_seat"` +} + // AccessUserSeatResponse represents the response from the access user seat endpoints. type UpdateAccessUserSeatResponse struct { Response @@ -71,7 +78,7 @@ func (api *API) UpdateAccessUserSeat(ctx context.Context, rc *ResourceContainer, // UpdateAccessUsersSeats updates many Access User Seats. // // API documentation: https://developers.cloudflare.com/api/operations/zero-trust-seats-update-a-user-seat -func (api *API) UpdateAccessUsersSeats(ctx context.Context, rc *ResourceContainer, params []UpdateAccessUserSeatParams) ([]AccessUpdateAccessUserSeatResult, error) { +func (api *API) UpdateAccessUsersSeats(ctx context.Context, rc *ResourceContainer, params UpdateAccessUsersSeatsParams) ([]AccessUpdateAccessUserSeatResult, error) { if rc.Level != AccountRouteLevel { return []AccessUpdateAccessUserSeatResult{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level) } diff --git a/access_seats_test.go b/access_seats_test.go index d54dbd4ec1b..90ef47511db 100644 --- a/access_seats_test.go +++ b/access_seats_test.go @@ -34,7 +34,7 @@ func TestUpdateAccessUsersSeats_MissingUID(t *testing.T) { setup() defer teardown() - _, err := client.UpdateAccessUsersSeats(context.Background(), testAccountRC, []UpdateAccessUserSeatParams{{GatewaySeat: BoolPtr(false), SeatUID: "seat_id"}, {SeatUID: "", AccessSeat: BoolPtr(true)}}) + _, err := client.UpdateAccessUsersSeats(context.Background(), testAccountRC, UpdateAccessUsersSeatsParams{{GatewaySeat: BoolPtr(false), SeatUID: "seat_id"}, {SeatUID: "", AccessSeat: BoolPtr(true)}}) assert.EqualError(t, err, "missing required access seat UID") } @@ -164,7 +164,7 @@ func TestUpdateAccessUsersSeats(t *testing.T) { }, } - actual, err := client.UpdateAccessUsersSeats(context.Background(), testAccountRC, []UpdateAccessUserSeatParams{ + actual, err := client.UpdateAccessUsersSeats(context.Background(), testAccountRC, UpdateAccessUsersSeatsParams{ { SeatUID: testAccessGroupSeatUID, AccessSeat: BoolPtr(false),