Implement extra field for Guests and created timestamp for Parties, Add documentation for errors
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
e4e7497b3e
commit
0949a6c2ad
116
backend/app.py
116
backend/app.py
@ -1,3 +1,4 @@
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
from fastapi import FastAPI, HTTPException, status, Depends
|
||||
from pydantic import BaseModel
|
||||
@ -7,6 +8,7 @@ from .db import MongoModel, PyObjectId, client
|
||||
from .settings import settings
|
||||
|
||||
db = client["party"]
|
||||
meta = client["party-meta"]
|
||||
|
||||
description = """
|
||||
Party party \U0001F973
|
||||
@ -44,25 +46,44 @@ Coming = Literal["yes", "no", "maybe"]
|
||||
GrammaticalGender = Literal["m", "f", "d"]
|
||||
|
||||
|
||||
class Guest(MongoModel):
|
||||
class HTTPError(BaseModel):
|
||||
detail: str
|
||||
|
||||
|
||||
# error_responses = {status.HTTP_401_UNAUTHORIZED: {"model": HTTPError}}
|
||||
def error_responses(*args):
|
||||
return {arg: {"model": HTTPError} for arg in args}
|
||||
|
||||
|
||||
class Guest(BaseModel):
|
||||
token: str
|
||||
name: str
|
||||
coming: Coming | None
|
||||
grammatical_gender: GrammaticalGender
|
||||
extra: dict[str, str]
|
||||
|
||||
|
||||
async def find_guest(party: str, token: str) -> Guest:
|
||||
class DBGuest(Guest, MongoModel):
|
||||
pass
|
||||
|
||||
|
||||
async def find_guest(party: str, token: str) -> DBGuest:
|
||||
guest = await db[party].find_one({"token": token})
|
||||
if not guest:
|
||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED)
|
||||
return Guest.parse_obj(guest)
|
||||
return DBGuest.parse_obj(guest)
|
||||
|
||||
|
||||
# Guest methods
|
||||
|
||||
|
||||
@app.get("/{party}/{token}/me", response_model=Guest, tags=["guests"])
|
||||
async def get_self(guest: Guest = Depends(find_guest)):
|
||||
@app.get(
|
||||
"/{party}/{token}/me",
|
||||
response_model=Guest,
|
||||
responses=error_responses(401),
|
||||
tags=["guests"],
|
||||
)
|
||||
async def get_self(guest: DBGuest = Depends(find_guest)):
|
||||
return guest
|
||||
|
||||
|
||||
@ -70,13 +91,19 @@ class GuestUpdate(BaseModel):
|
||||
coming: Coming
|
||||
|
||||
|
||||
@app.patch("/{party}/{token}/me", tags=["guests"])
|
||||
@app.patch(
|
||||
"/{party}/{token}/me",
|
||||
response_model=Guest,
|
||||
responses=error_responses(401),
|
||||
tags=["guests"],
|
||||
)
|
||||
async def update_self(
|
||||
party: str, update: GuestUpdate, guest: Guest = Depends(find_guest)
|
||||
party: str, update: GuestUpdate, guest: DBGuest = Depends(find_guest)
|
||||
):
|
||||
guest_dict = guest.dict()
|
||||
guest_dict = guest.dict(exclude={"id"})
|
||||
guest_dict.update(update.dict())
|
||||
await db[party].replace_one({"_id": guest.id}, guest_dict)
|
||||
return await db[party].find_one({"_id": guest.id})
|
||||
|
||||
|
||||
class PartyStatus(BaseModel):
|
||||
@ -84,7 +111,12 @@ class PartyStatus(BaseModel):
|
||||
maybe_coming: int
|
||||
|
||||
|
||||
@app.get("/{party}/{token}/status", response_model=PartyStatus, tags=["guests"])
|
||||
@app.get(
|
||||
"/{party}/{token}/status",
|
||||
response_model=PartyStatus,
|
||||
responses=error_responses(401),
|
||||
tags=["guests"],
|
||||
)
|
||||
async def get_party_status(party: str, _=Depends(find_guest)):
|
||||
definitely_coming = await db[party].count_documents({"coming": "yes"})
|
||||
maybe_coming = await db[party].count_documents({"coming": "maybe"})
|
||||
@ -103,17 +135,32 @@ async def auth_admin(admin_token: str):
|
||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
|
||||
@app.get("/{admin_token}", response_model=list[str], tags=["admin"])
|
||||
class Party(MongoModel):
|
||||
name: str
|
||||
created: datetime
|
||||
|
||||
|
||||
@app.get(
|
||||
"/{admin_token}",
|
||||
response_model=list[Party],
|
||||
responses=error_responses(401),
|
||||
tags=["admin"],
|
||||
)
|
||||
async def list_parties(_=Depends(auth_admin)):
|
||||
filter = {"name": {"$regex": r"^(?!system\.)"}}
|
||||
return await db.list_collection_names(filter=filter)
|
||||
return await meta["parties"].find().to_list(None)
|
||||
|
||||
|
||||
class PartyCreate(BaseModel):
|
||||
name: str
|
||||
|
||||
|
||||
@app.post("/{admin_token}", status_code=status.HTTP_204_NO_CONTENT, tags=["admin"])
|
||||
@app.post(
|
||||
"/{admin_token}",
|
||||
response_model=Party,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
responses=error_responses(400, 401),
|
||||
tags=["admin"],
|
||||
)
|
||||
async def create_party(party: PartyCreate, _=Depends(auth_admin)):
|
||||
try:
|
||||
await db.create_collection(party.name)
|
||||
@ -121,17 +168,37 @@ async def create_party(party: PartyCreate, _=Depends(auth_admin)):
|
||||
raise HTTPException(
|
||||
status.HTTP_400_BAD_REQUEST, f"Party {party.name!r} already exists"
|
||||
)
|
||||
inserted = await meta["parties"].insert_one(
|
||||
{
|
||||
"name": party.name,
|
||||
"created": datetime.now(),
|
||||
}
|
||||
)
|
||||
return await meta["parties"].find_one({"_id": inserted.inserted_id})
|
||||
|
||||
|
||||
@app.delete(
|
||||
"/{admin_token}/{party}", status_code=status.HTTP_204_NO_CONTENT, tags=["admin"]
|
||||
"/{admin_token}/{party}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
responses=error_responses(401, 404),
|
||||
tags=["admin"],
|
||||
)
|
||||
async def delete_party(party: str, _=Depends(auth_admin)):
|
||||
deleted = await meta["parties"].delete_one({"name": party})
|
||||
if deleted.deleted_count < 1:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
||||
await db.drop_collection(party)
|
||||
|
||||
|
||||
@app.get("/{admin_token}/{party}", response_model=list[Guest], tags=["admin"])
|
||||
@app.get(
|
||||
"/{admin_token}/{party}",
|
||||
response_model=list[DBGuest],
|
||||
responses=error_responses(401, 404),
|
||||
tags=["admin"],
|
||||
)
|
||||
async def list_guests(party: str, _=Depends(auth_admin)):
|
||||
if not await meta["parties"].find_one({"name": party}):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
||||
return await db[party].find().to_list(None)
|
||||
|
||||
|
||||
@ -140,15 +207,20 @@ class GuestCreate(BaseModel):
|
||||
name: str
|
||||
coming: Coming | None
|
||||
grammatical_gender: GrammaticalGender
|
||||
extra: dict[str, str] = dict()
|
||||
|
||||
|
||||
@app.post(
|
||||
"/{admin_token}/{party}",
|
||||
response_model=Guest,
|
||||
response_model=DBGuest,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
responses=error_responses(400, 401, 404),
|
||||
tags=["admin"],
|
||||
)
|
||||
async def create_new_guest(party: str, new_guest: GuestCreate, _=Depends(auth_admin)):
|
||||
if not await meta["parties"].find_one({"name": party}):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
existing = await db[party].find_one({"token": new_guest.token})
|
||||
if existing:
|
||||
raise HTTPException(
|
||||
@ -165,12 +237,21 @@ class GuestModify(BaseModel):
|
||||
name: str | None
|
||||
coming: Coming | None
|
||||
grammatical_gender: GrammaticalGender | None
|
||||
extra: dict[str, str] | None
|
||||
|
||||
|
||||
@app.patch("/{admin_token}/{party}/{id}", response_model=Guest, tags=["admin"])
|
||||
@app.patch(
|
||||
"/{admin_token}/{party}/{id}",
|
||||
response_model=DBGuest,
|
||||
responses=error_responses(401, 404),
|
||||
tags=["admin"],
|
||||
)
|
||||
async def modify_guest(
|
||||
party: str, id: PyObjectId, modified_guest: GuestModify, _=Depends(auth_admin)
|
||||
):
|
||||
if not await meta["parties"].find_one({"name": party}):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
existing = await db[party].find_one({"_id": id})
|
||||
if not existing:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND)
|
||||
@ -184,6 +265,7 @@ async def modify_guest(
|
||||
@app.delete(
|
||||
"/{admin_token}/{party}/{id}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
responses=error_responses(401, 404),
|
||||
tags=["admin"],
|
||||
)
|
||||
async def delete_guest(party: str, id: PyObjectId, _=Depends(auth_admin)):
|
||||
|
Loading…
Reference in New Issue
Block a user