Add service platform foundation
This commit is contained in:
@@ -6,7 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.config import settings
|
||||
from app.db.session import get_session
|
||||
from app.models.car import Car
|
||||
from app.models.car import AuditLog, Car, ServiceCenter, ServiceEmployee, VehicleAccess
|
||||
from app.models.user import User
|
||||
from app.services.telegram_auth import verify_webapp_init_data
|
||||
|
||||
@@ -20,6 +20,7 @@ async def get_or_create_telegram_user(
|
||||
last_name: str | None = None,
|
||||
locale: str | None = None,
|
||||
currency: str | None = None,
|
||||
platform_role: str | None = None,
|
||||
) -> User:
|
||||
result = await session.execute(select(User).where(User.telegram_id == telegram_id))
|
||||
user = result.scalar_one_or_none()
|
||||
@@ -30,6 +31,7 @@ async def get_or_create_telegram_user(
|
||||
"last_name": last_name,
|
||||
"locale": locale,
|
||||
"currency": currency,
|
||||
"platform_role": platform_role,
|
||||
}
|
||||
if user is None:
|
||||
user = User(**{key: value for key, value in payload.items() if value is not None})
|
||||
@@ -92,3 +94,95 @@ async def get_owned_car(
|
||||
if car.owner_id != current_user.id:
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
return car
|
||||
|
||||
|
||||
async def user_has_vehicle_access(
|
||||
session: AsyncSession, vehicle_id: int, user_id: int, roles: set[str] | None = None
|
||||
) -> bool:
|
||||
stmt = select(VehicleAccess).where(
|
||||
VehicleAccess.vehicle_id == vehicle_id,
|
||||
VehicleAccess.user_id == user_id,
|
||||
VehicleAccess.status == "active",
|
||||
)
|
||||
if roles:
|
||||
stmt = stmt.where(VehicleAccess.role.in_(roles))
|
||||
result = await session.execute(stmt)
|
||||
return result.scalar_one_or_none() is not None
|
||||
|
||||
|
||||
async def ensure_vehicle_owner_or_access(
|
||||
session: AsyncSession,
|
||||
vehicle_id: int,
|
||||
user: User,
|
||||
roles: set[str] | None = None,
|
||||
) -> Car:
|
||||
car = await session.get(Car, vehicle_id)
|
||||
if car is None:
|
||||
raise HTTPException(status_code=404, detail="Vehicle not found")
|
||||
if car.owner_id == user.id:
|
||||
return car
|
||||
if await user_has_vehicle_access(session, vehicle_id, user.id, roles):
|
||||
return car
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
|
||||
|
||||
def require_platform_role(user: User, allowed: set[str]) -> None:
|
||||
if user.platform_role not in allowed:
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
|
||||
|
||||
async def ensure_service_employee(
|
||||
session: AsyncSession,
|
||||
service_center_id: int,
|
||||
user: User,
|
||||
allowed_roles: set[str] | None = None,
|
||||
) -> ServiceEmployee:
|
||||
result = await session.execute(
|
||||
select(ServiceEmployee).where(
|
||||
ServiceEmployee.service_center_id == service_center_id,
|
||||
ServiceEmployee.user_id == user.id,
|
||||
ServiceEmployee.status == "active",
|
||||
)
|
||||
)
|
||||
employee = result.scalar_one_or_none()
|
||||
center = await session.get(ServiceCenter, service_center_id)
|
||||
owner_allowed = center is not None and center.owner_user_id == user.id
|
||||
if employee is None and owner_allowed:
|
||||
employee = ServiceEmployee(
|
||||
service_center_id=service_center_id,
|
||||
user_id=user.id,
|
||||
role="owner",
|
||||
status="active",
|
||||
)
|
||||
session.add(employee)
|
||||
await session.flush()
|
||||
if employee is None:
|
||||
raise HTTPException(status_code=403, detail="Service center access required")
|
||||
if allowed_roles and employee.role not in allowed_roles:
|
||||
raise HTTPException(status_code=403, detail="Insufficient service role")
|
||||
return employee
|
||||
|
||||
|
||||
async def log_audit(
|
||||
session: AsyncSession,
|
||||
*,
|
||||
actor: User | None,
|
||||
action: str,
|
||||
target_type: str,
|
||||
target_id: int | str | None = None,
|
||||
metadata: dict | None = None,
|
||||
ip: str | None = None,
|
||||
user_agent: str | None = None,
|
||||
) -> None:
|
||||
session.add(
|
||||
AuditLog(
|
||||
actor_user_id=actor.id if actor else None,
|
||||
actor_role=actor.platform_role if actor else None,
|
||||
action=action,
|
||||
target_type=target_type,
|
||||
target_id=str(target_id) if target_id is not None else None,
|
||||
metadata_json=metadata,
|
||||
ip=ip,
|
||||
user_agent=user_agent[:256] if user_agent else None,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user