-
Notifications
You must be signed in to change notification settings - Fork 55
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
Refactor apps [CLI-15] #111
Merged
Merged
Changes from 7 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
ae526b5
Cleanup apps commands
Widcket b1990b1
Refactor delete command
Widcket 0648f13
Refactor the create command
Widcket 6d450e8
Add apps update
Widcket 702f0bc
Fix identifier name
Widcket 55c2bb0
Fix command name
Widcket a6d3430
Fix test
Widcket 47b5645
Rename typeFor to appTypeFor
Widcket File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,7 +144,7 @@ auth0 apis create --name myapi --identifier http://my-api | |
if shouldPrompt(cmd, apiName) { | ||
input := prompt.TextInput( | ||
apiName, "Name:", | ||
"Name of the API. You can change the API name later in the API settings.", | ||
"Name of the API. You can change the name later in the API settings.", | ||
true) | ||
|
||
if err := prompt.AskOne(input, &flags); err != nil { | ||
|
@@ -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 | ||
} | ||
|
@@ -300,15 +300,9 @@ auth0 apis delete --id id | |
} | ||
} | ||
|
||
err := ansi.Spinner("Deleting API", func() error { | ||
return ansi.Spinner("Deleting API", func() error { | ||
return cli.api.ResourceServer.Delete(flags.ID) | ||
}) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
Comment on lines
-303
to
-311
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #winning |
||
}, | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,344 @@ | ||
package cli | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/auth0/auth0-cli/internal/ansi" | ||
"github.com/auth0/auth0-cli/internal/auth0" | ||
"github.com/auth0/auth0-cli/internal/prompt" | ||
"github.com/spf13/cobra" | ||
"gopkg.in/auth0.v5/management" | ||
) | ||
|
||
const ( | ||
appID = "id" | ||
appName = "name" | ||
appType = "type" | ||
appDescription = "description" | ||
) | ||
|
||
func appsCmd(cli *cli) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "apps", | ||
Short: "Manage resources for applications", | ||
Aliases: []string{"clients"}, | ||
} | ||
|
||
cmd.SetUsageTemplate(resourceUsageTemplate()) | ||
cmd.AddCommand(listAppsCmd(cli)) | ||
cmd.AddCommand(createAppCmd(cli)) | ||
cmd.AddCommand(updateAppCmd(cli)) | ||
cmd.AddCommand(deleteAppCmd(cli)) | ||
|
||
return cmd | ||
} | ||
|
||
func listAppsCmd(cli *cli) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "list", | ||
Short: "List your applications", | ||
Long: `auth0 apps list | ||
Lists your existing applications. To create one try: | ||
|
||
auth0 apps create | ||
`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
var list *management.ClientList | ||
err := ansi.Spinner("Loading applications", func() error { | ||
var err error | ||
list, err = cli.api.Client.List() | ||
return err | ||
}) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
cli.renderer.ApplicationList(list.Clients) | ||
return nil | ||
}, | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
func deleteAppCmd(cli *cli) *cobra.Command { | ||
var flags struct { | ||
ID string | ||
} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "delete", | ||
Short: "Delete an application", | ||
Long: `Delete an application: | ||
|
||
auth0 apps delete --id id | ||
`, | ||
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 !cli.force && canPrompt(cmd) { | ||
if confirmed := prompt.Confirm("Are you sure you want to proceed?"); !confirmed { | ||
return nil | ||
} | ||
} | ||
|
||
return ansi.Spinner("Deleting application", func() error { | ||
return cli.api.Client.Delete(flags.ID) | ||
}) | ||
}, | ||
} | ||
|
||
cmd.Flags().StringVarP(&flags.ID, appID, "i", "", "ID of the application.") | ||
mustRequireFlags(cmd, appID) | ||
|
||
return cmd | ||
} | ||
|
||
func createAppCmd(cli *cli) *cobra.Command { | ||
var flags struct { | ||
Name string | ||
Type string | ||
Description string | ||
Callbacks []string | ||
AuthMethod string | ||
} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "create", | ||
Short: "Create a new application", | ||
Long: `Create a new application: | ||
|
||
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( | ||
appName, "Name:", | ||
"Name of the application. You can change the name later in the application settings.", | ||
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("Creating application", func() error { | ||
return cli.api.Client.Create(a) | ||
}) | ||
|
||
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.ApplicationCreate(a, revealClientSecret) | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
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, appName, appType) | ||
|
||
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: "update", | ||
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, a) | ||
}) | ||
|
||
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": | ||
return "native" | ||
case "spa", "single page web application": | ||
return "spa" | ||
case "regular", "regular web application": | ||
return "regular_web" | ||
case "m2m", "machine to machine": | ||
return "non_interactive" | ||
|
||
default: | ||
return v | ||
} | ||
} | ||
|
||
func apiCallbacksFor(s []string) []interface{} { | ||
res := make([]interface{}, len(s)) | ||
for i, v := range s { | ||
res[i] = v | ||
} | ||
return res | ||
} | ||
|
||
func apiAuthMethodFor(v string) *string { | ||
switch strings.ToLower(v) { | ||
case "none": | ||
return auth0.String("none") | ||
case "post": | ||
return auth0.String("client_secret_post") | ||
case "basic": | ||
return auth0.String("client_secret_basic") | ||
default: | ||
return nil | ||
} | ||
} | ||
|
||
func callbacksFor(s []interface{}) []string { | ||
res := make([]string, len(s)) | ||
for i, v := range s { | ||
res[i] = fmt.Sprintf("%s", v) | ||
} | ||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: we don't need apiName because it's optional for creation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's optional for
update
(you can update any property). For create it's required.