From 6d450e825f3de8ddb5fca2550640bed5caaa3054 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Fri, 26 Feb 2021 13:18:24 -0300 Subject: [PATCH] Add apps update --- internal/cli/apis.go | 2 +- internal/cli/apps.go | 119 +++++++++++++++++++++++++++++++++--- internal/display/clients.go | 29 ++++++--- 3 files changed, 133 insertions(+), 17 deletions(-) diff --git a/internal/cli/apis.go b/internal/cli/apis.go index 019517252..a2abe1cc8 100644 --- a/internal/cli/apis.go +++ b/internal/cli/apis.go @@ -265,7 +265,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) + mustRequireFlags(cmd, apiID) return cmd } diff --git a/internal/cli/apps.go b/internal/cli/apps.go index 999fb63b7..33047e09f 100644 --- a/internal/cli/apps.go +++ b/internal/cli/apps.go @@ -28,6 +28,7 @@ func appsCmd(cli *cli) *cobra.Command { cmd.SetUsageTemplate(resourceUsageTemplate()) cmd.AddCommand(listAppsCmd(cli)) cmd.AddCommand(createAppCmd(cli)) + cmd.AddCommand(updateAppCmd(cli)) cmd.AddCommand(deleteAppCmd(cli)) return cmd @@ -54,7 +55,7 @@ Lists your existing applications. To create one try: return err } - cli.renderer.ClientList(list.Clients) + cli.renderer.ApplicationList(list.Clients) return nil }, } @@ -120,6 +121,9 @@ func createAppCmd(cli *cli) *cobra.Command { auth0 apps create --name myapp --type [native|spa|regular|m2m] `, + PreRun: func(cmd *cobra.Command, args []string) { + prepareInteractivity(cmd) + }, RunE: func(cmd *cobra.Command, args []string) error { if shouldPrompt(cmd, appName) { input := prompt.TextInput( @@ -149,17 +153,14 @@ auth0 apps create --name myapp --type [native|spa|regular|m2m] } if shouldPrompt(cmd, appDescription) { - input := prompt.TextInput( - appDescription, "Description:", - "Description of the application.", - false) + input := prompt.TextInput(appDescription, "Description:", "Description of the application.", false) if err := prompt.AskOne(input, &flags); err != nil { return err } } - c := &management.Client{ + a := &management.Client{ Name: &flags.Name, Description: &flags.Description, AppType: auth0.String(apiTypeFor(flags.Type)), @@ -168,7 +169,7 @@ auth0 apps create --name myapp --type [native|spa|regular|m2m] } err := ansi.Spinner("Creating application", func() error { - return cli.api.Client.Create(c) + return cli.api.Client.Create(a) }) if err != nil { @@ -176,8 +177,8 @@ auth0 apps create --name myapp --type [native|spa|regular|m2m] } // note: c is populated with the rest of the client fields by the API during creation. - revealClientSecret := auth0.StringValue(c.AppType) != "native" && auth0.StringValue(c.AppType) != "spa" - cli.renderer.ClientCreate(c, revealClientSecret) + revealClientSecret := auth0.StringValue(a.AppType) != "native" && auth0.StringValue(a.AppType) != "spa" + cli.renderer.ApplicationCreate(a, revealClientSecret) return nil }, @@ -197,6 +198,106 @@ auth0 apps create --name myapp --type [native|spa|regular|m2m] return cmd } +func updateAppCmd(cli *cli) *cobra.Command { + var flags struct { + ID string + Name string + Type string + Description string + Callbacks []string + AuthMethod string + } + + cmd := &cobra.Command{ + Use: "create", + Short: "Update a new application", + Long: `Update a new application: + +auth0 apps update --id id --name myapp --type [native|spa|regular|m2m] +`, + PreRun: func(cmd *cobra.Command, args []string) { + prepareInteractivity(cmd) + }, + RunE: func(cmd *cobra.Command, args []string) error { + if shouldPrompt(cmd, appID) { + input := prompt.TextInput(appID, "Id:", "Id of the application.", true) + + if err := prompt.AskOne(input, &flags); err != nil { + return err + } + } + + if shouldPrompt(cmd, appName) { + input := prompt.TextInput(appName, "Name:", "Name of the application", true) + + if err := prompt.AskOne(input, &flags); err != nil { + return err + } + } + + if shouldPrompt(cmd, appType) { + input := prompt.SelectInput( + appType, + "Type:", + "\n- Native: Mobile, desktop, CLI and smart device apps running natively."+ + "\n- Single Page Web Application: A JavaScript front-end app that uses an API."+ + "\n- Regular Web Application: Traditional web app using redirects."+ + "\n- Machine To Machine: CLIs, daemons or services running on your backend.", + []string{"Native", "Single Page Web Application", "Regular Web Application", "Machine to Machine"}, + true) + + if err := prompt.AskOne(input, &flags); err != nil { + return err + } + } + + if shouldPrompt(cmd, appDescription) { + input := prompt.TextInput(appDescription, "Description:", "Description of the application.", false) + + if err := prompt.AskOne(input, &flags); err != nil { + return err + } + } + + a := &management.Client{ + Name: &flags.Name, + Description: &flags.Description, + AppType: auth0.String(apiTypeFor(flags.Type)), + Callbacks: apiCallbacksFor(flags.Callbacks), + TokenEndpointAuthMethod: apiAuthMethodFor(flags.AuthMethod), + } + + err := ansi.Spinner("Updating application", func() error { + return cli.api.Client.Update(flags.ID, c) + }) + + if err != nil { + return err + } + + // note: c is populated with the rest of the client fields by the API during creation. + revealClientSecret := auth0.StringValue(a.AppType) != "native" && auth0.StringValue(a.AppType) != "spa" + cli.renderer.ApplicationUpdate(a, revealClientSecret) + + return nil + }, + } + + cmd.Flags().StringVarP(&flags.ID, appID, "i", "", "ID of the application.") + cmd.Flags().StringVarP(&flags.Name, "name", "n", "", "Name of the application.") + cmd.Flags().StringVarP(&flags.Type, "type", "t", "", "Type of application:\n"+ + "- native: mobile, desktop, CLI and smart device apps running natively.\n"+ + "- spa (single page application): a JavaScript front-end app that uses an API.\n"+ + "- regular: Traditional web app using redirects.\n"+ + "- m2m (machine to machine): CLIs, daemons or services running on your backend.") + cmd.Flags().StringVarP(&flags.Description, "description", "d", "", "Description of the application. Max character count is 140.") + cmd.Flags().StringSliceVarP(&flags.Callbacks, "callbacks", "c", nil, "After the user authenticates we will only call back to any of these URLs. You can specify multiple valid URLs by comma-separating them (typically to handle different environments like QA or testing). Make sure to specify the protocol (https://) otherwise the callback may fail in some cases. With the exception of custom URI schemes for native apps, all callbacks should use protocol https://.") + cmd.Flags().StringVar(&flags.AuthMethod, "auth-method", "", "Defines the requested authentication method for the token endpoint. Possible values are 'None' (public application without a client secret), 'Post' (application uses HTTP POST parameters) or 'Basic' (application uses HTTP Basic).") + mustRequireFlags(cmd, appID) + + return cmd +} + func apiTypeFor(v string) string { switch strings.ToLower(v) { case "native": diff --git a/internal/display/clients.go b/internal/display/clients.go index 25391fcb1..face736cd 100644 --- a/internal/display/clients.go +++ b/internal/display/clients.go @@ -53,8 +53,8 @@ func (v *clientView) AsTableRow() []string { } -func (r *Renderer) ClientList(clients []*management.Client) { - r.Heading(ansi.Bold(r.Tenant), "clients\n") +func (r *Renderer) ApplicationList(clients []*management.Client) { + r.Heading(ansi.Bold(r.Tenant), "applications\n") var res []View for _, c := range clients { if auth0.StringValue(c.Name) == deprecatedAppName { @@ -62,7 +62,7 @@ func (r *Renderer) ClientList(clients []*management.Client) { } res = append(res, &clientView{ Name: auth0.StringValue(c.Name), - Type: appTypeFor(c.AppType), + Type: typeFor(c.AppType), ClientID: auth0.StringValue(c.ClientID), ClientSecret: auth0.StringValue(c.ClientSecret), Callbacks: callbacksFor(c.Callbacks), @@ -72,15 +72,15 @@ func (r *Renderer) ClientList(clients []*management.Client) { r.Results(res) } -func (r *Renderer) ClientCreate(client *management.Client, revealSecrets bool) { - r.Heading(ansi.Bold(r.Tenant), "client created\n") +func (r *Renderer) ApplicationCreate(client *management.Client, revealSecrets bool) { + r.Heading(ansi.Bold(r.Tenant), "application created\n") // note(jfatta): list and create uses the same view for now, // eventually we might want to show different columns for each command: v := &clientView{ revealSecret: revealSecrets, Name: auth0.StringValue(client.Name), - Type: appTypeFor(client.AppType), + Type: typeFor(client.AppType), ClientID: auth0.StringValue(client.ClientID), ClientSecret: auth0.StringValue(client.ClientSecret), Callbacks: callbacksFor(client.Callbacks), @@ -91,10 +91,25 @@ func (r *Renderer) ClientCreate(client *management.Client, revealSecrets bool) { r.Infof("\nQuickstarts: %s", quickstartsURIFor(client.AppType)) } +func (r *Renderer) ApplicationUpdate(client *management.Client, revealSecrets bool) { + r.Heading(ansi.Bold(r.Tenant), "application updated\n") + + v := &clientView{ + revealSecret: revealSecrets, + Name: auth0.StringValue(client.Name), + Type: typeFor(client.AppType), + ClientID: auth0.StringValue(client.ClientID), + ClientSecret: auth0.StringValue(client.ClientSecret), + Callbacks: callbacksFor(client.Callbacks), + } + + r.Results([]View{v}) +} + // TODO(cyx): determine if there's a better way to filter this out. const deprecatedAppName = "All Applications" -func appTypeFor(v *string) string { +func typeFor(v *string) string { switch { case v == nil: return "generic"