feat: Implement user and role management with repositories
- Added RoleRepository and UserRepository for managing roles and users. - Implemented methods for creating, retrieving, and assigning roles to users. - Introduced functions to ensure default roles and an admin user exist in the system. - Updated UnitOfWork to include user and role repositories. - Created new security module for password hashing and JWT token management. - Added tests for authentication flows, including registration, login, and password reset. - Enhanced HTML templates for user registration, login, and password management with error handling. - Added a logo image to the static assets.
This commit is contained in:
67
schemas/auth.py
Normal file
67
schemas/auth.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, ValidationInfo, field_validator
|
||||
|
||||
|
||||
class FormModel(BaseModel):
|
||||
"""Base Pydantic model for HTML form submissions."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
|
||||
|
||||
|
||||
class RegistrationForm(FormModel):
|
||||
username: str = Field(min_length=3, max_length=128)
|
||||
email: str = Field(min_length=5, max_length=255)
|
||||
password: str = Field(min_length=8, max_length=256)
|
||||
confirm_password: str
|
||||
|
||||
@field_validator("email")
|
||||
@classmethod
|
||||
def validate_email(cls, value: str) -> str:
|
||||
if "@" not in value or value.startswith("@") or value.endswith("@"):
|
||||
raise ValueError("Invalid email address.")
|
||||
local, domain = value.split("@", 1)
|
||||
if not local or "." not in domain:
|
||||
raise ValueError("Invalid email address.")
|
||||
return value.lower()
|
||||
|
||||
@field_validator("confirm_password")
|
||||
@classmethod
|
||||
def passwords_match(cls, value: str, info: ValidationInfo) -> str:
|
||||
password = info.data.get("password")
|
||||
if password != value:
|
||||
raise ValueError("Passwords do not match.")
|
||||
return value
|
||||
|
||||
|
||||
class LoginForm(FormModel):
|
||||
username: str = Field(min_length=1, max_length=255)
|
||||
password: str = Field(min_length=1, max_length=256)
|
||||
|
||||
|
||||
class PasswordResetRequestForm(FormModel):
|
||||
email: str = Field(min_length=5, max_length=255)
|
||||
|
||||
@field_validator("email")
|
||||
@classmethod
|
||||
def validate_email(cls, value: str) -> str:
|
||||
if "@" not in value or value.startswith("@") or value.endswith("@"):
|
||||
raise ValueError("Invalid email address.")
|
||||
local, domain = value.split("@", 1)
|
||||
if not local or "." not in domain:
|
||||
raise ValueError("Invalid email address.")
|
||||
return value.lower()
|
||||
|
||||
|
||||
class PasswordResetForm(FormModel):
|
||||
token: str = Field(min_length=1)
|
||||
password: str = Field(min_length=8, max_length=256)
|
||||
confirm_password: str
|
||||
|
||||
@field_validator("confirm_password")
|
||||
@classmethod
|
||||
def reset_passwords_match(cls, value: str, info: ValidationInfo) -> str:
|
||||
password = info.data.get("password")
|
||||
if password != value:
|
||||
raise ValueError("Passwords do not match.")
|
||||
return value
|
||||
Reference in New Issue
Block a user