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:
@@ -6,12 +6,16 @@ from typing import Callable, Sequence
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from config.database import SessionLocal
|
||||
from models import Scenario
|
||||
from models import Role, Scenario
|
||||
from services.repositories import (
|
||||
FinancialInputRepository,
|
||||
ProjectRepository,
|
||||
RoleRepository,
|
||||
ScenarioRepository,
|
||||
SimulationParameterRepository,
|
||||
UserRepository,
|
||||
ensure_admin_user as ensure_admin_user_record,
|
||||
ensure_default_roles,
|
||||
)
|
||||
from services.scenario_validation import ScenarioComparisonValidator
|
||||
|
||||
@@ -23,6 +27,12 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
self._session_factory = session_factory
|
||||
self.session: Session | None = None
|
||||
self._scenario_validator: ScenarioComparisonValidator | None = None
|
||||
self.projects: ProjectRepository | None = None
|
||||
self.scenarios: ScenarioRepository | None = None
|
||||
self.financial_inputs: FinancialInputRepository | None = None
|
||||
self.simulation_parameters: SimulationParameterRepository | None = None
|
||||
self.users: UserRepository | None = None
|
||||
self.roles: RoleRepository | None = None
|
||||
|
||||
def __enter__(self) -> "UnitOfWork":
|
||||
self.session = self._session_factory()
|
||||
@@ -31,6 +41,8 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
self.financial_inputs = FinancialInputRepository(self.session)
|
||||
self.simulation_parameters = SimulationParameterRepository(
|
||||
self.session)
|
||||
self.users = UserRepository(self.session)
|
||||
self.roles = RoleRepository(self.session)
|
||||
self._scenario_validator = ScenarioComparisonValidator()
|
||||
return self
|
||||
|
||||
@@ -42,6 +54,12 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
self.session.rollback()
|
||||
self.session.close()
|
||||
self._scenario_validator = None
|
||||
self.projects = None
|
||||
self.scenarios = None
|
||||
self.financial_inputs = None
|
||||
self.simulation_parameters = None
|
||||
self.users = None
|
||||
self.roles = None
|
||||
|
||||
def flush(self) -> None:
|
||||
if not self.session:
|
||||
@@ -61,7 +79,7 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
def validate_scenarios_for_comparison(
|
||||
self, scenario_ids: Sequence[int]
|
||||
) -> list[Scenario]:
|
||||
if not self.session or not self._scenario_validator:
|
||||
if not self.session or not self._scenario_validator or not self.scenarios:
|
||||
raise RuntimeError("UnitOfWork session is not initialised")
|
||||
|
||||
scenarios = [self.scenarios.get(scenario_id)
|
||||
@@ -75,3 +93,26 @@ class UnitOfWork(AbstractContextManager["UnitOfWork"]):
|
||||
if not self._scenario_validator:
|
||||
raise RuntimeError("UnitOfWork session is not initialised")
|
||||
self._scenario_validator.validate(scenarios)
|
||||
|
||||
def ensure_default_roles(self) -> list[Role]:
|
||||
if not self.roles:
|
||||
raise RuntimeError("UnitOfWork session is not initialised")
|
||||
return ensure_default_roles(self.roles)
|
||||
|
||||
def ensure_admin_user(
|
||||
self,
|
||||
*,
|
||||
email: str,
|
||||
username: str,
|
||||
password: str,
|
||||
) -> None:
|
||||
if not self.users or not self.roles:
|
||||
raise RuntimeError("UnitOfWork session is not initialised")
|
||||
ensure_default_roles(self.roles)
|
||||
ensure_admin_user_record(
|
||||
self.users,
|
||||
self.roles,
|
||||
email=email,
|
||||
username=username,
|
||||
password=password,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user