feat: change email, export my data, delete account (with data anonymization)

This commit is contained in:
Florian Sylvain committed 2026-10-30 20:19:07 +01:00
1 parent bb191c389a
commit 10a66cd979
123 files changed
+10789 -76

No files matched your search

+81
View File
@@ -0,0 +1,81 @@
package test
import (
"RenewCMS/internal/domain/user"
entity "RenewCMS/internal/infrastructure/persistence/models"
persistence "RenewCMS/internal/infrastructure/persistence/repositories"
"errors"
"testing"
"gorm.io/gorm"
)
func failAccountDeleteKeyRemoval(t *testing.T, db *gorm.DB, name string, failure error) {
t.Helper()
err := db.Callback().Delete().Before("gorm:delete").Register(name, func(tx *gorm.DB) {
if tx.Statement.Table == "api_keys" {
_ = tx.AddError(failure)
}
})
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = db.Callback().Delete().Remove(name) })
}
func TestAccountDeleteContentionMapping(t *testing.T) {
cases := []struct {
name string
failure string
guards []uint32
notDeletable bool
}{
{"locked database with a guard role", "database is locked", []uint32{8}, true},
{"sqlite busy with a guard role", "SQLITE_BUSY: x", []uint32{8}, true},
{"deadlock with a guard role", "Deadlock found when trying to get lock", []uint32{8}, true},
{"serialization failure with a guard role", "could not serialize access", []uint32{8}, true},
{"locked database without a guard role", "database is locked", nil, false},
{"unrelated failure with a guard role", "disk exploded", []uint32{8}, false},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
db := openContractSQLite(t)
seedDeleteAccountRows(t, db, true)
failure := errors.New(tc.failure)
failAccountDeleteKeyRemoval(t, db, "test:account_delete_contention", failure)
err := persistence.NewAccountEraser(db).Erase(user.Erasure{UserID: 7, GuardRoleIDs: tc.guards})
if errors.Is(err, user.ErrAccountNotDeletable) != tc.notDeletable {
t.Errorf("ErrAccountNotDeletable = %v, want %v (err %v)", !tc.notDeletable, tc.notDeletable, err)
}
if !tc.notDeletable && !errors.Is(err, failure) {
t.Errorf("expected the original failure, got %v", err)
}
if deleteAccountRowCount(t, db, &entity.User{}, "id = ?", 7) != 1 {
t.Error("the user must still exist after a failed erasure")
}
})
}
}
func TestAccountDeleteSQLiteTakesTheWriteLockBeforeCounting(t *testing.T) {
db := openContractSQLite(t)
seedDeleteAccountRows(t, db, true)
roleWrites := 0
err := db.Callback().Update().Before("gorm:update").Register("test:account_delete_role_writes", func(tx *gorm.DB) {
if tx.Statement.Table == "roles" {
roleWrites++
}
})
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = db.Callback().Update().Remove("test:account_delete_role_writes") })
err = persistence.NewAccountEraser(db).Erase(user.Erasure{UserID: 7, GuardRoleIDs: []uint32{8}})
if err != nil || roleWrites != 1 {
t.Errorf("expected one lock write on the guard roles and no error, got %d writes and %v", roleWrites, err)
}
}