- Unify API: lib/api.ts uses /api/v1, inbox uses /api/inbox (rewrites) - Remove localhost refs: openapi, inbox page - Add rewrites: /api/inbox|tmc -> inbox-server, /api/v1 -> FastAPI - Add stub routes: knowledge/insights, recommendations, search, log-error - Transfer from PAPA: prompts (inspection, tmc), scripts, supabase, data/tmc-requests - Fix inbox-server: ORDER BY created_at, package.json - Remove redundant app/api/inbox/files route (rewrites handle it) - knowledge/ in gitignore (large PDFs) Co-authored-by: Cursor <cursoragent@cursor.com>
163 lines
6.8 KiB
Python
163 lines
6.8 KiB
Python
"""
|
||
API routes для управления модификациями воздушных судов.
|
||
|
||
Соответствует требованиям ИКАО Annex 8: отслеживание обязательных модификаций
|
||
(AD - Airworthiness Directives, SB - Service Bulletins, STC - Supplemental Type Certificates).
|
||
"""
|
||
|
||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||
from sqlalchemy.orm import Session
|
||
|
||
from app.api.deps import get_current_user, require_roles
|
||
from app.db.session import get_db
|
||
from app.models import AircraftModification, Aircraft
|
||
from app.schemas.modifications import (
|
||
AircraftModificationCreate,
|
||
AircraftModificationOut,
|
||
AircraftModificationUpdate,
|
||
)
|
||
|
||
router = APIRouter(tags=["modifications"])
|
||
|
||
|
||
@router.get("/aircraft/{aircraft_id}/modifications", response_model=list[AircraftModificationOut])
|
||
def list_modifications(
|
||
aircraft_id: str,
|
||
modification_type: str | None = Query(None, description="Filter by modification type (AD, SB, STC)"),
|
||
compliance_status: str | None = Query(None, description="Filter by compliance status"),
|
||
db: Session = Depends(get_db),
|
||
user=Depends(get_current_user),
|
||
):
|
||
"""Получить список модификаций для воздушного судна."""
|
||
# Проверка доступа к ВС
|
||
aircraft = db.query(Aircraft).filter(Aircraft.id == aircraft_id).first()
|
||
if not aircraft:
|
||
raise HTTPException(status_code=404, detail="Aircraft not found")
|
||
|
||
if user.role.startswith("operator") and user.organization_id and aircraft.operator_id != user.organization_id:
|
||
raise HTTPException(status_code=403, detail="Forbidden")
|
||
|
||
query = db.query(AircraftModification).filter(AircraftModification.aircraft_id == aircraft_id)
|
||
|
||
if modification_type:
|
||
query = query.filter(AircraftModification.modification_type == modification_type)
|
||
|
||
if compliance_status:
|
||
query = query.filter(AircraftModification.compliance_status == compliance_status)
|
||
|
||
return query.order_by(AircraftModification.compliance_date.desc()).all()
|
||
|
||
|
||
@router.post(
|
||
"/aircraft/{aircraft_id}/modifications",
|
||
response_model=AircraftModificationOut,
|
||
dependencies=[Depends(require_roles("admin", "operator_user", "operator_manager", "authority_inspector"))],
|
||
)
|
||
def create_modification(
|
||
aircraft_id: str,
|
||
payload: AircraftModificationCreate,
|
||
db: Session = Depends(get_db),
|
||
user=Depends(get_current_user),
|
||
):
|
||
"""Создать новую модификацию для воздушного судна."""
|
||
# Проверка существования ВС
|
||
aircraft = db.query(Aircraft).filter(Aircraft.id == aircraft_id).first()
|
||
if not aircraft:
|
||
raise HTTPException(status_code=404, detail="Aircraft not found")
|
||
|
||
# Проверка доступа
|
||
if user.role.startswith("operator") and user.organization_id and aircraft.operator_id != user.organization_id:
|
||
raise HTTPException(status_code=403, detail="Forbidden")
|
||
|
||
# Установка aircraft_id из URL
|
||
mod_data = payload.model_dump()
|
||
mod_data["aircraft_id"] = aircraft_id
|
||
|
||
# Автоматическое заполнение организации и пользователя (если не указаны)
|
||
if not mod_data.get("performed_by_org_id") and user.organization_id:
|
||
mod_data["performed_by_org_id"] = user.organization_id
|
||
if not mod_data.get("performed_by_user_id"):
|
||
mod_data["performed_by_user_id"] = user.id
|
||
|
||
modification = AircraftModification(**mod_data)
|
||
db.add(modification)
|
||
db.commit()
|
||
db.refresh(modification)
|
||
return modification
|
||
|
||
|
||
@router.get("/modifications/{mod_id}", response_model=AircraftModificationOut)
|
||
def get_modification(
|
||
mod_id: str,
|
||
db: Session = Depends(get_db),
|
||
user=Depends(get_current_user),
|
||
):
|
||
"""Получить модификацию по ID."""
|
||
modification = db.query(AircraftModification).filter(AircraftModification.id == mod_id).first()
|
||
if not modification:
|
||
raise HTTPException(status_code=404, detail="Not found")
|
||
|
||
# Проверка доступа к связанному ВС
|
||
aircraft = db.query(Aircraft).filter(Aircraft.id == modification.aircraft_id).first()
|
||
if user.role.startswith("operator") and user.organization_id and aircraft.operator_id != user.organization_id:
|
||
raise HTTPException(status_code=403, detail="Forbidden")
|
||
|
||
return modification
|
||
|
||
|
||
@router.patch(
|
||
"/modifications/{mod_id}",
|
||
response_model=AircraftModificationOut,
|
||
dependencies=[Depends(require_roles("admin", "operator_user", "operator_manager", "authority_inspector"))],
|
||
)
|
||
def update_modification(
|
||
mod_id: str,
|
||
payload: AircraftModificationUpdate,
|
||
db: Session = Depends(get_db),
|
||
user=Depends(get_current_user),
|
||
):
|
||
"""Обновить модификацию."""
|
||
modification = db.query(AircraftModification).filter(AircraftModification.id == mod_id).first()
|
||
if not modification:
|
||
raise HTTPException(status_code=404, detail="Not found")
|
||
|
||
# Проверка доступа к связанному ВС
|
||
aircraft = db.query(Aircraft).filter(Aircraft.id == modification.aircraft_id).first()
|
||
if user.role.startswith("operator") and user.organization_id and aircraft.operator_id != user.organization_id:
|
||
raise HTTPException(status_code=403, detail="Forbidden")
|
||
|
||
data = payload.model_dump(exclude_unset=True)
|
||
for k, v in data.items():
|
||
setattr(modification, k, v)
|
||
|
||
db.commit()
|
||
db.refresh(modification)
|
||
return modification
|
||
|
||
|
||
@router.get("/modifications", response_model=list[AircraftModificationOut])
|
||
def list_all_modifications(
|
||
compliance_required: bool | None = Query(None, description="Filter by compliance required"),
|
||
compliance_status: str | None = Query(None, description="Filter by compliance status"),
|
||
modification_type: str | None = Query(None, description="Filter by modification type"),
|
||
db: Session = Depends(get_db),
|
||
user=Depends(get_current_user),
|
||
):
|
||
"""Получить список всех модификаций (с фильтрацией)."""
|
||
query = db.query(AircraftModification)
|
||
|
||
# Operator-bound visibility
|
||
if user.role.startswith("operator") and user.organization_id:
|
||
query = query.join(Aircraft).filter(Aircraft.operator_id == user.organization_id)
|
||
|
||
if compliance_required is not None:
|
||
query = query.filter(AircraftModification.compliance_required == compliance_required)
|
||
|
||
if compliance_status:
|
||
query = query.filter(AircraftModification.compliance_status == compliance_status)
|
||
|
||
if modification_type:
|
||
query = query.filter(AircraftModification.modification_type == modification_type)
|
||
|
||
return query.order_by(AircraftModification.compliance_date.desc()).all()
|