Skip to content

Commit 0ddadac

Browse files
authored
Merge pull request #106 from onelogin/fix/role-empty-arrays
fix: ensure empty arrays are properly serialized in Role updates
2 parents 113e66a + 32310ae commit 0ddadac

File tree

4 files changed

+109
-3
lines changed

4 files changed

+109
-3
lines changed

changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [4.5.1]
4+
5+
### Fixed
6+
- Fixed issue with empty arrays in Role updates by ensuring empty arrays are properly serialized in JSON
7+
- Added documentation example for removing all users from a role
8+
39
## [4.5.0]
410

511
### Improved

docs/usage_examples.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ func main() {
7474
fmt.Println(err)
7575
}
7676
fmt.Printf("Updated role: %+v\n", updatedRole)
77+
78+
// Remove all users from a role by passing an empty array
79+
roleWithNoUsers, err := client.UpdateRole(roleID, &models.Role{
80+
Users: []int32{}, // Empty array will remove all users
81+
})
82+
if err != nil {
83+
fmt.Println(err)
84+
}
85+
fmt.Printf("Updated role with no users: %+v\n", roleWithNoUsers)
7786
}
7887
```
7988

pkg/onelogin/models/role.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,51 @@
11
package models
22

3+
import "encoding/json"
4+
35
// RoleQuery represents available query parameters
46
type RoleQuery struct {
57
Limit string `json:"limit,omitempty"`
68
Page string `json:"page,omitempty"`
79
Cursor string `json:"cursor,omitempty"`
810
}
911

12+
// initSlice ensures that a nil slice is initialized as an empty slice
13+
// This helper is needed for the Role.MarshalJSON method
14+
func initSlice(s []int32) []int32 {
15+
if s == nil {
16+
return []int32{}
17+
}
18+
return s
19+
}
20+
1021
// Role represents the Role resource in OneLogin
1122
type Role struct {
1223
ID *int32 `json:"id,omitempty"`
1324
Name *string `json:"name,omitempty"`
14-
Admins []int32 `json:"admins,omitempty"`
15-
Apps []int32 `json:"apps,omitempty"`
16-
Users []int32 `json:"users,omitempty"`
25+
Admins []int32 `json:"admins"`
26+
Apps []int32 `json:"apps"`
27+
Users []int32 `json:"users"`
28+
}
29+
30+
// MarshalJSON provides custom JSON marshaling to ensure empty arrays are included in the JSON output
31+
func (r *Role) MarshalJSON() ([]byte, error) {
32+
// Create a map to hold the serialized fields
33+
m := make(map[string]interface{})
34+
35+
// Add ID and Name if they are not nil
36+
if r.ID != nil {
37+
m["id"] = *r.ID
38+
}
39+
if r.Name != nil {
40+
m["name"] = *r.Name
41+
}
42+
43+
// Always include the arrays, even if they're nil (as empty arrays)
44+
m["admins"] = initSlice(r.Admins)
45+
m["apps"] = initSlice(r.Apps)
46+
m["users"] = initSlice(r.Users)
47+
48+
return json.Marshal(m)
1749
}
1850

1951
func (r *Role) GetKeyValidators() map[string]func(interface{}) bool {

tests/api_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package tests
22

33
import (
44
"bytes"
5+
"encoding/json"
56
"io"
67
"net/http"
78
"testing"
89

910
"github.com/onelogin/onelogin-go-sdk/v4/pkg/onelogin/api"
1011
"github.com/onelogin/onelogin-go-sdk/v4/pkg/onelogin/authentication"
12+
"github.com/onelogin/onelogin-go-sdk/v4/pkg/onelogin/models"
1113
)
1214

1315
type MockHttpClient struct {
@@ -142,3 +144,60 @@ func TestClientDeleteWithBody(t *testing.T) {
142144
t.Fatalf("Expected ``, got %s", string(body))
143145
}
144146
}
147+
148+
func TestRoleEmptyArraysSerialization(t *testing.T) {
149+
// Create role with empty arrays
150+
role := &models.Role{
151+
Name: new(string),
152+
Users: []int32{}, // Empty array
153+
Admins: []int32{}, // Empty array
154+
Apps: []int32{}, // Empty array
155+
}
156+
*role.Name = "Test Role"
157+
158+
// Serialize to JSON
159+
jsonData, err := json.Marshal(role)
160+
if err != nil {
161+
t.Fatalf("Failed to marshal role: %v", err)
162+
}
163+
164+
// Verify that empty arrays are included in JSON
165+
jsonStr := string(jsonData)
166+
t.Logf("Serialized JSON: %s", jsonStr)
167+
168+
// Check for empty arrays in the JSON
169+
if !bytes.Contains(jsonData, []byte(`"users":[]`)) {
170+
t.Error("JSON should contain empty users array")
171+
}
172+
if !bytes.Contains(jsonData, []byte(`"admins":[]`)) {
173+
t.Error("JSON should contain empty admins array")
174+
}
175+
if !bytes.Contains(jsonData, []byte(`"apps":[]`)) {
176+
t.Error("JSON should contain empty apps array")
177+
}
178+
179+
// Also check with nil slices
180+
roleWithNil := &models.Role{
181+
Name: role.Name,
182+
// All arrays are nil by default
183+
}
184+
185+
jsonData, err = json.Marshal(roleWithNil)
186+
if err != nil {
187+
t.Fatalf("Failed to marshal role with nil arrays: %v", err)
188+
}
189+
190+
jsonStr = string(jsonData)
191+
t.Logf("Serialized JSON with nil arrays: %s", jsonStr)
192+
193+
// Check for empty arrays in the JSON
194+
if !bytes.Contains(jsonData, []byte(`"users":[]`)) {
195+
t.Error("JSON should contain empty users array for nil slice")
196+
}
197+
if !bytes.Contains(jsonData, []byte(`"admins":[]`)) {
198+
t.Error("JSON should contain empty admins array for nil slice")
199+
}
200+
if !bytes.Contains(jsonData, []byte(`"apps":[]`)) {
201+
t.Error("JSON should contain empty apps array for nil slice")
202+
}
203+
}

0 commit comments

Comments
 (0)