Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[A0CLI-57] feat: add 'scopes list' subcommand #89

Merged
merged 1 commit into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 105 additions & 2 deletions internal/cli/apis.go
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -11,6 +13,7 @@ const (
apiID = "id"
apiName = "name"
apiIdentifier = "identifier"
apiScopes = "scopes"
)

func apisCmd(cli *cli) *cobra.Command {
Expand All @@ -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
}
Expand Down Expand Up @@ -111,6 +127,7 @@ func createApiCmd(cli *cli) *cobra.Command {
var flags struct {
Name string
Identifier string
Scopes string
}

cmd := &cobra.Command{
Expand Down Expand Up @@ -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)
})
Expand All @@ -166,15 +195,17 @@ 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
}

func updateApiCmd(cli *cli) *cobra.Command {
var flags struct {
ID string
Name string
ID string
Name string
Scopes string
}

cmd := &cobra.Command{
Expand Down Expand Up @@ -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)
})
Expand All @@ -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
Expand Down Expand Up @@ -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
}
56 changes: 47 additions & 9 deletions internal/display/apis.go
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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),
}
}