diff --git a/tradein-mvp/backend/app/api/v1/admin.py b/tradein-mvp/backend/app/api/v1/admin.py index 210bcbc7..07deca99 100644 --- a/tradein-mvp/backend/app/api/v1/admin.py +++ b/tradein-mvp/backend/app/api/v1/admin.py @@ -931,3 +931,92 @@ async def scrape_yandex_valuation( total_objects=result.house.total_objects, history_items_count=len(result.history_items), ) + + +class CianDetailTriggerResp(BaseModel): + ok: bool + offer_url: str + cian_id: int | None + price_changes_count: int + saved: bool + listing_id: int | None + + +@router.post("/scrape/cian-detail", response_model=CianDetailTriggerResp) +async def scrape_cian_detail( + offer_url: str, + listing_id: int | None = None, + db: Session = Depends(get_db), # noqa: B008 +) -> CianDetailTriggerResp: + """Ad-hoc parse one Cian offer detail page. + + If `listing_id` provided → save enrichment (offer_price_history + listings updates). + Without it → debug-only (no DB write). + """ + from app.services.scrapers.cian_detail import fetch_detail, save_detail_enrichment + + enrichment = await fetch_detail(offer_url) + if enrichment is None: + raise HTTPException(404, f"Could not parse Cian detail page: {offer_url}") + + saved = False + if listing_id is not None: + save_detail_enrichment(db, listing_id, enrichment) + saved = True + + return CianDetailTriggerResp( + ok=True, + offer_url=offer_url, + cian_id=enrichment.cian_id, + price_changes_count=len(enrichment.price_changes), + saved=saved, + listing_id=listing_id, + ) + + +class CianNewbuildingTriggerResp(BaseModel): + ok: bool + zhk_url: str + cian_internal_house_id: int | None + name: str | None + price_dynamics_count: int + has_management_company: bool + saved: bool + house_id: int | None + + +@router.post("/scrape/cian-newbuilding", response_model=CianNewbuildingTriggerResp) +async def scrape_cian_newbuilding( + zhk_url: str, + house_id: int | None = None, + db: Session = Depends(get_db), # noqa: B008 +) -> CianNewbuildingTriggerResp: + """Ad-hoc parse a Cian ЖК (newbuilding) catalog page. + + If `house_id` provided → persist (houses + houses_price_dynamics + management_companies). + Without it → debug-only (no DB write). + """ + from app.services.scrapers.cian_newbuilding import ( + fetch_newbuilding, + save_newbuilding_enrichment, + ) + + enrichment = await fetch_newbuilding(zhk_url) + if enrichment is None: + raise HTTPException(404, f"Could not parse Cian newbuilding page: {zhk_url}") + + saved = False + if house_id is not None: + await save_newbuilding_enrichment(db, house_id, enrichment) + saved = True + + return CianNewbuildingTriggerResp( + ok=True, + zhk_url=zhk_url, + cian_internal_house_id=enrichment.cian_internal_house_id, + name=enrichment.name, + price_dynamics_count=len(enrichment.realty_valuation_chart), + has_management_company=bool(enrichment.management_company), + saved=saved, + house_id=house_id, + )