We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
T - the API to support subscription management
The backend pieces needed for https://github.com/mdn/kuma/issues/6703

That way we, can Reactify the subscription management page. 

What we need is to endpoints:

1. Getting your subscriptions (plural but it's probably never more than 1)
2. Cancel a subscription (or cancel them all if that's easier)



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kuma/users/stripe_utils.py`
Content:
```
1 from datetime import datetime
2 
3 import stripe
4 from django.conf import settings
5 from django.utils import timezone
6 
7 from kuma.core.urlresolvers import reverse
8 from kuma.wiki.templatetags.jinja_helpers import absolutify
9 
10 from .models import UserSubscription
11 
12 
13 def retrieve_stripe_subscription(customer):
14     for subscription in customer.subscriptions.list().auto_paging_iter():
15         # We have to use array indexing syntax, as stripe uses dicts to
16         # represent its objects (dicts come with an .items method)
17         for item in subscription["items"].auto_paging_iter():
18             if item.plan.id == settings.STRIPE_PLAN_ID:
19                 return subscription
20 
21     return None
22 
23 
24 def retrieve_and_synchronize_subscription_info(user):
25     """For the given user, if it has as 'stripe_customer_id' retrieve the info
26     about the subscription if it's there. All packaged in a way that is
27     practical for the stripe_subscription.html template.
28 
29     Also, whilst doing this check, we also verify that the UserSubscription record
30     for this user is right. Doing that check is a second-layer check in case
31     our webhooks have failed us.
32     """
33     subscription_info = None
34     stripe_customer = get_stripe_customer(user)
35     if stripe_customer:
36         stripe_subscription_info = get_stripe_subscription_info(stripe_customer)
37         if stripe_subscription_info:
38             source = stripe_customer.default_source
39             if source.object == "card":
40                 card = source
41             elif source.object == "source":
42                 card = source.card
43             else:
44                 raise ValueError(
45                     f"unexpected stripe customer default_source of type {source.object!r}"
46                 )
47 
48             subscription_info = {
49                 "id": stripe_subscription_info.id,
50                 "amount": stripe_subscription_info.plan.amount,
51                 "brand": card.brand,
52                 "expires_at": f"{card.exp_month}/{card.exp_year}",
53                 "last4": card.last4,
54                 # Cards that are part of a "source" don't have a zip
55                 "zip": card.get("address_zip", None),
56                 # TODO: Deprecated. Only used in the Edit Profile view
57                 "next_payment_at": datetime.fromtimestamp(
58                     stripe_subscription_info.current_period_end
59                 ),
60             }
61 
62             # To perfect the synchronization, take this opportunity to make sure
63             # we have an up-to-date record of this.
64             UserSubscription.set_active(user, stripe_subscription_info.id)
65         else:
66             # The user has a stripe_customer_id but no active subscription
67             # on the current settings.STRIPE_PLAN_ID! Perhaps it has been cancelled
68             # and not updated in our own records.
69             for user_subscription in UserSubscription.objects.filter(
70                 user=user, canceled__isnull=True
71             ):
72                 user_subscription.canceled = timezone.now()
73                 user_subscription.save()
74 
75     return subscription_info
76 
77 
78 def create_stripe_customer_and_subscription_for_user(user, email, stripe_token):
79     customer = (
80         stripe.Customer.retrieve(user.stripe_customer_id)
81         if user.stripe_customer_id
82         else None
83     )
84     if not customer or customer.email != email:
85         customer = stripe.Customer.create(email=email, source=stripe_token,)
86         user.stripe_customer_id = customer.id
87         user.save()
88 
89     subscription = retrieve_stripe_subscription(customer)
90     if not subscription:
91         subscription = stripe.Subscription.create(
92             customer=customer.id, items=[{"plan": settings.STRIPE_PLAN_ID}],
93         )
94 
95     UserSubscription.set_active(user, subscription.id)
96 
97 
98 def cancel_stripe_customer_subscriptions(user):
99     """Delete all subscriptions for a Stripe customer."""
100     assert user.stripe_customer_id
101     customer = stripe.Customer.retrieve(user.stripe_customer_id)
102     for sub in customer.subscriptions.data:
103         s = stripe.Subscription.retrieve(sub.id)
104         UserSubscription.set_canceled(user, s.id)
105         s.delete()
106 
107 
108 def get_stripe_customer(user):
109     if settings.STRIPE_PLAN_ID and user.stripe_customer_id:
110         return stripe.Customer.retrieve(
111             user.stripe_customer_id, expand=["default_source"]
112         )
113 
114 
115 def get_stripe_subscription_info(stripe_customer):
116     return retrieve_stripe_subscription(stripe_customer)
117 
118 
119 def create_missing_stripe_webhook():
120     url_path = reverse("users.stripe_hooks")
121     url = (
122         "https://" + settings.STRIPE_WEBHOOK_HOSTNAME + url_path
123         if settings.STRIPE_WEBHOOK_HOSTNAME
124         else absolutify(url_path)
125     )
126 
127     # From https://stripe.com/docs/api/webhook_endpoints/create
128     events = (
129         # "Occurs whenever an invoice payment attempt succeeds."
130         "invoice.payment_succeeded",
131         # "Occurs whenever a customer’s subscription ends."
132         # Also, if you go into the Stripe Dashboard, click Billing, Subscriptions,
133         # and find a customer and click the "Cancel subscription" button, this
134         # triggers.
135         "customer.subscription.deleted",
136     )
137 
138     for webhook in stripe.WebhookEndpoint.list().auto_paging_iter():
139         if webhook.url == url and set(events) == set(webhook.enabled_events):
140             return
141 
142     stripe.WebhookEndpoint.create(
143         url=url, enabled_events=events,
144     )
145
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kuma/users/stripe_utils.py b/kuma/users/stripe_utils.py
--- a/kuma/users/stripe_utils.py
+++ b/kuma/users/stripe_utils.py
@@ -64,7 +64,7 @@
             UserSubscription.set_active(user, stripe_subscription_info.id)
         else:
             # The user has a stripe_customer_id but no active subscription
-            # on the current settings.STRIPE_PLAN_ID! Perhaps it has been cancelled
+            # on the current settings.STRIPE_PLAN_ID! Perhaps it has been canceled
             # and not updated in our own records.
             for user_subscription in UserSubscription.objects.filter(
                 user=user, canceled__isnull=True
@@ -82,7 +82,7 @@
         else None
     )
     if not customer or customer.email != email:
-        customer = stripe.Customer.create(email=email, source=stripe_token,)
+        customer = stripe.Customer.create(email=email, source=stripe_token)
         user.stripe_customer_id = customer.id
         user.save()
 
@@ -99,10 +99,13 @@
     """Delete all subscriptions for a Stripe customer."""
     assert user.stripe_customer_id
     customer = stripe.Customer.retrieve(user.stripe_customer_id)
+    canceled = []
     for sub in customer.subscriptions.data:
         s = stripe.Subscription.retrieve(sub.id)
         UserSubscription.set_canceled(user, s.id)
         s.delete()
+        canceled.append(s)
+    return canceled
 
 
 def get_stripe_customer(user):

{"golden_diff": "diff --git a/kuma/users/stripe_utils.py b/kuma/users/stripe_utils.py\n--- a/kuma/users/stripe_utils.py\n+++ b/kuma/users/stripe_utils.py\n@@ -64,7 +64,7 @@\n             UserSubscription.set_active(user, stripe_subscription_info.id)\n         else:\n             # The user has a stripe_customer_id but no active subscription\n-            # on the current settings.STRIPE_PLAN_ID! Perhaps it has been cancelled\n+            # on the current settings.STRIPE_PLAN_ID! Perhaps it has been canceled\n             # and not updated in our own records.\n             for user_subscription in UserSubscription.objects.filter(\n                 user=user, canceled__isnull=True\n@@ -82,7 +82,7 @@\n         else None\n     )\n     if not customer or customer.email != email:\n-        customer = stripe.Customer.create(email=email, source=stripe_token,)\n+        customer = stripe.Customer.create(email=email, source=stripe_token)\n         user.stripe_customer_id = customer.id\n         user.save()\n \n@@ -99,10 +99,13 @@\n     \"\"\"Delete all subscriptions for a Stripe customer.\"\"\"\n     assert user.stripe_customer_id\n     customer = stripe.Customer.retrieve(user.stripe_customer_id)\n+    canceled = []\n     for sub in customer.subscriptions.data:\n         s = stripe.Subscription.retrieve(sub.id)\n         UserSubscription.set_canceled(user, s.id)\n         s.delete()\n+        canceled.append(s)\n+    return canceled\n \n \n def get_stripe_customer(user):\n", "issue": "T - the API to support subscription management\nThe backend pieces needed for https://github.com/mdn/kuma/issues/6703\r\n\r\nThat way we, can Reactify the subscription management page. \r\n\r\nWhat we need is to endpoints:\r\n\r\n1. Getting your subscriptions (plural but it's probably never more than 1)\r\n2. Cancel a subscription (or cancel them all if that's easier)\r\n\r\n\n", "before_files": [{"content": "from datetime import datetime\n\nimport stripe\nfrom django.conf import settings\nfrom django.utils import timezone\n\nfrom kuma.core.urlresolvers import reverse\nfrom kuma.wiki.templatetags.jinja_helpers import absolutify\n\nfrom .models import UserSubscription\n\n\ndef retrieve_stripe_subscription(customer):\n    for subscription in customer.subscriptions.list().auto_paging_iter():\n        # We have to use array indexing syntax, as stripe uses dicts to\n        # represent its objects (dicts come with an .items method)\n        for item in subscription[\"items\"].auto_paging_iter():\n            if item.plan.id == settings.STRIPE_PLAN_ID:\n                return subscription\n\n    return None\n\n\ndef retrieve_and_synchronize_subscription_info(user):\n    \"\"\"For the given user, if it has as 'stripe_customer_id' retrieve the info\n    about the subscription if it's there. All packaged in a way that is\n    practical for the stripe_subscription.html template.\n\n    Also, whilst doing this check, we also verify that the UserSubscription record\n    for this user is right. Doing that check is a second-layer check in case\n    our webhooks have failed us.\n    \"\"\"\n    subscription_info = None\n    stripe_customer = get_stripe_customer(user)\n    if stripe_customer:\n        stripe_subscription_info = get_stripe_subscription_info(stripe_customer)\n        if stripe_subscription_info:\n            source = stripe_customer.default_source\n            if source.object == \"card\":\n                card = source\n            elif source.object == \"source\":\n                card = source.card\n            else:\n                raise ValueError(\n                    f\"unexpected stripe customer default_source of type {source.object!r}\"\n                )\n\n            subscription_info = {\n                \"id\": stripe_subscription_info.id,\n                \"amount\": stripe_subscription_info.plan.amount,\n                \"brand\": card.brand,\n                \"expires_at\": f\"{card.exp_month}/{card.exp_year}\",\n                \"last4\": card.last4,\n                # Cards that are part of a \"source\" don't have a zip\n                \"zip\": card.get(\"address_zip\", None),\n                # TODO: Deprecated. Only used in the Edit Profile view\n                \"next_payment_at\": datetime.fromtimestamp(\n                    stripe_subscription_info.current_period_end\n                ),\n            }\n\n            # To perfect the synchronization, take this opportunity to make sure\n            # we have an up-to-date record of this.\n            UserSubscription.set_active(user, stripe_subscription_info.id)\n        else:\n            # The user has a stripe_customer_id but no active subscription\n            # on the current settings.STRIPE_PLAN_ID! Perhaps it has been cancelled\n            # and not updated in our own records.\n            for user_subscription in UserSubscription.objects.filter(\n                user=user, canceled__isnull=True\n            ):\n                user_subscription.canceled = timezone.now()\n                user_subscription.save()\n\n    return subscription_info\n\n\ndef create_stripe_customer_and_subscription_for_user(user, email, stripe_token):\n    customer = (\n        stripe.Customer.retrieve(user.stripe_customer_id)\n        if user.stripe_customer_id\n        else None\n    )\n    if not customer or customer.email != email:\n        customer = stripe.Customer.create(email=email, source=stripe_token,)\n        user.stripe_customer_id = customer.id\n        user.save()\n\n    subscription = retrieve_stripe_subscription(customer)\n    if not subscription:\n        subscription = stripe.Subscription.create(\n            customer=customer.id, items=[{\"plan\": settings.STRIPE_PLAN_ID}],\n        )\n\n    UserSubscription.set_active(user, subscription.id)\n\n\ndef cancel_stripe_customer_subscriptions(user):\n    \"\"\"Delete all subscriptions for a Stripe customer.\"\"\"\n    assert user.stripe_customer_id\n    customer = stripe.Customer.retrieve(user.stripe_customer_id)\n    for sub in customer.subscriptions.data:\n        s = stripe.Subscription.retrieve(sub.id)\n        UserSubscription.set_canceled(user, s.id)\n        s.delete()\n\n\ndef get_stripe_customer(user):\n    if settings.STRIPE_PLAN_ID and user.stripe_customer_id:\n        return stripe.Customer.retrieve(\n            user.stripe_customer_id, expand=[\"default_source\"]\n        )\n\n\ndef get_stripe_subscription_info(stripe_customer):\n    return retrieve_stripe_subscription(stripe_customer)\n\n\ndef create_missing_stripe_webhook():\n    url_path = reverse(\"users.stripe_hooks\")\n    url = (\n        \"https://\" + settings.STRIPE_WEBHOOK_HOSTNAME + url_path\n        if settings.STRIPE_WEBHOOK_HOSTNAME\n        else absolutify(url_path)\n    )\n\n    # From https://stripe.com/docs/api/webhook_endpoints/create\n    events = (\n        # \"Occurs whenever an invoice payment attempt succeeds.\"\n        \"invoice.payment_succeeded\",\n        # \"Occurs whenever a customer\u2019s subscription ends.\"\n        # Also, if you go into the Stripe Dashboard, click Billing, Subscriptions,\n        # and find a customer and click the \"Cancel subscription\" button, this\n        # triggers.\n        \"customer.subscription.deleted\",\n    )\n\n    for webhook in stripe.WebhookEndpoint.list().auto_paging_iter():\n        if webhook.url == url and set(events) == set(webhook.enabled_events):\n            return\n\n    stripe.WebhookEndpoint.create(\n        url=url, enabled_events=events,\n    )\n", "path": "kuma/users/stripe_utils.py"}], "after_files": [{"content": "from datetime import datetime\n\nimport stripe\nfrom django.conf import settings\nfrom django.utils import timezone\n\nfrom kuma.core.urlresolvers import reverse\nfrom kuma.wiki.templatetags.jinja_helpers import absolutify\n\nfrom .models import UserSubscription\n\n\ndef retrieve_stripe_subscription(customer):\n    for subscription in customer.subscriptions.list().auto_paging_iter():\n        # We have to use array indexing syntax, as stripe uses dicts to\n        # represent its objects (dicts come with an .items method)\n        for item in subscription[\"items\"].auto_paging_iter():\n            if item.plan.id == settings.STRIPE_PLAN_ID:\n                return subscription\n\n    return None\n\n\ndef retrieve_and_synchronize_subscription_info(user):\n    \"\"\"For the given user, if it has as 'stripe_customer_id' retrieve the info\n    about the subscription if it's there. All packaged in a way that is\n    practical for the stripe_subscription.html template.\n\n    Also, whilst doing this check, we also verify that the UserSubscription record\n    for this user is right. Doing that check is a second-layer check in case\n    our webhooks have failed us.\n    \"\"\"\n    subscription_info = None\n    stripe_customer = get_stripe_customer(user)\n    if stripe_customer:\n        stripe_subscription_info = get_stripe_subscription_info(stripe_customer)\n        if stripe_subscription_info:\n            source = stripe_customer.default_source\n            if source.object == \"card\":\n                card = source\n            elif source.object == \"source\":\n                card = source.card\n            else:\n                raise ValueError(\n                    f\"unexpected stripe customer default_source of type {source.object!r}\"\n                )\n\n            subscription_info = {\n                \"id\": stripe_subscription_info.id,\n                \"amount\": stripe_subscription_info.plan.amount,\n                \"brand\": card.brand,\n                \"expires_at\": f\"{card.exp_month}/{card.exp_year}\",\n                \"last4\": card.last4,\n                # Cards that are part of a \"source\" don't have a zip\n                \"zip\": card.get(\"address_zip\", None),\n                # TODO: Deprecated. Only used in the Edit Profile view\n                \"next_payment_at\": datetime.fromtimestamp(\n                    stripe_subscription_info.current_period_end\n                ),\n            }\n\n            # To perfect the synchronization, take this opportunity to make sure\n            # we have an up-to-date record of this.\n            UserSubscription.set_active(user, stripe_subscription_info.id)\n        else:\n            # The user has a stripe_customer_id but no active subscription\n            # on the current settings.STRIPE_PLAN_ID! Perhaps it has been canceled\n            # and not updated in our own records.\n            for user_subscription in UserSubscription.objects.filter(\n                user=user, canceled__isnull=True\n            ):\n                user_subscription.canceled = timezone.now()\n                user_subscription.save()\n\n    return subscription_info\n\n\ndef create_stripe_customer_and_subscription_for_user(user, email, stripe_token):\n    customer = (\n        stripe.Customer.retrieve(user.stripe_customer_id)\n        if user.stripe_customer_id\n        else None\n    )\n    if not customer or customer.email != email:\n        customer = stripe.Customer.create(email=email, source=stripe_token)\n        user.stripe_customer_id = customer.id\n        user.save()\n\n    subscription = retrieve_stripe_subscription(customer)\n    if not subscription:\n        subscription = stripe.Subscription.create(\n            customer=customer.id, items=[{\"plan\": settings.STRIPE_PLAN_ID}],\n        )\n\n    UserSubscription.set_active(user, subscription.id)\n\n\ndef cancel_stripe_customer_subscriptions(user):\n    \"\"\"Delete all subscriptions for a Stripe customer.\"\"\"\n    assert user.stripe_customer_id\n    customer = stripe.Customer.retrieve(user.stripe_customer_id)\n    canceled = []\n    for sub in customer.subscriptions.data:\n        s = stripe.Subscription.retrieve(sub.id)\n        UserSubscription.set_canceled(user, s.id)\n        s.delete()\n        canceled.append(s)\n    return canceled\n\n\ndef get_stripe_customer(user):\n    if settings.STRIPE_PLAN_ID and user.stripe_customer_id:\n        return stripe.Customer.retrieve(\n            user.stripe_customer_id, expand=[\"default_source\"]\n        )\n\n\ndef get_stripe_subscription_info(stripe_customer):\n    return retrieve_stripe_subscription(stripe_customer)\n\n\ndef create_missing_stripe_webhook():\n    url_path = reverse(\"users.stripe_hooks\")\n    url = (\n        \"https://\" + settings.STRIPE_WEBHOOK_HOSTNAME + url_path\n        if settings.STRIPE_WEBHOOK_HOSTNAME\n        else absolutify(url_path)\n    )\n\n    # From https://stripe.com/docs/api/webhook_endpoints/create\n    events = (\n        # \"Occurs whenever an invoice payment attempt succeeds.\"\n        \"invoice.payment_succeeded\",\n        # \"Occurs whenever a customer\u2019s subscription ends.\"\n        # Also, if you go into the Stripe Dashboard, click Billing, Subscriptions,\n        # and find a customer and click the \"Cancel subscription\" button, this\n        # triggers.\n        \"customer.subscription.deleted\",\n    )\n\n    for webhook in stripe.WebhookEndpoint.list().auto_paging_iter():\n        if webhook.url == url and set(events) == set(webhook.enabled_events):\n            return\n\n    stripe.WebhookEndpoint.create(\n        url=url, enabled_events=events,\n    )\n", "path": "kuma/users/stripe_utils.py"}]}