Skip to content

Commit

Permalink
Add ability to retrieve job errors (#141)
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiught authored Dec 19, 2022
1 parent b4cb956 commit 495cb29
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 0 deletions.
23 changes: 23 additions & 0 deletions management/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ type JobSummary struct {
Total *int `json:"total,omitempty"`
}

// JobError is used to check for errors during jobs.
//
// See: https://auth0.com/docs/manage-users/user-migration/bulk-user-imports#retrieve-failed-entries
type JobError struct {
User map[string]interface{} `json:"user,omitempty"`
Errors []JobUserErrors `json:"errors,omitempty"`
}

// JobUserErrors holds errors for the specific user during a job.
type JobUserErrors struct {
Code string `json:"code,omitempty"`
Message string `json:"message,omitempty"`
Path string `json:"path,omitempty"`
}

// JobManager manages Auth0 Job resources.
type JobManager struct {
*Management
Expand All @@ -86,6 +101,14 @@ func (m *JobManager) Read(id string, opts ...RequestOption) (j *Job, err error)
return
}

// ReadErrors retrieves error details of a failed job.
//
// See: https://auth0.com/docs/api/management/v2#!/Jobs/get_errors
func (m *JobManager) ReadErrors(id string, opts ...RequestOption) (jobErrors []JobError, err error) {
err = m.Request("GET", m.URI("jobs", id, "errors"), &jobErrors, opts...)
return
}

// VerifyEmail sends an email to the specified user that asks them to
// click a link to verify their email address.
func (m *JobManager) VerifyEmail(j *Job, opts ...RequestOption) error {
Expand Down
41 changes: 41 additions & 0 deletions management/job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,44 @@ func TestJobManager_ImportUsers(t *testing.T) {
cleanupUser(t, users[0].GetID())
})
}

func TestJobManager_ReadErrors(t *testing.T) {
setupHTTPRecordings(t)

alreadyExistingUser := givenAUser(t)
conn, err := m.Connection.ReadByName("Username-Password-Authentication")
require.NoError(t, err)

job := &Job{
ConnectionID: conn.ID,
Users: []map[string]interface{}{
{
"email": alreadyExistingUser.GetEmail(),
"email_verified": true,
},
},
}
err = m.Job.ImportUsers(job)
assert.NoError(t, err)

// Let's give the ImportUsers job enough time to complete.
time.Sleep(time.Second * 2)

expectedJobErrors := JobError{
User: map[string]interface{}{
"email": alreadyExistingUser.GetEmail(),
"email_verified": true,
},
Errors: []JobUserErrors{
{
Code: "DUPLICATED_USER",
Message: "The user already exist and upsert parameter is false",
},
},
}

actualJobErrors, err := m.Job.ReadErrors(job.GetID())
assert.NoError(t, err)
assert.Len(t, actualJobErrors, 1)
assert.Equal(t, expectedJobErrors, actualJobErrors[0])
}
10 changes: 10 additions & 0 deletions management/management.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions management/management.gen_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

102 changes: 102 additions & 0 deletions management/testdata/recordings/TestJobManager_ReadErrors.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
version: 1
interactions:
- request:
body: |
{"connection":"Username-Password-Authentication","email":"[email protected]","given_name":"Chuck","family_name":"Sanchez","username":"test-user636","nickname":"Chucky","password":"Passwords hide their chuck","user_metadata":{"favourite_attack":"roundhouse_kick"},"verify_email":false,"app_metadata":{"facts":["count_to_infinity_twice","kill_two_stones_with_one_bird","can_hear_sign_language"]},"picture":"https://example-picture-url.jpg","blocked":false,"email_verified":true}
form: { }
headers:
Content-Type:
- application/json
User-Agent:
- Go-Auth0-SDK/latest
url: https://go-auth0-dev.eu.auth0.com/api/v2/users
method: POST
response:
body: '{"blocked":false,"created_at":"2022-12-19T12:51:38.614Z","email":"[email protected]","email_verified":true,"family_name":"Sanchez","given_name":"Chuck","identities":[{"connection":"Username-Password-Authentication","user_id":"63a05e5a6ea7634fae1893af","provider":"auth0","isSocial":false}],"name":"[email protected]","nickname":"Chucky","picture":"https://example-picture-url.jpg","updated_at":"2022-12-19T12:51:38.614Z","user_id":"auth0|63a05e5a6ea7634fae1893af","user_metadata":{"favourite_attack":"roundhouse_kick"},"username":"test-user636","app_metadata":{"facts":["count_to_infinity_twice","kill_two_stones_with_one_bird","can_hear_sign_language"]}}'
headers:
Content-Length:
- "661"
Content-Type:
- application/json; charset=utf-8
status: 201 Created
code: 201
duration: 1ms
- request:
body: |
null
form: { }
headers:
Content-Type:
- application/json
User-Agent:
- Go-Auth0-SDK/latest
url: https://go-auth0-dev.eu.auth0.com/api/v2/connections?include_totals=true&name=Username-Password-Authentication&per_page=50
method: GET
response:
body: '{"total":1,"start":0,"limit":50,"connections":[{"id":"con_ftSSLHb0O7rcUGmF","options":{"mfa":{"active":true,"return_enroll_settings":true},"validation":{"username":{"max":15,"min":1}},"import_mode":false,"configuration":{},"passwordPolicy":"good","password_history":{"size":5,"enable":false},"strategy_version":2,"requires_username":true,"password_dictionary":{"enable":false,"dictionary":[]},"brute_force_protection":true,"password_no_personal_info":{"enable":false},"password_complexity_options":{"min_length":8},"enabledDatabaseCustomization":false},"strategy":"auth0","name":"Username-Password-Authentication","is_domain_connection":false,"realms":["Username-Password-Authentication"],"enabled_clients":[]}]}'
headers:
Access-Control-Expose-Headers:
- WWW-Authenticate,Server-Authorization
Content-Type:
- application/json; charset=utf-8
status: 200 OK
code: 200
duration: 1ms
- request:
body: "--86d8458dcd43f0d49b30ae345c6469ce927f3429a5c0c6b0a201643d51d8\r\nContent-Disposition: form-data; name=\"connection_id\"\r\n\r\ncon_ftSSLHb0O7rcUGmF\r\n--86d8458dcd43f0d49b30ae345c6469ce927f3429a5c0c6b0a201643d51d8\r\nContent-Disposition: form-data; name=\"upsert\"\r\n\r\nfalse\r\n--86d8458dcd43f0d49b30ae345c6469ce927f3429a5c0c6b0a201643d51d8\r\nContent-Disposition: form-data; name=\"external_id\"\r\n\r\n\r\n--86d8458dcd43f0d49b30ae345c6469ce927f3429a5c0c6b0a201643d51d8\r\nContent-Disposition: form-data; name=\"send_completion_email\"\r\n\r\nfalse\r\n--86d8458dcd43f0d49b30ae345c6469ce927f3429a5c0c6b0a201643d51d8\r\nContent-Disposition: form-data; name=\"users\"; filename=\"users.json\"\r\nContent-Type: application/json\r\n\r\n[{\"email\":\"[email protected]\",\"email_verified\":true}]\r\n--86d8458dcd43f0d49b30ae345c6469ce927f3429a5c0c6b0a201643d51d8--\r\n"
form: { }
headers:
Content-Type:
- multipart/form-data; boundary=86d8458dcd43f0d49b30ae345c6469ce927f3429a5c0c6b0a201643d51d8
User-Agent:
- Go-Auth0-SDK/latest
url: https://go-auth0-dev.eu.auth0.com/api/v2/jobs/users-imports
method: POST
response:
body: '{"type":"users_import","status":"pending","connection_id":"con_ftSSLHb0O7rcUGmF","connection":"Username-Password-Authentication","created_at":"2022-12-19T12:51:39.606Z","id":"job_Atb40xBugG7DP1bz"}'
headers:
Content-Length:
- "197"
Content-Type:
- application/json; charset=utf-8
status: 202 Accepted
code: 202
duration: 1ms
- request:
body: |
null
form: { }
headers:
Content-Type:
- application/json
User-Agent:
- Go-Auth0-SDK/latest
url: https://go-auth0-dev.eu.auth0.com/api/v2/jobs/job_Atb40xBugG7DP1bz/errors
method: GET
response:
body: '[{"user":{"email":"[email protected]","email_verified":true},"errors":[{"code":"DUPLICATED_USER","message":"The user already exist and upsert parameter is false"}]}]'
headers:
Content-Type:
- application/json
status: 200 OK
code: 200
duration: 1ms
- request:
body: ""
form: { }
headers:
Content-Type:
- application/json
User-Agent:
- Go-Auth0-SDK/latest
url: https://go-auth0-dev.eu.auth0.com/api/v2/users/auth0%7C63a05e5a6ea7634fae1893af
method: DELETE
response:
body: ""
headers:
Content-Type:
- application/json; charset=utf-8
status: 204 No Content
code: 204
duration: 1ms

0 comments on commit 495cb29

Please sign in to comment.