mirror of
http://88.130.71.182:3000/BlitTech/deals24togo_be.git
synced 2026-06-12 23:33:21 +00:00
186 lines
5.4 KiB
Python
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)
|