Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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())
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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()
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
                            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
Ejemplo n.º 9
0
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:
Ejemplo n.º 10
0
            # 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"})