Files
deals24togo_be/app/api/v1/endpoints/listings.py
belviskhoremk c4d836a0f9 Initial commit
2026-03-06 22:57:58 +00:00

186 lines
5.4 KiB
Python

"""Listing CRUD + search endpoints."""
from __future__ import annotations
from typing import Optional
from fastapi import APIRouter, BackgroundTasks, Depends, Query
from app.middleware.auth import get_current_user, get_optional_user, require_admin
from app.schemas.listing import (
ListingCreate,
ListingListResponse,
ListingResponse,
ListingStatusUpdate,
ListingUpdate,
)
from app.services.agency_service import AgencyService
from app.services.listing_service import ListingService
router = APIRouter(prefix="/listings", tags=["Listings"])
# ── Public ───────────────────────────────────────────────
@router.get("/", response_model=ListingListResponse)
def list_listings(
search: Optional[str] = None,
category: Optional[str] = None,
agency_id: Optional[str] = None,
min_price: Optional[float] = None,
max_price: Optional[float] = None,
location: Optional[str] = None,
listing_type: Optional[str] = None,
condition: Optional[str] = None,
sort_by: str = Query("newest"),
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
):
svc = ListingService()
return svc.list_listings(
search=search,
category=category,
agency_id=agency_id,
min_price=min_price,
max_price=max_price,
location=location,
listing_type=listing_type,
condition=condition,
sort_by=sort_by,
page=page,
page_size=page_size,
status="approved",
)
@router.get("/featured", response_model=ListingListResponse)
def featured_listings():
"""Return top 8 most viewed approved listings."""
svc = ListingService()
return svc.list_listings(
sort_by="popular",
page=1,
page_size=8,
status="approved",
)
@router.get("/{listing_id}", response_model=ListingResponse)
def get_listing(
listing_id: str,
background_tasks: BackgroundTasks,
user: Optional[dict] = Depends(get_optional_user),
):
svc = ListingService()
listing = svc.get_listing(listing_id)
background_tasks.add_task(svc.increment_views, listing_id)
return listing
# ── Agency ───────────────────────────────────────────────
@router.get("/agency/mine", response_model=ListingListResponse)
def my_listings(
status: Optional[str] = None,
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
user: dict = Depends(get_current_user),
):
agency_svc = AgencyService()
agency = agency_svc.get_agency_by_user(user["id"])
svc = ListingService()
return svc.list_listings(
agency_id=agency["id"],
status=status,
page=page,
page_size=page_size,
)
@router.post("/", response_model=ListingResponse, status_code=201)
def create_listing(body: ListingCreate, user: dict = Depends(get_current_user)):
agency_svc = AgencyService()
agency = agency_svc.get_agency_by_user(user["id"])
svc = ListingService()
return svc.create_listing(agency["id"], body.model_dump())
@router.patch("/{listing_id}", response_model=ListingResponse)
def update_listing(
listing_id: str,
body: ListingUpdate,
user: dict = Depends(get_current_user),
):
svc = ListingService()
return svc.update_listing(
listing_id, user["id"], user["role"], body.model_dump(exclude_unset=True)
)
@router.delete("/{listing_id}")
def delete_listing(listing_id: str, user: dict = Depends(get_current_user)):
svc = ListingService()
return svc.delete_listing(listing_id, user["id"], user["role"])
# ── Admin ────────────────────────────────────────────────
@router.get("/admin/all", response_model=ListingListResponse)
def admin_list_all(
status: Optional[str] = None,
search: Optional[str] = None,
category: Optional[str] = None,
min_price: Optional[float] = None,
max_price: Optional[float] = None,
location: Optional[str] = None,
listing_type: Optional[str] = None,
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
_admin: dict = Depends(require_admin),
):
svc = ListingService()
return svc.list_listings(
search=search,
status=status,
category=category,
min_price=min_price,
max_price=max_price,
location=location,
listing_type=listing_type,
page=page,
page_size=page_size,
)
@router.patch("/{listing_id}/status", response_model=ListingResponse)
def update_listing_status(
listing_id: str,
body: ListingStatusUpdate,
_admin: dict = Depends(require_admin),
):
svc = ListingService()
return svc.update_status(listing_id, body.status, body.rejection_reason)
@router.get("/stats/overview")
def listing_stats(
agency_id: Optional[str] = None,
user: dict = Depends(get_current_user),
):
svc = ListingService()
if user["role"] != "admin":
# Non-admins always see their own agency's stats only
agency_svc = AgencyService()
try:
agency = agency_svc.get_agency_by_user(user["id"])
agency_id = agency["id"]
except Exception:
return {"total": 0, "pending": 0, "approved": 0, "rejected": 0}
return svc.get_stats(agency_id)