website/pkg/models/deletion/delete_user.go
Noah 49ffa277e8 User Account Busywork
* Add "forgot password" workflow.
* Add ability to change user email address (confirmation link sent)
* Add ability to change user's password.
* Add rate limiter to deter brute force login attempts.
* Add user deep delete functionality (delete account).
* Ping user LastLoginAt every 8 hours for long-lived session cookies.
* Add age filters to user search page.
* Add sort options to user search (last login, created, username/name)
2022-08-14 14:40:57 -07:00

124 lines
2.9 KiB
Go

package deletion
import (
"fmt"
"git.kirsle.net/apps/gosocial/pkg/log"
"git.kirsle.net/apps/gosocial/pkg/models"
"git.kirsle.net/apps/gosocial/pkg/photo"
)
// DeleteUser wipes a user and all associated data from the database.
func DeleteUser(user *models.User) error {
log.Error("BEGIN DeleteUser(%d, %s)", user.ID, user.Username)
// Remove all linked tables and assets.
type remover struct {
Step string
Fn func(uint64) error
}
var todo = []remover{
{"Photos", DeleteUserPhotos},
{"Certification Photo", DeleteCertification},
{"Messages", DeleteUserMessages},
{"Friends", DeleteFriends},
{"Profile Fields", DeleteProfile},
}
for _, item := range todo {
if err := item.Fn(user.ID); err != nil {
return fmt.Errorf("%s: %s", item.Step, err)
}
}
// Remove the user itself.
return user.Delete()
}
// DeleteUserPhotos scrubs data for deleting a user.
func DeleteUserPhotos(userID uint64) error {
log.Error("DeleteUser: BEGIN DeleteUserPhotos(%d)", userID)
// Deeply scrub all user photos.
pager := &models.Pagination{
Page: 1,
PerPage: 20,
Sort: "photos.id",
}
for {
photos, err := models.PaginateUserPhotos(
userID,
models.PhotoVisibilityAll,
true,
pager,
)
if err != nil {
return err
}
if len(photos) == 0 {
break
}
for _, item := range photos {
log.Warn("DeleteUserPhotos(%d): remove file %s", userID, item.Filename)
photo.Delete(item.Filename)
if item.CroppedFilename != "" {
log.Warn("DeleteUserPhotos(%d): remove file %s", userID, item.CroppedFilename)
photo.Delete(item.CroppedFilename)
}
if err := item.Delete(); err != nil {
return err
}
}
}
log.Error("DeleteUser: END DeleteUserPhotos(%d)", userID)
return nil
}
// DeleteCertification scrubs data for deleting a user.
func DeleteCertification(userID uint64) error {
log.Error("DeleteUser: DeleteCertification(%d)", userID)
if cert, err := models.GetCertificationPhoto(userID); err == nil {
if cert.Filename != "" {
log.Warn("DeleteCertification(%d): remove file %s", userID, cert.Filename)
photo.Delete(cert.Filename)
}
return cert.Delete()
}
return nil
}
// DeleteUserMessages scrubs data for deleting a user.
func DeleteUserMessages(userID uint64) error {
log.Error("DeleteUser: DeleteUserMessages(%d)", userID)
result := models.DB.Where(
"source_user_id = ? OR target_user_id = ?",
userID, userID,
).Delete(&models.Message{})
return result.Error
}
// DeleteFriends scrubs data for deleting a user.
func DeleteFriends(userID uint64) error {
log.Error("DeleteUser: DeleteUserFriends(%d)", userID)
result := models.DB.Where(
"source_user_id = ? OR target_user_id = ?",
userID, userID,
).Delete(&models.Friend{})
return result.Error
}
// DeleteProfile scrubs data for deleting a user.
func DeleteProfile(userID uint64) error {
log.Error("DeleteUser: DeleteProfile(%d)", userID)
result := models.DB.Where(
"user_id = ?",
userID,
).Delete(&models.ProfileField{})
return result.Error
}