forked from jiaoly/financial_system
241 lines
8.4 KiB
Python
241 lines
8.4 KiB
Python
from __future__ import annotations
|
||
|
||
from collections.abc import Generator
|
||
from typing import Callable
|
||
|
||
from fastapi import Depends, HTTPException
|
||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||
from sqlalchemy.orm import Session
|
||
|
||
from ..core.logger import AppLogger
|
||
from ..core.permissions import has_permission
|
||
from ..core.security import TokenError, decode_access_token
|
||
from ..core.settings import AppSettings, get_settings
|
||
from ..database import SessionLocal
|
||
from ..database.orm import UserORM
|
||
from ..repositories import (
|
||
CommissionRepository,
|
||
EmployeeRepository,
|
||
MonthlyPayrollRepository,
|
||
OperationLogRepository,
|
||
OrganizationRepository,
|
||
PayrollRepository,
|
||
RealtimeAttendanceRepository,
|
||
ReportRepository,
|
||
SalaryConfigRepository,
|
||
SalaryProfileRepository,
|
||
UserRepository,
|
||
)
|
||
from ..services import (
|
||
AuthService,
|
||
CommissionService,
|
||
EmployeeService,
|
||
MonthlyPayrollService,
|
||
OperationLogService,
|
||
OrganizationService,
|
||
PayrollApplicationService,
|
||
RealtimeAttendanceService,
|
||
ReportService,
|
||
SalaryConfigService,
|
||
SalaryProfileService,
|
||
)
|
||
from ..io.storage import FileStorage
|
||
|
||
bearer_scheme = HTTPBearer(auto_error=False)
|
||
logger = AppLogger.get_logger(__name__)
|
||
|
||
|
||
def get_db_session() -> Generator[Session, None, None]:
|
||
"""为单次 HTTP 请求提供数据库会话,并在请求结束后关闭。"""
|
||
session = SessionLocal()
|
||
try:
|
||
yield session
|
||
finally:
|
||
session.close()
|
||
|
||
|
||
def get_app_settings() -> AppSettings:
|
||
return get_settings()
|
||
|
||
|
||
def get_payroll_repository(session: Session = Depends(get_db_session)) -> PayrollRepository:
|
||
return PayrollRepository(session)
|
||
|
||
|
||
def get_monthly_payroll_repository(session: Session = Depends(get_db_session)) -> MonthlyPayrollRepository:
|
||
return MonthlyPayrollRepository(session)
|
||
|
||
|
||
def get_realtime_attendance_repository(session: Session = Depends(get_db_session)) -> RealtimeAttendanceRepository:
|
||
return RealtimeAttendanceRepository(session)
|
||
|
||
|
||
def get_commission_repository(session: Session = Depends(get_db_session)) -> CommissionRepository:
|
||
return CommissionRepository(session)
|
||
|
||
|
||
def get_employee_repository(session: Session = Depends(get_db_session)) -> EmployeeRepository:
|
||
return EmployeeRepository(session)
|
||
|
||
|
||
def get_report_repository(session: Session = Depends(get_db_session)) -> ReportRepository:
|
||
return ReportRepository(session)
|
||
|
||
|
||
def get_salary_config_repository(session: Session = Depends(get_db_session)) -> SalaryConfigRepository:
|
||
return SalaryConfigRepository(session)
|
||
|
||
|
||
def get_salary_profile_repository(session: Session = Depends(get_db_session)) -> SalaryProfileRepository:
|
||
return SalaryProfileRepository(session)
|
||
|
||
|
||
def get_user_repository(session: Session = Depends(get_db_session)) -> UserRepository:
|
||
return UserRepository(session)
|
||
|
||
|
||
def get_operation_log_repository(session: Session = Depends(get_db_session)) -> OperationLogRepository:
|
||
return OperationLogRepository(session)
|
||
|
||
|
||
def get_organization_repository(session: Session = Depends(get_db_session)) -> OrganizationRepository:
|
||
return OrganizationRepository(session)
|
||
|
||
|
||
def get_auth_service(
|
||
repository: UserRepository = Depends(get_user_repository),
|
||
settings: AppSettings = Depends(get_app_settings),
|
||
) -> AuthService:
|
||
return AuthService(repository=repository, settings=settings)
|
||
|
||
|
||
def get_operation_log_service(
|
||
repository: OperationLogRepository = Depends(get_operation_log_repository),
|
||
) -> OperationLogService:
|
||
return OperationLogService(repository=repository)
|
||
|
||
|
||
def get_organization_service(
|
||
repository: OrganizationRepository = Depends(get_organization_repository),
|
||
) -> OrganizationService:
|
||
return OrganizationService(repository=repository)
|
||
|
||
|
||
def get_employee_service(
|
||
repository: EmployeeRepository = Depends(get_employee_repository),
|
||
) -> EmployeeService:
|
||
return EmployeeService(repository=repository)
|
||
|
||
|
||
def get_salary_profile_service(
|
||
repository: SalaryProfileRepository = Depends(get_salary_profile_repository),
|
||
employee_repository: EmployeeRepository = Depends(get_employee_repository),
|
||
) -> SalaryProfileService:
|
||
return SalaryProfileService(repository=repository, employee_repository=employee_repository)
|
||
|
||
|
||
def get_commission_service(
|
||
repository: CommissionRepository = Depends(get_commission_repository),
|
||
employee_repository: EmployeeRepository = Depends(get_employee_repository),
|
||
settings: AppSettings = Depends(get_app_settings),
|
||
) -> CommissionService:
|
||
return CommissionService(
|
||
repository=repository,
|
||
employee_repository=employee_repository,
|
||
storage=FileStorage(settings),
|
||
)
|
||
|
||
|
||
def get_salary_config_service(
|
||
repository: SalaryConfigRepository = Depends(get_salary_config_repository),
|
||
) -> SalaryConfigService:
|
||
return SalaryConfigService(repository=repository)
|
||
|
||
|
||
def get_report_service(
|
||
repository: ReportRepository = Depends(get_report_repository),
|
||
) -> ReportService:
|
||
return ReportService(repository=repository)
|
||
|
||
|
||
def get_payroll_service(
|
||
repository: PayrollRepository = Depends(get_payroll_repository),
|
||
salary_repository: SalaryProfileRepository = Depends(get_salary_profile_repository),
|
||
commission_repository: CommissionRepository = Depends(get_commission_repository),
|
||
config_repository: SalaryConfigRepository = Depends(get_salary_config_repository),
|
||
settings: AppSettings = Depends(get_app_settings),
|
||
) -> PayrollApplicationService:
|
||
return PayrollApplicationService(
|
||
repository=repository,
|
||
settings=settings,
|
||
salary_repository=salary_repository,
|
||
commission_repository=commission_repository,
|
||
config_service=SalaryConfigService(config_repository),
|
||
)
|
||
|
||
|
||
def get_realtime_attendance_service(
|
||
repository: RealtimeAttendanceRepository = Depends(get_realtime_attendance_repository),
|
||
payroll_service: PayrollApplicationService = Depends(get_payroll_service),
|
||
) -> RealtimeAttendanceService:
|
||
return RealtimeAttendanceService(repository=repository, payroll_service=payroll_service)
|
||
|
||
|
||
def get_monthly_payroll_service(
|
||
repository: MonthlyPayrollRepository = Depends(get_monthly_payroll_repository),
|
||
payroll_service: PayrollApplicationService = Depends(get_payroll_service),
|
||
employee_repository: EmployeeRepository = Depends(get_employee_repository),
|
||
) -> MonthlyPayrollService:
|
||
return MonthlyPayrollService(
|
||
repository=repository,
|
||
payroll_service=payroll_service,
|
||
employee_repository=employee_repository,
|
||
)
|
||
|
||
|
||
def get_current_user(
|
||
credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
|
||
repository: UserRepository = Depends(get_user_repository),
|
||
settings: AppSettings = Depends(get_app_settings),
|
||
) -> UserORM:
|
||
"""解析 Bearer token,并返回仍然有效的当前用户。"""
|
||
if credentials is None:
|
||
logger.error("认证失败 reason=missing_bearer_token")
|
||
raise HTTPException(status_code=401, detail="请先登录")
|
||
try:
|
||
payload = decode_access_token(credentials.credentials, settings.auth_secret_key)
|
||
user_id = int(payload["sub"])
|
||
except (KeyError, TypeError, ValueError, TokenError) as exc:
|
||
logger.error("认证失败 reason=invalid_or_expired_token")
|
||
raise HTTPException(status_code=401, detail="登录状态无效或已过期") from exc
|
||
user = repository.get_by_id(user_id)
|
||
if user is None or not user.is_active:
|
||
logger.error("认证失败 user_id=%s reason=user_not_found_or_inactive", user_id)
|
||
raise HTTPException(status_code=401, detail="用户不存在或已停用")
|
||
logger.info("认证成功 user_id=%s username=%s role=%s", user.id, user.username, user.role)
|
||
return user
|
||
|
||
|
||
def require_permission(permission: str) -> Callable:
|
||
"""生成路由级权限依赖,让路由只声明所需权限。"""
|
||
def dependency(user: UserORM = Depends(get_current_user)) -> UserORM:
|
||
if not has_permission(user.role, permission):
|
||
logger.error(
|
||
"权限校验失败 user_id=%s username=%s role=%s permission=%s",
|
||
user.id,
|
||
user.username,
|
||
user.role,
|
||
permission,
|
||
)
|
||
raise HTTPException(status_code=403, detail="没有该操作权限")
|
||
logger.info(
|
||
"权限校验通过 user_id=%s username=%s role=%s permission=%s",
|
||
user.id,
|
||
user.username,
|
||
user.role,
|
||
permission,
|
||
)
|
||
return user
|
||
|
||
return dependency
|