85 lines
2.8 KiB
Python
85 lines
2.8 KiB
Python
"""Editor HTTP router — file read/write and impact analysis endpoints."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import asdict
|
|
|
|
from fastapi import APIRouter
|
|
from fastapi.responses import JSONResponse
|
|
from pydantic import BaseModel
|
|
|
|
from app.modules.project.application.services import ProjectService
|
|
from app.modules.scanner.application.services import ScanService
|
|
from app.modules.editor.application.services import EditorService
|
|
|
|
router = APIRouter(prefix="/projects/{project_id}/files", tags=["editor"])
|
|
|
|
_project_service: ProjectService | None = None
|
|
_scan_service: ScanService | None = None
|
|
_editor_service: EditorService | None = None
|
|
|
|
|
|
def init_router(
|
|
project_service: ProjectService,
|
|
scan_service: ScanService,
|
|
editor_service: EditorService,
|
|
) -> None:
|
|
global _project_service, _scan_service, _editor_service
|
|
_project_service = project_service
|
|
_scan_service = scan_service
|
|
_editor_service = editor_service
|
|
|
|
|
|
class SaveFileRequest(BaseModel):
|
|
content: str
|
|
|
|
|
|
def _get_or_trigger_scan(project_id: str):
|
|
"""Get cached scan or trigger a new one."""
|
|
result = _scan_service.get_latest_scan(project_id)
|
|
if result is None:
|
|
project = _project_service.get_project(project_id)
|
|
result = _scan_service.scan(project)
|
|
return result
|
|
|
|
|
|
@router.get("/{path:path}/impact")
|
|
def get_impact(project_id: str, path: str):
|
|
"""Return impact analysis for a given file."""
|
|
project = _project_service.get_project(project_id)
|
|
scan_result = _get_or_trigger_scan(project_id)
|
|
impact = _editor_service.get_impact(project, path, scan_result)
|
|
return asdict(impact)
|
|
|
|
|
|
@router.get("/{path:path}")
|
|
def get_file(project_id: str, path: str):
|
|
"""Read a design file and return its content."""
|
|
project = _project_service.get_project(project_id)
|
|
editable = _editor_service.get_file(project, path)
|
|
return {
|
|
"path": editable.path,
|
|
"format": editable.format,
|
|
"content": editable.content,
|
|
"last_modified": editable.last_modified.isoformat(),
|
|
}
|
|
|
|
|
|
@router.put("/{path:path}")
|
|
def save_file(project_id: str, path: str, body: SaveFileRequest):
|
|
"""Write content to a design file and re-scan."""
|
|
project = _project_service.get_project(project_id)
|
|
scan_result = _editor_service.save_file(project, path, body.content)
|
|
return {
|
|
"project_id": scan_result.project_id,
|
|
"scanned_at": scan_result.scanned_at.isoformat(),
|
|
"summary": {
|
|
"total_files": scan_result.summary.total_files,
|
|
"ok": scan_result.summary.ok,
|
|
"sparse": scan_result.summary.sparse,
|
|
"missing": scan_result.summary.missing,
|
|
"placeholder_heavy": scan_result.summary.placeholder_heavy,
|
|
"template_residue": scan_result.summary.template_residue,
|
|
},
|
|
}
|