def test_response_spec(): resp = Response('HTTP_200', HTTP_201=DemoModel) spec = resp.generate_spec() assert spec['200']['description'] == DEFAULT_CODE_DESC['HTTP_200'] assert spec['201']['description'] == DEFAULT_CODE_DESC['HTTP_201'] assert spec['201']['content']['application/json']['schema']['$ref'].split( '/')[-1] == 'DemoModel' assert spec.get(200) is None assert spec.get(404) is None
class FormsList(Route): """ List all available forms for authorized viewers. """ name = "forms_list_create" path = "/" @requires(["authenticated", "Admins"]) @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() for form in await cursor.to_list(None): forms.append(Form(**form)) # For converting _id to id # Covert them back to dictionaries forms = [form.dict() for form in forms] return JSONResponse(forms) @requires(["authenticated", "Helpers"]) @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() # Verify Webhook try: # Get url from request webhook = form_data[WebHook.__name__.lower()] if webhook is not None: url = webhook[WebHook.URL.value] # Validate URL validation = await validate_hook_url(url) if validation: return JSONResponse(validation.errors(), status_code=422) except KeyError: pass form = Form(**form_data) 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())
def test_response_spec(): resp = Response("HTTP_200", HTTP_201=DemoModel) spec = resp.generate_spec() assert spec["200"]["description"] == DEFAULT_CODE_DESC["HTTP_200"] assert spec["201"]["description"] == DEFAULT_CODE_DESC["HTTP_201"] assert spec["422"]["description"] == DEFAULT_CODE_DESC["HTTP_422"] assert (spec["201"]["content"]["application/json"]["schema"]["$ref"].split( "/")[-1] == "DemoModel") assert (spec["422"]["content"]["application/json"]["schema"]["$ref"].split( "/")[-1] == "UnprocessableEntity") assert spec.get(200) is None assert spec.get(404) is None
class DiscoverableFormsList(Route): """ List all discoverable forms that should be shown on the homepage. """ 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" }).sort("name") # Parse it to Form and then back to dictionary # to replace _id with id for form in await cursor.to_list(None): forms.append(Form(**form)) forms = [form.dict(admin=False) for form in forms] # Return an empty form in development environments to help with authentication. if not forms and not constants.PRODUCTION: forms.append(EMPTY_FORM.dict(admin=False)) return JSONResponse(forms)
def test_init_response(): for args, kwargs in [ ([200], {}), (['HTTP_110'], {}), ([], { 'HTTP_200': NormalClass }), ]: with pytest.raises(AssertionError): Response(*args, **kwargs) resp = Response('HTTP_200', HTTP_201=DemoModel) assert resp.has_model() assert resp.find_model(201) == DemoModel assert DemoModel in resp.models resp = Response(HTTP_200=None, HTTP_403=DemoModel) assert resp.has_model() assert resp.find_model(403) == DemoModel assert resp.find_model(200) is None assert DemoModel in resp.models assert not Response().has_model()
class TokenRefreshRoute(Route): """ Use the refresh code from a JWT to get a new token and generate a new JWT token. """ name = "refresh" path = "/refresh" @requires(["authenticated"]) @api.validate( resp=Response(HTTP_200=AuthorizeResponse, HTTP_400=ErrorMessage), tags=["auth"] ) async def post(self, request: Request) -> responses.JSONResponse: """Refresh an authorization token.""" try: token = request.user.decoded_token.get("refresh") url = request.headers.get("origin") bearer_token = await fetch_bearer_token(token, url, refresh=True) except httpx.HTTPStatusError: return AUTH_FAILURE return await process_token(bearer_token, request)
class AuthorizeRoute(Route): """ Use the authorization code from Discord to generate a JWT token. """ name = "authorize" path = "/authorize" @api.validate( json=AuthorizeRequest, resp=Response(HTTP_200=AuthorizeResponse, HTTP_400=ErrorMessage), tags=["auth"] ) async def post(self, request: Request) -> responses.JSONResponse: """Generate an authorization token.""" data = await request.json() try: url = request.headers.get("origin") bearer_token = await fetch_bearer_token(data["token"], url, refresh=False) except httpx.HTTPStatusError: return AUTH_FAILURE return await process_token(bearer_token, request)
parse_resp, has_model, parse_code, parse_name) from spectree.spec import SpecTree from spectree.response import Response from .common import DemoModel api = SpecTree() def undecorated_func(): """summary description""" pass @api.validate(json=DemoModel, resp=Response(HTTP_200=DemoModel)) def demo_func(): """ summary description""" pass class DemoClass: @api.validate(query=DemoModel) def demo_method(self): """summary description """ pass
class SingleForm(Route): """ Returns, updates or deletes a single form given an ID. Returns all fields for admins, otherwise only public fields. """ 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.""" form_id = request.path_params["form_id"].lower() try: await discord.verify_edit_access(form_id, request) admin = True except discord.FormNotFoundError: if not constants.PRODUCTION and form_id == EMPTY_FORM.id: # Empty form to help with authentication in development. return JSONResponse(EMPTY_FORM.dict(admin=False)) raise except discord.UnauthorizedError: admin = False filters = {"_id": form_id} if not admin: filters["features"] = {"$in": ["OPEN", "DISCOVERABLE"]} form = Form(**await request.state.db.forms.find_one(filters)) if not admin: form = filter_unittests(form) return JSONResponse(form.dict(admin=admin)) @requires(["authenticated"]) @api.validate(resp=Response( HTTP_200=OkayResponse, HTTP_400=ErrorMessage, HTTP_404=ErrorMessage, ), tags=["forms"]) async def patch(self, request: Request) -> JSONResponse: """Updates form by ID.""" try: data = await request.json() except json.decoder.JSONDecodeError: return JSONResponse("Expected a JSON body.", 400) form_id = request.path_params["form_id"].lower() await discord.verify_edit_access(form_id, request) if raw_form := await request.state.db.forms.find_one({"_id": form_id}): if "_id" in data or "id" in data: if (data.get("id") or data.get("_id")) != form_id: return JSONResponse({"error": "locked_field"}, status_code=400) # Build Data Merger merge_strategy = [(dict, ["merge"])] merger = deepmerge.Merger(merge_strategy, ["override"], ["override"]) # Merge Form Data updated_form = merger.merge(raw_form, data) try: form = Form(**updated_form) except ValidationError as e: return JSONResponse(e.errors(), status_code=422) await request.state.db.forms.replace_one({"_id": form_id}, form.dict()) return JSONResponse(form.dict()) else:
# Merge Form Data updated_form = merger.merge(raw_form, data) try: form = Form(**updated_form) except ValidationError as e: return JSONResponse(e.errors(), status_code=422) await request.state.db.forms.replace_one({"_id": form_id}, form.dict()) return JSONResponse(form.dict()) else: return JSONResponse({"error": "not_found"}, status_code=404) @requires(["authenticated", "admin"]) @api.validate(resp=Response(HTTP_200=OkayResponse, HTTP_401=ErrorMessage, HTTP_404=ErrorMessage), tags=["forms"]) async def delete(self, request: Request) -> JSONResponse: """Deletes form by ID.""" form_id = request.path_params["form_id"].lower() await discord.verify_edit_access(form_id, request) await request.state.db.forms.delete_one({"_id": form_id}) await request.state.db.responses.delete_many({"form_id": form_id}) return JSONResponse({"status": "ok"})