# retoor from typing import Annotated from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse from devplacepy.models import GameSlotForm from devplacepy.responses import respond, wants_json from devplacepy.schemas import GameFarmViewOut from devplacepy.services.game import GameError, store from devplacepy.utils import ( create_notification, get_current_user, require_user, track_action, ) from ._shared import action_error, game_seo, notify_farm, owner_by_username router = APIRouter() @router.get("/farm/{username}", response_class=HTMLResponse) async def view_farm(request: Request, username: str): viewer = get_current_user(request) owner = owner_by_username(username) if not owner: raise HTTPException(status_code=404, detail="Farm not found") farm = store.ensure_farm(owner["uid"]) data = store.serialize_farm(farm, viewer=viewer, owner=owner) seo_ctx = game_seo( request, f"{owner['username']}'s Code Farm", f"Visit {owner['username']}'s Code Farm on DevPlace and water their builds.", ) return respond( request, "game_farm.html", { **seo_ctx, "request": request, "user": viewer, "viewer": viewer, "farm": data, "game_error": request.query_params.get("error", ""), }, model=GameFarmViewOut, ) @router.post("/farm/{username}/water") async def water_farm( request: Request, username: str, data: Annotated[GameSlotForm, Form()] ): viewer = require_user(request) owner = owner_by_username(username) if not owner: raise HTTPException(status_code=404, detail="Farm not found") try: store.water(viewer, owner, data.slot) except GameError as exc: return action_error(request, str(exc), f"/game/farm/{username}") track_action(viewer["uid"], "water") await notify_farm(owner["username"]) if wants_json(request): payload = store.serialize_farm( store.ensure_farm(owner["uid"]), viewer=viewer, owner=owner ) return JSONResponse(GameFarmViewOut(farm=payload).model_dump(mode="json")) return RedirectResponse(url=f"/game/farm/{username}", status_code=302) @router.post("/farm/{username}/steal") async def steal_farm( request: Request, username: str, data: Annotated[GameSlotForm, Form()] ): viewer = require_user(request) owner = owner_by_username(username) if not owner: raise HTTPException(status_code=404, detail="Farm not found") try: result = store.steal(viewer, owner, data.slot) except GameError as exc: return action_error(request, str(exc), f"/game/farm/{username}") track_action(viewer["uid"], "harvest_stolen") track_action(owner["uid"], "got_stolen_from") if result.get("underdog_triggered"): track_action(viewer["uid"], "underdog_raid") create_notification( owner["uid"], "harvest_stolen", ( f"{viewer['username']} raided your Code Farm and took " f"{result['coins']} coins ({round(result['share'] * 100)}%) " f"from your {result['crop_name']} build. You keep the rest - harvest it." ), viewer["uid"], "/game", ) await notify_farm(owner["username"]) await notify_farm(viewer["username"]) if wants_json(request): payload = store.serialize_farm( store.ensure_farm(owner["uid"]), viewer=viewer, owner=owner ) return JSONResponse( GameFarmViewOut(farm=payload, stole_coins=result["coins"]).model_dump( mode="json" ) ) return RedirectResponse(url=f"/game/farm/{username}", status_code=302)