From fb10f29e2b31a431ad68e240c228cb3d30a9a007 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 13 Mar 2023 23:26:12 +0100 Subject: [PATCH] feat: add clean db script --- backend/db/user.go | 5 ++ scripts/cleandb/main.go | 109 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 scripts/cleandb/main.go diff --git a/backend/db/user.go b/backend/db/user.go index bfb268a..eb3a7ae 100644 --- a/backend/db/user.go +++ b/backend/db/user.go @@ -55,6 +55,11 @@ const ( MaxLinkLength = 256 ) +const ( + SelfDeleteAfter = 30 * 24 * time.Hour + ModDeleteAfter = 180 * 24 * time.Hour +) + // CreateUser creates a user with the given username. func (db *DB) CreateUser(ctx context.Context, tx pgx.Tx, username string) (u User, err error) { // check if the username is valid diff --git a/scripts/cleandb/main.go b/scripts/cleandb/main.go new file mode 100644 index 0000000..8fa2089 --- /dev/null +++ b/scripts/cleandb/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "context" + "fmt" + "os" + "time" + + dbpkg "codeberg.org/u1f320/pronouns.cc/backend/db" + "github.com/georgysavva/scany/pgxscan" + "github.com/joho/godotenv" + "github.com/rs/xid" +) + +func main() { + err := godotenv.Load() + if err != nil { + fmt.Println("error loading .env file:", err) + os.Exit(1) + } + + ctx := context.Background() + + db, err := dbpkg.New() + if err != nil { + fmt.Println("error opening database:", err) + os.Exit(1) + } + defer db.Close() + + fmt.Println("opened database") + + fmt.Println("deleting invalidated tokens") + + ct, err := db.Exec(ctx, "DELETE FROM tokens WHERE invalidated = true OR expires < $1", time.Now()) + if err != nil { + fmt.Println("executing query:", err) + os.Exit(1) + } + + fmt.Printf("deleted %v invalidated or expired tokens\n", ct.RowsAffected()) + + var users []dbpkg.User + err = pgxscan.Select(ctx, db, &users, `SELECT * FROM users WHERE + deleted_at IS NOT NULL AND + (self_delete = true AND deleted_at < $1) + OR (self_delete = false AND deleted_at < $2) + ORDER BY id`, time.Now().Add(-dbpkg.SelfDeleteAfter), time.Now().Add(-dbpkg.ModDeleteAfter)) + if err != nil { + fmt.Println("error getting to-be-deleted users:", err) + os.Exit(1) + } + + if len(users) == 0 { + fmt.Println("there are no users pending deletion") + os.Exit(0) + } + + for _, u := range users { + members, err := db.UserMembers(ctx, u.ID) + if err != nil { + fmt.Printf("error getting members for user %v: %v\n", u.ID, err) + continue + } + + for _, m := range members { + if m.Avatar == nil { + continue + } + + fmt.Printf("deleting avatars for member %v\n", m.ID) + + err = db.DeleteMemberAvatar(ctx, m.ID, *m.Avatar) + if err != nil { + fmt.Printf("error deleting avatars for member %v: %v", m.ID, err) + continue + } + + fmt.Printf("deleted avatars for member %v\n", m.ID) + } + + if u.Avatar == nil { + continue + } + + fmt.Printf("deleting avatars for user %v\n", u.ID) + + err = db.DeleteUserAvatar(ctx, u.ID, *u.Avatar) + if err != nil { + fmt.Printf("error deleting avatars for user %v: %v", u.ID, err) + continue + } + + fmt.Printf("deleted avatars for user %v\n", u.ID) + } + + ids := make([]xid.ID, len(users)) + for _, u := range users { + ids = append(ids, u.ID) + } + + ct, err = db.Exec(ctx, "DELETE FROM users WHERE id = ANY($1)", ids) + if err != nil { + fmt.Printf("error deleting users: %v\n", err) + os.Exit(1) + } + + fmt.Printf("deleted %v users!\n", ct.RowsAffected()) +}