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

Add tenants open and apis open [CLI-101] [CLI-133] #253

Merged
merged 8 commits into from
Apr 19, 2021
Merged
55 changes: 55 additions & 0 deletions internal/cli/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/auth0/auth0-cli/internal/ansi"
"github.com/auth0/auth0-cli/internal/prompt"
"github.com/spf13/cobra"
"gopkg.in/auth0.v5"
"gopkg.in/auth0.v5/management"
)

Expand Down Expand Up @@ -53,6 +54,7 @@ func apisCmd(cli *cli) *cobra.Command {
cmd.AddCommand(showApiCmd(cli))
cmd.AddCommand(updateApiCmd(cli))
cmd.AddCommand(deleteApiCmd(cli))
cmd.AddCommand(openApiCmd(cli))
cmd.AddCommand(scopesCmd(cli))

return cmd
Expand Down Expand Up @@ -324,6 +326,52 @@ auth0 apis delete <id>`,
return cmd
}

func openApiCmd(cli *cli) *cobra.Command {
var inputs struct {
ID string
}

cmd := &cobra.Command{
Use: "open",
Args: cobra.MaximumNArgs(1),
Short: "Open API settings page in Auth0 Manage",
Long: "Open API settings page in Auth0 Manage.",
Example: "auth0 apis open <id>",
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
err := apiID.Pick(cmd, &inputs.ID, cli.apiPickerOptions)
if err != nil {
return err
}
} else {
inputs.ID = args[0]
}

// Heuristics to determine if this a valid ID, or an audience value
if _, err := url.ParseRequestURI(inputs.ID); err == nil || len(inputs.ID) != 24 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's 24coming from ? is inputs.ID a url? in that case I wonder if we can make it more explicit on the command help

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

24 is the string length of the ID. Audiences are usually URLs, but not necessarily, so there is that additional heuristic to help disambiguate. I'll make it more explicit on the command help and add a comment explaining the values, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 62c64d5

if err := ansi.Waiting(func() error {
api, err := cli.api.ResourceServer.Read(url.PathEscape(inputs.ID))
if err != nil {
return err
}
inputs.ID = auth0.StringValue(api.ID)
return nil
}); err != nil {
return fmt.Errorf("An unexpected error occurred while trying to get the API Id for '%s': %w", inputs.ID, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB: I know we're doing this in other places already, but I'd suggest starting error messages with lowercase (as well as avoiding ending punctuation). More context here: https://github.com/golang/go/wiki/CodeReviewComments#error-strings

Copy link
Contributor Author

@Widcket Widcket Apr 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the thing is that the reasoning behind that best practice is that errors are usually printed among other information, so there should not be a sentence-cased string in the middle of other text. In this particular case, that error message is going to be shown as-is, so we want the casing. We'll totally revisit this in the future, though, when we rethink the error handling.

}
}

openManageURL(cli, cli.config.DefaultTenant, formatApiSettingsPath(inputs.ID))
return nil
},
}

return cmd
}

func listScopesCmd(cli *cli) *cobra.Command {
var inputs struct {
ID string
Expand Down Expand Up @@ -368,6 +416,13 @@ auth0 apis scopes ls <id>`,
return cmd
}

func formatApiSettingsPath(id string) string {
if len(id) == 0 {
return ""
}
return fmt.Sprintf("apis/%s/settings", id)
}

func apiScopesFor(scopes []string) []*management.ResourceServerScope {
models := []*management.ResourceServerScope{}

Expand Down
34 changes: 5 additions & 29 deletions internal/cli/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/auth0/auth0-cli/internal/ansi"
"github.com/auth0/auth0-cli/internal/auth0"
"github.com/auth0/auth0-cli/internal/open"
"github.com/auth0/auth0-cli/internal/prompt"
"github.com/spf13/cobra"
"gopkg.in/auth0.v5/management"
Expand All @@ -22,7 +21,6 @@ const (
appTypeRegularWeb = "regular_web"
appTypeNonInteractive = "non_interactive"
appDefaultURL = "http://localhost:3000"
manageDomain = "https://manage.auth0.com"
)

var (
Expand Down Expand Up @@ -669,7 +667,7 @@ func openAppCmd(cli *cli) *cobra.Command {
Args: cobra.MaximumNArgs(1),
Short: "Open application settings page in Auth0 Manage",
Long: "Open application settings page in Auth0 Manage.",
Example: `auth0 apps open <id>`,
Example: "auth0 apps open <id>",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from prev comment, If id could adopt different forms (I'm not sure) I'd suggest including some placeholders here in the example section.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do, thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with auth0 apps open <id|audience> in 62c64d5

PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
Expand All @@ -683,41 +681,19 @@ func openAppCmd(cli *cli) *cobra.Command {
inputs.ID = args[0]
}

manageUrl := formatManageURL(cli.config, inputs.ID)
if manageUrl == "" {
cli.renderer.Warnf("Unable to format the correct URL, please ensure you have run auth0 login and try again.")
return nil
}
if err := open.URL(manageUrl); err != nil {
cli.renderer.Warnf("Couldn't open the URL, please do it manually: %s.", manageUrl)
}
openManageURL(cli, cli.config.DefaultTenant, formatAppSettingsPath(inputs.ID))
return nil
},
}

return cmd
}

func formatManageURL(cfg config, id string) string {
if cfg.DefaultTenant == "" || id == "" {
return ""
}
// ex: dev-tti06f6y.us.auth0.com
s := strings.Split(cfg.DefaultTenant, ".")
if len(s) < 4 {
func formatAppSettingsPath(id string) string {
if len(id) == 0 {
return ""
}
region := s[len(s)-3]
tenant := cfg.Tenants[cfg.DefaultTenant].Name
if tenant == "" {
return ""
}
return fmt.Sprintf("%s/dashboard/%s/%s/applications/%s/settings",
manageDomain,
region,
tenant,
id,
)
return fmt.Sprintf("applications/%s/settings", id)
}

func apiTypeFor(v string) string {
Expand Down
72 changes: 72 additions & 0 deletions internal/cli/tenants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import (
"github.com/spf13/cobra"
)

var (
tenantDomain = Argument{
Name: "Tenant",
Help: "Tenant to select",
}
)

func tenantsCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "tenants",
Expand All @@ -17,6 +24,7 @@ func tenantsCmd(cli *cli) *cobra.Command {
cmd.SetUsageTemplate(resourceUsageTemplate())
cmd.AddCommand(useTenantCmd(cli))
cmd.AddCommand(listTenantCmd(cli))
cmd.AddCommand(openTenantCmd(cli))
return cmd
}

Expand Down Expand Up @@ -93,3 +101,67 @@ func useTenantCmd(cli *cli) *cobra.Command {

return cmd
}

func openTenantCmd(cli *cli) *cobra.Command {
var inputs struct {
Domain string
}

cmd := &cobra.Command{
Use: "open",
Args: cobra.MaximumNArgs(1),
Short: "Open tenant settings page in Auth0 Manage",
Long: "Open tenant settings page in Auth0 Manage.",
Example: "auth0 tenants open <tenant>",
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
err := tenantDomain.Pick(cmd, &inputs.Domain, cli.tenantPickerOptions)
if err != nil {
return err
}
} else {
inputs.Domain = args[0]

if _, ok := cli.config.Tenants[inputs.Domain]; !ok {
return fmt.Errorf("Unable to find tenant %s; run 'auth0 login' to configure a new tenant", inputs.Domain)
}
}

openManageURL(cli, inputs.Domain, "tenant/general")
return nil
},
}

return cmd
}

func (c *cli) tenantPickerOptions() (pickerOptions, error) {
tens, err := c.listTenants()
if err != nil {
return nil, fmt.Errorf("Unable to load tenants due to an unexpected error: %w", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

}

var (
priorityOpts, opts pickerOptions
)
Widcket marked this conversation as resolved.
Show resolved Hide resolved

for _, t := range tens {
opt := pickerOption{value: t.Domain, label: t.Domain}

// check if this is currently the default tenant.
if t.Domain == c.config.DefaultTenant {
priorityOpts = append(priorityOpts, opt)
} else {
opts = append(opts, opt)
}
}

if len(opts)+len(priorityOpts) == 0 {
return nil, errNoApps
}

return append(priorityOpts, opts...), nil
}
42 changes: 42 additions & 0 deletions internal/cli/utils_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cli
import (
"crypto/rand"
"fmt"
"strings"

"encoding/base64"
"encoding/json"
Expand All @@ -24,6 +25,7 @@ const (
cliLoginTestingCallbackURL string = "http://localhost:8484"
cliLoginTestingInitiateLoginURI string = "https://cli.auth0.com"
cliLoginTestingStateSize int = 64
manageURL string = "https://manage.auth0.com"
)

var (
Expand Down Expand Up @@ -272,3 +274,43 @@ func containsStr(s []interface{}, u string) bool {
}
return false
}

func openManageURL(cli *cli, tenant string, path string) {
manageTenantURL := formatManageTenantURL(tenant, cli.config)
if len(manageTenantURL) == 0 || len(path) == 0 {
cli.renderer.Warnf("Unable to format the correct URL, please ensure you have run 'auth0 login' and try again.")
return
}
if err := open.URL(fmt.Sprintf("%s%s", manageTenantURL, path)); err != nil {
cli.renderer.Warnf("Couldn't open the URL, please do it manually: %s.", manageTenantURL)
}
}

func formatManageTenantURL(tenant string, cfg config) string {
if len(tenant) == 0 {
return ""
}
// ex: dev-tti06f6y.us.auth0.com
s := strings.Split(tenant, ".")

if len(s) < 3 {
return ""
}

var region string
if len(s) == 3 { // It's a PUS1 tenant, ex: dev-tti06f6y.auth0.com
region = "us"
} else {
region = s[len(s)-3]
}

tenantName := cfg.Tenants[tenant].Name
if len(tenantName) == 0 {
return ""
}
return fmt.Sprintf("%s/dashboard/%s/%s/",
manageURL,
region,
tenantName,
)
}