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

+80
View File
@@ -6,6 +6,8 @@ import (
"RenewCMS/internal/infrastructure/useCases"
"errors"
"sort"
"strings"
"sync"
"testing"
"time"
)
@@ -58,6 +60,7 @@ type mockUserRepo struct {
beforeTransfer func()
beforeClearVerification func()
knownRoles *mockRoleRepo
confirmLock sync.Mutex
}
func newMockUserRepo() *mockUserRepo {
@@ -80,6 +83,8 @@ func (m *mockUserRepo) sortedIds() []uint32 {
}
func (m *mockUserRepo) Get(id uint32) (user.User, error) {
m.confirmLock.Lock()
defer m.confirmLock.Unlock()
m.getCalls++
if err := m.fail.trigger("Get"); err != nil {
return user.User{}, err
@@ -117,6 +122,81 @@ func (m *mockUserRepo) GetByEmail(email string) (user.User, error) {
return user.User{}, user.ErrUserNotFound
}
func (m *mockUserRepo) IsEmailInUse(email string, exceptUserId uint32) (bool, error) {
m.confirmLock.Lock()
defer m.confirmLock.Unlock()
return m.emailInUse(email, exceptUserId)
}
func (m *mockUserRepo) emailInUse(email string, exceptUserId uint32) (bool, error) {
if err := m.fail.trigger("IsEmailInUse"); err != nil {
return false, err
}
for id, stored := range m.users {
if id != exceptUserId && strings.EqualFold(stored.Email, email) {
return true, nil
}
}
return false, nil
}
func (m *mockUserRepo) SetPendingEmailChange(userId uint32, pendingEmail string, code string, expiration time.Time) (user.User, error) {
if err := m.fail.trigger("SetPendingEmailChange"); err != nil {
return user.User{}, err
}
stored, ok := m.users[userId]
if !ok {
return user.User{}, user.ErrUserNotFound
}
stored.PendingEmail = pendingEmail
stored.EmailChangeCode = code
stored.EmailChangeExpiration = expiration
m.users[userId] = stored
return stored, nil
}
func (m *mockUserRepo) ClearPendingEmailChange(userId uint32) (user.User, error) {
if err := m.fail.trigger("ClearPendingEmailChange"); err != nil {
return user.User{}, err
}
stored, ok := m.users[userId]
if !ok {
return user.User{}, user.ErrUserNotFound
}
stored.PendingEmail = ""
stored.EmailChangeCode = ""
stored.EmailChangeExpiration = time.Time{}
m.users[userId] = stored
return stored, nil
}
func (m *mockUserRepo) ConfirmEmailChange(userId uint32, pendingEmail string, code string, now time.Time) (user.User, error) {
m.confirmLock.Lock()
defer m.confirmLock.Unlock()
if err := m.fail.trigger("ConfirmEmailChange"); err != nil {
return user.User{}, err
}
stored, ok := m.users[userId]
if !ok {
return user.User{}, user.ErrUserNotFound
}
if stored.PendingEmail != pendingEmail || stored.EmailChangeCode != code || !now.Before(stored.EmailChangeExpiration) {
return user.User{}, user.ErrInvalidEmailChangeCode
}
taken, _ := m.emailInUse(pendingEmail, userId)
if !taken {
stored.Email = pendingEmail
}
stored.PendingEmail = ""
stored.EmailChangeCode = ""
stored.EmailChangeExpiration = time.Time{}
m.users[userId] = stored
if taken {
return user.User{}, user.ErrEmailUnavailable
}
return stored, nil
}
func (m *mockUserRepo) GetAll() ([]user.User, error) {
m.getAllCalls++
if err := m.fail.trigger("GetAll"); err != nil {