From 11852adc66eaaa368cfa68342149d185175897c1 Mon Sep 17 00:00:00 2001 From: Mondo Diaz Date: Fri, 12 Dec 2025 09:38:38 -0600 Subject: [PATCH] Revert "Add API endpoints for listing tagged versions and artifacts" This reverts commit 54e33e67ce339008dc22d07345f5827fd8086a0f. --- backend/app/routes.py | 261 ++--------------------------------------- backend/app/schemas.py | 72 ------------ 2 files changed, 9 insertions(+), 324 deletions(-) diff --git a/backend/app/routes.py b/backend/app/routes.py index 711225c..ab012a8 100644 --- a/backend/app/routes.py +++ b/backend/app/routes.py @@ -1,4 +1,3 @@ -from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form, Request, Query, Header, Response from fastapi.responses import StreamingResponse from sqlalchemy.orm import Session @@ -11,13 +10,13 @@ import hashlib from .database import get_db from .storage import get_storage, S3Storage, MULTIPART_CHUNK_SIZE -from .models import Project, Package, Artifact, Tag, TagHistory, Upload, Consumer +from .models import Project, Package, Artifact, Tag, Upload, Consumer from .schemas import ( ProjectCreate, ProjectResponse, PackageCreate, PackageResponse, PackageDetailResponse, TagSummary, PACKAGE_FORMATS, PACKAGE_PLATFORMS, - ArtifactResponse, ArtifactDetailResponse, ArtifactTagInfo, PackageArtifactResponse, - TagCreate, TagResponse, TagDetailResponse, TagHistoryResponse, + ArtifactResponse, + TagCreate, TagResponse, UploadResponse, ConsumerResponse, HealthResponse, @@ -851,17 +850,8 @@ def download_artifact_compat( # Tag routes -@router.get("/api/v1/project/{project_name}/{package_name}/tags", response_model=PaginatedResponse[TagDetailResponse]) -def list_tags( - project_name: str, - package_name: str, - page: int = Query(default=1, ge=1, description="Page number"), - limit: int = Query(default=20, ge=1, le=100, description="Items per page"), - search: Optional[str] = Query(default=None, description="Search by tag name"), - sort: str = Query(default="name", description="Sort field (name, created_at)"), - order: str = Query(default="asc", description="Sort order (asc, desc)"), - db: Session = Depends(get_db), -): +@router.get("/api/v1/project/{project_name}/{package_name}/tags", response_model=List[TagResponse]) +def list_tags(project_name: str, package_name: str, db: Session = Depends(get_db)): project = db.query(Project).filter(Project.name == project_name).first() if not project: raise HTTPException(status_code=404, detail="Project not found") @@ -870,65 +860,8 @@ def list_tags( if not package: raise HTTPException(status_code=404, detail="Package not found") - # Validate sort field - valid_sort_fields = {"name": Tag.name, "created_at": Tag.created_at} - if sort not in valid_sort_fields: - raise HTTPException(status_code=400, detail=f"Invalid sort field. Must be one of: {', '.join(valid_sort_fields.keys())}") - - # Validate order - if order not in ("asc", "desc"): - raise HTTPException(status_code=400, detail="Invalid order. Must be 'asc' or 'desc'") - - # Base query with JOIN to artifact for metadata - query = db.query(Tag, Artifact).join(Artifact, Tag.artifact_id == Artifact.id).filter(Tag.package_id == package.id) - - # Apply search filter (case-insensitive on tag name) - if search: - query = query.filter(func.lower(Tag.name).contains(search.lower())) - - # Get total count before pagination - total = query.count() - - # Apply sorting - sort_column = valid_sort_fields[sort] - if order == "desc": - query = query.order_by(sort_column.desc()) - else: - query = query.order_by(sort_column.asc()) - - # Apply pagination - offset = (page - 1) * limit - results = query.offset(offset).limit(limit).all() - - # Calculate total pages - total_pages = math.ceil(total / limit) if total > 0 else 1 - - # Build detailed responses with artifact metadata - detailed_tags = [] - for tag, artifact in results: - detailed_tags.append(TagDetailResponse( - id=tag.id, - package_id=tag.package_id, - name=tag.name, - artifact_id=tag.artifact_id, - created_at=tag.created_at, - created_by=tag.created_by, - artifact_size=artifact.size, - artifact_content_type=artifact.content_type, - artifact_original_name=artifact.original_name, - artifact_created_at=artifact.created_at, - artifact_format_metadata=artifact.format_metadata, - )) - - return PaginatedResponse( - items=detailed_tags, - pagination=PaginationMeta( - page=page, - limit=limit, - total=total, - total_pages=total_pages, - ), - ) + tags = db.query(Tag).filter(Tag.package_id == package.id).order_by(Tag.name).all() + return tags @router.post("/api/v1/project/{project_name}/{package_name}/tags", response_model=TagResponse) @@ -975,70 +908,6 @@ def create_tag( return db_tag -@router.get("/api/v1/project/{project_name}/{package_name}/tags/{tag_name}", response_model=TagDetailResponse) -def get_tag( - project_name: str, - package_name: str, - tag_name: str, - db: Session = Depends(get_db), -): - """Get a single tag with full artifact metadata""" - project = db.query(Project).filter(Project.name == project_name).first() - if not project: - raise HTTPException(status_code=404, detail="Project not found") - - package = db.query(Package).filter(Package.project_id == project.id, Package.name == package_name).first() - if not package: - raise HTTPException(status_code=404, detail="Package not found") - - result = db.query(Tag, Artifact).join(Artifact, Tag.artifact_id == Artifact.id).filter( - Tag.package_id == package.id, - Tag.name == tag_name - ).first() - - if not result: - raise HTTPException(status_code=404, detail="Tag not found") - - tag, artifact = result - return TagDetailResponse( - id=tag.id, - package_id=tag.package_id, - name=tag.name, - artifact_id=tag.artifact_id, - created_at=tag.created_at, - created_by=tag.created_by, - artifact_size=artifact.size, - artifact_content_type=artifact.content_type, - artifact_original_name=artifact.original_name, - artifact_created_at=artifact.created_at, - artifact_format_metadata=artifact.format_metadata, - ) - - -@router.get("/api/v1/project/{project_name}/{package_name}/tags/{tag_name}/history", response_model=List[TagHistoryResponse]) -def get_tag_history( - project_name: str, - package_name: str, - tag_name: str, - db: Session = Depends(get_db), -): - """Get the history of artifact assignments for a tag""" - project = db.query(Project).filter(Project.name == project_name).first() - if not project: - raise HTTPException(status_code=404, detail="Project not found") - - package = db.query(Package).filter(Package.project_id == project.id, Package.name == package_name).first() - if not package: - raise HTTPException(status_code=404, detail="Package not found") - - tag = db.query(Tag).filter(Tag.package_id == package.id, Tag.name == tag_name).first() - if not tag: - raise HTTPException(status_code=404, detail="Tag not found") - - history = db.query(TagHistory).filter(TagHistory.tag_id == tag.id).order_by(TagHistory.changed_at.desc()).all() - return history - - # Consumer routes @router.get("/api/v1/project/{project_name}/{package_name}/consumers", response_model=List[ConsumerResponse]) def get_consumers(project_name: str, package_name: str, db: Session = Depends(get_db)): @@ -1054,122 +923,10 @@ def get_consumers(project_name: str, package_name: str, db: Session = Depends(ge return consumers -# Package artifacts -@router.get("/api/v1/project/{project_name}/{package_name}/artifacts", response_model=PaginatedResponse[PackageArtifactResponse]) -def list_package_artifacts( - project_name: str, - package_name: str, - page: int = Query(default=1, ge=1, description="Page number"), - limit: int = Query(default=20, ge=1, le=100, description="Items per page"), - content_type: Optional[str] = Query(default=None, description="Filter by content type"), - created_after: Optional[datetime] = Query(default=None, description="Filter artifacts created after this date"), - created_before: Optional[datetime] = Query(default=None, description="Filter artifacts created before this date"), - db: Session = Depends(get_db), -): - """List all unique artifacts uploaded to a package""" - project = db.query(Project).filter(Project.name == project_name).first() - if not project: - raise HTTPException(status_code=404, detail="Project not found") - - package = db.query(Package).filter(Package.project_id == project.id, Package.name == package_name).first() - if not package: - raise HTTPException(status_code=404, detail="Package not found") - - # Get distinct artifacts uploaded to this package via uploads table - artifact_ids_subquery = db.query(func.distinct(Upload.artifact_id)).filter( - Upload.package_id == package.id - ).subquery() - - query = db.query(Artifact).filter(Artifact.id.in_(artifact_ids_subquery)) - - # Apply content_type filter - if content_type: - query = query.filter(Artifact.content_type == content_type) - - # Apply date range filters - if created_after: - query = query.filter(Artifact.created_at >= created_after) - if created_before: - query = query.filter(Artifact.created_at <= created_before) - - # Get total count before pagination - total = query.count() - - # Apply pagination - offset = (page - 1) * limit - artifacts = query.order_by(Artifact.created_at.desc()).offset(offset).limit(limit).all() - - # Calculate total pages - total_pages = math.ceil(total / limit) if total > 0 else 1 - - # Build responses with tag info - artifact_responses = [] - for artifact in artifacts: - # Get tags pointing to this artifact in this package - tags = db.query(Tag.name).filter( - Tag.package_id == package.id, - Tag.artifact_id == artifact.id - ).all() - tag_names = [t.name for t in tags] - - artifact_responses.append(PackageArtifactResponse( - id=artifact.id, - size=artifact.size, - content_type=artifact.content_type, - original_name=artifact.original_name, - created_at=artifact.created_at, - created_by=artifact.created_by, - format_metadata=artifact.format_metadata, - tags=tag_names, - )) - - return PaginatedResponse( - items=artifact_responses, - pagination=PaginationMeta( - page=page, - limit=limit, - total=total, - total_pages=total_pages, - ), - ) - - # Artifact by ID -@router.get("/api/v1/artifact/{artifact_id}", response_model=ArtifactDetailResponse) +@router.get("/api/v1/artifact/{artifact_id}", response_model=ArtifactResponse) def get_artifact(artifact_id: str, db: Session = Depends(get_db)): - """Get artifact metadata including list of packages/tags referencing it""" artifact = db.query(Artifact).filter(Artifact.id == artifact_id).first() if not artifact: raise HTTPException(status_code=404, detail="Artifact not found") - - # Get all tags referencing this artifact with package and project info - tags_with_context = db.query(Tag, Package, Project).join( - Package, Tag.package_id == Package.id - ).join( - Project, Package.project_id == Project.id - ).filter( - Tag.artifact_id == artifact_id - ).all() - - tag_infos = [ - ArtifactTagInfo( - id=tag.id, - name=tag.name, - package_id=package.id, - package_name=package.name, - project_name=project.name, - ) - for tag, package, project in tags_with_context - ] - - return ArtifactDetailResponse( - id=artifact.id, - size=artifact.size, - content_type=artifact.content_type, - original_name=artifact.original_name, - created_at=artifact.created_at, - created_by=artifact.created_by, - ref_count=artifact.ref_count, - format_metadata=artifact.format_metadata, - tags=tag_infos, - ) + return artifact diff --git a/backend/app/schemas.py b/backend/app/schemas.py index 5077646..837c0ce 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -129,78 +129,6 @@ class TagResponse(BaseModel): from_attributes = True -class TagDetailResponse(BaseModel): - """Tag with embedded artifact metadata""" - id: UUID - package_id: UUID - name: str - artifact_id: str - created_at: datetime - created_by: str - # Artifact metadata - artifact_size: int - artifact_content_type: Optional[str] - artifact_original_name: Optional[str] - artifact_created_at: datetime - artifact_format_metadata: Optional[Dict[str, Any]] = None - - class Config: - from_attributes = True - - -class TagHistoryResponse(BaseModel): - """History entry for tag changes""" - id: UUID - tag_id: UUID - old_artifact_id: Optional[str] - new_artifact_id: str - changed_at: datetime - changed_by: str - - class Config: - from_attributes = True - - -class ArtifactTagInfo(BaseModel): - """Tag info for embedding in artifact responses""" - id: UUID - name: str - package_id: UUID - package_name: str - project_name: str - - -class ArtifactDetailResponse(BaseModel): - """Artifact with list of tags/packages referencing it""" - id: str - size: int - content_type: Optional[str] - original_name: Optional[str] - created_at: datetime - created_by: str - ref_count: int - format_metadata: Optional[Dict[str, Any]] = None - tags: List[ArtifactTagInfo] = [] - - class Config: - from_attributes = True - - -class PackageArtifactResponse(BaseModel): - """Artifact with tags for package artifact listing""" - id: str - size: int - content_type: Optional[str] - original_name: Optional[str] - created_at: datetime - created_by: str - format_metadata: Optional[Dict[str, Any]] = None - tags: List[str] = [] # Tag names pointing to this artifact - - class Config: - from_attributes = True - - # Upload response class UploadResponse(BaseModel): artifact_id: str