From 2da388df2e84bc466a61431b6a29fb08b014019a Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 10 Sep 2023 17:44:35 +0200 Subject: [PATCH] add username cleanup --- backend/db/user.go | 21 +++++++++++++++++++++ scripts/cleandb/main.go | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/backend/db/user.go b/backend/db/user.go index 80d380d..57e0a71 100644 --- a/backend/db/user.go +++ b/backend/db/user.go @@ -825,3 +825,24 @@ func (db *DB) CleanUser(ctx context.Context, id xid.ID) error { } return nil } + +const inactiveUsersSQL = `select id, snowflake_id from users +where last_active < now() - '30 days'::interval +and display_name is null and bio is null and timezone is null +and links is null and avatar is null and member_title is null +and names = '[]' and pronouns = '[]' +and (select count(m.id) from members m where user_id = users.id) = 0 +and (select count(f.id) from user_fields f where user_id = users.id) = 0;` + +// InactiveUsers gets the list of inactive users from the database. +// "Inactive" is defined as: +// - not logged in for 30 days or more +// - no display name, bio, avatar, names, pronouns, profile links, or profile fields +// - no members +func (db *DB) InactiveUsers(ctx context.Context, tx pgx.Tx) (us []User, err error) { + err = pgxscan.Select(ctx, tx, &us, inactiveUsersSQL) + if err != nil { + return nil, errors.Wrap(err, "executing query") + } + return us, nil +} diff --git a/scripts/cleandb/main.go b/scripts/cleandb/main.go index 994671b..317951b 100644 --- a/scripts/cleandb/main.go +++ b/scripts/cleandb/main.go @@ -3,6 +3,7 @@ package cleandb import ( "context" "fmt" + "os" "time" dbpkg "codeberg.org/pronounscc/pronouns.cc/backend/db" @@ -25,6 +26,8 @@ func run(c *cli.Context) error { return err } + changeUnusedUsernames := os.Getenv("DB_CLEAN_CHANGE_UNUSED_USERNAMES") == "true" + ctx := context.Background() db, err := dbpkg.New() @@ -66,6 +69,41 @@ func run(c *cli.Context) error { fmt.Printf("deleted %v expired exports\n", len(exports)) + if changeUnusedUsernames { + fmt.Println("cleaning unused usernames") + + tx, err := db.Begin(ctx) + if err != nil { + fmt.Printf("error starting transaction: %v\n", err) + return err + } + defer tx.Rollback(ctx) + + inactiveUsers, err := db.InactiveUsers(ctx, tx) + if err != nil { + fmt.Printf("getting inactive users: %v\n", err) + return err + } + + for _, u := range inactiveUsers { + err = db.UpdateUsername(ctx, tx, u.ID, fmt.Sprintf("inactive-user-%v", u.SnowflakeID)) + if err != nil { + fmt.Printf("changing username for user %v: %v\n", u.SnowflakeID, err) + return err + } + } + + err = tx.Commit(ctx) + if err != nil { + fmt.Printf("committing transaction: %v\n", err) + return err + } + + fmt.Printf("changed usernames for %v inactive users\n", len(inactiveUsers)) + } else { + fmt.Println("not cleaning unused usernames") + } + var users []dbpkg.User err = pgxscan.Select(ctx, db, &users, `SELECT * FROM users WHERE deleted_at IS NOT NULL AND @@ -78,7 +116,7 @@ func run(c *cli.Context) error { } if len(users) == 0 { - fmt.Println("there are no users pending deletion") + fmt.Println("there are no users pending deletion\nfinished cleaning database!") return nil } @@ -132,5 +170,6 @@ func run(c *cli.Context) error { } fmt.Printf("deleted %v users!\n", ct.RowsAffected()) + fmt.Println("finished cleaning database!") return nil }