From ac921f9f4bac16683345f1aad637fbb24846a046 Mon Sep 17 00:00:00 2001 From: Marcel van der Boom Date: Tue, 4 Aug 2020 13:48:59 +0200 Subject: [PATCH] Add user silencing to CLI interface --- app.go | 45 +++++++++++++++++++++++++++++++++++++++++ cmd/writefreely/main.go | 7 +++++++ cmd/writefreely/user.go | 19 +++++++++++++++++ database.go | 28 +++++++++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/app.go b/app.go index 2ba43fc..5fd926b 100644 --- a/app.go +++ b/app.go @@ -747,6 +747,51 @@ func DoDeleteAccount(apper Apper, username string) error { return nil } +func DoSilenceAccount(apper Apper, username string) error { + // Connect to the database + apper.LoadConfig() + connectToDatabase(apper.App()) + defer shutdown(apper.App()) + + // check user exists + u, err := apper.App().db.GetUserForAuth(username) + if err != nil { + log.Error("%s", err) + os.Exit(1) + } + userID := u.ID + + // do not silence the admin account + // TODO: check for other admins and skip? + if u.IsAdmin() { + log.Error("Can not silence admin account") + os.Exit(1) + } + + // confirm deletion, w/ w/out posts + prompt := promptui.Prompt{ + Templates: &promptui.PromptTemplates{ + Success: "{{ . | bold | faint }}: ", + }, + Label: fmt.Sprintf("Really silence user : %s", username), + IsConfirm: true, + } + _, err = prompt.Run() + if err != nil { + log.Info("Aborted...") + os.Exit(0) + } + + log.Info("Silencing...") + err = apper.App().db.SilenceAccount(userID) + if err != nil { + log.Error("%s", err) + os.Exit(1) + } + log.Info("Success.") + return nil +} + func connectToDatabase(app *App) { log.Info("Connecting to %s database...", app.cfg.Database.Type) diff --git a/cmd/writefreely/main.go b/cmd/writefreely/main.go index 45dfb80..d424dd8 100644 --- a/cmd/writefreely/main.go +++ b/cmd/writefreely/main.go @@ -85,6 +85,11 @@ func main() { Usage: "Delete a user with the given username", Hidden: true, }, + &cli.StringFlag{ + Name: "silence-user", + Usage: "Silence a user with the given username", + Hidden: true, + }, &cli.StringFlag{ Name: "reset-pass", Usage: "Reset the given user's password", @@ -152,6 +157,8 @@ func legacyActions(c *cli.Context) error { return writefreely.CreateUser(app, username, password, false) case c.IsSet("delete-user"): return writefreely.DoDeleteAccount(app, c.String("delete-user")) + case c.IsSet("silence-user"): + return writefreely.DoSilenceAccount(app, c.String("silence-user")) case c.IsSet("reset-pass"): return writefreely.ResetPassword(app, c.String("reset-pass")) } diff --git a/cmd/writefreely/user.go b/cmd/writefreely/user.go index 58ecbfb..ff1ceae 100644 --- a/cmd/writefreely/user.go +++ b/cmd/writefreely/user.go @@ -25,6 +25,7 @@ var ( Subcommands: []*cli.Command{ &cmdAddUser, &cmdDelUser, + &cmdSilenceUser, &cmdResetPass, // TODO: possibly add a user list command }, @@ -51,6 +52,13 @@ var ( Action: delUserAction, } + cmdSilenceUser cli.Command = cli.Command{ + Name: "silence", + Usage: "Silence user", + Aliases: []string{"sil", "s"}, + Action: silenceUserAction, + } + cmdResetPass cli.Command = cli.Command{ Name: "reset-pass", Usage: "Reset user's password", @@ -85,6 +93,17 @@ func delUserAction(c *cli.Context) error { return writefreely.DoDeleteAccount(app, username) } +func silenceUserAction(c *cli.Context) error { + username := "" + if c.NArg() > 0 { + username = c.Args().Get(0) + } else { + return fmt.Errorf("No user passed. Example: writefreely user silence [USER]") + } + app := writefreely.NewApp(c.String("c")) + return writefreely.DoSilenceAccount(app, username) +} + func resetPassAction(c *cli.Context) error { username := "" if c.NArg() > 0 { diff --git a/database.go b/database.go index 6f97d8c..bd06d85 100644 --- a/database.go +++ b/database.go @@ -68,6 +68,7 @@ type writestore interface { GetTemporaryAccessToken(userID int64, validSecs int) (string, error) GetTemporaryOneTimeAccessToken(userID int64, validSecs int, oneTime bool) (string, error) DeleteAccount(userID int64) error + SilenceAccount(userID int64) error ChangeSettings(app *App, u *User, s *userSettings) error ChangePassphrase(userID int64, sudo bool, curPass string, hashedPass []byte) error @@ -2329,6 +2330,33 @@ func (db *datastore) DeleteAccount(userID int64) error { return nil } +func (db *datastore) SilenceAccount(userID int64) error { + // Start transaction + t, err := db.Begin() + if err != nil { + log.Error("Unable to begin: %v", err) + return err + } + + // Update user state + _, err = t.Exec("UPDATE users SET state=1 WHERE id=?", userID) + if err != nil { + t.Rollback() + return fmt.Errorf("Unable to update user state: %s", err) + } + + // Commit all changes to the database + err = t.Commit() + if err != nil { + t.Rollback() + log.Error("Unable to commit: %v", err) + return err + } + + // TODO: federate delete actor here too? + return nil +} + func (db *datastore) GetAPActorKeys(collectionID int64) ([]byte, []byte) { var pub, priv []byte err := db.QueryRow("SELECT public_key, private_key FROM collectionkeys WHERE collection_id = ?", collectionID).Scan(&pub, &priv)