improved error handling, always save callback body, various fixes

This commit is contained in:
Thomas Steen Rasmussen 2017-04-03 18:00:25 +02:00
parent 3be7319dc3
commit 1b98c01f63
3 changed files with 51 additions and 10 deletions

View file

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-04-03 15:52
from __future__ import unicode_literals
import django.contrib.postgres.fields.jsonb
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shop', '0038_auto_20170323_2021'),
]
operations = [
migrations.AddField(
model_name='coinifyapicallback',
name='body',
field=models.TextField(default=''),
),
migrations.AlterField(
model_name='coinifyapicallback',
name='payload',
field=django.contrib.postgres.fields.jsonb.JSONField(null=True),
),
]

View file

@ -410,7 +410,8 @@ class CoinifyAPIInvoice(CreatedUpdatedModel):
class CoinifyAPICallback(CreatedUpdatedModel): class CoinifyAPICallback(CreatedUpdatedModel):
headers = JSONField() headers = JSONField()
payload = JSONField() payload = JSONField(null=True)
body = models.TextField(default='')
order = models.ForeignKey('shop.Order') order = models.ForeignKey('shop.Order')
valid = models.BooleanField(default=False) valid = models.BooleanField(default=False)

View file

@ -537,7 +537,7 @@ class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUn
# this coinifyinvoice expired, delete it # this coinifyinvoice expired, delete it
logger.warning("deleting expired coinifyinvoice id %s" % order.coinifyapiinvoice.invoicejson['id']) logger.warning("deleting expired coinifyinvoice id %s" % order.coinifyapiinvoice.invoicejson['id'])
order.coinifyapiinvoice.delete() order.coinifyapiinvoice.delete()
order = self.get_object() order.refresh_from_db()
# create a new coinify invoice if needed # create a new coinify invoice if needed
if not hasattr(order, 'coinifyapiinvoice'): if not hasattr(order, 'coinifyapiinvoice'):
@ -601,38 +601,52 @@ class CoinifyCallbackView(SingleObjectMixin, View):
if key[:5] == 'HTTP_': if key[:5] == 'HTTP_':
headerdict[key[5:]] = value headerdict[key[5:]] = value
# parse json
try:
parsed = json.loads(str(request.body))
except JSONDecodeError:
parsed = None
# save callback to db # save callback to db
callbackobject = CoinifyAPICallback.objects.create( callbackobject = CoinifyAPICallback.objects.create(
headers=headerdict, headers=headerdict,
payload=json.loads(str(request.body)), body=request.body,
payload=parsed,
order=self.get_object() order=self.get_object()
) )
# do we have a json body?
if not parsed:
# no, return an error
logger.error("unable to parse JSON body in callback for order %s" % callbackobject.order.id)
return HttpResponseBadRequest('unable to parse json')
# attemt to validate the callbackc
if sdk.validate_callback(request.body, signature): if sdk.validate_callback(request.body, signature):
# mark callback as valid in db # mark callback as valid in db
callbackobject.valid=True callbackobject.valid=True
callbackobject.save() callbackobject.save()
# parse json if callbackobject.payload['event'] == 'invoice_state_change' or callbackobject.payload['event'] == 'invoice_manual_resend':
callbackjson = json.loads(str(request.body))
if callbackjson['event'] == 'invoice_state_change' or callbackjson['event'] == 'invoice_manual_resend':
# find coinify invoice in db # find coinify invoice in db
try: try:
coinifyinvoice = CoinifyAPIInvoice.objects.get(invoicejson__id=callbackjson['data']['id']) coinifyinvoice = CoinifyAPIInvoice.objects.get(invoicejson__id=callbackobject.payload['data']['id'])
except CoinifyAPIInvoice.DoesNotExist: except CoinifyAPIInvoice.DoesNotExist:
logger.error("unable to find CoinifyAPIInvoice with id %s" % callbackjson['data']['id']) logger.error("unable to find CoinifyAPIInvoice with id %s" % callbackobject.payload['data']['id'])
return HttpResponseBadRequest('bad coinifyinvoice id') return HttpResponseBadRequest('bad coinifyinvoice id')
# save new coinifyinvoice payload # save new coinifyinvoice payload
coinifyinvoice.invoicejson = callbackjson['data'] coinifyinvoice.invoicejson = callbackobject.payload['data']
coinifyinvoice.save() coinifyinvoice.save()
# so, is the order paid in full now? # so, is the order paid in full now?
if callbackjson['data']['state'] == 'complete': if callbackobject.payload['data']['state'] == 'complete':
coinifyinvoice.order.mark_as_paid() coinifyinvoice.order.mark_as_paid()
# return 200 OK # return 200 OK
return HttpResponse('OK') return HttpResponse('OK')
else: else:
logger.error("unsupported callback event %s" % callbackobject.payload['event'])
return HttpResponseBadRequest('unsupported event') return HttpResponseBadRequest('unsupported event')
else: else:
logger.error("invalid coinify callback detected") logger.error("invalid coinify callback detected")