From 7e6138a79c5fce6a9d8234c05e4f5a7da0be6872 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 28 Jan 2021 00:00:32 -0300 Subject: [PATCH] feat: add 'scopes list' subcommand --- internal/cli/apis.go | 107 ++++++++++++++++++++++++++++++++++++++- internal/display/apis.go | 56 ++++++++++++++++---- 2 files changed, 152 insertions(+), 11 deletions(-) diff --git a/internal/cli/apis.go b/internal/cli/apis.go index 821cebbeb..871ef54da 100644 --- a/internal/cli/apis.go +++ b/internal/cli/apis.go @@ -1,6 +1,8 @@ package cli import ( + "strings" + "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/prompt" "github.com/spf13/cobra" @@ -11,6 +13,7 @@ const ( apiID = "id" apiName = "name" apiIdentifier = "identifier" + apiScopes = "scopes" ) func apisCmd(cli *cli) *cobra.Command { @@ -26,6 +29,19 @@ func apisCmd(cli *cli) *cobra.Command { cmd.AddCommand(createApiCmd(cli)) cmd.AddCommand(updateApiCmd(cli)) cmd.AddCommand(deleteApiCmd(cli)) + cmd.AddCommand(scopesCmd(cli)) + + return cmd +} + +func scopesCmd(cli *cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "scopes", + Short: "Manage resources for API scopes", + } + + cmd.SetUsageTemplate(resourceUsageTemplate()) + cmd.AddCommand(listScopesCmd(cli)) return cmd } @@ -111,6 +127,7 @@ func createApiCmd(cli *cli) *cobra.Command { var flags struct { Name string Identifier string + Scopes string } cmd := &cobra.Command{ @@ -146,11 +163,23 @@ auth0 apis create --name myapi --identifier http://my-api } } + if shouldPrompt(cmd, apiScopes) { + input := prompt.TextInput(apiScopes, "Scopes:", "Space-separated list of scopes.", false) + + if err := prompt.AskOne(input, &flags); err != nil { + return err + } + } + api := &management.ResourceServer{ Name: &flags.Name, Identifier: &flags.Identifier, } + if flags.Scopes != "" { + api.Scopes = getScopes(flags.Scopes) + } + err := ansi.Spinner("Creating API", func() error { return cli.api.ResourceServer.Create(api) }) @@ -166,6 +195,7 @@ auth0 apis create --name myapi --identifier http://my-api cmd.Flags().StringVarP(&flags.Name, apiName, "n", "", "Name of the API.") cmd.Flags().StringVarP(&flags.Identifier, apiIdentifier, "i", "", "Identifier of the API.") + cmd.Flags().StringVarP(&flags.Scopes, apiScopes, "s", "", "Space-separated list of scopes.") mustRequireFlags(cmd, apiName, apiIdentifier) return cmd @@ -173,8 +203,9 @@ auth0 apis create --name myapi --identifier http://my-api func updateApiCmd(cli *cli) *cobra.Command { var flags struct { - ID string - Name string + ID string + Name string + Scopes string } cmd := &cobra.Command{ @@ -204,8 +235,20 @@ auth0 apis update --id id --name myapi } } + if shouldPrompt(cmd, apiScopes) { + input := prompt.TextInput(apiScopes, "Scopes:", "Space-separated list of scopes.", false) + + if err := prompt.AskOne(input, &flags); err != nil { + return err + } + } + api := &management.ResourceServer{Name: &flags.Name} + if flags.Scopes != "" { + api.Scopes = getScopes(flags.Scopes) + } + err := ansi.Spinner("Updating API", func() error { return cli.api.ResourceServer.Update(flags.ID, api) }) @@ -221,6 +264,7 @@ auth0 apis update --id id --name myapi cmd.Flags().StringVarP(&flags.ID, apiID, "i", "", "ID of the API.") cmd.Flags().StringVarP(&flags.Name, apiName, "n", "", "Name of the API.") + cmd.Flags().StringVarP(&flags.Scopes, apiScopes, "s", "", "Space-separated list of scopes.") mustRequireFlags(cmd, apiID, apiName) return cmd @@ -273,3 +317,62 @@ auth0 apis delete --id id return cmd } + +func listScopesCmd(cli *cli) *cobra.Command { + var flags struct { + ID string + } + + cmd := &cobra.Command{ + Use: "list", + Short: "List the scopes of an API", + Long: `List the scopes of an API: + +auth0 apis scopes list --id id +`, + PreRun: func(cmd *cobra.Command, args []string) { + prepareInteractivity(cmd) + }, + RunE: func(cmd *cobra.Command, args []string) error { + if shouldPrompt(cmd, apiID) { + input := prompt.TextInput(apiID, "Id:", "Id of the API.", true) + + if err := prompt.AskOne(input, &flags); err != nil { + return err + } + } + + api := &management.ResourceServer{ID: &flags.ID} + + err := ansi.Spinner("Loading scopes", func() error { + var err error + api, err = cli.api.ResourceServer.Read(flags.ID) + return err + }) + + if err != nil { + return err + } + + cli.renderer.ScopesList(api.GetName(), api.Scopes) + return nil + }, + } + + cmd.Flags().StringVarP(&flags.ID, apiID, "i", "", "ID of the API.") + mustRequireFlags(cmd, apiID) + + return cmd +} + +func getScopes(scopes string) []*management.ResourceServerScope { + list := strings.Fields(scopes) + models := []*management.ResourceServerScope{} + + for _, scope := range list { + value := scope + models = append(models, &management.ResourceServerScope{Value: &value}) + } + + return models +} diff --git a/internal/display/apis.go b/internal/display/apis.go index f0f3fdf4c..1519c0cf4 100644 --- a/internal/display/apis.go +++ b/internal/display/apis.go @@ -1,6 +1,8 @@ package display import ( + "fmt" + "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" "gopkg.in/auth0.v5/management" @@ -10,47 +12,83 @@ type apiView struct { ID string Name string Identifier string + Scopes int } func (v *apiView) AsTableHeader() []string { - return []string{"ID", "Name", "Identifier"} + return []string{"ID", "Name", "Identifier", "Scopes"} } func (v *apiView) AsTableRow() []string { - return []string{ansi.Faint(v.ID), v.Name, v.Identifier} + return []string{ansi.Faint(v.ID), v.Name, v.Identifier, fmt.Sprint(v.Scopes)} } func (r *Renderer) ApiList(apis []*management.ResourceServer) { r.Heading(ansi.Bold(r.Tenant), "APIs\n") - var res []View + results := []View{} for _, api := range apis { - res = append(res, makeView(api)) + results = append(results, makeApiView(api)) } - r.Results(res) + r.Results(results) } func (r *Renderer) ApiShow(api *management.ResourceServer) { r.Heading(ansi.Bold(r.Tenant), "API\n") - r.Results([]View{makeView(api)}) + r.Results([]View{makeApiView(api)}) } func (r *Renderer) ApiCreate(api *management.ResourceServer) { r.Heading(ansi.Bold(r.Tenant), "API created\n") - r.Results([]View{makeView(api)}) + r.Results([]View{makeApiView(api)}) } func (r *Renderer) ApiUpdate(api *management.ResourceServer) { r.Heading(ansi.Bold(r.Tenant), "API updated\n") - r.Results([]View{makeView(api)}) + r.Results([]View{makeApiView(api)}) } -func makeView(api *management.ResourceServer) *apiView { +func makeApiView(api *management.ResourceServer) *apiView { + scopes := len(api.Scopes) + return &apiView{ ID: auth0.StringValue(api.ID), Name: auth0.StringValue(api.Name), Identifier: auth0.StringValue(api.Identifier), + Scopes: auth0.IntValue(&scopes), + } +} + +type scopeView struct { + Scope string + Description string +} + +func (v *scopeView) AsTableHeader() []string { + return []string{"Scope", "Description"} +} + +func (v *scopeView) AsTableRow() []string { + return []string{v.Scope, v.Description} +} + +func (r *Renderer) ScopesList(api string, scopes []*management.ResourceServerScope) { + r.Heading(ansi.Bold(r.Tenant), fmt.Sprintf("Scopes of %s\n", ansi.Bold(api))) + + results := []View{} + + for _, scope := range scopes { + results = append(results, makeScopeView(scope)) + } + + r.Results(results) +} + +func makeScopeView(scope *management.ResourceServerScope) *scopeView { + return &scopeView{ + Scope: auth0.StringValue(scope.Value), + Description: auth0.StringValue(scope.Description), } }