Skip to content

Commit cdd6571

Browse files
authored
Merge pull request #104 from onelogin/feature/user-mappings
feat: add User Mappings API support
2 parents 21586bc + 68bfe41 commit cdd6571

File tree

17 files changed

+971
-179
lines changed

17 files changed

+971
-179
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
./vendor
22
coverage.out
33
bin
4+
5+
**/.claude/settings.local.json

changelog.md

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

3+
## [4.4.0]
4+
5+
### Added
6+
- Complete implementation of User Mappings API endpoints:
7+
- Added strongly typed methods for all User Mappings operations
8+
- Added proper model structures for User Mappings
9+
- Added query parameters support for filtering User Mappings
10+
- Added examples for User Mappings API usage
11+
- Improved handling of API responses that return minimal data (ID only)
12+
- Added comprehensive test suite for User Mappings functionality
13+
14+
### Fixed
15+
- Fixed HTTP response handling for endpoints that return only an ID
16+
- Improved error reporting for API responses
17+
318
## [4.3.0]
419

520
### Added

cmd/simple_test/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ func main() {
4040

4141
fmt.Println("Success! Connected to OneLogin API.")
4242
fmt.Printf("Connectors data type: %T\n", connectors)
43-
43+
4444
// Test the token generation
4545
token, err := sdk.GetToken()
4646
if err != nil {
4747
fmt.Printf("Error getting token: %v\n", err)
4848
os.Exit(1)
4949
}
50-
50+
5151
fmt.Println("Successfully retrieved token!")
5252
fmt.Printf("Token length: %d\n", len(token))
53-
}
53+
}

cmd/user_mappings_test/main.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"os"
7+
8+
"github.com/onelogin/onelogin-go-sdk/v4/pkg/onelogin"
9+
"github.com/onelogin/onelogin-go-sdk/v4/pkg/onelogin/models"
10+
)
11+
12+
func main() {
13+
// Initialize the SDK
14+
sdk, err := onelogin.NewOneloginSDK()
15+
if err != nil {
16+
log.Fatalf("Failed to create OneLogin client: %v", err)
17+
}
18+
19+
// Get authentication token
20+
log.Println("Getting authentication token...")
21+
_, err = sdk.GetToken()
22+
if err != nil {
23+
log.Fatalf("Failed to get token: %v", err)
24+
}
25+
log.Println("Authentication token retrieved successfully.")
26+
27+
fmt.Println("=== User Mappings API Example ===")
28+
29+
// Skip listing and just create a mapping
30+
fmt.Println("\n-- Creating a User Mapping --")
31+
name := "Test Mapping via SDK"
32+
match := "all"
33+
enabled := true
34+
position := int32(1)
35+
36+
// Set up conditions
37+
sourceCondition := "email"
38+
equalsOperator := "="
39+
valueCondition := "test@example.com"
40+
41+
// Set up actions
42+
actionName := "set_status"
43+
actionValue := []string{"1"}
44+
45+
newMapping := models.UserMapping{
46+
Name: &name,
47+
Match: &match,
48+
Enabled: &enabled,
49+
Position: &position,
50+
Conditions: []models.UserMappingConditions{
51+
{
52+
Source: &sourceCondition,
53+
Operator: &equalsOperator,
54+
Value: &valueCondition,
55+
},
56+
},
57+
Actions: []models.UserMappingActions{
58+
{
59+
Action: &actionName,
60+
Value: actionValue,
61+
},
62+
},
63+
}
64+
65+
// Set to true to keep the mapping for demonstration
66+
leaveMapping := true
67+
68+
createdMapping, err := sdk.CreateUserMapping(newMapping)
69+
if err != nil {
70+
log.Printf("Failed to create user mapping: %v", err)
71+
} else {
72+
fmt.Printf("Created new mapping with ID: %d\n", *createdMapping.ID)
73+
74+
// Get the created mapping
75+
fmt.Println("\n-- Getting a User Mapping --")
76+
retrievedMapping, err := sdk.GetUserMapping(*createdMapping.ID)
77+
if err != nil {
78+
log.Printf("Failed to get user mapping: %v", err)
79+
} else {
80+
fmt.Printf("Retrieved mapping: ID: %d, Name: %s\n", *retrievedMapping.ID, *retrievedMapping.Name)
81+
}
82+
83+
// The update might fail due to API constraints, but we want to clean up regardless
84+
fmt.Println("\n-- Updating a User Mapping --")
85+
updatedName := "Updated Test Mapping"
86+
retrievedMapping.Name = &updatedName
87+
88+
var mappingIDToDelete int32
89+
mappingIDToDelete = *retrievedMapping.ID
90+
91+
updatedMapping, err := sdk.UpdateUserMapping(*retrievedMapping.ID, *retrievedMapping)
92+
if err != nil {
93+
log.Printf("Failed to update user mapping: %v", err)
94+
// Check if the mapping was actually updated despite the error
95+
checkMapping, checkErr := sdk.GetUserMapping(*retrievedMapping.ID)
96+
if checkErr == nil && *checkMapping.Name == "Updated Test Mapping" {
97+
log.Printf("Note: The mapping was actually updated successfully despite the error")
98+
fmt.Printf("Updated mapping: ID: %d, Name: %s\n", *checkMapping.ID, *checkMapping.Name)
99+
mappingIDToDelete = *checkMapping.ID
100+
}
101+
} else {
102+
fmt.Printf("Updated mapping: ID: %d, Name: %s\n", *updatedMapping.ID, *updatedMapping.Name)
103+
mappingIDToDelete = *updatedMapping.ID
104+
}
105+
106+
// Only delete if not keeping the mapping
107+
if !leaveMapping {
108+
// Clean up - delete the mapping
109+
fmt.Println("\n-- Deleting a User Mapping --")
110+
err = sdk.DeleteUserMapping(mappingIDToDelete)
111+
if err != nil {
112+
log.Printf("Failed to delete user mapping: %v", err)
113+
} else {
114+
fmt.Printf("Deleted mapping with ID: %d\n", mappingIDToDelete)
115+
}
116+
} else {
117+
fmt.Println("\n-- Skipping deletion (leaving mapping for demonstration) --")
118+
fmt.Printf("Mapping with ID: %d was created successfully and left in place\n", mappingIDToDelete)
119+
}
120+
}
121+
122+
fmt.Println("\n=== Example Complete ===")
123+
os.Exit(0)
124+
}

cmd/user_types_test/main.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ func main() {
3636
// Test 1: Create a user with the fixed properties
3737
fmt.Println("Test 1: Create a user with the fixed properties")
3838
user := models.User{
39-
Firstname: "Test",
40-
Lastname: "User",
41-
Email: "testuser@example.com",
42-
Username: "testuser@example.com",
43-
MemberOf: []string{"Group1", "Group2"},
44-
ManagerADID: 12345,
45-
ExternalID: "ext-id-123",
46-
RoleIDs: []int32{1, 2, 3},
39+
Firstname: "Test",
40+
Lastname: "User",
41+
Email: "testuser@example.com",
42+
Username: "testuser@example.com",
43+
MemberOf: []string{"Group1", "Group2"},
44+
ManagerADID: 12345,
45+
ExternalID: "ext-id-123",
46+
RoleIDs: []int32{1, 2, 3},
4747
CustomAttributes: map[string]interface{}{
4848
"department": "Engineering",
4949
"location": "Remote",
@@ -58,7 +58,7 @@ func main() {
5858
// Continue with other tests even if this fails
5959
} else {
6060
fmt.Printf("User created successfully: %+v\n", userResp)
61-
61+
6262
// Get the user ID from the response
6363
// Note: This is a simplified approach, in a real test you'd parse the response properly
6464
// userID := ... get from response
@@ -101,4 +101,4 @@ func main() {
101101
}
102102

103103
fmt.Println("\nTests completed")
104-
}
104+
}

docs/usage_examples.md

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,20 +136,99 @@ import (
136136
)
137137

138138
func main() {
139+
// Initialize the SDK
139140
client, err := onelogin.NewOneloginSDK()
140141
if err != nil {
141142
fmt.Println(err)
142143
}
143144

144-
userMappingsQuery := models.UserMappingsQuery{}
145-
userMappings, err := client.GetUserMappings(&userMappingsQuery)
145+
// Get authentication token
146+
_, err = client.GetToken()
146147
if err != nil {
147148
fmt.Println(err)
148149
}
149-
fmt.Printf("%+v\n", userMappings)
150+
151+
// List all user mappings with query parameters
152+
userMappingsQuery := &models.UserMappingsQuery{
153+
Limit: "10",
154+
Page: "1",
155+
}
156+
157+
mappings, err := client.ListUserMappings(userMappingsQuery)
158+
if err != nil {
159+
fmt.Println(err)
160+
}
161+
fmt.Printf("Found %d user mappings\n", len(mappings))
162+
163+
// Create a new user mapping
164+
name := "Test Mapping via SDK"
165+
match := "all"
166+
enabled := true
167+
position := int32(1)
168+
169+
// Set up conditions
170+
sourceCondition := "firstname"
171+
equalsOperator := "eq"
172+
valueCondition := "Test"
173+
174+
// Set up actions
175+
actionName := "set_status"
176+
actionValue := []string{"2"}
177+
178+
newMapping := models.UserMapping{
179+
Name: &name,
180+
Match: &match,
181+
Enabled: &enabled,
182+
Position: &position,
183+
Conditions: []models.UserMappingConditions{
184+
{
185+
Source: &sourceCondition,
186+
Operator: &equalsOperator,
187+
Value: &valueCondition,
188+
},
189+
},
190+
Actions: []models.UserMappingActions{
191+
{
192+
Action: &actionName,
193+
Value: actionValue,
194+
},
195+
},
196+
}
197+
198+
createdMapping, err := client.CreateUserMapping(newMapping)
199+
if err != nil {
200+
fmt.Println(err)
201+
}
202+
fmt.Printf("Created new mapping with ID: %d\n", *createdMapping.ID)
203+
204+
// Get a specific mapping
205+
mapping, err := client.GetUserMapping(*createdMapping.ID)
206+
if err != nil {
207+
fmt.Println(err)
208+
}
209+
fmt.Printf("Retrieved mapping: %s\n", *mapping.Name)
210+
211+
// Update a mapping
212+
updatedName := "Updated Test Mapping"
213+
mapping.Name = &updatedName
214+
215+
updatedMapping, err := client.UpdateUserMapping(*mapping.ID, *mapping)
216+
if err != nil {
217+
fmt.Println(err)
218+
}
219+
fmt.Printf("Updated mapping: %s\n", *updatedMapping.Name)
220+
221+
// Delete a mapping
222+
err = client.DeleteUserMapping(*updatedMapping.ID)
223+
if err != nil {
224+
fmt.Println(err)
225+
}
226+
fmt.Println("Deleted mapping successfully")
150227
}
151228
```
152229

230+
For a more detailed example, see the `cmd/user_mappings_test/main.go` file.
231+
153232
6. **AppRule model**
154233

155234
```go

pkg/onelogin/models/user.go

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type PaginationInfo struct {
3333

3434
// PagedResponse represents a paginated response with both data and pagination information
3535
type PagedResponse struct {
36-
Data interface{} `json:"data"`
36+
Data interface{} `json:"data"`
3737
Pagination PaginationInfo `json:"pagination"`
3838
}
3939

@@ -65,41 +65,41 @@ type UserQuery struct {
6565

6666
// User represents a OneLogin User
6767
type User struct {
68-
Firstname string `json:"firstname,omitempty"`
69-
Lastname string `json:"lastname,omitempty"`
70-
Username string `json:"username,omitempty"`
71-
Email string `json:"email,omitempty"`
72-
DistinguishedName string `json:"distinguished_name,omitempty"`
73-
Samaccountname string `json:"samaccountname,omitempty"`
74-
UserPrincipalName string `json:"userprincipalname,omitempty"`
75-
MemberOf []string `json:"member_of,omitempty"`
76-
Phone string `json:"phone,omitempty"`
77-
Password string `json:"password,omitempty"`
78-
PasswordConfirmation string `json:"password_confirmation,omitempty"`
79-
PasswordAlgorithm string `json:"password_algorithm,omitempty"`
80-
Salt string `json:"salt,omitempty"`
81-
Title string `json:"title,omitempty"`
82-
Company string `json:"company,omitempty"`
83-
Department string `json:"department,omitempty"`
84-
ManagerADID int32 `json:"manager_ad_id,omitempty"`
85-
Comment string `json:"comment,omitempty"`
86-
CreatedAt time.Time `json:"created_at,omitempty"`
87-
UpdatedAt time.Time `json:"updated_at,omitempty"`
88-
ActivatedAt time.Time `json:"activated_at,omitempty"`
89-
LastLogin time.Time `json:"last_login,omitempty"`
90-
PasswordChangedAt time.Time `json:"password_changed_at,omitempty"`
91-
LockedUntil time.Time `json:"locked_until,omitempty"`
92-
InvitationSentAt time.Time `json:"invitation_sent_at,omitempty"`
93-
State int32 `json:"state,omitempty"`
94-
Status int32 `json:"status,omitempty"`
95-
InvalidLoginAttempts int32 `json:"invalid_login_attempts,omitempty"`
96-
GroupID int32 `json:"group_id,omitempty"`
97-
RoleIDs []int32 `json:"role_ids,omitempty"`
98-
DirectoryID int32 `json:"directory_id,omitempty"`
99-
TrustedIDPID int32 `json:"trusted_idp_id,omitempty"`
100-
ManagerUserID int32 `json:"manager_user_id,omitempty"`
101-
ExternalID string `json:"external_id,omitempty"`
102-
ID int32 `json:"id,omitempty"`
68+
Firstname string `json:"firstname,omitempty"`
69+
Lastname string `json:"lastname,omitempty"`
70+
Username string `json:"username,omitempty"`
71+
Email string `json:"email,omitempty"`
72+
DistinguishedName string `json:"distinguished_name,omitempty"`
73+
Samaccountname string `json:"samaccountname,omitempty"`
74+
UserPrincipalName string `json:"userprincipalname,omitempty"`
75+
MemberOf []string `json:"member_of,omitempty"`
76+
Phone string `json:"phone,omitempty"`
77+
Password string `json:"password,omitempty"`
78+
PasswordConfirmation string `json:"password_confirmation,omitempty"`
79+
PasswordAlgorithm string `json:"password_algorithm,omitempty"`
80+
Salt string `json:"salt,omitempty"`
81+
Title string `json:"title,omitempty"`
82+
Company string `json:"company,omitempty"`
83+
Department string `json:"department,omitempty"`
84+
ManagerADID int32 `json:"manager_ad_id,omitempty"`
85+
Comment string `json:"comment,omitempty"`
86+
CreatedAt time.Time `json:"created_at,omitempty"`
87+
UpdatedAt time.Time `json:"updated_at,omitempty"`
88+
ActivatedAt time.Time `json:"activated_at,omitempty"`
89+
LastLogin time.Time `json:"last_login,omitempty"`
90+
PasswordChangedAt time.Time `json:"password_changed_at,omitempty"`
91+
LockedUntil time.Time `json:"locked_until,omitempty"`
92+
InvitationSentAt time.Time `json:"invitation_sent_at,omitempty"`
93+
State int32 `json:"state,omitempty"`
94+
Status int32 `json:"status,omitempty"`
95+
InvalidLoginAttempts int32 `json:"invalid_login_attempts,omitempty"`
96+
GroupID int32 `json:"group_id,omitempty"`
97+
RoleIDs []int32 `json:"role_ids,omitempty"`
98+
DirectoryID int32 `json:"directory_id,omitempty"`
99+
TrustedIDPID int32 `json:"trusted_idp_id,omitempty"`
100+
ManagerUserID int32 `json:"manager_user_id,omitempty"`
101+
ExternalID string `json:"external_id,omitempty"`
102+
ID int32 `json:"id,omitempty"`
103103
CustomAttributes map[string]interface{} `json:"custom_attributes,omitempty"`
104104
}
105105

0 commit comments

Comments
 (0)