Noah Petherbridge
0caf12eb00
* 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)
124 lines
2.9 KiB
Go
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
|
|
}
|