Skip to content

Commit

Permalink
PPR API allow callback URLs when large report data size. (#1904)
Browse files Browse the repository at this point in the history
Signed-off-by: Doug Lovett <doug@diamante.ca>
  • Loading branch information
doug-lovett authored May 30, 2024
1 parent 86c731e commit 90ad85f
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 24 deletions.
11 changes: 10 additions & 1 deletion ppr-api/src/ppr_api/models/search_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,16 @@ def update_selection(self, search_select, account_name: str = None, callback_url
if account_name:
self.account_name = account_name
if callback_url:
self.callback_url = callback_url
size_threshold = current_app.config.get('SEARCH_PDF_ASYNC_THRESHOLD')
if detail_response.get('totalResultsSize') >= size_threshold:
self.callback_url = callback_url
else:
results_length = len(json.dumps(new_results))
current_app.logger.debug(f'Search id={self.search_id} data size={results_length}.')
if results_length > current_app.config.get('MAX_SIZE_SEARCH_RT'):
# Small results size but large report data: allow callback
self.callback_url = callback_url
current_app.logger.info(f'Search {self.search_id} async with callback {self.callback_url}.')
else:
results_length = len(json.dumps(new_results))
current_app.logger.debug(f'Search id= {self.search_id} results size={results_length}.')
Expand Down
57 changes: 34 additions & 23 deletions ppr-api/src/ppr_api/resources/v1/search_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
@bp.route('/<string:search_id>', methods=['POST', 'OPTIONS'])
@cross_origin(origin='*')
@jwt.requires_auth
def post_search_results(search_id: str): # pylint: disable=too-many-branches, too-many-locals
def post_search_results(search_id: str): # pylint: disable=too-many-branches
"""Execute a search detail request using selection choices in the request body."""
try:
if search_id is None:
Expand Down Expand Up @@ -98,6 +98,8 @@ def post_search_results(search_id: str): # pylint: disable=too-many-branches, t
error = f'Large search report required callbackURL parameter missing for {search_id}.'
current_app.logger.warn(error)
return resource_utils.error_response(HTTPStatus.BAD_REQUEST, error)
elif callback_url and not is_ui_pdf and resource_utils.is_pdf(request):
current_app.logger.debug(f'Search report {search_id} results size < threshold callback={callback_url}.')
else:
callback_url = None
is_ui_pdf = False
Expand All @@ -114,27 +116,7 @@ def post_search_results(search_id: str): # pylint: disable=too-many-branches, t
callback_url = search_detail.callback_url
is_ui_pdf = True
if resource_utils.is_pdf(request) or is_ui_pdf:
# If results over threshold return JSON with callbackURL, getReportURL
if callback_url is not None:
# Add enqueue report generation event here.
enqueue_search_report(search_id)
response_data['callbackURL'] = requests.utils.unquote(callback_url)
response_data['getReportURL'] = REPORT_URL.format(search_id=search_id)
return jsonify(response_data), HTTPStatus.OK

# Return report if request header Accept MIME type is application/pdf.
raw_data, status_code, headers = get_pdf(response_data,
account_id,
ReportTypes.SEARCH_DETAIL_REPORT.value,
jwt.get_token_auth_header())
current_app.logger.debug(f'report api call status={status_code}, headers=' + json.dumps(headers))
if raw_data and status_code in (HTTPStatus.OK, HTTPStatus.CREATED):
doc_name = model_utils.get_search_doc_storage_name(search_detail.search)
response = GoogleStorageService.save_document(doc_name, raw_data)
current_app.logger.info(f'Save {doc_name} document storage response: ' + json.dumps(response))
search_detail.doc_storage_url = doc_name
search_detail.save()
return raw_data, HTTPStatus.OK, {'Content-Type': 'application/pdf'}
return results_pdf_response(response_data, search_id, account_id, search_detail, callback_url)

return jsonify(response_data), HTTPStatus.OK

Expand Down Expand Up @@ -382,6 +364,35 @@ def post_notifications(search_id: str): # pylint: disable=too-many-branches, to
str(default_err))


def results_pdf_response(response_data: dict,
search_id: str,
account_id: str,
search_detail: SearchResult,
callback_url: str = None):
"""For PDF search result requests build the response with conditional async/callback set up."""
# If results over threshold return JSON with callbackURL, getReportURL
if callback_url is not None:
# Add enqueue report generation event here.
enqueue_search_report(search_id)
response_data['callbackURL'] = requests.utils.unquote(callback_url)
response_data['getReportURL'] = REPORT_URL.format(search_id=search_id)
return jsonify(response_data), HTTPStatus.OK
raw_data, status_code, headers = get_pdf(response_data,
account_id,
ReportTypes.SEARCH_DETAIL_REPORT.value,
jwt.get_token_auth_header())
current_app.logger.debug(f'report api call status={status_code}, headers=' + json.dumps(headers))
if raw_data and status_code in (HTTPStatus.OK, HTTPStatus.CREATED):
doc_name = model_utils.get_search_doc_storage_name(search_detail.search)
response = GoogleStorageService.save_document(doc_name, raw_data)
current_app.logger.info(f'Save {doc_name} document storage response: ' + json.dumps(response))
search_detail.doc_storage_url = doc_name
search_detail.save()
return raw_data, HTTPStatus.OK, {'Content-Type': 'application/pdf'}

return jsonify(response_data), HTTPStatus.OK


def callback_error(code: str, search_id: str, status_code, message: str = None):
"""Return to the event listener callback error response based on the code."""
error = CALLBACK_MESSAGES[code].format(search_id=search_id)
Expand Down Expand Up @@ -425,7 +436,7 @@ def send_notification(callback_url: str, search_id):
'Content-Type': 'application/json'
}
current_app.logger.info('Sending ' + data_json + ' to ' + callback_url)
response = requests.post(url=callback_url, headers=headers, data=data_json, timeout=3.0)
response = requests.post(url=callback_url, headers=headers, data=data_json, timeout=30.0)
return response


Expand Down

0 comments on commit 90ad85f

Please sign in to comment.