Skip to content

Commit

Permalink
Create webhook endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
kaapstorm committed Nov 22, 2023
1 parent 96b6c9b commit d77b480
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
13 changes: 13 additions & 0 deletions hq_superset/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from dataclasses import dataclass
from typing import Any, Literal


@dataclass
class DataSetChange:
action: Literal['UPSERT', 'DELETE']
data_source_id: str
data: dict[str, Any]

def __post_init__(self):
if 'doc_id' not in self.data:
raise TypeError("'data' missing required key: 'doc_id'")
51 changes: 50 additions & 1 deletion hq_superset/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import ast
import json
import logging
import os
from http import HTTPStatus

import superset
from flask import Response, abort, flash, g, redirect, request, url_for
Expand All @@ -14,9 +16,11 @@
DatasetForbiddenError,
DatasetNotFoundError,
)
from superset.views.base import BaseSupersetView
from superset.superset_typing import FlaskResponse
from superset.views.base import BaseSupersetView, json_error_response

from .hq_domain import user_domains
from .models import DataSetChange
from .oauth import get_valid_cchq_oauth_token
from .tasks import refresh_hq_datasource_task
from .utils import (
Expand Down Expand Up @@ -236,3 +240,48 @@ def select(self, hq_domain):
response.set_cookie('hq_domain', hq_domain)
DomainSyncUtil(superset.appbuilder.sm).sync_domain_role(hq_domain)
return response


class DataSetChangeAPI(BaseSupersetView):
"""
Accepts changes to datasets from CommCare HQ data forwarding
"""

MAX_REQUEST_LENGTH = 10_485_760 # reject >10MB JSON requests

def __init__(self):
self.route_base = '/hq_webhook'
self.default_view = 'post'
super().__init__()

@expose('/change/', methods=['POST'])
# TODO: Authenticate
def post(self) -> FlaskResponse:
if request.content_length > self.MAX_REQUEST_LENGTH:
return json_error_response(
HTTPStatus.REQUEST_ENTITY_TOO_LARGE.description,
status=HTTPStatus.REQUEST_ENTITY_TOO_LARGE.value,
)

try:
request_json = json.loads(request.get_data(as_text=True))
except json.JSONDecodeError:
return json_error_response(
'Invalid JSON syntax',
status=HTTPStatus.BAD_REQUEST.value,
)

try:
change = DataSetChange(**request_json)
except TypeError as err:
return json_error_response(
str(err),
status=HTTPStatus.BAD_REQUEST.value,
)

# TODO: SC-3212: Update dataset with change

return self.json_response(
'Request accepted; updating dataset',
status=HTTPStatus.ACCEPTED.value,
)

0 comments on commit d77b480

Please sign in to comment.