CLI delete account by username and delete posts

this changed the CLI flag to use the username instead of the userID
leaving the underlying database function as is.

also now posts are all deleted with no option to skip as this is likely
never needed.
This commit is contained in:
Rob Loranger 2019-11-05 09:14:20 -08:00
parent c87ca11a52
commit 41166e5c35
No known key found for this signature in database
GPG key ID: D6F1633A4F0903B8
4 changed files with 39 additions and 44 deletions

View file

@ -1069,6 +1069,6 @@ func getTempInfo(app *App, key string, r *http.Request, w http.ResponseWriter) s
return s return s
} }
func deleteAccount(app *App, userID int64, posts bool) error { func deleteAccount(app *App, userID int64) error {
return app.db.DeleteAccount(userID, posts) return app.db.DeleteAccount(userID)
} }

25
app.go
View file

@ -682,21 +682,24 @@ func ResetPassword(apper Apper, username string) error {
} }
// DoDeleteAccount runs the confirmation and account delete process. // DoDeleteAccount runs the confirmation and account delete process.
func DoDeleteAccount(apper Apper, userID int64, posts bool) error { func DoDeleteAccount(apper Apper, username string) error {
// Connect to the database // Connect to the database
apper.LoadConfig() apper.LoadConfig()
connectToDatabase(apper.App()) connectToDatabase(apper.App())
defer shutdown(apper.App()) defer shutdown(apper.App())
// do not delete the root admin account // check user exists
// TODO: check for other admins and skip? u, err := apper.App().db.GetUserForAuth(username)
if userID == 1 { if err != nil {
log.Error("Can not delete admin account") log.Error("%s", err)
os.Exit(1) os.Exit(1)
} }
// check user exists userID := u.ID
if _, err := apper.App().db.GetUserByID(userID); err != nil {
log.Error("%s", err) // do not delete the admin account
// TODO: check for other admins and skip?
if u.IsAdmin() {
log.Error("Can not delete admin account")
os.Exit(1) os.Exit(1)
} }
@ -705,17 +708,17 @@ func DoDeleteAccount(apper Apper, userID int64, posts bool) error {
Templates: &promptui.PromptTemplates{ Templates: &promptui.PromptTemplates{
Success: "{{ . | bold | faint }}: ", Success: "{{ . | bold | faint }}: ",
}, },
Label: fmt.Sprintf("Delete user with ID: %d", userID), Label: fmt.Sprintf("Really delete user : %s", username),
IsConfirm: true, IsConfirm: true,
} }
_, err := prompt.Run() _, err = prompt.Run()
if err != nil { if err != nil {
log.Info("Aborted...") log.Info("Aborted...")
os.Exit(0) os.Exit(0)
} }
log.Info("Deleting...") log.Info("Deleting...")
err = deleteAccount(apper.App(), userID, posts) err = deleteAccount(apper.App(), userID)
if err != nil { if err != nil {
log.Error("%s", err) log.Error("%s", err)
os.Exit(1) os.Exit(1)

View file

@ -39,8 +39,7 @@ func main() {
// Admin actions // Admin actions
createAdmin := flag.String("create-admin", "", "Create an admin with the given username:password") createAdmin := flag.String("create-admin", "", "Create an admin with the given username:password")
createUser := flag.String("create-user", "", "Create a regular user with the given username:password") createUser := flag.String("create-user", "", "Create a regular user with the given username:password")
deleteUserID := flag.Int64("delete-user", 0, "Delete a user with the given id, does not delete posts. Use `--delete-user id --posts`") deleteUsername := flag.String("delete-user", "", "Delete a user with the given username")
deletePosts := flag.Bool("posts", false, "Optionally delete the user's posts during account deletion")
resetPassUser := flag.String("reset-pass", "", "Reset the given user's password") resetPassUser := flag.String("reset-pass", "", "Reset the given user's password")
outputVersion := flag.Bool("v", false, "Output the current version") outputVersion := flag.Bool("v", false, "Output the current version")
flag.Parse() flag.Parse()
@ -105,8 +104,8 @@ func main() {
os.Exit(1) os.Exit(1)
} }
os.Exit(0) os.Exit(0)
} else if *deleteUserID != 0 { } else if *deleteUsername != "" {
err := writefreely.DoDeleteAccount(app, *deleteUserID, *deletePosts) err := writefreely.DoDeleteAccount(app, *deleteUsername)
if err != nil { if err != nil {
log.Error(err.Error()) log.Error(err.Error())
os.Exit(1) os.Exit(1)

View file

@ -61,7 +61,7 @@ type writestore interface {
GetAccessToken(userID int64) (string, error) GetAccessToken(userID int64) (string, error)
GetTemporaryAccessToken(userID int64, validSecs int) (string, error) GetTemporaryAccessToken(userID int64, validSecs int) (string, error)
GetTemporaryOneTimeAccessToken(userID int64, validSecs int, oneTime bool) (string, error) GetTemporaryOneTimeAccessToken(userID int64, validSecs int, oneTime bool) (string, error)
DeleteAccount(userID int64, posts bool) error DeleteAccount(userID int64) error
ChangeSettings(app *App, u *User, s *userSettings) error ChangeSettings(app *App, u *User, s *userSettings) error
ChangePassphrase(userID int64, sudo bool, curPass string, hashedPass []byte) error ChangePassphrase(userID int64, sudo bool, curPass string, hashedPass []byte) error
@ -2079,9 +2079,8 @@ func (db *datastore) CollectionHasAttribute(id int64, attr string) bool {
return true return true
} }
// DeleteAccount will delete the entire account for userID, and if posts // DeleteAccount will delete the entire account for userID
// is true, also all posts associated with the userID func (db *datastore) DeleteAccount(userID int64) error {
func (db *datastore) DeleteAccount(userID int64, posts bool) error {
// Get all collections // Get all collections
rows, err := db.Query("SELECT id, alias FROM collections WHERE owner_id = ?", userID) rows, err := db.Query("SELECT id, alias FROM collections WHERE owner_id = ?", userID)
if err != nil { if err != nil {
@ -2110,7 +2109,6 @@ func (db *datastore) DeleteAccount(userID int64, posts bool) error {
// Clean up all collection related information // Clean up all collection related information
var res sql.Result var res sql.Result
for _, c := range colls { for _, c := range colls {
// TODO: user deleteCollection() func
// Delete tokens // Delete tokens
res, err = t.Exec("DELETE FROM collectionattributes WHERE collection_id = ?", c.ID) res, err = t.Exec("DELETE FROM collectionattributes WHERE collection_id = ?", c.ID)
if err != nil { if err != nil {
@ -2151,18 +2149,15 @@ func (db *datastore) DeleteAccount(userID int64, posts bool) error {
rs, _ = res.RowsAffected() rs, _ = res.RowsAffected()
log.Info("Deleted %d for %s from collectionkeys", rs, c.Alias) log.Info("Deleted %d for %s from collectionkeys", rs, c.Alias)
// only remove collection in posts if not deleting the user posts // Float all collection's posts
if !posts { res, err = t.Exec("UPDATE posts SET collection_id = NULL WHERE collection_id = ? AND owner_id = ?", c.ID, userID)
// Float all collection's posts if err != nil {
res, err = t.Exec("UPDATE posts SET collection_id = NULL WHERE collection_id = ? AND owner_id = ?", c.ID, userID) t.Rollback()
if err != nil { log.Error("Unable to update collection %s for posts: %v", c.Alias, err)
t.Rollback() return err
log.Error("Unable to update collection %s for posts: %v", err)
return err
}
rs, _ = res.RowsAffected()
log.Info("Removed %d posts from collection %s", rs, c.Alias)
} }
rs, _ = res.RowsAffected()
log.Info("Removed %d posts from collection %s", rs, c.Alias)
// TODO: federate delete collection // TODO: federate delete collection
@ -2198,18 +2193,16 @@ func (db *datastore) DeleteAccount(userID int64, posts bool) error {
log.Info("Deleted %d from accesstokens", rs) log.Info("Deleted %d from accesstokens", rs)
// Delete posts // Delete posts
if posts { // TODO: should maybe get each row so we can federate a delete
// TODO: should maybe get each row so we can federate a delete // if so needs to be outside of transaction like collections
// if so needs to be outside of transaction like collections res, err = t.Exec("DELETE FROM posts WHERE owner_id = ?", userID)
res, err = t.Exec("DELETE FROM posts WHERE owner_id = ?", userID) if err != nil {
if err != nil { t.Rollback()
t.Rollback() log.Error("Unable to delete posts: %v", err)
log.Error("Unable to delete posts: %v", err) return err
return err
}
rs, _ = res.RowsAffected()
log.Info("Deleted %d from posts", rs)
} }
rs, _ = res.RowsAffected()
log.Info("Deleted %d from posts", rs)
// Delete user attributes // Delete user attributes
res, err = t.Exec("DELETE FROM userattributes WHERE user_id = ?", userID) res, err = t.Exec("DELETE FROM userattributes WHERE user_id = ?", userID)