From e3b82d17e87da03ad0f65f3c1bf83f6b544b7825 Mon Sep 17 00:00:00 2001 From: Cyril David Date: Fri, 14 May 2021 16:00:36 -0700 Subject: [PATCH] Complete rest of CRUD commands --- internal/cli/roles.go | 251 ++++++++++++++++++++++++++++++++++++++ internal/display/roles.go | 45 +++---- 2 files changed, 275 insertions(+), 21 deletions(-) diff --git a/internal/cli/roles.go b/internal/cli/roles.go index ea3472d83..f120c2473 100644 --- a/internal/cli/roles.go +++ b/internal/cli/roles.go @@ -1,13 +1,39 @@ package cli import ( + "errors" "fmt" "github.com/auth0/auth0-cli/internal/ansi" + "github.com/auth0/auth0-cli/internal/prompt" "github.com/spf13/cobra" "gopkg.in/auth0.v5/management" ) +// errNoRoles signifies no roles exist in a tenant +var errNoRoles = errors.New("there are currently no roles") + +var ( + roleID = Argument{ + Name: "Role ID", + Help: "Id of the role.", + } + roleName = Flag{ + Name: "Name", + LongForm: "name", + ShortForm: "n", + Help: "Name of the role.", + IsRequired: true, + } + roleDescription = Flag{ + Name: "Description", + LongForm: "description", + ShortForm: "d", + Help: "Description of the role.", + // IsRequired: true, + } +) + func rolesCmd(cli *cli) *cobra.Command { cmd := &cobra.Command{ Use: "roles", @@ -18,6 +44,10 @@ func rolesCmd(cli *cli) *cobra.Command { cmd.SetUsageTemplate(resourceUsageTemplate()) cmd.AddCommand(listRolesCmd(cli)) + cmd.AddCommand(showRoleCmd(cli)) + cmd.AddCommand(createRoleCmd(cli)) + cmd.AddCommand(updateRoleCmd(cli)) + cmd.AddCommand(deleteRoleCmd(cli)) return cmd } @@ -50,3 +80,224 @@ auth0 roles ls`, return cmd } + +func showRoleCmd(cli *cli) *cobra.Command { + var inputs struct { + ID string + } + + cmd := &cobra.Command{ + Use: "show", + Args: cobra.MaximumNArgs(1), + Short: "Show a role", + Long: "Show a role.", + Example: `auth0 roles show +auth0 roles show `, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + err := roleID.Pick(cmd, &inputs.ID, cli.rolePickerOptions) + if err != nil { + return err + } + } else { + inputs.ID = args[0] + } + + r := &management.Role{ID: &inputs.ID} + + if err := ansi.Waiting(func() error { + var err error + r, err = cli.api.Role.Read(inputs.ID) + return err + }); err != nil { + return fmt.Errorf("Unable to load role. The Id %v specified doesn't exist", inputs.ID) + } + + cli.renderer.RoleShow(r) + return nil + }, + } + + return cmd +} + +func createRoleCmd(cli *cli) *cobra.Command { + var inputs struct { + Name string + Description string + } + + cmd := &cobra.Command{ + Use: "create", + Args: cobra.NoArgs, + Short: "Create a new role", + Long: "Create a new role.", + Example: `auth0 roles create +auth0 roles create --name myrole +auth0 roles create -n myrole --description "awesome role"`, + RunE: func(cmd *cobra.Command, args []string) error { + // Prompt for role name + if err := roleName.Ask(cmd, &inputs.Name, nil); err != nil { + return err + } + + // Prompt for role description + if err := roleDescription.Ask(cmd, &inputs.Description, nil); err != nil { + return err + } + + // Load values into a fresh role instance + r := &management.Role{ + Name: &inputs.Name, + Description: &inputs.Description, + } + + // Create role + if err := ansi.Waiting(func() error { + return cli.api.Role.Create(r) + }); err != nil { + return fmt.Errorf("Unable to create role: %v", err) + } + + // Render role creation specific view + cli.renderer.RoleCreate(r) + return nil + }, + } + + roleName.RegisterString(cmd, &inputs.Name, "") + roleDescription.RegisterString(cmd, &inputs.Description, "") + + return cmd +} + +func updateRoleCmd(cli *cli) *cobra.Command { + var inputs struct { + ID string + Name string + Description string + } + + cmd := &cobra.Command{ + Use: "update", + Args: cobra.MaximumNArgs(1), + Short: "Update a role", + Long: "Update a role.", + Example: `auth0 roles update +auth0 roles update --name myrole +auth0 roles update -n myrole --description "awesome role"`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + err := roleID.Pick(cmd, &inputs.ID, cli.rolePickerOptions) + if err != nil { + return err + } + } else { + inputs.ID = args[0] + } + + // Prompt for role name + if err := roleName.AskU(cmd, &inputs.Name, nil); err != nil { + return err + } + + // Prompt for role description + if err := roleDescription.AskU(cmd, &inputs.Description, nil); err != nil { + return err + } + + // Start with an empty role object. We'll conditionally + // hydrate it based on the provided parameters since + // we'll do PATCH semantics. + r := &management.Role{} + + if inputs.Name != "" { + r.Name = &inputs.Name + } + + if inputs.Description != "" { + r.Description = &inputs.Description + } + + // Update role + if err := ansi.Waiting(func() error { + return cli.api.Role.Update(inputs.ID, r) + }); err != nil { + return fmt.Errorf("Unable to update role: %v", err) + } + + // Render role creation specific view + cli.renderer.RoleUpdate(r) + return nil + }, + } + + roleName.RegisterStringU(cmd, &inputs.Name, "") + roleDescription.RegisterStringU(cmd, &inputs.Description, "") + + return cmd +} + +func deleteRoleCmd(cli *cli) *cobra.Command { + var inputs struct { + ID string + } + + cmd := &cobra.Command{ + Use: "delete", + Args: cobra.MaximumNArgs(1), + Short: "Delete an role", + Long: "Delete an role.", + Example: `auth0 roles delete +auth0 roles delete `, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + err := roleID.Pick(cmd, &inputs.ID, cli.rolePickerOptions) + if err != nil { + return err + } + } else { + inputs.ID = args[0] + } + + if !cli.force && canPrompt(cmd) { + if confirmed := prompt.Confirm("Are you sure you want to proceed?"); !confirmed { + return nil + } + } + + return ansi.Spinner("Deleting Role", func() error { + _, err := cli.api.Role.Read(inputs.ID) + + if err != nil { + return fmt.Errorf("Unable to delete role. The specified Id: %v doesn't exist", inputs.ID) + } + + return cli.api.Role.Delete(inputs.ID) + }) + }, + } + + return cmd +} + +func (c *cli) rolePickerOptions() (pickerOptions, error) { + list, err := c.api.Role.List() + if err != nil { + return nil, err + } + + var opts pickerOptions + + for _, c := range list.Roles { + value := c.GetID() + label := fmt.Sprintf("%s %s", c.GetName(), ansi.Faint("("+value+")")) + opts = append(opts, pickerOption{value: value, label: label}) + } + + if len(opts) == 0 { + return nil, errNoRoles + } + + return opts, nil +} diff --git a/internal/display/roles.go b/internal/display/roles.go index 0944be3cc..3dc71d4f1 100644 --- a/internal/display/roles.go +++ b/internal/display/roles.go @@ -2,7 +2,6 @@ package display import ( "github.com/auth0/auth0-cli/internal/ansi" - "github.com/auth0/auth0-cli/internal/auth0" "gopkg.in/auth0.v5/management" ) @@ -24,6 +23,14 @@ func (v *roleView) AsTableRow() []string { } } +func (v *roleView) KeyValues() [][]string { + return [][]string{ + []string{"ID", ansi.Faint(v.ID)}, + []string{"NAME", v.Name}, + []string{"DESCRIPTION", v.Description}, + } +} + func (r *Renderer) RoleList(roles []*management.Role) { resource := "roles" @@ -47,29 +54,25 @@ func (r *Renderer) RoleList(roles []*management.Role) { r.Results(res) } -func (r *Renderer) RoleGet(role *management.Role) { - r.Heading(ansi.Bold(r.Tenant), "role\n") - r.Results([]View{&roleView{ - Name: auth0.StringValue(role.Name), - ID: auth0.StringValue(role.ID), - Description: auth0.StringValue(role.Description), - }}) +func (r *Renderer) RoleShow(role *management.Role) { + r.Heading("role") + r.roleResult(role) +} + +func (r *Renderer) RoleCreate(role *management.Role) { + r.Heading("role created") + r.roleResult(role) } func (r *Renderer) RoleUpdate(role *management.Role) { - r.Heading(ansi.Bold(r.Tenant), "role\n") - r.Results([]View{&roleView{ - Name: auth0.StringValue(role.Name), - ID: auth0.StringValue(role.ID), - Description: auth0.StringValue(role.Description), - }}) + r.Heading("role updated") + r.roleResult(role) } -func (r *Renderer) RoleCreate(role *management.Role) { - r.Heading(ansi.Bold(r.Tenant), "role\n") - r.Results([]View{&roleView{ - Name: auth0.StringValue(role.Name), - ID: auth0.StringValue(role.ID), - Description: auth0.StringValue(role.Description), - }}) +func (r *Renderer) roleResult(role *management.Role) { + r.Result(&roleView{ + Name: role.GetName(), + ID: ansi.Faint(role.GetID()), + Description: role.GetDescription(), + }) }