From 61dad4acb8a561dd997e739c8e9c33d468dd5b76 Mon Sep 17 00:00:00 2001 From: ramya18101 Date: Wed, 9 Oct 2024 12:00:30 +0530 Subject: [PATCH 1/8] DXCDT-677 : Format methods to support different strategies connection while creating a user --- internal/cli/users.go | 103 ++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/internal/cli/users.go b/internal/cli/users.go index f91c6114d..8e121ca40 100644 --- a/internal/cli/users.go +++ b/internal/cli/users.go @@ -218,13 +218,12 @@ func searchUsersCmd(cli *cli) *cobra.Command { func createUserCmd(cli *cli) *cobra.Command { var inputs struct { - ConnectionName string - Email string - Password string - Username string - Name string + connectionName string + username string } + var user = management.User{} + cmd := &cobra.Command{ Use: "create", Args: cobra.NoArgs, @@ -243,77 +242,105 @@ func createUserCmd(cli *cli) *cobra.Command { return err } - if err := userConnectionName.Select(cmd, &inputs.ConnectionName, options, nil); err != nil { + if err := userConnectionName.Select(cmd, &inputs.connectionName, options, nil); err != nil { return err } - connection, err := cli.api.Connection.ReadByName(cmd.Context(), inputs.ConnectionName) + connection, err := cli.api.Connection.ReadByName(cmd.Context(), inputs.connectionName) if err != nil { - return fmt.Errorf("failed to find connection with name %q: %w", inputs.ConnectionName, err) + return fmt.Errorf("failed to find connection with name %q: %w", inputs.connectionName, err) } if len(connection.GetEnabledClients()) == 0 { return fmt.Errorf( "failed to continue due to the connection with name %q being disabled, enable an application on this connection and try again", - inputs.ConnectionName, + inputs.connectionName, ) } - if err := userName.Ask(cmd, &inputs.Name, nil); err != nil { - return err - } - - if err := userEmail.Ask(cmd, &inputs.Email, nil); err != nil { + // Fetch user info basis on the connection's strategy + // if connection.GetStrategy() == management.ConnectionStrategyAuth0 { + user, err := fetchOAuthRequiredDetails(cmd) + if err != nil { return err } + //} - if err := userPassword.AskPassword(cmd, &inputs.Password); err != nil { - return err - } + user.Connection = &inputs.connectionName // The getConnReqUsername returns the value for the requires_username field for the selected connection // The result will be used to determine whether to prompt for username. - conn := cli.getConnReqUsername(cmd.Context(), auth0.StringValue(&inputs.ConnectionName)) - requireUsername := auth0.BoolValue(conn) - - // Prompt for username if the requireUsername is set to true - // Load values including the username's field into a fresh users instance. - a := &management.User{ - Connection: &inputs.ConnectionName, - Email: &inputs.Email, - Name: &inputs.Name, - Password: &inputs.Password, - } + conn := cli.getConnReqUsername(cmd.Context(), auth0.StringValue(&inputs.connectionName)) + requiredUsername := auth0.BoolValue(conn) - if requireUsername { - if err := userUsername.Ask(cmd, &inputs.Username, nil); err != nil { + if requiredUsername { + if err := userUsername.Ask(cmd, &inputs.username, nil); err != nil { return err } - a.Username = &inputs.Username + + user.Username = &inputs.username } if err := ansi.Waiting(func() error { - return cli.api.User.Create(cmd.Context(), a) + return cli.api.User.Create(cmd.Context(), user) }); err != nil { return fmt.Errorf("failed to create user: %w", err) } - cli.renderer.UserCreate(a, requireUsername) + cli.renderer.UserCreate(user, requiredUsername) return nil }, } cmd.Flags().BoolVar(&cli.json, "json", false, "Output in json format.") - userName.RegisterString(cmd, &inputs.Name, "") - userConnectionName.RegisterString(cmd, &inputs.ConnectionName, "") - userPassword.RegisterString(cmd, &inputs.Password, "") - userEmail.RegisterString(cmd, &inputs.Email, "") - userUsername.RegisterString(cmd, &inputs.Username, "") + + userConnectionName.RegisterString(cmd, &inputs.connectionName, "") + userUsername.RegisterString(cmd, &inputs.username, "") + //if connection.GetStrategy() == management.ConnectionStrategyAuth0 { + registerOAuthDetailsInfo(cmd, &user) + //} return cmd } +func fetchOAuthRequiredDetails(cmd *cobra.Command) (*management.User, error) { + var inputs struct { + Email string + Password string + Name string + } + + if err := userName.Ask(cmd, &inputs.Name, nil); err != nil { + return nil, err + } + + if err := userEmail.Ask(cmd, &inputs.Email, nil); err != nil { + return nil, err + } + + if err := userPassword.AskPassword(cmd, &inputs.Password); err != nil { + return nil, err + } + + // Prompt for username if the requireUsername is set to true + // Load values including the username's field into a fresh users instance. + userInfo := &management.User{ + + Email: &inputs.Email, + Name: &inputs.Name, + Password: &inputs.Password, + } + + return userInfo, nil +} + +func registerOAuthDetailsInfo(cmd *cobra.Command, user *management.User) { + userName.RegisterString(cmd, user.Name, "") + userPassword.RegisterString(cmd, user.Password, "") + userEmail.RegisterString(cmd, user.Email, "") +} + func showUserCmd(cli *cli) *cobra.Command { var inputs struct { ID string From cad6de41bda1e8e64a34137657c8d450b9c5eec3 Mon Sep 17 00:00:00 2001 From: ramya18101 Date: Wed, 9 Oct 2024 16:06:39 +0530 Subject: [PATCH 2/8] DXCDT-677 : Fix logic in create users basis on strategy --- internal/cli/users.go | 62 +++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/internal/cli/users.go b/internal/cli/users.go index 8e121ca40..7608672dd 100644 --- a/internal/cli/users.go +++ b/internal/cli/users.go @@ -216,13 +216,16 @@ func searchUsersCmd(cli *cli) *cobra.Command { return cmd } -func createUserCmd(cli *cli) *cobra.Command { - var inputs struct { - connectionName string - username string - } +type userInput struct { + connectionName string + username string + email string + password string + name string +} - var user = management.User{} +func createUserCmd(cli *cli) *cobra.Command { + var inputs userInput cmd := &cobra.Command{ Use: "create", @@ -260,19 +263,19 @@ func createUserCmd(cli *cli) *cobra.Command { // Fetch user info basis on the connection's strategy // if connection.GetStrategy() == management.ConnectionStrategyAuth0 { - user, err := fetchOAuthRequiredDetails(cmd) + user, err := fetchOAuthUserDetails(cmd, &inputs) if err != nil { return err } //} - user.Connection = &inputs.connectionName - // The getConnReqUsername returns the value for the requires_username field for the selected connection // The result will be used to determine whether to prompt for username. conn := cli.getConnReqUsername(cmd.Context(), auth0.StringValue(&inputs.connectionName)) requiredUsername := auth0.BoolValue(conn) + // Prompt for username if the requireUsername is set to true + // Load values including the username's field into a fresh users instance. if requiredUsername { if err := userUsername.Ask(cmd, &inputs.username, nil); err != nil { return err @@ -295,50 +298,41 @@ func createUserCmd(cli *cli) *cobra.Command { cmd.Flags().BoolVar(&cli.json, "json", false, "Output in json format.") - userConnectionName.RegisterString(cmd, &inputs.connectionName, "") - userUsername.RegisterString(cmd, &inputs.username, "") - //if connection.GetStrategy() == management.ConnectionStrategyAuth0 { - registerOAuthDetailsInfo(cmd, &user) - //} + registerDetailsInfo(cmd, &inputs) return cmd } -func fetchOAuthRequiredDetails(cmd *cobra.Command) (*management.User, error) { - var inputs struct { - Email string - Password string - Name string - } - - if err := userName.Ask(cmd, &inputs.Name, nil); err != nil { +// as name, email and password are required fields for oauth strategy +func fetchOAuthUserDetails(cmd *cobra.Command, input *userInput) (*management.User, error) { + if err := userName.Ask(cmd, &input.name, nil); err != nil { return nil, err } - if err := userEmail.Ask(cmd, &inputs.Email, nil); err != nil { + if err := userEmail.Ask(cmd, &input.email, nil); err != nil { return nil, err } - if err := userPassword.AskPassword(cmd, &inputs.Password); err != nil { + if err := userPassword.AskPassword(cmd, &input.password); err != nil { return nil, err } - // Prompt for username if the requireUsername is set to true - // Load values including the username's field into a fresh users instance. userInfo := &management.User{ - - Email: &inputs.Email, - Name: &inputs.Name, - Password: &inputs.Password, + Email: &input.email, + Name: &input.name, + Password: &input.password, + Connection: &input.connectionName, } return userInfo, nil } -func registerOAuthDetailsInfo(cmd *cobra.Command, user *management.User) { - userName.RegisterString(cmd, user.Name, "") - userPassword.RegisterString(cmd, user.Password, "") - userEmail.RegisterString(cmd, user.Email, "") +func registerDetailsInfo(cmd *cobra.Command, input *userInput) { + userConnectionName.RegisterString(cmd, &input.connectionName, "") + userUsername.RegisterString(cmd, &input.username, "") + userName.RegisterString(cmd, &input.name, "") + userPassword.RegisterString(cmd, &input.password, "") + userEmail.RegisterString(cmd, &input.email, "") } func showUserCmd(cli *cli) *cobra.Command { From 9970f02034fdf37e1ca145e6326744d9b93d9383 Mon Sep 17 00:00:00 2001 From: ramya18101 Date: Thu, 10 Oct 2024 10:28:07 +0530 Subject: [PATCH 3/8] DXCDT-677 : Add logic to support creation of users with sms and email connections --- internal/cli/users.go | 82 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/internal/cli/users.go b/internal/cli/users.go index 7608672dd..63ba3aace 100644 --- a/internal/cli/users.go +++ b/internal/cli/users.go @@ -42,6 +42,13 @@ var ( Help: "The user's email.", IsRequired: true, } + userPhoneNumber = Flag{ + Name: "Phone Number", + LongForm: "phone-number", + ShortForm: "m", + Help: "The user's phone number.", + IsRequired: true, + } userPassword = Flag{ Name: "Password", LongForm: "password", @@ -218,10 +225,11 @@ func searchUsersCmd(cli *cli) *cobra.Command { type userInput struct { connectionName string + name string username string - email string password string - name string + email string + phoneNumber string } func createUserCmd(cli *cli) *cobra.Command { @@ -238,7 +246,11 @@ func createUserCmd(cli *cli) *cobra.Command { auth0 users create --name "John Doe" auth0 users create --name "John Doe" --email john@example.com auth0 users create --name "John Doe" --email john@example.com --connection-name "Username-Password-Authentication" --username "example" - auth0 users create -n "John Doe" -e john@example.com -c "Username-Password-Authentication" -u "example" --json`, + auth0 users create -n "John Doe" -e john@example.com -c "Username-Password-Authentication" -u "example" --json + auth0 users create -n "John Doe" -e john@example.com -c "email" --json + auth0 users create -e john@example.com -c "Username-Password-Authentication" + auth0 users create --name "John Doe" --phone-number +916898989898 --connection-name "sms" + auth0 users create -n "John Doe" -m +916898989898 -c "sms" --json`, RunE: func(cmd *cobra.Command, args []string) error { options, err := cli.databaseAndPasswordlessConnectionOptions(cmd.Context()) if err != nil { @@ -261,13 +273,31 @@ func createUserCmd(cli *cli) *cobra.Command { ) } - // Fetch user info basis on the connection's strategy - // if connection.GetStrategy() == management.ConnectionStrategyAuth0 { - user, err := fetchOAuthUserDetails(cmd, &inputs) - if err != nil { - return err + var ( + user *management.User + strategy = connection.GetStrategy() + ) + + // Fetch user info based on the connection's strategy + switch strategy { + case management.ConnectionStrategyAuth0: + user, err = retrieveAuth0UserDetails(cmd, &inputs) + if err != nil { + return err + } + + case management.ConnectionStrategySMS: + user, err = retrieveSMSUserDetails(cmd, &inputs) + if err != nil { + return err + } + + case management.ConnectionStrategyEmail: + user, err = retrieveEmailUserDetails(cmd, &inputs) + if err != nil { + return err + } } - //} // The getConnReqUsername returns the value for the requires_username field for the selected connection // The result will be used to determine whether to prompt for username. @@ -303,8 +333,8 @@ func createUserCmd(cli *cli) *cobra.Command { return cmd } -// as name, email and password are required fields for oauth strategy -func fetchOAuthUserDetails(cmd *cobra.Command, input *userInput) (*management.User, error) { +// retrieveAuth0UserDetails retrieves required fields: name, email, and password for Auth0 strategy. +func retrieveAuth0UserDetails(cmd *cobra.Command, input *userInput) (*management.User, error) { if err := userName.Ask(cmd, &input.name, nil); err != nil { return nil, err } @@ -327,12 +357,42 @@ func fetchOAuthUserDetails(cmd *cobra.Command, input *userInput) (*management.Us return userInfo, nil } +// retrieveSMSUserDetails retrieves required fields: name, email, and password for sms strategy. +func retrieveSMSUserDetails(cmd *cobra.Command, input *userInput) (*management.User, error) { + if err := userPhoneNumber.Ask(cmd, &input.phoneNumber, nil); err != nil { + return nil, err + } + + userInfo := &management.User{ + PhoneNumber: &input.phoneNumber, + PhoneVerified: auth0.Bool(true), + Connection: &input.connectionName, + } + + return userInfo, nil +} + +// retrieveEmailUserDetails retrieves required fields: email for email strategy. +func retrieveEmailUserDetails(cmd *cobra.Command, input *userInput) (*management.User, error) { + if err := userEmail.Ask(cmd, &input.email, nil); err != nil { + return nil, err + } + + userInfo := &management.User{ + Email: &input.email, + Connection: &input.connectionName, + } + + return userInfo, nil +} + func registerDetailsInfo(cmd *cobra.Command, input *userInput) { userConnectionName.RegisterString(cmd, &input.connectionName, "") userUsername.RegisterString(cmd, &input.username, "") userName.RegisterString(cmd, &input.name, "") userPassword.RegisterString(cmd, &input.password, "") userEmail.RegisterString(cmd, &input.email, "") + userPhoneNumber.RegisterString(cmd, &input.phoneNumber, "") } func showUserCmd(cli *cli) *cobra.Command { From 5b3eabadf727547465d286f924d113eca8c4383a Mon Sep 17 00:00:00 2001 From: ramya18101 Date: Sat, 12 Oct 2024 20:17:17 +0530 Subject: [PATCH 4/8] DXCDT-677 : Update docs and add tests and support new output format basis on the type of connection --- docs/auth0_users_create.md | 5 ++ internal/cli/users.go | 27 +++++---- internal/display/users.go | 26 +++++++- test/integration/users-test-cases.yaml | 83 +++++++++++++++++++------- 4 files changed, 107 insertions(+), 34 deletions(-) diff --git a/docs/auth0_users_create.md b/docs/auth0_users_create.md index a0b96d996..dfb253cb1 100644 --- a/docs/auth0_users_create.md +++ b/docs/auth0_users_create.md @@ -24,6 +24,10 @@ auth0 users create [flags] auth0 users create --name "John Doe" --email john@example.com auth0 users create --name "John Doe" --email john@example.com --connection-name "Username-Password-Authentication" --username "example" auth0 users create -n "John Doe" -e john@example.com -c "Username-Password-Authentication" -u "example" --json + auth0 users create -n "John Doe" -e john@example.com -c "email" --json + auth0 users create -e john@example.com -c "email" + auth0 users create --phone-number +916898989898 --connection-name "sms" + auth0 users create -m +916898989898 -c "sms" --json ``` @@ -35,6 +39,7 @@ auth0 users create [flags] --json Output in json format. -n, --name string The user's full name. -p, --password string Initial password for this user (mandatory for non-SMS connections). + -m, --phone-number string The user's phone number. -u, --username string The user's username. Only valid if the connection requires a username. ``` diff --git a/internal/cli/users.go b/internal/cli/users.go index 63ba3aace..75c511dea 100644 --- a/internal/cli/users.go +++ b/internal/cli/users.go @@ -67,7 +67,7 @@ var ( LongForm: "name", ShortForm: "n", Help: "The user's full name.", - IsRequired: true, + IsRequired: false, AlwaysPrompt: true, } userQuery = Flag{ @@ -248,9 +248,9 @@ func createUserCmd(cli *cli) *cobra.Command { auth0 users create --name "John Doe" --email john@example.com --connection-name "Username-Password-Authentication" --username "example" auth0 users create -n "John Doe" -e john@example.com -c "Username-Password-Authentication" -u "example" --json auth0 users create -n "John Doe" -e john@example.com -c "email" --json - auth0 users create -e john@example.com -c "Username-Password-Authentication" - auth0 users create --name "John Doe" --phone-number +916898989898 --connection-name "sms" - auth0 users create -n "John Doe" -m +916898989898 -c "sms" --json`, + auth0 users create -e john@example.com -c "email" + auth0 users create --phone-number +916898989898 --connection-name "sms" + auth0 users create -m +916898989898 -c "sms" --json`, RunE: func(cmd *cobra.Command, args []string) error { options, err := cli.databaseAndPasswordlessConnectionOptions(cmd.Context()) if err != nil { @@ -333,12 +333,8 @@ func createUserCmd(cli *cli) *cobra.Command { return cmd } -// retrieveAuth0UserDetails retrieves required fields: name, email, and password for Auth0 strategy. +// retrieveAuth0UserDetails retrieves required fields: email, and password for Auth0 strategy. func retrieveAuth0UserDetails(cmd *cobra.Command, input *userInput) (*management.User, error) { - if err := userName.Ask(cmd, &input.name, nil); err != nil { - return nil, err - } - if err := userEmail.Ask(cmd, &input.email, nil); err != nil { return nil, err } @@ -349,15 +345,19 @@ func retrieveAuth0UserDetails(cmd *cobra.Command, input *userInput) (*management userInfo := &management.User{ Email: &input.email, - Name: &input.name, Password: &input.password, Connection: &input.connectionName, } + // user's name is optional for auth0 connection and takes the email-id as default + if input.name != "" { + userInfo.Name = &input.name + } + return userInfo, nil } -// retrieveSMSUserDetails retrieves required fields: name, email, and password for sms strategy. +// retrieveSMSUserDetails retrieves required fields: phone-number for sms strategy. func retrieveSMSUserDetails(cmd *cobra.Command, input *userInput) (*management.User, error) { if err := userPhoneNumber.Ask(cmd, &input.phoneNumber, nil); err != nil { return nil, err @@ -383,6 +383,11 @@ func retrieveEmailUserDetails(cmd *cobra.Command, input *userInput) (*management Connection: &input.connectionName, } + // user's name is optional for email connection and takes the email-id as default + if input.name != "" { + userInfo.Name = &input.name + } + return userInfo, nil } diff --git a/internal/display/users.go b/internal/display/users.go index c8849ff45..6a0349424 100644 --- a/internal/display/users.go +++ b/internal/display/users.go @@ -13,6 +13,7 @@ import ( type userView struct { UserID string Email string + PhoneNumber string Connection string Username string RequireUsername bool @@ -20,6 +21,14 @@ type userView struct { } func (v *userView) AsTableHeader() []string { + if v.Connection == management.ConnectionStrategySMS { + return []string{ + "UserID", + "PhoneNumber", + "Connection", + } + } + return []string{ "UserID", "Email", @@ -28,6 +37,14 @@ func (v *userView) AsTableHeader() []string { } func (v *userView) AsTableRow() []string { + if v.Connection == management.ConnectionStrategySMS { + return []string{ + ansi.Faint(v.UserID), + v.PhoneNumber, + v.Connection, + } + } + return []string{ ansi.Faint(v.UserID), v.Email, @@ -36,7 +53,13 @@ func (v *userView) AsTableRow() []string { } func (v *userView) KeyValues() [][]string { - if v.RequireUsername { + if v.Connection == management.ConnectionStrategySMS { + return [][]string{ + {"ID", ansi.Faint(v.UserID)}, + {"PHONE-NUMBER", v.PhoneNumber}, + {"CONNECTION", v.Connection}, + } + } else if v.RequireUsername { return [][]string{ {"ID", ansi.Faint(v.UserID)}, {"EMAIL", v.Email}, @@ -95,6 +118,7 @@ func makeUserView(user *management.User, requireUsername bool) *userView { Email: auth0.StringValue(user.Email), Connection: stringSliceToCommaSeparatedString(getUserConnection(user)), Username: auth0.StringValue(user.Username), + PhoneNumber: auth0.StringValue(user.PhoneNumber), raw: user, } } diff --git a/test/integration/users-test-cases.yaml b/test/integration/users-test-cases.yaml index ec8eff3ac..902bef743 100644 --- a/test/integration/users-test-cases.yaml +++ b/test/integration/users-test-cases.yaml @@ -8,6 +8,7 @@ tests: exit-code: 0 stdout: json: + user_id: "auth0|" email: "testuser@example.com" connection: "Username-Password-Authentication" @@ -16,14 +17,52 @@ tests: exit-code: 0 stdout: contains: + - ID auth0| - EMAIL testuser2@example.com - CONNECTION Username-Password-Authentication - 003 - users create test user: + 003 - users create and check data for an email connection: + command: auth0 users create --name integration-test-user-new --connection-name email --email testemailuser@example.com --json --no-input + exit-code: 0 + stdout: + json: + user_id: "email|" + email: "testemailuser@example.com" + connection: "email" + + 004 - users create and check output for an email connection: + command: auth0 users create --name integration-test-user-new2 --connection-name email --email testemailuser2@example.com --no-input + exit-code: 0 + stdout: + contains: + - ID email| + - EMAIL testemailuser2@example.com + - CONNECTION email + + 005 - users create and check data for an sms connection: + command: auth0 users create --connection-name sms --phone-number +919898989898 --json --no-input + exit-code: 0 + stdout: + json: + user_id: "sms|" + phone_number: "+919898989898" + connection: "sms" + + 006 - users create and check output for an sms connection: + command: auth0 users create --connection-name sms --m testemailuser2@example.com --no-input + exit-code: 0 + stdout: + contains: + - ID sms| + - EMAIL +919898989898 + - CONNECTION sms + + + 007 - users create test user: command: ./test/integration/scripts/get-user-id.sh exit-code: 0 - 004 - users show json: + 008 - users show json: command: auth0 users show $(./test/integration/scripts/get-user-id.sh) --json stdout: json: @@ -31,7 +70,7 @@ tests: connection: "Username-Password-Authentication" exit-code: 0 - 005 - users show: + 009 - users show: command: auth0 users show $(./test/integration/scripts/get-user-id.sh) stdout: contains: @@ -39,40 +78,40 @@ tests: - CONNECTION Username-Password-Authentication exit-code: 0 - 005 - users search: + 010 - users search: command: auth0 users search --query user_id:"$(./test/integration/scripts/get-user-id.sh)" --number 1 --sort "name:-1" exit-code: 0 stdout: contains: - newuser@example.com - 006 - users search with invalid number flag: + 011 - users search with invalid number flag: command: auth0 users search --query "*" --number 1001 exit-code: 1 stderr: contains: - Number flag invalid, please pass a number between 1 and 1000 - 007 - users search with csv output: + 012 - users search with csv output: command: auth0 users search --query user_id:"$(./test/integration/scripts/get-user-id.sh)" --number 1 --sort "name:-1" --csv exit-code: 0 stdout: contains: - "UserID,Email,Connection" - 008 - users update minimal flags: + 013 - users update minimal flags: command: auth0 users update $(./test/integration/scripts/get-user-id.sh) --json --no-input stdout: contains: - "id" exit-code: 0 - 009 - users update password: #needs to be done in isolation + 014 - users update password: #needs to be done in isolation command: auth0 users update $(./test/integration/scripts/get-user-id.sh) --password 'S0me-new-P@$$Word' --json --no-input stdout: json: password: "S0me-new-P@$$Word" exit-code: 0 - 010 - users update maximal flags: + 015 - users update maximal flags: command: auth0 users update $(./test/integration/scripts/get-user-id.sh) --email betteruser@example.com --connection-name Username-Password-Authentication --name integration-test-user-bettername --json --no-input stdout: json: @@ -81,70 +120,70 @@ tests: connection: Username-Password-Authentication exit-code: 0 - 011 - users roles show no results: + 016 - users roles show no results: command: auth0 users roles show $(./test/integration/scripts/get-user-id.sh) exit-code: 0 stderr: contains: - "No user roles available. Use 'auth0 users roles assign' to assign roles to a user" - 012 - users roles show no results (json): + 017 - users roles show no results (json): command: auth0 users roles show $(./test/integration/scripts/get-user-id.sh) --json exit-code: 0 stdout: exactly: "[]" - 013 - users roles show with invalid number: + 018 - users roles show with invalid number: command: auth0 users roles show $(./test/integration/scripts/get-user-id.sh) --number 1001 exit-code: 1 stderr: contains: - Number flag invalid, please pass a number between 1 and 1000 - 014 - users roles add: + 019 - users roles add: command: auth0 users roles add $(./test/integration/scripts/get-user-id.sh) -r $(./test/integration/scripts/get-role-id.sh) exit-code: 0 - 015 - users roles remove: + 020 - users roles remove: command: auth0 users roles rm $(./test/integration/scripts/get-user-id.sh) -r $(./test/integration/scripts/get-role-id.sh) exit-code: 0 - 016 - users blocks list by email: + 021 - users blocks list by email: command: auth0 users blocks list "newuser@example.com" exit-code: 0 stderr: contains: - No user blocks available. - 017 - users blocks list by user ID: + 022 - users blocks list by user ID: command: auth0 users blocks list $(./test/integration/scripts/get-user-id.sh) exit-code: 0 stderr: contains: - No user blocks available. - 018 - users blocks list (json): + 023 - users blocks list (json): command: auth0 users blocks list $(./test/integration/scripts/get-user-id.sh) --json exit-code: 0 stdout: exactly: "[]" - 019 - users unblock by user email: + 024 - users unblock by user email: command: auth0 users blocks unblock "newuser@example.com" exit-code: 0 - 020 - users unblock by user ID: + 025 - users unblock by user ID: command: auth0 users blocks unblock $(./test/integration/scripts/get-user-id.sh) exit-code: 0 - 021 - open user dashboard page: + 026 - open user dashboard page: command: auth0 users open $(./test/integration/scripts/get-user-id.sh) --no-input exit-code: 0 stderr: contains: - "Open the following URL in a browser: https://manage.auth0.com/dashboard/" - 022 - users import: + 027 - users import: command: auth0 users import -c "Username-Password-Authentication" --users "[]" --email-results=false --no-input exit-code: 0 stderr: @@ -154,7 +193,7 @@ tests: - "successfully started" - "to get the status of the job" - 023 - users import with piped data: + 028 - users import with piped data: command: echo "[]" | auth0 users import -c "Username-Password-Authentication" --email-results=false --no-input exit-code: 0 stderr: From 503a7f09e63ab904efcbac194fea4c46ec5ba535 Mon Sep 17 00:00:00 2001 From: ramya18101 Date: Sat, 12 Oct 2024 21:43:21 +0530 Subject: [PATCH 5/8] DXCDT-677 : Fix lints and add a manual check on provided flags info basis on the connection type. --- internal/cli/users.go | 51 +++++++++++++++++++++++--- test/integration/users-test-cases.yaml | 5 +-- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/internal/cli/users.go b/internal/cli/users.go index 75c511dea..5b4f5b68f 100644 --- a/internal/cli/users.go +++ b/internal/cli/users.go @@ -35,33 +35,38 @@ var ( Help: "Name of the database connection this user should be created in.", IsRequired: true, } + userEmail = Flag{ Name: "Email", LongForm: "email", ShortForm: "e", Help: "The user's email.", - IsRequired: true, + IsRequired: false, } + userPhoneNumber = Flag{ Name: "Phone Number", LongForm: "phone-number", ShortForm: "m", Help: "The user's phone number.", - IsRequired: true, + IsRequired: false, } + userPassword = Flag{ Name: "Password", LongForm: "password", ShortForm: "p", Help: "Initial password for this user (mandatory for non-SMS connections).", - IsRequired: true, + IsRequired: false, } + userUsername = Flag{ Name: "Username", LongForm: "username", ShortForm: "u", Help: "The user's username. Only valid if the connection requires a username.", } + userName = Flag{ Name: "Name", LongForm: "name", @@ -70,6 +75,7 @@ var ( IsRequired: false, AlwaysPrompt: true, } + userQuery = Flag{ Name: "Query", LongForm: "query", @@ -77,18 +83,21 @@ var ( Help: "Search query in Lucene query syntax.\n\nFor example: `email:\"user123@*.com\" OR (user_id:\"user-id-123\" AND name:\"Bob\")`\n\n For more info: https://auth0.com/docs/users/user-search/user-search-query-syntax.", IsRequired: true, } + userSort = Flag{ Name: "Sort", LongForm: "sort", ShortForm: "s", Help: "Field to sort by. Use 'field:order' where 'order' is '1' for ascending and '-1' for descending. e.g. 'created_at:1'.", } + userNumber = Flag{ Name: "Number", LongForm: "number", ShortForm: "n", Help: "Number of users, that match the search criteria, to retrieve. Minimum 1, maximum 1000. If limit is hit, refine the search query.", } + userImportTemplate = Flag{ Name: "Template", LongForm: "template", @@ -97,6 +106,7 @@ var ( "Options include: 'Empty', 'Basic Example', 'Custom Password Hash Example' and 'MFA Factors Example'.", IsRequired: false, } + userImportBody = Flag{ Name: "Users Payload", LongForm: "users", @@ -104,18 +114,21 @@ var ( Help: "JSON payload that contains an array of user(s) to be imported. Cannot be used if the '--template' flag is passed.", IsRequired: false, } + userEmailResults = Flag{ Name: "Email Completion Results", LongForm: "email-results", Help: "When true, sends a completion email to all tenant owners when the job is finished. The default is true, so you must explicitly set this parameter to false if you do not want emails sent.", IsRequired: false, } + userImportUpsert = Flag{ Name: "Upsert", LongForm: "upsert", Help: "When set to false, pre-existing users that match on email address, user ID, or username will fail. When set to true, pre-existing users that match on any of these fields will be updated, but only with upsertable attributes.", IsRequired: false, } + userImportOptions = pickerOptions{ {"Empty", users.EmptyExample}, {"Basic Example", users.BasicExample}, @@ -252,6 +265,13 @@ func createUserCmd(cli *cli) *cobra.Command { auth0 users create --phone-number +916898989898 --connection-name "sms" auth0 users create -m +916898989898 -c "sms" --json`, RunE: func(cmd *cobra.Command, args []string) error { + // Validate provided flags basis on the given connection type. + if cli.noInput { + if err := validateRequiredFlags(&inputs); err != nil { + return err + } + } + options, err := cli.databaseAndPasswordlessConnectionOptions(cmd.Context()) if err != nil { return err @@ -278,7 +298,7 @@ func createUserCmd(cli *cli) *cobra.Command { strategy = connection.GetStrategy() ) - // Fetch user info based on the connection's strategy + // Fetch user info based on the connection's strategy. switch strategy { case management.ConnectionStrategyAuth0: user, err = retrieveAuth0UserDetails(cmd, &inputs) @@ -349,7 +369,7 @@ func retrieveAuth0UserDetails(cmd *cobra.Command, input *userInput) (*management Connection: &input.connectionName, } - // user's name is optional for auth0 connection and takes the email-id as default + // User's name is optional for auth0 connection and takes the email-id as default. if input.name != "" { userInfo.Name = &input.name } @@ -383,7 +403,7 @@ func retrieveEmailUserDetails(cmd *cobra.Command, input *userInput) (*management Connection: &input.connectionName, } - // user's name is optional for email connection and takes the email-id as default + // User's name is optional for email connection and takes the email-id as default. if input.name != "" { userInfo.Name = &input.name } @@ -400,6 +420,25 @@ func registerDetailsInfo(cmd *cobra.Command, input *userInput) { userPhoneNumber.RegisterString(cmd, &input.phoneNumber, "") } +func validateRequiredFlags(inputs *userInput) error { + switch inputs.connectionName { + case "email": + if inputs.email == "" { + return fmt.Errorf("required flag email not set") + } + case "sms": + if inputs.phoneNumber == "" { + return fmt.Errorf("required flag phone-number not set") + } + default: + if inputs.email == "" || inputs.password == "" { + return fmt.Errorf("required flag email or password not set") + } + } + + return nil +} + func showUserCmd(cli *cli) *cobra.Command { var inputs struct { ID string diff --git a/test/integration/users-test-cases.yaml b/test/integration/users-test-cases.yaml index 902bef743..ea2ddef53 100644 --- a/test/integration/users-test-cases.yaml +++ b/test/integration/users-test-cases.yaml @@ -8,7 +8,6 @@ tests: exit-code: 0 stdout: json: - user_id: "auth0|" email: "testuser@example.com" connection: "Username-Password-Authentication" @@ -26,7 +25,6 @@ tests: exit-code: 0 stdout: json: - user_id: "email|" email: "testemailuser@example.com" connection: "email" @@ -44,12 +42,11 @@ tests: exit-code: 0 stdout: json: - user_id: "sms|" phone_number: "+919898989898" connection: "sms" 006 - users create and check output for an sms connection: - command: auth0 users create --connection-name sms --m testemailuser2@example.com --no-input + command: auth0 users create --connection-name sms -m +919898989899 --no-input exit-code: 0 stdout: contains: From dd040d0da38a96c12622d497d67ccc0d9fb0671c Mon Sep 17 00:00:00 2001 From: ramya18101 Date: Sun, 13 Oct 2024 00:47:42 +0530 Subject: [PATCH 6/8] DXCDT-677 : Update logic for update-user --- internal/cli/users.go | 120 ++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/internal/cli/users.go b/internal/cli/users.go index 5b4f5b68f..68e8f4afe 100644 --- a/internal/cli/users.go +++ b/internal/cli/users.go @@ -542,13 +542,10 @@ func deleteUserCmd(cli *cli) *cobra.Command { } func updateUserCmd(cli *cli) *cobra.Command { - var inputs struct { - ID string - Email string - Password string - Name string - ConnectionName string - } + var ( + inputs userInput + id string + ) cmd := &cobra.Command{ Use: "update", @@ -563,70 +560,37 @@ func updateUserCmd(cli *cli) *cobra.Command { auth0 users update --name "John Doe" --email john.doe@example.com`, RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { - if err := userID.Ask(cmd, &inputs.ID); err != nil { + if err := userID.Ask(cmd, &id); err != nil { return err } } else { - inputs.ID = args[0] + id = args[0] } var current *management.User if err := ansi.Waiting(func() error { var err error - current, err = cli.api.User.Read(cmd.Context(), inputs.ID) + current, err = cli.api.User.Read(cmd.Context(), id) return err }); err != nil { - return fmt.Errorf("failed to read user with ID %q: %w", inputs.ID, err) + return fmt.Errorf("failed to read user with ID %q: %w", id, err) } // Using getUserConnection to get connection name from user Identities // just using current.connection will return empty. conn := stringSliceToCommaSeparatedString(cli.getUserConnection(current)) current.Connection = auth0.String(conn) - if err := userName.AskU(cmd, &inputs.Name, current.Name); err != nil { + if err := fetchUserInputByConnection(cmd, inputs, current); err != nil { return err } - if err := userEmail.AskU(cmd, &inputs.Email, current.Email); err != nil { - return err - } - - if err := userPassword.AskPasswordU(cmd, &inputs.Password); err != nil { - return err - } - - // Username cannot be updated for database connections - // if err := userUsername.AskU(cmd, &inputs.Username, current.Username); err != nil { - // return err - // }. - - user := &management.User{} - - if len(inputs.Name) == 0 { - user.Name = current.Name - } else { - user.Name = &inputs.Name - } - - if len(inputs.Email) != 0 { - user.Email = &inputs.Email - } - - if len(inputs.Password) != 0 { - user.Password = &inputs.Password - } - - if len(inputs.ConnectionName) == 0 { - user.Connection = current.Connection - } else { - user.Connection = &inputs.ConnectionName - } + user := fetchUpdateUserDetails(inputs, current) if err := ansi.Waiting(func() error { return cli.api.User.Update(cmd.Context(), current.GetID(), user) }); err != nil { - return fmt.Errorf("failed to update user with ID %q: %w", inputs.ID, err) + return fmt.Errorf("failed to update user with ID %q: %w", id, err) } con := cli.getConnReqUsername(cmd.Context(), auth0.StringValue(user.Connection)) @@ -638,14 +602,68 @@ func updateUserCmd(cli *cli) *cobra.Command { } cmd.Flags().BoolVar(&cli.json, "json", false, "Output in json format.") - userName.RegisterStringU(cmd, &inputs.Name, "") - userConnectionName.RegisterStringU(cmd, &inputs.ConnectionName, "") - userPassword.RegisterStringU(cmd, &inputs.Password, "") - userEmail.RegisterStringU(cmd, &inputs.Email, "") + registerDetailsInfo(cmd, &inputs) return cmd } +func fetchUserInputByConnection(cmd *cobra.Command, inputs userInput, current *management.User) error { + switch *current.Connection { + case "email": + if err := userEmail.AskU(cmd, &inputs.email, current.Email); err != nil { + return err + } + case "sms": + if err := userPhoneNumber.AskU(cmd, &inputs.phoneNumber, current.PhoneNumber); err != nil { + return err + } + default: + if err := userName.AskU(cmd, &inputs.name, current.Name); err != nil { + return err + } + if err := userEmail.AskU(cmd, &inputs.email, current.Email); err != nil { + return err + } + if err := userPassword.AskPasswordU(cmd, &inputs.password); err != nil { + return err + } + } + return nil +} + +func fetchUpdateUserDetails(inputs userInput, current *management.User) *management.User { + user := &management.User{} + + switch *current.Connection { + case "email": + user.Email = current.Email + case "sms": + user.PhoneNumber = current.PhoneNumber + default: + if len(inputs.email) != 0 && current.Email != &inputs.email { + user.Email = &inputs.email + } + + if len(inputs.password) != 0 { + user.Password = &inputs.password + } + } + + if len(inputs.name) == 0 { + user.Name = current.Name + } else { + user.Name = &inputs.name + } + + if len(inputs.connectionName) == 0 { + user.Connection = current.Connection + } else { + user.Connection = &inputs.connectionName + } + + return user +} + func openUserCmd(cli *cli) *cobra.Command { var inputs struct { ID string From 88e5d7652bed3664fe3c852060aec2ae30aa37c4 Mon Sep 17 00:00:00 2001 From: ramya18101 Date: Mon, 14 Oct 2024 06:17:53 +0530 Subject: [PATCH 7/8] DXCDT-677 : Fix logic for update-user and update docs --- docs/auth0_users_update.md | 9 +++++- internal/cli/users.go | 57 +++++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/docs/auth0_users_update.md b/docs/auth0_users_update.md index f8063d438..d7bab4bb9 100644 --- a/docs/auth0_users_update.md +++ b/docs/auth0_users_update.md @@ -22,7 +22,12 @@ auth0 users update [flags] auth0 users update auth0 users update auth0 users update --name "John Doe" - auth0 users update --name "John Doe" --email john.doe@example.com + auth0 users update -n "John Kennedy" -e johnk@example.com --json + auth0 users update -n "John Kennedy" -p + auth0 users update -p + auth0 users update -e johnk@example.com + auth0 users update --phone-number +916898989899 + auth0 users update -m +916898989899 --json ``` @@ -34,6 +39,8 @@ auth0 users update [flags] --json Output in json format. -n, --name string The user's full name. -p, --password string Initial password for this user (mandatory for non-SMS connections). + -m, --phone-number string The user's phone number. + -u, --username string The user's username. Only valid if the connection requires a username. ``` diff --git a/internal/cli/users.go b/internal/cli/users.go index 68e8f4afe..f55f47746 100644 --- a/internal/cli/users.go +++ b/internal/cli/users.go @@ -37,27 +37,30 @@ var ( } userEmail = Flag{ - Name: "Email", - LongForm: "email", - ShortForm: "e", - Help: "The user's email.", - IsRequired: false, + Name: "Email", + LongForm: "email", + ShortForm: "e", + Help: "The user's email.", + IsRequired: false, + AlwaysPrompt: true, } userPhoneNumber = Flag{ - Name: "Phone Number", - LongForm: "phone-number", - ShortForm: "m", - Help: "The user's phone number.", - IsRequired: false, + Name: "Phone Number", + LongForm: "phone-number", + ShortForm: "m", + Help: "The user's phone number.", + IsRequired: false, + AlwaysPrompt: true, } userPassword = Flag{ - Name: "Password", - LongForm: "password", - ShortForm: "p", - Help: "Initial password for this user (mandatory for non-SMS connections).", - IsRequired: false, + Name: "Password", + LongForm: "password", + ShortForm: "p", + Help: "Initial password for this user (mandatory for non-SMS connections).", + IsRequired: false, + AlwaysPrompt: true, } userUsername = Flag{ @@ -543,7 +546,7 @@ func deleteUserCmd(cli *cli) *cobra.Command { func updateUserCmd(cli *cli) *cobra.Command { var ( - inputs userInput + inputs = &userInput{} id string ) @@ -557,7 +560,13 @@ func updateUserCmd(cli *cli) *cobra.Command { Example: ` auth0 users update auth0 users update auth0 users update --name "John Doe" - auth0 users update --name "John Doe" --email john.doe@example.com`, + auth0 users update -n "John Kennedy" -e johnk@example.com --json + auth0 users update -n "John Kennedy" -p + auth0 users update -p + auth0 users update -e johnk@example.com + auth0 users update --phone-number +916898989899 + auth0 users update -m +916898989899 --json`, + RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { if err := userID.Ask(cmd, &id); err != nil { @@ -602,12 +611,12 @@ func updateUserCmd(cli *cli) *cobra.Command { } cmd.Flags().BoolVar(&cli.json, "json", false, "Output in json format.") - registerDetailsInfo(cmd, &inputs) + registerDetailsInfo(cmd, inputs) return cmd } -func fetchUserInputByConnection(cmd *cobra.Command, inputs userInput, current *management.User) error { +func fetchUserInputByConnection(cmd *cobra.Command, inputs *userInput, current *management.User) error { switch *current.Connection { case "email": if err := userEmail.AskU(cmd, &inputs.email, current.Email); err != nil { @@ -631,14 +640,18 @@ func fetchUserInputByConnection(cmd *cobra.Command, inputs userInput, current *m return nil } -func fetchUpdateUserDetails(inputs userInput, current *management.User) *management.User { +func fetchUpdateUserDetails(inputs *userInput, current *management.User) *management.User { user := &management.User{} switch *current.Connection { case "email": - user.Email = current.Email + if len(inputs.email) != 0 { + user.Email = &inputs.email + } case "sms": - user.PhoneNumber = current.PhoneNumber + if len(inputs.phoneNumber) != 0 { + user.PhoneNumber = &inputs.phoneNumber + } default: if len(inputs.email) != 0 && current.Email != &inputs.email { user.Email = &inputs.email From ea6f2229f6bd370c9f90544acaf7a1456461c44b Mon Sep 17 00:00:00 2001 From: ramya18101 Date: Wed, 16 Oct 2024 10:42:06 +0530 Subject: [PATCH 8/8] DXCDT-677 : Revert integration tests for users create related to password-less connections --- test/integration/users-test-cases.yaml | 81 ++++++++------------------ 1 file changed, 23 insertions(+), 58 deletions(-) diff --git a/test/integration/users-test-cases.yaml b/test/integration/users-test-cases.yaml index ea2ddef53..66118d3ed 100644 --- a/test/integration/users-test-cases.yaml +++ b/test/integration/users-test-cases.yaml @@ -20,46 +20,11 @@ tests: - EMAIL testuser2@example.com - CONNECTION Username-Password-Authentication - 003 - users create and check data for an email connection: - command: auth0 users create --name integration-test-user-new --connection-name email --email testemailuser@example.com --json --no-input - exit-code: 0 - stdout: - json: - email: "testemailuser@example.com" - connection: "email" - - 004 - users create and check output for an email connection: - command: auth0 users create --name integration-test-user-new2 --connection-name email --email testemailuser2@example.com --no-input - exit-code: 0 - stdout: - contains: - - ID email| - - EMAIL testemailuser2@example.com - - CONNECTION email - - 005 - users create and check data for an sms connection: - command: auth0 users create --connection-name sms --phone-number +919898989898 --json --no-input - exit-code: 0 - stdout: - json: - phone_number: "+919898989898" - connection: "sms" - - 006 - users create and check output for an sms connection: - command: auth0 users create --connection-name sms -m +919898989899 --no-input - exit-code: 0 - stdout: - contains: - - ID sms| - - EMAIL +919898989898 - - CONNECTION sms - - - 007 - users create test user: + 003 - users create test user: command: ./test/integration/scripts/get-user-id.sh exit-code: 0 - 008 - users show json: + 004 - users show json: command: auth0 users show $(./test/integration/scripts/get-user-id.sh) --json stdout: json: @@ -67,7 +32,7 @@ tests: connection: "Username-Password-Authentication" exit-code: 0 - 009 - users show: + 005 - users show: command: auth0 users show $(./test/integration/scripts/get-user-id.sh) stdout: contains: @@ -75,40 +40,40 @@ tests: - CONNECTION Username-Password-Authentication exit-code: 0 - 010 - users search: + 006 - users search: command: auth0 users search --query user_id:"$(./test/integration/scripts/get-user-id.sh)" --number 1 --sort "name:-1" exit-code: 0 stdout: contains: - newuser@example.com - 011 - users search with invalid number flag: + 007 - users search with invalid number flag: command: auth0 users search --query "*" --number 1001 exit-code: 1 stderr: contains: - Number flag invalid, please pass a number between 1 and 1000 - 012 - users search with csv output: + 008 - users search with csv output: command: auth0 users search --query user_id:"$(./test/integration/scripts/get-user-id.sh)" --number 1 --sort "name:-1" --csv exit-code: 0 stdout: contains: - "UserID,Email,Connection" - 013 - users update minimal flags: + 009 - users update minimal flags: command: auth0 users update $(./test/integration/scripts/get-user-id.sh) --json --no-input stdout: contains: - "id" exit-code: 0 - 014 - users update password: #needs to be done in isolation + 010 - users update password: #needs to be done in isolation command: auth0 users update $(./test/integration/scripts/get-user-id.sh) --password 'S0me-new-P@$$Word' --json --no-input stdout: json: password: "S0me-new-P@$$Word" exit-code: 0 - 015 - users update maximal flags: + 011 - users update maximal flags: command: auth0 users update $(./test/integration/scripts/get-user-id.sh) --email betteruser@example.com --connection-name Username-Password-Authentication --name integration-test-user-bettername --json --no-input stdout: json: @@ -117,70 +82,70 @@ tests: connection: Username-Password-Authentication exit-code: 0 - 016 - users roles show no results: + 012 - users roles show no results: command: auth0 users roles show $(./test/integration/scripts/get-user-id.sh) exit-code: 0 stderr: contains: - "No user roles available. Use 'auth0 users roles assign' to assign roles to a user" - 017 - users roles show no results (json): + 013 - users roles show no results (json): command: auth0 users roles show $(./test/integration/scripts/get-user-id.sh) --json exit-code: 0 stdout: exactly: "[]" - 018 - users roles show with invalid number: + 014 - users roles show with invalid number: command: auth0 users roles show $(./test/integration/scripts/get-user-id.sh) --number 1001 exit-code: 1 stderr: contains: - Number flag invalid, please pass a number between 1 and 1000 - 019 - users roles add: + 015 - users roles add: command: auth0 users roles add $(./test/integration/scripts/get-user-id.sh) -r $(./test/integration/scripts/get-role-id.sh) exit-code: 0 - 020 - users roles remove: + 016 - users roles remove: command: auth0 users roles rm $(./test/integration/scripts/get-user-id.sh) -r $(./test/integration/scripts/get-role-id.sh) exit-code: 0 - 021 - users blocks list by email: + 017 - users blocks list by email: command: auth0 users blocks list "newuser@example.com" exit-code: 0 stderr: contains: - No user blocks available. - - 022 - users blocks list by user ID: + + 018 - users blocks list by user ID: command: auth0 users blocks list $(./test/integration/scripts/get-user-id.sh) exit-code: 0 stderr: contains: - No user blocks available. - 023 - users blocks list (json): + 019 - users blocks list (json): command: auth0 users blocks list $(./test/integration/scripts/get-user-id.sh) --json exit-code: 0 stdout: exactly: "[]" - 024 - users unblock by user email: + 020 - users unblock by user email: command: auth0 users blocks unblock "newuser@example.com" exit-code: 0 - 025 - users unblock by user ID: + 021 - users unblock by user ID: command: auth0 users blocks unblock $(./test/integration/scripts/get-user-id.sh) exit-code: 0 - 026 - open user dashboard page: + 022 - open user dashboard page: command: auth0 users open $(./test/integration/scripts/get-user-id.sh) --no-input exit-code: 0 stderr: contains: - "Open the following URL in a browser: https://manage.auth0.com/dashboard/" - 027 - users import: + 023 - users import: command: auth0 users import -c "Username-Password-Authentication" --users "[]" --email-results=false --no-input exit-code: 0 stderr: @@ -190,7 +155,7 @@ tests: - "successfully started" - "to get the status of the job" - 028 - users import with piped data: + 024 - users import with piped data: command: echo "[]" | auth0 users import -c "Username-Password-Authentication" --email-results=false --no-input exit-code: 0 stderr: