From e90e9ab2d4b9aba860c26512486c3d6eca058c24 Mon Sep 17 00:00:00 2001 From: CURZOLA Pierre Date: Fri, 9 Feb 2024 18:15:56 +0100 Subject: [PATCH] feat(cmd): add database user password update --- cmd/commands.go | 1 + cmd/databases.go | 37 ++++++++++++++++++++++++ db/users/update.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 db/users/update.go diff --git a/cmd/commands.go b/cmd/commands.go index 18c2327b2..e1c43c734 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -250,6 +250,7 @@ var ( &databaseListUsers, &databaseDeleteUser, &databaseCreateUser, + &databaseUpdateUserPassword, // Maintenance &databaseMaintenanceList, diff --git a/cmd/databases.go b/cmd/databases.go index a81a856a7..dd630ba2d 100644 --- a/cmd/databases.go +++ b/cmd/databases.go @@ -242,6 +242,43 @@ Only available on ` + fmt.Sprintf("%s", dbUsers.SupportedAddons), return nil }, } + databaseUpdateUserPassword = cli.Command{ + Name: "database-users-update-password", + Aliases: []string{"database-update-user-password"}, + Category: "Addons", + ArgsUsage: "user", + Usage: "Update a database user's password", + Flags: []cli.Flag{ + &appFlag, + &addonFlag, + }, + Description: CommandDescription{ + Description: `Update a non-protected database user's password. + +Only available on ` + fmt.Sprintf("%s", dbUsers.SupportedAddons), + Examples: []string{ + "scalingo --app myapp --addon addon-uuid database-users-update-password my_user", + }, + }.Render(), + + Action: func(c *cli.Context) error { + if c.NArg() < 1 { + return cli.ShowCommandHelp(c, "database-users-update-password") + } + + currentApp := detect.CurrentApp(c) + utils.CheckForConsent(c.Context, currentApp, utils.ConsentTypeDBs) + addonName := addonUUIDFromFlags(c, currentApp, true) + + username := c.Args().First() + + err := dbUsers.UpdateUser(c.Context, currentApp, addonName, username) + if err != nil { + errorQuit(c.Context, err) + } + return nil + }, + } ) func parseScheduleAtFlag(flag string) (int, *time.Location, error) { diff --git a/db/users/update.go b/db/users/update.go new file mode 100644 index 000000000..b1f6d2a3a --- /dev/null +++ b/db/users/update.go @@ -0,0 +1,70 @@ +package users + +import ( + "context" + "fmt" + + "github.com/Scalingo/cli/config" + "github.com/Scalingo/cli/io" + "github.com/Scalingo/go-scalingo/v6" + "github.com/Scalingo/go-utils/errors/v2" + "github.com/Scalingo/gopassword" +) + +func UpdateUser(ctx context.Context, app, addonUUID, username string) error { + isSupported, err := doesDatabaseHandleUserManagement(ctx, app, addonUUID) + if err != nil { + return errors.Wrap(ctx, err, "get user management information") + } + + if !isSupported { + io.Error(ErrDatabaseNotSupportUserManagement) + return nil + } + + if usernameValidation, ok := isUsernameValid(username); !ok { + io.Error(usernameValidation) + return nil + } + + password, confirmedPassword, err := askForPassword(ctx) + if err != nil { + return errors.Wrap(ctx, err, "ask for password") + } + + passwordValidation, ok := isPasswordValid(password, confirmedPassword) + if !ok && password != "" { + io.Error(passwordValidation) + return nil + } + + isPasswordGenerated := false + if password == "" { + isPasswordGenerated = true + password = gopassword.Generate(64) + confirmedPassword = password + } + + c, err := config.ScalingoClient(ctx) + if err != nil { + return errors.Wrap(ctx, err, "get Scalingo client") + } + + user := scalingo.DatabaseUpdateUserParam{ + DatabaseID: addonUUID, + Password: password, + PasswordConfirmation: confirmedPassword, + } + databaseUsers, err := c.DatabaseUpdateUser(ctx, app, addonUUID, username, user) + if err != nil { + return errors.Wrap(ctx, err, "update password of the given database user") + } + + if isPasswordGenerated { + fmt.Printf("User \"%s\" updated with password \"%s\".\n", databaseUsers.Name, password) + return nil + } + + fmt.Printf("User \"%s\" password updated.\n", databaseUsers.Name) + return nil +}