feature/cliente-proveedor-permisos

This commit is contained in:
2026-05-05 12:32:04 -06:00
parent 9435e73761
commit 63939e3aa7
9 changed files with 197 additions and 32 deletions

View File

@@ -9,7 +9,7 @@ from uuid import uuid4
from fastapi import APIRouter, File, HTTPException, Query, UploadFile, Depends
from sqlalchemy.orm import Session
from typing import Dict, Any
from typing import Dict, Any, Optional
from core.celery_app import celery_app
from core.database import get_core_db
@@ -33,6 +33,54 @@ router = APIRouter()
logger = logging.getLogger(__name__)
def _assert_cp_csv_job_access(
db: Session,
job_id: str,
current_user: Dict[str, Any],
) -> None:
"""
Exige autenticación + csv_upload.process para la compañía asociada al job
(task_runs, meta Redis del job, o meta del layout_import_job_id en commits).
"""
from api.v1.modules.core.tasks_tracking.models import TaskRun
company_id: Optional[int] = None
row = db.query(TaskRun).filter(TaskRun.task_id == job_id).first()
if row is not None and row.company_id is not None:
company_id = int(row.company_id)
r = _get_redis()
if company_id is None:
raw = r.get(f"{CP_IMPORT_META_PREFIX}{job_id}")
if raw:
meta = json.loads(raw.decode("utf-8"))
cid = meta.get("company_id")
if cid is not None:
company_id = int(cid)
if company_id is None and row is not None and row.meta_payload:
layout_jid = row.meta_payload.get("layout_import_job_id")
if layout_jid:
raw2 = r.get(f"{CP_IMPORT_META_PREFIX}{layout_jid}")
if raw2:
meta2 = json.loads(raw2.decode("utf-8"))
cid2 = meta2.get("company_id")
if cid2 is not None:
company_id = int(cid2)
if company_id is None:
raise HTTPException(status_code=403, detail="Sin acceso a este job")
try:
validate_access_to_resource(
db, company_id, current_user, ["csv_upload.process"]
)
except HTTPException:
raise
except Exception as e:
logger.error("CP import: job access validation failed: %s", e)
raise HTTPException(status_code=403, detail="Sin acceso a este job") from None
def _get_redis():
import redis
url = os.getenv("VALKEY_URL", os.getenv("REDIS_URL", "redis://valkey:6379/0"))
@@ -109,10 +157,15 @@ async def upload_import_file(
@router.get("/{job_id}/status")
async def get_import_status(job_id: str):
async def get_import_status(
job_id: str,
db: Session = Depends(get_core_db),
current_user: Dict[str, Any] = Depends(get_current_user),
):
"""
Polling: estado del escaneo o del commit.
"""
_assert_cp_csv_job_access(db, job_id, current_user)
task_result = celery_app.AsyncResult(job_id)
if task_result.state == "PENDING":
@@ -166,7 +219,6 @@ async def commit_import_job(
"""
Fase 2: Usuario confirma; se encola la inserción de filas válidas.
"""
validate_access_to_resource(db, company_id, current_user, ["csv_upload.process"]) # company_id will be extracted from Redis meta
r = _get_redis()
commit_id = dispatch_tracked_layouts_csv_commit(
db=db,
@@ -178,6 +230,7 @@ async def commit_import_job(
task_name="clients_and_providers_insert_valid_rows",
task_origin="a76/layouts_csv/clients_and_providers/commit",
args=[job_id],
required_permissions=["csv_upload.process"],
)
return {
"status": "committing",
@@ -187,5 +240,10 @@ async def commit_import_job(
@router.get("/{job_id}/errors/scan-csv")
async def download_scan_errors_csv(job_id: str):
async def download_scan_errors_csv(
job_id: str,
db: Session = Depends(get_core_db),
current_user: Dict[str, Any] = Depends(get_current_user),
):
_assert_cp_csv_job_access(db, job_id, current_user)
return download_scan_errors_csv_stream("cp", job_id)

View File

@@ -24,6 +24,7 @@ def dispatch_tracked_layouts_csv_commit(
task_name: str,
task_origin: str,
args: list[Any],
required_permissions: list[str] | None = None,
) -> str:
"""
Lee tenant_id / company_id del meta en Redis, valida acceso y despacha la tarea Celery
@@ -37,7 +38,11 @@ def dispatch_tracked_layouts_csv_commit(
company_id = meta.get("company_id")
if company_id is not None:
try:
validate_access_to_resource(db, int(company_id), current_user)
validate_access_to_resource(
db, int(company_id), current_user, required_permissions
)
except HTTPException:
raise
except Exception:
raise HTTPException(status_code=403, detail="Sin acceso a este job") from None

View File

@@ -166,7 +166,6 @@ async def commit_import_job(
"""
Fase 2: Usuario confirma; se encola la inserción de filas válidas.
"""
validate_access_to_resource(db, company_id, current_user, ["csv_upload.process"]) # company_id will be extracted from Redis meta
r = _get_redis()
commit_id = dispatch_tracked_layouts_csv_commit(
db=db,
@@ -178,6 +177,7 @@ async def commit_import_job(
task_name="customs_brokers_insert_valid_rows",
task_origin="a76/layouts_csv/customs_brokers/commit",
args=[job_id],
required_permissions=["csv_upload.process"],
)
return {
"status": "committing",