diff options
author | 2020-12-14 17:53:10 +0000 | |
---|---|---|
committer | 2020-12-14 17:53:10 +0000 | |
commit | afc3596943db58b62a78f121310605696300f7fa (patch) | |
tree | f76bc6827a0fb9286414627d1537740a532e2de4 /backend | |
parent | Restructure single response route (diff) | |
parent | Merge pull request #25 from python-discord/bugfix/route-collision (diff) |
Merge branch 'main' into ks123/single-response-route
Diffstat (limited to 'backend')
-rw-r--r-- | backend/constants.py | 2 | ||||
-rw-r--r-- | backend/models/form.py | 21 | ||||
-rw-r--r-- | backend/route_manager.py | 3 | ||||
-rw-r--r-- | backend/routes/forms/discover.py | 2 | ||||
-rw-r--r-- | backend/routes/forms/form.py | 36 | ||||
-rw-r--r-- | backend/routes/forms/index.py | 19 | ||||
-rw-r--r-- | backend/routes/forms/new.py | 35 |
7 files changed, 80 insertions, 38 deletions
diff --git a/backend/constants.py b/backend/constants.py index 61519ed..fdf7092 100644 --- a/backend/constants.py +++ b/backend/constants.py @@ -13,7 +13,7 @@ OAUTH2_CLIENT_ID = os.getenv("OAUTH2_CLIENT_ID") OAUTH2_CLIENT_SECRET = os.getenv("OAUTH2_CLIENT_SECRET") OAUTH2_REDIRECT_URI = os.getenv( "OAUTH2_REDIRECT_URI", - "http://forms.pythondiscord.com/callback" + "https://forms.pythondiscord.com/callback" ) SECRET_KEY = os.getenv("SECRET_KEY", binascii.hexlify(os.urandom(30)).decode()) diff --git a/backend/models/form.py b/backend/models/form.py index 8d7fe9b..2cf8486 100644 --- a/backend/models/form.py +++ b/backend/models/form.py @@ -5,6 +5,8 @@ from pydantic import BaseModel, Field, validator from backend.constants import FormFeatures from .question import Question +PUBLIC_FIELDS = ["id", "features", "questions", "name", "description"] + class Form(BaseModel): """Schema model for form.""" @@ -31,3 +33,22 @@ class Form(BaseModel): raise ValueError("COLLECT_EMAIL feature require REQUIRES_LOGIN feature.") return value + + def dict(self, admin: bool = True, **kwargs: t.Dict) -> t.Dict[str, t.Any]: + """Wrapper for original function to exclude private data for public access.""" + data = super().dict(**kwargs) + + returned_data = {} + + if not admin: + for field in PUBLIC_FIELDS: + if field == "id" and kwargs.get("by_alias"): + fetch_field = "_id" + else: + fetch_field = field + + returned_data[field] = data[fetch_field] + else: + returned_data = data + + return returned_data diff --git a/backend/route_manager.py b/backend/route_manager.py index 3d83ee7..25529eb 100644 --- a/backend/route_manager.py +++ b/backend/route_manager.py @@ -20,6 +20,9 @@ def construct_route_map_from_dict(route_dict: dict) -> list: else: route_map.append(Mount(mount, routes=construct_route_map_from_dict(item))) + # Order non-capturing routes before capturing routes + route_map.sort(key=lambda route: "{" in route.path) + return route_map diff --git a/backend/routes/forms/discover.py b/backend/routes/forms/discover.py index af6066e..bba6fd4 100644 --- a/backend/routes/forms/discover.py +++ b/backend/routes/forms/discover.py @@ -25,7 +25,7 @@ class DiscoverableFormsList(Route): for form in await cursor.to_list(None): forms.append(Form(**form)) - forms = [form.dict() for form in forms] + forms = [form.dict(admin=False) for form in forms] return JSONResponse( forms diff --git a/backend/routes/forms/form.py b/backend/routes/forms/form.py new file mode 100644 index 0000000..599632e --- /dev/null +++ b/backend/routes/forms/form.py @@ -0,0 +1,36 @@ +""" +Returns single form information by ID. +""" +from starlette.requests import Request +from starlette.responses import JSONResponse + +from backend.route import Route +from backend.models import Form + + +class SingleForm(Route): + """ + Returns single form information by ID. + + Returns all fields for admins, otherwise only public fields. + """ + + name = "form" + path = "/{form_id:str}" + + 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 + + filters = { + "_id": request.path_params["form_id"] + } + + if not admin: + filters["features"] = "OPEN" + + if raw_form := await request.state.db.forms.find_one(filters): + form = Form(**raw_form) + return JSONResponse(form.dict(admin=admin)) + + return JSONResponse({"error": "not_found"}, status_code=404) diff --git a/backend/routes/forms/index.py b/backend/routes/forms/index.py index f1df210..bb2b299 100644 --- a/backend/routes/forms/index.py +++ b/backend/routes/forms/index.py @@ -1,6 +1,7 @@ """ Return a list of all forms to authenticated users. """ +from pydantic import ValidationError from starlette.authentication import requires from starlette.requests import Request from starlette.responses import JSONResponse @@ -14,7 +15,7 @@ class FormsList(Route): List all available forms for administrator viewing. """ - name = "forms_list" + name = "forms_list_create" path = "/" @requires(["authenticated", "admin"]) @@ -31,3 +32,19 @@ class FormsList(Route): return JSONResponse( forms ) + + @requires(["authenticated", "admin"]) + async def post(self, request: Request) -> JSONResponse: + form_data = await request.json() + try: + form = Form(**form_data) + except ValidationError as e: + return JSONResponse(e.errors()) + + if await request.state.db.forms.find_one({"_id": form.id}): + return JSONResponse({ + "error": "id_taken" + }, status_code=400) + + await request.state.db.forms.insert_one(form.dict(by_alias=True)) + return JSONResponse(form.dict()) diff --git a/backend/routes/forms/new.py b/backend/routes/forms/new.py deleted file mode 100644 index 6437a4a..0000000 --- a/backend/routes/forms/new.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Creates new form based on data provided. -""" -from pydantic import ValidationError -from starlette.authentication import requires -from starlette.requests import Request -from starlette.responses import JSONResponse - -from backend.models import Form -from backend.route import Route - - -class FormCreate(Route): - """ - Creates new form from JSON data. - """ - - name = "forms_create" - path = "/new" - - @requires(["authenticated", "admin"]) - async def post(self, request: Request) -> JSONResponse: - form_data = await request.json() - try: - form = Form(**form_data) - except ValidationError as e: - return JSONResponse(e.errors()) - - if await request.state.db.forms.find_one({"_id": form.id}): - return JSONResponse({ - "error": "Form with same ID already exists." - }, status_code=400) - - await request.state.db.forms.insert_one(form.dict(by_alias=True)) - return JSONResponse(form.dict()) |