Skip to content
Permalink
Browse files

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.
  • Loading branch information
robjloranger committed Nov 5, 2019
1 parent c87ca11 commit 41166e5c356df10d36237e9296979cae65652504
Showing with 39 additions and 44 deletions.
  1. +2 −2 account.go
  2. +14 −11 app.go
  3. +3 −4 cmd/writefreely/main.go
  4. +20 −27 database.go
@@ -1069,6 +1069,6 @@ func getTempInfo(app *App, key string, r *http.Request, w http.ResponseWriter) s
return s
}

func deleteAccount(app *App, userID int64, posts bool) error {
return app.db.DeleteAccount(userID, posts)
func deleteAccount(app *App, userID int64) error {
return app.db.DeleteAccount(userID)
}
25 app.go
@@ -682,40 +682,43 @@ func ResetPassword(apper Apper, username string) error {
}

// 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
apper.LoadConfig()
connectToDatabase(apper.App())
defer shutdown(apper.App())

// do not delete the root admin account
// TODO: check for other admins and skip?
if userID == 1 {
log.Error("Can not delete admin account")
os.Exit(1)
}
// check user exists
if _, err := apper.App().db.GetUserByID(userID); err != nil {
u, err := apper.App().db.GetUserForAuth(username)
if err != nil {
log.Error("%s", err)
os.Exit(1)
}
userID := u.ID

// 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)
}

// confirm deletion, w/ w/out posts
prompt := promptui.Prompt{
Templates: &promptui.PromptTemplates{
Success: "{{ . | bold | faint }}: ",
},
Label: fmt.Sprintf("Delete user with ID: %d", userID),
Label: fmt.Sprintf("Really delete user : %s", username),
IsConfirm: true,
}
_, err := prompt.Run()
_, err = prompt.Run()
if err != nil {
log.Info("Aborted...")
os.Exit(0)
}

log.Info("Deleting...")
err = deleteAccount(apper.App(), userID, posts)
err = deleteAccount(apper.App(), userID)
if err != nil {
log.Error("%s", err)
os.Exit(1)
@@ -39,8 +39,7 @@ func main() {
// Admin actions
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")
deleteUserID := flag.Int64("delete-user", 0, "Delete a user with the given id, does not delete posts. Use `--delete-user id --posts`")
deletePosts := flag.Bool("posts", false, "Optionally delete the user's posts during account deletion")
deleteUsername := flag.String("delete-user", "", "Delete a user with the given username")
resetPassUser := flag.String("reset-pass", "", "Reset the given user's password")
outputVersion := flag.Bool("v", false, "Output the current version")
flag.Parse()
@@ -105,8 +104,8 @@ func main() {
os.Exit(1)
}
os.Exit(0)
} else if *deleteUserID != 0 {
err := writefreely.DoDeleteAccount(app, *deleteUserID, *deletePosts)
} else if *deleteUsername != "" {
err := writefreely.DoDeleteAccount(app, *deleteUsername)
if err != nil {
log.Error(err.Error())
os.Exit(1)
@@ -61,7 +61,7 @@ type writestore interface {
GetAccessToken(userID int64) (string, error)
GetTemporaryAccessToken(userID int64, validSecs int) (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
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
}

// DeleteAccount will delete the entire account for userID, and if posts
// is true, also all posts associated with the userID
func (db *datastore) DeleteAccount(userID int64, posts bool) error {
// DeleteAccount will delete the entire account for userID
func (db *datastore) DeleteAccount(userID int64) error {
// Get all collections
rows, err := db.Query("SELECT id, alias FROM collections WHERE owner_id = ?", userID)
if err != nil {
@@ -2110,7 +2109,6 @@ func (db *datastore) DeleteAccount(userID int64, posts bool) error {
// Clean up all collection related information
var res sql.Result
for _, c := range colls {
// TODO: user deleteCollection() func
// Delete tokens
res, err = t.Exec("DELETE FROM collectionattributes WHERE collection_id = ?", c.ID)
if err != nil {
@@ -2151,18 +2149,15 @@ func (db *datastore) DeleteAccount(userID int64, posts bool) error {
rs, _ = res.RowsAffected()
log.Info("Deleted %d for %s from collectionkeys", rs, c.Alias)

// only remove collection in posts if not deleting the user posts
if !posts {
// Float all collection's posts
res, err = t.Exec("UPDATE posts SET collection_id = NULL WHERE collection_id = ? AND owner_id = ?", c.ID, userID)
if err != nil {
t.Rollback()
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)
// Float all collection's posts
res, err = t.Exec("UPDATE posts SET collection_id = NULL WHERE collection_id = ? AND owner_id = ?", c.ID, userID)
if err != nil {
t.Rollback()
log.Error("Unable to update collection %s for posts: %v", c.Alias, err)
return err
}
rs, _ = res.RowsAffected()
log.Info("Removed %d posts from collection %s", rs, c.Alias)

// TODO: federate delete collection

@@ -2198,18 +2193,16 @@ func (db *datastore) DeleteAccount(userID int64, posts bool) error {
log.Info("Deleted %d from accesstokens", rs)

// Delete posts
if posts {
// TODO: should maybe get each row so we can federate a delete
// if so needs to be outside of transaction like collections
res, err = t.Exec("DELETE FROM posts WHERE owner_id = ?", userID)
if err != nil {
t.Rollback()
log.Error("Unable to delete posts: %v", err)
return err
}
rs, _ = res.RowsAffected()
log.Info("Deleted %d from posts", rs)
// TODO: should maybe get each row so we can federate a delete
// if so needs to be outside of transaction like collections
res, err = t.Exec("DELETE FROM posts WHERE owner_id = ?", userID)
if err != nil {
t.Rollback()
log.Error("Unable to delete posts: %v", err)
return err
}
rs, _ = res.RowsAffected()
log.Info("Deleted %d from posts", rs)

// Delete user attributes
res, err = t.Exec("DELETE FROM userattributes WHERE user_id = ?", userID)

0 comments on commit 41166e5

Please sign in to comment.
You can’t perform that action at this time.