This commit is contained in:
2026-10-03 13:22:11 +07:00
parent 05090722a0
commit 2caa2c1a88
74 changed files with 44 additions and 676 deletions
+1 -27
View File
@@ -30,10 +30,6 @@ func NewUserRepo(pool *pgxpool.Pool) *UsersRepo {
}
}
// AddUserWithAgreements создаёт пользователя и фиксирует акцепты документов
// (user_agreements) в одной транзакции: пользователь либо существует вместе с
// записями о согласиях, либо не существует вовсе (доказуемое согласие,
// ст. 9 152-ФЗ). Возвращает id созданного пользователя.
func (s *UsersRepo) AddUserWithAgreements(
ctx context.Context,
username string,
@@ -42,8 +38,6 @@ func (s *UsersRepo) AddUserWithAgreements(
roles []string,
agreements []user_agreements_repo.Agreement,
) (int, error) {
// Инвариант «пользователь не существует без записей о согласиях»
// держится на том, что акцепты передаются всегда.
if len(agreements) == 0 {
return 0, errors.New("Не переданы записи об акцепте соглашений")
}
@@ -73,15 +67,11 @@ func (s *UsersRepo) AddUserWithAgreements(
email,
).Scan(&id)
if err != nil {
// Ничего не вставлено — занят username или email.
if errors.Is(err, pgx.ErrNoRows) {
return 0, errors.New("Username или email уже используется")
}
// Гонка: между проверкой NOT EXISTS и INSERT другой запрос успел
// создать пользователя с тем же username/email — нарушение
// уникальности. Возвращаем тот же понятный клиенту ответ.
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "23505" { // нарушение уникальности
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
return 0, errors.New("Username или email уже используется")
}
return 0, err
@@ -266,12 +256,6 @@ func (s *UsersRepo) DeleteUserRole(
return err
}
// DeleteUser удаляет учётную запись и персональные данные пользователя
// (ст. 21 152-ФЗ — уничтожение ПДн при удалении аккаунта). Выполняется в одной
// транзакции. Публичный контент пользователя (сценарии, команды) сохраняется:
// FK-ограничения с ON DELETE SET NULL (миграция
// 20260818232725_keep_content_on_user_delete.sql) обнуляют привязку к автору —
// контент остаётся в обезличенном виде.
func (s *UsersRepo) DeleteUser(
ctx context.Context,
userID int,
@@ -282,7 +266,6 @@ func (s *UsersRepo) DeleteUser(
}
defer tx.Rollback(ctx) //nolint:errcheck
// Refresh-токены (FK CASCADE, удаляем явно для предсказуемости).
if _, err = tx.Exec(
ctx,
`DELETE FROM refresh_tokens WHERE user_id = $1`,
@@ -291,13 +274,6 @@ func (s *UsersRepo) DeleteUser(
return err
}
// Зафиксированные акцепты соглашений НЕ удаляются: ст. 9 ч. 4 152-ФЗ
// возлагает на оператора бремя доказывания получения согласия, поэтому
// факт акцепта (документ, версия, время) сохраняется в обезличенном виде:
// ссылка на пользователя и персональные данные внутри записи (ip,
// user_agent) обнуляются. FK ON DELETE SET NULL (миграция
// 20260818231943_create_user_agreements_table.sql) гарантирует, что при
// удалении users строки акцептов остаются с user_id = NULL.
if _, err = tx.Exec(
ctx,
`UPDATE user_agreements
@@ -308,8 +284,6 @@ func (s *UsersRepo) DeleteUser(
return err
}
// Пользователь. Связанные сценарии (author_id) и команды (creator_id)
// обнуляются автоматически через ON DELETE SET NULL.
tag, err := tx.Exec(
ctx,
`DELETE FROM users WHERE id = $1`,