From 8997f54a8c8d49ade7cd374e4d5e7bef453e50a3 Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Tue, 22 Nov 2022 13:32:29 +0100 Subject: [PATCH] Add drupal_user command --- cmd/drupal_user.go | 76 +++++++++++++++++++ cmd/wdcli/main.go | 1 + .../wisski/ingredient/barrel/drush/user.go | 41 ++++++++++ 3 files changed, 118 insertions(+) create mode 100644 cmd/drupal_user.go create mode 100644 internal/wisski/ingredient/barrel/drush/user.go diff --git a/cmd/drupal_user.go b/cmd/drupal_user.go new file mode 100644 index 0000000..be99450 --- /dev/null +++ b/cmd/drupal_user.go @@ -0,0 +1,76 @@ +package cmd + +import ( + wisski_distillery "github.com/FAU-CDI/wisski-distillery" + "github.com/FAU-CDI/wisski-distillery/internal/cli" + "github.com/FAU-CDI/wisski-distillery/internal/wisski" + "github.com/tkw1536/goprogram/exit" +) + +// DrupalUser is the 'drupal_user' setting +var DrupalUser wisski_distillery.Command = duser{} + +type duser struct { + Passwd bool `short:"p" long:"password" description:"reset password for user"` + Login bool `short:"l" long:"login" description:"print url to login as"` + Positionals struct { + Slug string `positional-arg-name:"SLUG" required:"1-1" description:"slug of instance to manage"` + User string `positional-arg-name:"USER" description:"username to manage"` + } `positional-args:"true"` +} + +func (duser) Description() wisski_distillery.Description { + return wisski_distillery.Description{ + Requirements: cli.Requirements{ + NeedsDistillery: true, + }, + Command: "drupal_user", + Description: "set a password for a specific user", + } +} + +var errPasswordsNotIdentical = exit.Error{ + Message: "Passwords are not identical", + ExitCode: exit.ExitGeneric, +} + +func (du duser) Run(context wisski_distillery.Context) error { + instance, err := context.Environment.Instances().WissKI(du.Positionals.Slug) + if err != nil { + return err + } + + if du.Passwd { + return du.resetPassword(context, instance) + } + return du.login(context, instance) +} + +func (du duser) login(context wisski_distillery.Context, instance *wisski.WissKI) error { + link, err := instance.Drush().Login(context.IOStream, du.Positionals.User) + if err != nil { + return err + } + context.Println(link) + return nil +} + +func (du duser) resetPassword(context wisski_distillery.Context, instance *wisski.WissKI) error { + context.Printf("Enter new password for user %s:", du.Positionals.User) + passwd1, err := context.IOStream.ReadPassword() + if err != nil { + return err + } + + context.Printf("Enter the same password again:") + passwd2, err := context.IOStream.ReadPassword() + if err != nil { + return err + } + + if passwd1 != passwd2 { + return errPasswordsNotIdentical + } + + return instance.Drush().ResetPassword(context.IOStream, du.Positionals.User, passwd1) +} diff --git a/cmd/wdcli/main.go b/cmd/wdcli/main.go index 391aeb7..53de0af 100644 --- a/cmd/wdcli/main.go +++ b/cmd/wdcli/main.go @@ -48,6 +48,7 @@ func init() { wdcli.Register(cmd.Pathbuilders) wdcli.Register(cmd.Prefixes) wdcli.Register(cmd.DrupalSetting) + wdcli.Register(cmd.DrupalUser) // backup & cron wdcli.Register(cmd.Snapshot) diff --git a/internal/wisski/ingredient/barrel/drush/user.go b/internal/wisski/ingredient/barrel/drush/user.go new file mode 100644 index 0000000..1745489 --- /dev/null +++ b/internal/wisski/ingredient/barrel/drush/user.go @@ -0,0 +1,41 @@ +package drush + +import ( + "strings" + + "github.com/alessio/shellescape" + "github.com/tkw1536/goprogram/exit" + "github.com/tkw1536/goprogram/stream" +) + +var errLoginFailed = exit.Error{ + Message: "Failed to login", + ExitCode: exit.ExitGeneric, +} + +// Login generates a one-time login url for the given user +func (drush *Drush) Login(io stream.IOStream, user string) (string, error) { + var builder strings.Builder + + url := drush.Liquid.URL().String() + command := shellescape.QuoteCommand([]string{"drush", "user:login", "--name=" + user, "--no-browser", "--uri=" + url}) + + code, err := drush.Barrel.Shell(io.Streams(&builder, nil, nil, 0), "-c", command) + if code != 0 || err != nil { + return "", errLoginFailed + } + return strings.TrimSpace(builder.String()), nil +} + +var errSetPasswordFailed = exit.Error{ + Message: "Failed to set password", + ExitCode: exit.ExitGeneric, +} + +func (drush *Drush) ResetPassword(io stream.IOStream, user, password string) error { + code, err := drush.Barrel.Shell(io, "-c", "drush", "user:password", user, password) + if code != 0 || err != nil { + return errSetPasswordFailed + } + return nil +}