90d0d10ee5
* Forums are disowned on user account deletion (their owner_id=0) * A forum without an owner shows a notice at the bottom with a link to petition to adopt the forum. It goes to the Contact form with a special subject. * Note: there is no easy way to re-assign ownership yet other than a direct database query. * Code cleanup * Alphabetize the DB.AutoMigrate tables. * Delete more things on user deletion: forum_memberships, admin_group_users * Vacuum worker to clean up orphaned polls after the threads are removed
111 lines
2.7 KiB
Go
111 lines
2.7 KiB
Go
package worker
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"code.nonshy.com/nonshy/website/pkg/log"
|
|
"code.nonshy.com/nonshy/website/pkg/models"
|
|
"code.nonshy.com/nonshy/website/pkg/photo"
|
|
)
|
|
|
|
// Vacuum runs database cleanup tasks for data consistency. Run it like `nonshy vacuum` from the CLI.
|
|
func Vacuum(dryrun bool) error {
|
|
|
|
var steps = []struct {
|
|
Label string
|
|
Fn func(bool) (int64, error)
|
|
}{
|
|
{"Comment Photos", VacuumOrphanedCommentPhotos},
|
|
{"Photos", VacuumOrphanedPhotos},
|
|
{"Polls", VacuumOrphanedPolls},
|
|
}
|
|
|
|
for _, step := range steps {
|
|
log.Warn("Vacuum: %s", step.Label)
|
|
if total, err := step.Fn(dryrun); err != nil {
|
|
log.Error("%s: %s", step.Label, err)
|
|
} else {
|
|
log.Info("Removed %d rows", total)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// VacuumOrphanedPolls removes any polls with forum threads no longer pointing to them.
|
|
func VacuumOrphanedPolls(dryrun bool) (int64, error) {
|
|
polls, count, err := models.GetOrphanedPolls()
|
|
if err != nil {
|
|
return count, err
|
|
}
|
|
|
|
if dryrun {
|
|
return count, nil
|
|
}
|
|
|
|
for _, row := range polls {
|
|
log.Info(" #%d: %s", row.ID, row.Choices)
|
|
if err := row.Delete(); err != nil {
|
|
return count, fmt.Errorf("deleting orphaned poll (%d): %s", row.ID, err)
|
|
}
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// VacuumOrphanedPhotos removes any lingering photo from failed account deletion.
|
|
func VacuumOrphanedPhotos(dryrun bool) (int64, error) {
|
|
photos, count, err := models.GetOrphanedPhotos()
|
|
if err != nil {
|
|
return count, err
|
|
}
|
|
|
|
if dryrun {
|
|
return count, nil
|
|
}
|
|
|
|
for _, row := range photos {
|
|
log.Info(" #%d: %s", row.ID, row.Filename)
|
|
if err := photo.Delete(row.Filename); err != nil {
|
|
return count, fmt.Errorf("photo ID %d: removing file %s: %s", row.ID, row.Filename, err)
|
|
}
|
|
|
|
if row.CroppedFilename != "" {
|
|
if err := photo.Delete(row.CroppedFilename); err != nil {
|
|
return count, fmt.Errorf("photo ID %d: removing file %s: %s", row.ID, row.Filename, err)
|
|
}
|
|
}
|
|
|
|
if err := row.Delete(); err != nil {
|
|
return count, fmt.Errorf("deleting orphaned photo (%d): %s", row.ID, err)
|
|
}
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// VacuumOrphanedCommentPhotos cleans up comment photos that weren't associated to a post, returning the count removed.
|
|
func VacuumOrphanedCommentPhotos(dryrun bool) (int64, error) {
|
|
// Do the needful.
|
|
photos, total, err := models.GetOrphanedCommentPhotos()
|
|
if err != nil {
|
|
return total, err
|
|
}
|
|
|
|
if dryrun {
|
|
return total, nil
|
|
}
|
|
|
|
for _, row := range photos {
|
|
if err := photo.Delete(row.Filename); err != nil {
|
|
return total, fmt.Errorf("photo ID %d: removing file %s: %s", row.ID, row.Filename, err)
|
|
}
|
|
|
|
if err := row.Delete(); err != nil {
|
|
return total, fmt.Errorf("deleting orphaned comment photo (%d): %s", row.ID, err)
|
|
}
|
|
}
|
|
|
|
return total, nil
|
|
}
|