diff options
Diffstat (limited to 'pysite')
| -rw-r--r-- | pysite/base_route.py | 12 | ||||
| -rw-r--r-- | pysite/constants.py | 1 | ||||
| -rw-r--r-- | pysite/views/api/asana.py | 96 | 
3 files changed, 107 insertions, 2 deletions
diff --git a/pysite/base_route.py b/pysite/base_route.py index 04694186..a3e8615b 100644 --- a/pysite/base_route.py +++ b/pysite/base_route.py @@ -33,10 +33,18 @@ class APIView(RouteView):              "error_message": "Unknown error"          } +        http_code = 200 +          if error_code is ErrorCodes.unknown_route:              data["error_message"] = "Unknown API route" - -        return jsonify(data) +            http_code = 404 +        elif error_code is ErrorCodes.unauthorized: +            data["error_message"] = "Unauthorized" +            http_code = 403 + +        response = jsonify(data) +        response.status_code = http_code +        return response  class ErrorView(BaseView): diff --git a/pysite/constants.py b/pysite/constants.py index 8c3d9c1c..e5a283a7 100644 --- a/pysite/constants.py +++ b/pysite/constants.py @@ -6,3 +6,4 @@ from enum import IntEnum  class ErrorCodes(IntEnum):      unknown_route = 0 +    unauthorized = 1 diff --git a/pysite/views/api/asana.py b/pysite/views/api/asana.py new file mode 100644 index 00000000..ca9c5624 --- /dev/null +++ b/pysite/views/api/asana.py @@ -0,0 +1,96 @@ +# coding=utf-8 +import json +import os + +from flask import make_response, request + +import requests + +from pysite.base_route import APIView +from pysite.constants import ErrorCodes + +ASANA_KEY = os.environ.get("ASANA_KEY") +ASANA_WEBHOOK = os.environ.get("ASANA_WEBHOOK") + +COLOUR_RED = 0xFF0000 +COLOUR_GREEN = 0x00FF00 +COLOUR_BLUE = 0x0000FF + + +class IndexView(APIView): +    path = "/asana/<asana_key>" +    name = "asana" + +    def post(self, asana_key): +        if asana_key != ASANA_KEY: +            return self.error(ErrorCodes.unauthorized) + +        if "X-Hook-Secret" in request.headers:  # Confirm to Asana that we would like to make this hook +            response = make_response()  # type: flask.Response +            response.headers["X-Hook-Secret"] = request.headers["X-Hook-Secret"] +            return response + +        events = request.get_json()["events"] + +        for event in events: +            func_name = f"asana_{event['type']}_{event['action']}" + +            if hasattr(self, func_name): +                func = getattr(self, func_name) +            else: +                func = self.asana_unknown + +            try: +                func(**event) +            except Exception as e: +                pretty_event = json.dumps(event, indent=4, sort_key=True) + +                try: +                    self.send_webhook( +                        title="Error during webhook", +                        description=f"Failed to handle webhook: {e}\n\n```json\n{pretty_event}\n```", +                        color=COLOUR_RED +                    ) +                except Exception as e: +                    print(f"Fatal error sending webhook: {e}") + +        return "", 200  # Empty 200 response + +    def send_webhook(self, *, title, description, color=COLOUR_BLUE, url=None, author_name=None, author_icon=None): +        session = requests.session() + +        embed = { +            "title": title, +            "description": description, +            "color": color +        } + +        if url: +            embed["url"] = url + +        if author_name: +            embed["author"] = { +                "name": author_name, +                "icon_url": author_icon +            } + +        session.post(ASANA_WEBHOOK, json={"embeds": [embed]}) + +    def asana_unknown(self, *, resource, parent, created_at, user, action, _type): +        pretty_event = json.dumps( +            { +                "resource": resource, +                "parent": parent, +                "created_at": created_at, +                "user": user, +                "action": action, +                "type": _type +            }, +            indent=4, +            sort_key=True +        ) + +        self.send_webhook( +            title="Unknown event", +            description=f"```json\n{pretty_event}\n```" +        )  |