Skip to content

Commit

Permalink
Merge 3d6d389 into d67eeb7
Browse files Browse the repository at this point in the history
  • Loading branch information
poxip committed Aug 23, 2017
2 parents d67eeb7 + 3d6d389 commit 29bccc3
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 46 deletions.
21 changes: 21 additions & 0 deletions aa_stripe/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,24 @@ class StripeWebhook(models.Model):
updated = models.DateTimeField(auto_now=True)
is_parsed = models.BooleanField(default=False)
raw_data = JSONField()

def parse(self, save=False):
event_type = self.raw_data.get("type")
if "." not in event_type:
return

event_model, event_action = event_type.split(".")
if event_model == "coupon":
if event_action == "deleted":
coupon_id = self.raw_data["data"]["object"]["id"]
StripeCoupon.objects.filter(coupon_id=coupon_id).update(is_deleted=True)

self.is_parsed = True
if save:
self.save()

def save(self, *args, **kwargs):
if not self.is_parsed:
self.parse()

return super(StripeWebhook, self).save(*args, **kwargs)
Empty file added tests/__init__.py
Empty file.
30 changes: 2 additions & 28 deletions tests/test_coupons.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,13 @@
import simplejson as json
from django.utils import timezone
from freezegun import freeze_time
from rest_framework.test import APITestCase
from tests.test_utils import BaseTestCase

from aa_stripe.forms import StripeCouponForm
from aa_stripe.models import StripeCoupon


class TestCoupons(APITestCase):
def _create_coupon(self, coupon_id, amount_off=None, duration=StripeCoupon.DURATION_FOREVER):
with requests_mock.Mocker() as m:
# create a simple coupon which will be used for tests
stripe_response = {
"id": coupon_id,
"object": "coupon",
"amount_off": amount_off,
"created": int(time.mktime(datetime.now().timetuple())),
"currency": "usd",
"duration": duration,
"duration_in_months": None,
"livemode": False,
"max_redemptions": None,
"metadata": {},
"percent_off": 25,
"redeem_by": None,
"times_redeemed": 0,
"valid": True
}
m.register_uri("POST", "https://api.stripe.com/v1/coupons", text=json.dumps(stripe_response))
return StripeCoupon.objects.create(
coupon_id=coupon_id,
duration=duration,
amount_off=amount_off
)

class TestCoupons(BaseTestCase):
@freeze_time("2016-01-01 00:00:00")
def test_create(self):
# test creating simple coupon with no coupon_id specified (will be generated by Stripe)
Expand Down
50 changes: 50 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import time
from datetime import datetime

import requests_mock
import simplejson as json
from django.conf import settings
from rest_framework.test import APITestCase
from stripe.webhook import WebhookSignature

from aa_stripe.models import StripeCoupon


class BaseTestCase(APITestCase):
def _create_coupon(self, coupon_id, amount_off=None, duration=StripeCoupon.DURATION_FOREVER):
with requests_mock.Mocker() as m:
# create a simple coupon which will be used for tests
stripe_response = {
"id": coupon_id,
"object": "coupon",
"amount_off": amount_off,
"created": int(time.mktime(datetime.now().timetuple())),
"currency": "usd",
"duration": duration,
"duration_in_months": None,
"livemode": False,
"max_redemptions": None,
"metadata": {},
"percent_off": 25,
"redeem_by": None,
"times_redeemed": 0,
"valid": True
}
m.register_uri("POST", "https://api.stripe.com/v1/coupons", text=json.dumps(stripe_response))
return StripeCoupon.objects.create(
coupon_id=coupon_id,
duration=duration,
amount_off=amount_off
)

def _get_signature_headers(self, payload):
timestamp = int(time.time())

raw_payload = json.dumps(payload).replace(": ", ":")
raw_payload = raw_payload.replace(", ", ",")
signed_payload = "{timestamp:d}.{raw_payload}".format(timestamp=timestamp, raw_payload=raw_payload)
signature = WebhookSignature._compute_signature(signed_payload, settings.STRIPE_WEBHOOK_ENDPOINT_SECRET)
return {
"HTTP_STRIPE_SIGNATURE": ("t={timestamp:d},v1={signature}"
",v0=not_important".format(timestamp=timestamp, signature=signature))
}
76 changes: 58 additions & 18 deletions tests/test_webhooks.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import time

import simplejson as json
from django.conf import settings
from rest_framework.reverse import reverse
from rest_framework.test import APITestCase
from stripe.webhook import WebhookSignature
from tests.test_utils import BaseTestCase

from aa_stripe.models import StripeWebhook
from aa_stripe.models import StripeCoupon, StripeWebhook


class TestWebhook(APITestCase):
class TestWebhook(BaseTestCase):

def test_subscription_creation(self):
self.assertEqual(StripeWebhook.objects.count(), 0)
Expand Down Expand Up @@ -108,20 +104,64 @@ def test_subscription_creation(self):
response = self.client.post(url, data=payload, format="json")
self.assertEqual(response.status_code, 400) # wrong signature

timestamp = int(time.time())
raw_payload = json.dumps(payload).replace(": ", ":")
raw_payload = raw_payload.replace(", ", ",")
signed_payload = "{timestamp:d}.{raw_payload}".format(timestamp=timestamp, raw_payload=raw_payload)
signature = WebhookSignature._compute_signature(signed_payload, settings.STRIPE_WEBHOOK_ENDPOINT_SECRET)
headers = {
"HTTP_STRIPE_SIGNATURE": ("t={timestamp:d},v1={signature}"
",v0=not_important".format(timestamp=timestamp, signature=signature))
}
self.client.credentials(**headers)
self.client.credentials(**self._get_signature_headers(payload))
response = self.client.post(url, data=payload, format="json")
self.assertEqual(response.status_code, 201)
self.assertEqual(StripeWebhook.objects.count(), 1)
webhook = StripeWebhook.objects.first()
self.assertEqual(webhook.id, payload["id"])
self.assertEqual(webhook.raw_data, payload)
self.assertFalse(webhook.is_parsed)
self.assertTrue(webhook.is_parsed)

def test_coupon_delete(self):
coupon = self._create_coupon("nicecoupon", amount_off=10000, duration=StripeCoupon.DURATION_ONCE)
self.assertFalse(coupon.is_deleted)
payload = json.loads("""{
"id": "evt_1Atthtasdsaf6pRwkdLOSKls",
"object": "event",
"api_version": "2017-06-05",
"created": 1503474921,
"data": {
"object": {
"id": "nicecoupon",
"object": "coupon",
"amount_off": 10000,
"created": 1503474890,
"currency": "usd",
"duration": "once",
"duration_in_months": null,
"livemode": false,
"max_redemptions": null,
"metadata": {
},
"percent_off": null,
"redeem_by": null,
"times_redeemed": 0,
"valid": false
}
},
"livemode": false,
"pending_webhooks": 1,
"request": {
"id": "req_9UO71nsJyOhQfi",
"idempotency_key": null
},
"type": "coupon.deleted"
}""")

url = reverse("stripe-webhooks")
self.client.credentials(**self._get_signature_headers(payload))
response = self.client.post(url, data=payload, format="json")
coupon.refresh_from_db()
self.assertEqual(response.status_code, 201)
self.assertTrue(coupon.is_deleted)

# test deleting event that has already been deleted - should not raise any errors
# it will just make sure is_deleted is set for this coupon
payload["id"] = "evt_someother"
payload["request"]["id"] = ["req_someother"]
self.client.credentials(**self._get_signature_headers(payload))
response = self.client.post(url, data=payload, format="json")
coupon.refresh_from_db()
self.assertEqual(response.status_code, 201)
self.assertTrue(coupon.is_deleted)

0 comments on commit 29bccc3

Please sign in to comment.