✨ Añade pagetop-user, con autenticación y RBAC

Identidad de usuario, sesiones en base de datos, roles y permisos (RBAC)
con "authenticated" implícito, contraseñas con Argon2id, tokens de
un solo uso para verificación de email y restablecimiento de contraseña,
y la UI de administración completa (usuarios, roles, permisos) sobre
pagetop-admin.

Incluye datos de demostración opcionales tras la feature `demo-data`.
This commit is contained in:
Manuel Cillero 2026-08-28 20:59:17 +02:00
parent 043873a954
commit def0513246
57 changed files with 7409 additions and 0 deletions

View file

@ -0,0 +1,69 @@
//! Errores de `pagetop-user`.
use thiserror::Error;
#[derive(Debug, Error)]
pub enum AuthError {
#[error("invalid credentials")]
InvalidCredentials,
#[error("account is blocked")]
AccountBlocked,
#[error("account is pending email verification")]
AccountPending,
#[error("account is temporarily locked due to too many failed login attempts")]
AccountLocked,
#[error("password hashing failed: {0}")]
PasswordHash(String),
#[error("database error: {0}")]
Database(#[from] pagetop_seaorm::db::DbErr),
#[error("token is invalid or has expired")]
InvalidToken,
#[error("username is already taken")]
UsernameTaken,
#[error("email is already registered")]
EmailTaken,
#[error("passwords do not match")]
PasswordMismatch,
#[error("password must be at least {0} characters")]
PasswordTooShort(usize),
#[error("user not found")]
UserNotFound,
#[error("role not found")]
RoleNotFound,
#[error("role machine name is already taken")]
RoleMachineNameTaken,
#[error("role machine name must contain only lowercase letters, digits and underscores")]
InvalidMachineName,
#[error("role is locked and cannot be modified or deleted")]
RoleLocked,
#[error("role has users assigned and cannot be deleted")]
RoleInUse,
#[error("cannot remove the last administrator")]
LastAdministrator,
#[error("cannot block your own account")]
CannotBlockSelf,
#[error("cannot modify your own administrator flag")]
CannotModifyOwnAdminFlag,
#[error("unknown permission key: {0}")]
UnknownPermission(String),
}