diff options
author | 2020-12-16 23:26:45 +0000 | |
---|---|---|
committer | 2020-12-16 23:26:45 +0000 | |
commit | a9006d82f5ba54054c3fe239dbf38361365e11b8 (patch) | |
tree | 2eeb196e20af64a7942073fd876cf24f9320e93c | |
parent | Make model changes (diff) |
Document forms routes
-rw-r--r-- | backend/routes/forms/discover.py | 6 | ||||
-rw-r--r-- | backend/routes/forms/form.py | 7 | ||||
-rw-r--r-- | backend/routes/forms/index.py | 19 | ||||
-rw-r--r-- | backend/routes/forms/response.py | 14 | ||||
-rw-r--r-- | backend/routes/forms/responses.py | 8 | ||||
-rw-r--r-- | backend/routes/forms/submit.py | 25 |
6 files changed, 69 insertions, 10 deletions
diff --git a/backend/routes/forms/discover.py b/backend/routes/forms/discover.py index bba6fd4..9400f05 100644 --- a/backend/routes/forms/discover.py +++ b/backend/routes/forms/discover.py @@ -1,11 +1,13 @@ """ Return a list of all publicly discoverable forms to unauthenticated users. """ +from spectree.response import Response from starlette.requests import Request from starlette.responses import JSONResponse -from backend.models import Form +from backend.models import Form, FormList from backend.route import Route +from backend.validation import api class DiscoverableFormsList(Route): @@ -16,7 +18,9 @@ class DiscoverableFormsList(Route): name = "discoverable_forms_list" path = "/discoverable" + @api.validate(resp=Response(HTTP_200=FormList), tags=["forms"]) async def get(self, request: Request) -> JSONResponse: + """List all discoverable forms that should be shown on the homepage.""" forms = [] cursor = request.state.db.forms.find({"features": "DISCOVERABLE"}) diff --git a/backend/routes/forms/form.py b/backend/routes/forms/form.py index 8fdd8a2..c953135 100644 --- a/backend/routes/forms/form.py +++ b/backend/routes/forms/form.py @@ -1,12 +1,14 @@ """ Returns or deletes a single form given an ID. """ +from spectree.response import Response from starlette.authentication import requires from starlette.requests import Request from starlette.responses import JSONResponse from backend.route import Route from backend.models import Form +from backend.validation import OkayResponse, api, ErrorMessage class SingleForm(Route): @@ -19,6 +21,7 @@ class SingleForm(Route): name = "form" path = "/{form_id:str}" + @api.validate(resp=Response(HTTP_200=Form, HTTP_404=ErrorMessage), tags=["forms"]) async def get(self, request: Request) -> JSONResponse: """Returns single form information by ID.""" admin = request.user.payload["admin"] if request.user.is_authenticated else False # noqa @@ -37,6 +40,10 @@ class SingleForm(Route): return JSONResponse({"error": "not_found"}, status_code=404) @requires(["authenticated", "admin"]) + @api.validate( + resp=Response(HTTP_200=OkayResponse, HTTP_404=ErrorMessage), + tags=["forms"] + ) async def delete(self, request: Request) -> JSONResponse: """Deletes form by ID.""" if not await request.state.db.forms.find_one( diff --git a/backend/routes/forms/index.py b/backend/routes/forms/index.py index bb2b299..d1373e4 100644 --- a/backend/routes/forms/index.py +++ b/backend/routes/forms/index.py @@ -1,13 +1,14 @@ """ Return a list of all forms to authenticated users. """ -from pydantic import ValidationError +from spectree.response import Response from starlette.authentication import requires from starlette.requests import Request from starlette.responses import JSONResponse from backend.route import Route -from backend.models import Form +from backend.models import Form, FormList +from backend.validation import ErrorMessage, OkayResponse, api class FormsList(Route): @@ -19,7 +20,9 @@ class FormsList(Route): path = "/" @requires(["authenticated", "admin"]) + @api.validate(resp=Response(HTTP_200=FormList), tags=["forms"]) async def get(self, request: Request) -> JSONResponse: + """Return a list of all forms to authenticated users.""" forms = [] cursor = request.state.db.forms.find() @@ -34,12 +37,16 @@ class FormsList(Route): ) @requires(["authenticated", "admin"]) + @api.validate( + json=Form, + resp=Response(HTTP_200=OkayResponse, HTTP_400=ErrorMessage), + tags=["forms"] + ) async def post(self, request: Request) -> JSONResponse: + """Create a new form.""" form_data = await request.json() - try: - form = Form(**form_data) - except ValidationError as e: - return JSONResponse(e.errors()) + + form = Form(**form_data) if await request.state.db.forms.find_one({"_id": form.id}): return JSONResponse({ diff --git a/backend/routes/forms/response.py b/backend/routes/forms/response.py index acaa647..d8d8d17 100644 --- a/backend/routes/forms/response.py +++ b/backend/routes/forms/response.py @@ -1,12 +1,14 @@ """ Returns or deletes form response by ID. """ +from spectree import Response as RouteResponse from starlette.authentication import requires from starlette.requests import Request from starlette.responses import JSONResponse from backend.models import FormResponse from backend.route import Route +from backend.validation import ErrorMessage, OkayResponse, api class Response(Route): @@ -16,8 +18,12 @@ class Response(Route): path = "/{form_id:str}/responses/{response_id:str}" @requires(["authenticated", "admin"]) + @api.validate( + resp=RouteResponse(HTTP_200=FormResponse, HTTP_404=ErrorMessage), + tags=["forms", "responses"] + ) async def get(self, request: Request) -> JSONResponse: - """Returns single form response by ID.""" + """Return a single form response by ID.""" if raw_response := await request.state.db.responses.find_one( { "_id": request.path_params["response_id"], @@ -30,8 +36,12 @@ class Response(Route): return JSONResponse({"error": "not_found"}, status_code=404) @requires(["authenticated", "admin"]) + @api.validate( + resp=RouteResponse(HTTP_200=OkayResponse, HTTP_404=ErrorMessage), + tags=["forms", "responses"] + ) async def delete(self, request: Request) -> JSONResponse: - """Deletes form response by ID.""" + """Delete a form response by ID.""" if not await request.state.db.responses.find_one( { "_id": request.path_params["response_id"], diff --git a/backend/routes/forms/responses.py b/backend/routes/forms/responses.py index ee8ab84..54da246 100644 --- a/backend/routes/forms/responses.py +++ b/backend/routes/forms/responses.py @@ -1,12 +1,14 @@ """ Returns all form responses by form ID. """ +from spectree import Response from starlette.authentication import requires from starlette.requests import Request from starlette.responses import JSONResponse -from backend.models import FormResponse +from backend.models import FormResponse, ResponseList from backend.route import Route +from backend.validation import api, ErrorMessage class Responses(Route): @@ -18,6 +20,10 @@ class Responses(Route): path = "/{form_id:str}/responses" @requires(["authenticated", "admin"]) + @api.validate( + resp=Response(HTTP_200=ResponseList, HTTP_404=ErrorMessage), + tags=["forms", "responses"] + ) async def get(self, request: Request) -> JSONResponse: """Returns all form responses by form ID.""" if not await request.state.db.forms.find_one( diff --git a/backend/routes/forms/submit.py b/backend/routes/forms/submit.py index 3ecbda0..150a343 100644 --- a/backend/routes/forms/submit.py +++ b/backend/routes/forms/submit.py @@ -4,11 +4,14 @@ Submit a form. import binascii import hashlib +from typing import Any, Optional import uuid import httpx +from pydantic.main import BaseModel import pydnsbl from pydantic import ValidationError +from spectree import Response from starlette.requests import Request from starlette.responses import JSONResponse @@ -16,6 +19,7 @@ from starlette.responses import JSONResponse from backend.constants import HCAPTCHA_API_SECRET, FormFeatures from backend.models import Form, FormResponse from backend.route import Route +from backend.validation import AuthorizationHeaders, ErrorMessage, api HCAPTCHA_VERIFY_URL = "https://hcaptcha.com/siteverify" HCAPTCHA_HEADERS = { @@ -23,6 +27,16 @@ HCAPTCHA_HEADERS = { } +class SubmissionResponse(BaseModel): + form: Form + response: FormResponse + + +class PartialSubmission(BaseModel): + response: dict[str, Any] + captcha: Optional[str] + + class SubmitForm(Route): """ Submit a form with the provided form ID. @@ -31,7 +45,18 @@ class SubmitForm(Route): name = "submit_form" path = "/submit/{form_id:str}" + @api.validate( + json=PartialSubmission, + resp=Response( + HTTP_200=SubmissionResponse, + HTTP_404=ErrorMessage, + HTTP_400=ErrorMessage + ), + headers=AuthorizationHeaders, + tags=["forms", "responses"] + ) async def post(self, request: Request) -> JSONResponse: + """Submit a response to the form.""" data = await request.json() if form := await request.state.db.forms.find_one( |