- Guard total_count with `if not csv` ternary to avoid unnecessary COUNT query on CSV export paths (10 files) - Consolidate rewards.py from 3 COUNT queries to 1 (used for both empty-check and response) - Clean up scout_claims.py double `if limit is not None` block - Normalize scout_opportunities.py from max(1,...) to max(0,...) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
210 lines
6.2 KiB
Python
210 lines
6.2 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Response
|
|
from typing import Optional
|
|
import logging
|
|
import pydantic
|
|
from pandas import DataFrame
|
|
|
|
from ..db_engine import Event, model_to_dict, fn, DoesNotExist
|
|
from ..dependencies import oauth2_scheme, valid_token
|
|
|
|
|
|
router = APIRouter(prefix="/api/v2/events", tags=["events"])
|
|
|
|
|
|
class EventModel(pydantic.BaseModel):
|
|
name: str
|
|
short_desc: str
|
|
long_desc: str
|
|
url: Optional[str] = None
|
|
thumbnail: Optional[str] = None
|
|
active: Optional[bool] = False
|
|
|
|
|
|
@router.get("")
|
|
async def v1_events_get(
|
|
name: Optional[str] = None,
|
|
in_desc: Optional[str] = None,
|
|
active: Optional[bool] = None,
|
|
csv: Optional[bool] = None,
|
|
limit: Optional[int] = 100,
|
|
):
|
|
all_events = Event.select().order_by(Event.id)
|
|
|
|
if name is not None:
|
|
all_events = all_events.where(fn.Lower(Event.name) == name.lower())
|
|
if in_desc is not None:
|
|
all_events = all_events.where(
|
|
(fn.Lower(Event.short_desc).contains(in_desc.lower()))
|
|
| (fn.Lower(Event.long_desc).contains(in_desc.lower()))
|
|
)
|
|
if active is not None:
|
|
all_events = all_events.where(Event.active == active)
|
|
|
|
total_count = all_events.count() if not csv else 0
|
|
all_events = all_events.limit(max(0, min(limit, 500)))
|
|
|
|
if csv:
|
|
data_list = [
|
|
["id", "name", "short_desc", "long_desc", "url", "thumbnail", "active"]
|
|
]
|
|
for line in all_events:
|
|
data_list.append(
|
|
[
|
|
line.id,
|
|
line.name,
|
|
line.short_desc,
|
|
line.long_desc,
|
|
line.url,
|
|
line.thumbnail,
|
|
line.active,
|
|
]
|
|
)
|
|
return_val = DataFrame(data_list).to_csv(header=False, index=False)
|
|
|
|
return Response(content=return_val, media_type="text/csv")
|
|
|
|
else:
|
|
return_val = {"count": total_count, "events": []}
|
|
for x in all_events:
|
|
return_val["events"].append(model_to_dict(x))
|
|
|
|
return return_val
|
|
|
|
|
|
@router.get("/{event_id}")
|
|
async def v1_events_get_one(event_id, csv: Optional[bool] = False):
|
|
try:
|
|
this_event = Event.get_by_id(event_id)
|
|
except DoesNotExist:
|
|
raise HTTPException(
|
|
status_code=404, detail=f"No event found with id {event_id}"
|
|
)
|
|
|
|
if csv:
|
|
data_list = [
|
|
["id", "name", "short_desc", "long_desc", "url", "thumbnail", "active"],
|
|
[
|
|
this_event.id,
|
|
this_event.name,
|
|
this_event.short_desc,
|
|
this_event.long_desc,
|
|
this_event.url,
|
|
this_event.thumbnail,
|
|
this_event.active,
|
|
],
|
|
]
|
|
return_val = DataFrame(data_list).to_csv(header=False, index=False)
|
|
|
|
return Response(content=return_val, media_type="text/csv")
|
|
|
|
else:
|
|
return_val = model_to_dict(this_event)
|
|
return return_val
|
|
|
|
|
|
@router.post("")
|
|
async def v1_events_post(event: EventModel, token: str = Depends(oauth2_scheme)):
|
|
if not valid_token(token):
|
|
logging.warning("Bad Token: [REDACTED]")
|
|
raise HTTPException(
|
|
status_code=401,
|
|
detail="You are not authorized to post events. This event has been logged.",
|
|
)
|
|
|
|
dupe_event = Event.get_or_none(Event.name == event.name)
|
|
if dupe_event:
|
|
raise HTTPException(
|
|
status_code=400, detail=f"There is already an event using {event.name}"
|
|
)
|
|
|
|
this_event = Event(
|
|
name=event.name,
|
|
short_desc=event.short_desc,
|
|
long_desc=event.long_desc,
|
|
url=event.url,
|
|
thumbnail=event.thumbnail,
|
|
active=event.active,
|
|
)
|
|
|
|
saved = this_event.save()
|
|
if saved == 1:
|
|
return_val = model_to_dict(this_event)
|
|
return return_val
|
|
else:
|
|
raise HTTPException(
|
|
status_code=418,
|
|
detail="Well slap my ass and call me a teapot; I could not save that cardset",
|
|
)
|
|
|
|
|
|
@router.patch("/{event_id}")
|
|
async def v1_events_patch(
|
|
event_id,
|
|
name: Optional[str] = None,
|
|
short_desc: Optional[str] = None,
|
|
long_desc: Optional[str] = None,
|
|
url: Optional[str] = None,
|
|
thumbnail: Optional[str] = None,
|
|
active: Optional[bool] = None,
|
|
token: str = Depends(oauth2_scheme),
|
|
):
|
|
if not valid_token(token):
|
|
logging.warning("Bad Token: [REDACTED]")
|
|
raise HTTPException(
|
|
status_code=401,
|
|
detail="You are not authorized to patch events. This event has been logged.",
|
|
)
|
|
try:
|
|
this_event = Event.get_by_id(event_id)
|
|
except DoesNotExist:
|
|
raise HTTPException(
|
|
status_code=404, detail=f"No event found with id {event_id}"
|
|
)
|
|
|
|
if name is not None:
|
|
this_event.name = name
|
|
if short_desc is not None:
|
|
this_event.short_desc = short_desc
|
|
if long_desc is not None:
|
|
this_event.long_desc = long_desc
|
|
if url is not None:
|
|
this_event.url = url
|
|
if thumbnail is not None:
|
|
this_event.thumbnail = thumbnail
|
|
if active is not None:
|
|
this_event.active = active
|
|
|
|
if this_event.save() == 1:
|
|
return_val = model_to_dict(this_event)
|
|
return return_val
|
|
else:
|
|
raise HTTPException(
|
|
status_code=418,
|
|
detail="Well slap my ass and call me a teapot; I could not save that event",
|
|
)
|
|
|
|
|
|
@router.delete("/{event_id}")
|
|
async def v1_events_delete(event_id, token: str = Depends(oauth2_scheme)):
|
|
if not valid_token(token):
|
|
logging.warning("Bad Token: [REDACTED]")
|
|
raise HTTPException(
|
|
status_code=401,
|
|
detail="You are not authorized to delete events. This event has been logged.",
|
|
)
|
|
try:
|
|
this_event = Event.get_by_id(event_id)
|
|
except DoesNotExist:
|
|
raise HTTPException(
|
|
status_code=404, detail=f"No event found with id {event_id}"
|
|
)
|
|
|
|
count = this_event.delete_instance()
|
|
|
|
if count == 1:
|
|
raise HTTPException(
|
|
status_code=200, detail=f"Event {event_id} has been deleted"
|
|
)
|
|
else:
|
|
raise HTTPException(status_code=500, detail=f"Event {event_id} was not deleted")
|