|
# retoor <retoor@molodetz.nl>
|
|
|
|
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)
|