From 8cf8129cf5f7c8735a4ca6ec55f2de3abf8a8396 Mon Sep 17 00:00:00 2001 From: Thor Kell Date: Thu, 19 Apr 2018 21:35:58 -0400 Subject: [PATCH 1/5] Log and return 500 if we fail to send an item to knack --- sync/views.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sync/views.py b/sync/views.py index 4936fcb..695647f 100644 --- a/sync/views.py +++ b/sync/views.py @@ -7,11 +7,12 @@ from knackload import knackload from django.conf import settings -from django.http import HttpResponse, HttpResponseForbidden +from django.http import HttpResponse +from django.http import HttpResponseForbidden +from django.http import HttpResponseServerError from django.shortcuts import render from django.views.decorators.csrf import csrf_exempt - @csrf_exempt def sync(request): authorized = auth(request) @@ -24,11 +25,18 @@ def sync(request): # Will depend on how many line items we get. for knack_value in knack_values: if getattr(settings, 'DEBUG'): - print("sent {} to knack".format(json.dumps(knack_value, indent=4))) - (return_status, result_string) = knackload.load( json.dumps(knack_value) ) - result_data = json.loads(result_string) - if getattr(settings, 'DEBUG'): - print(json.dumps(result_data, indent=4)) + print('sent {} to knack'.format(json.dumps(knack_value, indent=4))) + + return_status, result_string = knackload.load(json.dumps(knack_value)) + + if return_status != 200: + print('Error: We failed to send {} to knack'.format(knack_value)) + return HttpResponseServerError() + else: + result_data = json.loads(result_string) + if getattr(settings, 'DEBUG'): + print(json.dumps(result_data, indent=4)) + return HttpResponse('') else: return HttpResponseForbidden() From 30f52d5b0a7735bc2397aef2b965b3eac1eccd0c Mon Sep 17 00:00:00 2001 From: Thor Kell Date: Thu, 19 Apr 2018 21:41:27 -0400 Subject: [PATCH 2/5] lint --- sync/views.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/sync/views.py b/sync/views.py index 695647f..37c2e10 100644 --- a/sync/views.py +++ b/sync/views.py @@ -10,11 +10,15 @@ from django.http import HttpResponse from django.http import HttpResponseForbidden from django.http import HttpResponseServerError -from django.shortcuts import render from django.views.decorators.csrf import csrf_exempt @csrf_exempt def sync(request): + """ + Entry point. Receives a POST from ActBlue, transforms it, and POSTs it on to Knack + + Returns a 200, 403, or 500 to ActBlue. + """ authorized = auth(request) if request.method == 'POST' and authorized: actblue_data = json.loads(request.body) @@ -50,13 +54,13 @@ def get_lineitems(actblue_values, mapping): """ knack_lineitems = [] lineitems = actblue_values['lineitems'] - amountKey = mapping['lineitems#amount'] - entityKey = mapping['lineitems#entityId'] + amount_key = mapping['lineitems#amount'] + entity_key = mapping['lineitems#entityId'] for lineitem in lineitems: knack_lineitem = {} - knack_lineitem[amountKey] = lineitem.get('amount') - knack_lineitem[entityKey] = lineitem.get('entityId') + knack_lineitem[amount_key] = lineitem.get('amount') + knack_lineitem[entity_key] = lineitem.get('entityId') knack_lineitems.append(knack_lineitem) return knack_lineitems @@ -79,8 +83,8 @@ def transform(actblue_values): for key, value in scalar_mapping: path = key.split('#') if isinstance(value, list): - for v in value: - knack_values[v] = walk(path, actblue_values) + for val in value: + knack_values[val] = walk(path, actblue_values) else: knack_values[value] = walk(path, actblue_values) @@ -115,6 +119,11 @@ def walk(path, container): def auth(request): + """ + Make sure an incoming request is authorized. + + Returns a boolean. + """ auth_header = request.META['HTTP_AUTHORIZATION'] encoded = auth_header.split(' ')[1].encode('ascii') username, password = base64.urlsafe_b64decode(encoded).split(b':') From 39f9249fb23204ff6771c04c281cb43735a05c1c Mon Sep 17 00:00:00 2001 From: Thor Kell Date: Fri, 20 Apr 2018 21:42:20 -0400 Subject: [PATCH 3/5] Don't log the entire object in production, add log_debug helper --- sync/views.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/sync/views.py b/sync/views.py index 37c2e10..f446f0d 100644 --- a/sync/views.py +++ b/sync/views.py @@ -12,6 +12,10 @@ from django.http import HttpResponseServerError from django.views.decorators.csrf import csrf_exempt +def log_debug(string): + if getattr(settings, 'DEBUG'): + print(string) + @csrf_exempt def sync(request): """ @@ -28,18 +32,20 @@ def sync(request): # This _could_ cause timeouts, but might be OK? # Will depend on how many line items we get. for knack_value in knack_values: - if getattr(settings, 'DEBUG'): - print('sent {} to knack'.format(json.dumps(knack_value, indent=4))) + log_debug('sent {} to knack'.format(json.dumps(knack_value, indent=4))) return_status, result_string = knackload.load(json.dumps(knack_value)) if return_status != 200: - print('Error: We failed to send {} to knack'.format(knack_value)) + contribution_refcode = knack_value['field_638'] + lineitem_entity_id = knack_value['field_684'] + error_msg = 'Error: We failed to send refcode {}, lineitem {} to knack' + print(error_msg.format(contribution_refcode, lineitem_entity_id)) + log_debug('Error: We failed to send ' + knack_value) return HttpResponseServerError() else: result_data = json.loads(result_string) - if getattr(settings, 'DEBUG'): - print(json.dumps(result_data, indent=4)) + log_debug(json.dumps(result_data, indent=4)) return HttpResponse('') else: From a940566add9b1b0b8a768eaa085f688228b2e73c Mon Sep 17 00:00:00 2001 From: Thor Kell Date: Mon, 23 Apr 2018 19:58:14 -0400 Subject: [PATCH 4/5] Get correct keys to log --- sync/views.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sync/views.py b/sync/views.py index f446f0d..d09e7fa 100644 --- a/sync/views.py +++ b/sync/views.py @@ -37,11 +37,14 @@ def sync(request): return_status, result_string = knackload.load(json.dumps(knack_value)) if return_status != 200: - contribution_refcode = knack_value['field_638'] - lineitem_entity_id = knack_value['field_684'] - error_msg = 'Error: We failed to send refcode {}, lineitem {} to knack' - print(error_msg.format(contribution_refcode, lineitem_entity_id)) + order_id = actblue_data['contribution']['orderNumber'] + entity_id_key = settings.ACTBLUE_TO_KNACK_MAPPING_SCALARS['lineitems#entityId'] + lineitem_entity_id = knack_value[entity_id_key] + + error_msg = 'Error: We failed to send order {}, lineitem {} to knack' + print(error_msg.format(order_id, lineitem_entity_id)) log_debug('Error: We failed to send ' + knack_value) + return HttpResponseServerError() else: result_data = json.loads(result_string) From a66a5a27904ad8dc82a353bc6b1946d68b2ebe1a Mon Sep 17 00:00:00 2001 From: Thor Kell Date: Mon, 23 Apr 2018 20:19:45 -0400 Subject: [PATCH 5/5] Log the same way --- sync/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/views.py b/sync/views.py index d09e7fa..1602129 100644 --- a/sync/views.py +++ b/sync/views.py @@ -43,7 +43,7 @@ def sync(request): error_msg = 'Error: We failed to send order {}, lineitem {} to knack' print(error_msg.format(order_id, lineitem_entity_id)) - log_debug('Error: We failed to send ' + knack_value) + log_debug('Error: We failed to send {}'.format(json.dumps(knack_value, indent=4))) return HttpResponseServerError() else: