We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
tickets should be decoded on python 3
As seen from the recent quicket hook posts

TypeError at /tickets/quicket_hook/
the JSON object must be str, not 'bytes'


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wafer/tickets/views.py`
Content:
```
1 import json
2 import logging
3 
4 from django.conf import settings
5 from django.contrib.auth import get_user_model
6 from django.core.exceptions import PermissionDenied, ValidationError
7 from django.core.urlresolvers import reverse
8 from django.http import HttpResponse, Http404
9 from django.views.decorators.csrf import csrf_exempt
10 from django.views.decorators.http import require_POST
11 from django.views.generic.edit import FormView
12 
13 from wafer.tickets.models import Ticket, TicketType
14 from wafer.tickets.forms import TicketForm
15 
16 log = logging.getLogger(__name__)
17 
18 
19 class ClaimView(FormView):
20     template_name = 'wafer.tickets/claim.html'
21     form_class = TicketForm
22 
23     def get_context_data(self, **kwargs):
24         context = super(ClaimView, self).get_context_data(**kwargs)
25         context['can_claim'] = self.can_claim()
26         return context
27 
28     def can_claim(self):
29         if settings.WAFER_REGISTRATION_MODE != 'ticket':
30             raise Http404('Ticket-based registration is not in use')
31         if not settings.WAFER_REGISTRATION_OPEN:
32             return False
33         return not self.request.user.userprofile.is_registered()
34 
35     def form_valid(self, form):
36         if not self.can_claim():
37             raise ValidationError('User may not claim a ticket')
38         ticket = Ticket.objects.get(barcode=form.cleaned_data['barcode'])
39         ticket.user = self.request.user
40         ticket.save()
41         return super(ClaimView, self).form_valid(form)
42 
43     def get_success_url(self):
44         return reverse(
45             'wafer_user_profile', args=(self.request.user.username,))
46 
47 
48 @csrf_exempt
49 @require_POST
50 def quicket_hook(request):
51     '''
52     Quicket.co.za can POST something like this when tickets are bought:
53     {
54       "reference": "REF00123456",
55       "event_id": 123,
56       "event_name": "My Big Event",
57       "amount": 0.00,
58       "email": "demo@example.com",
59       "action": "checkout_started",
60       // Options are "checkout_started","checkout_cancelled","eft_pending",
61       //             "checkout_completed"
62       "tickets": [
63         {
64           "id": 122,
65           "attendee_name": "",
66           "attendee_email": "",
67           "ticket_type": "Free Ticket",
68           "price": 0.00,
69           "barcode": 12345,
70         },
71         ...
72       ],
73     }
74     '''
75     if request.GET.get('secret') != settings.WAFER_TICKETS_SECRET:
76         raise PermissionDenied('Incorrect secret')
77 
78     payload = json.load(request)
79     for ticket in payload['tickets']:
80         import_ticket(ticket['barcode'], ticket['ticket_type'],
81                       ticket['attendee_email'])
82 
83     return HttpResponse("Noted\n", content_type='text/plain')
84 
85 
86 def import_ticket(ticket_barcode, ticket_type, email):
87     if Ticket.objects.filter(barcode=ticket_barcode).exists():
88         log.debug('Ticket already registered: %s', ticket_barcode)
89         return
90 
91     # truncate long ticket type names to length allowed by database
92     ticket_type = ticket_type[:TicketType.MAX_NAME_LENGTH]
93     type_, created = TicketType.objects.get_or_create(name=ticket_type)
94 
95     UserModel = get_user_model()
96 
97     try:
98         user = UserModel.objects.get(email=email, ticket=None)
99     except UserModel.DoesNotExist:
100         user = None
101     except UserModel.MultipleObjectsReturned:
102         # We're can't uniquely identify the user to associate this ticket
103         # with, so leave it for them to figure out via the 'claim ticket'
104         # interface
105         user = None
106 
107     ticket = Ticket.objects.create(
108         barcode=ticket_barcode,
109         email=email,
110         type=type_,
111         user=user,
112     )
113     ticket.save()
114 
115     if user:
116         log.info('Ticket registered: %s and linked to user', ticket)
117     else:
118         log.info('Ticket registered: %s. Unclaimed', ticket)
119
```
--- 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/wafer/tickets/views.py b/wafer/tickets/views.py
--- a/wafer/tickets/views.py
+++ b/wafer/tickets/views.py
@@ -75,7 +75,8 @@
     if request.GET.get('secret') != settings.WAFER_TICKETS_SECRET:
         raise PermissionDenied('Incorrect secret')
 
-    payload = json.load(request)
+    # This is required for python 3, and in theory fine on python 2
+    payload = json.loads(request.body.decode('utf8'))
     for ticket in payload['tickets']:
         import_ticket(ticket['barcode'], ticket['ticket_type'],
                       ticket['attendee_email'])

{"golden_diff": "diff --git a/wafer/tickets/views.py b/wafer/tickets/views.py\n--- a/wafer/tickets/views.py\n+++ b/wafer/tickets/views.py\n@@ -75,7 +75,8 @@\n     if request.GET.get('secret') != settings.WAFER_TICKETS_SECRET:\n         raise PermissionDenied('Incorrect secret')\n \n-    payload = json.load(request)\n+    # This is required for python 3, and in theory fine on python 2\n+    payload = json.loads(request.body.decode('utf8'))\n     for ticket in payload['tickets']:\n         import_ticket(ticket['barcode'], ticket['ticket_type'],\n                       ticket['attendee_email'])\n", "issue": "tickets should be decoded on python 3\nAs seen from the recent quicket hook posts\n\nTypeError at /tickets/quicket_hook/\nthe JSON object must be str, not 'bytes'\n\n", "before_files": [{"content": "import json\nimport logging\n\nfrom django.conf import settings\nfrom django.contrib.auth import get_user_model\nfrom django.core.exceptions import PermissionDenied, ValidationError\nfrom django.core.urlresolvers import reverse\nfrom django.http import HttpResponse, Http404\nfrom django.views.decorators.csrf import csrf_exempt\nfrom django.views.decorators.http import require_POST\nfrom django.views.generic.edit import FormView\n\nfrom wafer.tickets.models import Ticket, TicketType\nfrom wafer.tickets.forms import TicketForm\n\nlog = logging.getLogger(__name__)\n\n\nclass ClaimView(FormView):\n    template_name = 'wafer.tickets/claim.html'\n    form_class = TicketForm\n\n    def get_context_data(self, **kwargs):\n        context = super(ClaimView, self).get_context_data(**kwargs)\n        context['can_claim'] = self.can_claim()\n        return context\n\n    def can_claim(self):\n        if settings.WAFER_REGISTRATION_MODE != 'ticket':\n            raise Http404('Ticket-based registration is not in use')\n        if not settings.WAFER_REGISTRATION_OPEN:\n            return False\n        return not self.request.user.userprofile.is_registered()\n\n    def form_valid(self, form):\n        if not self.can_claim():\n            raise ValidationError('User may not claim a ticket')\n        ticket = Ticket.objects.get(barcode=form.cleaned_data['barcode'])\n        ticket.user = self.request.user\n        ticket.save()\n        return super(ClaimView, self).form_valid(form)\n\n    def get_success_url(self):\n        return reverse(\n            'wafer_user_profile', args=(self.request.user.username,))\n\n\n@csrf_exempt\n@require_POST\ndef quicket_hook(request):\n    '''\n    Quicket.co.za can POST something like this when tickets are bought:\n    {\n      \"reference\": \"REF00123456\",\n      \"event_id\": 123,\n      \"event_name\": \"My Big Event\",\n      \"amount\": 0.00,\n      \"email\": \"demo@example.com\",\n      \"action\": \"checkout_started\",\n      // Options are \"checkout_started\",\"checkout_cancelled\",\"eft_pending\",\n      //             \"checkout_completed\"\n      \"tickets\": [\n        {\n          \"id\": 122,\n          \"attendee_name\": \"\",\n          \"attendee_email\": \"\",\n          \"ticket_type\": \"Free Ticket\",\n          \"price\": 0.00,\n          \"barcode\": 12345,\n        },\n        ...\n      ],\n    }\n    '''\n    if request.GET.get('secret') != settings.WAFER_TICKETS_SECRET:\n        raise PermissionDenied('Incorrect secret')\n\n    payload = json.load(request)\n    for ticket in payload['tickets']:\n        import_ticket(ticket['barcode'], ticket['ticket_type'],\n                      ticket['attendee_email'])\n\n    return HttpResponse(\"Noted\\n\", content_type='text/plain')\n\n\ndef import_ticket(ticket_barcode, ticket_type, email):\n    if Ticket.objects.filter(barcode=ticket_barcode).exists():\n        log.debug('Ticket already registered: %s', ticket_barcode)\n        return\n\n    # truncate long ticket type names to length allowed by database\n    ticket_type = ticket_type[:TicketType.MAX_NAME_LENGTH]\n    type_, created = TicketType.objects.get_or_create(name=ticket_type)\n\n    UserModel = get_user_model()\n\n    try:\n        user = UserModel.objects.get(email=email, ticket=None)\n    except UserModel.DoesNotExist:\n        user = None\n    except UserModel.MultipleObjectsReturned:\n        # We're can't uniquely identify the user to associate this ticket\n        # with, so leave it for them to figure out via the 'claim ticket'\n        # interface\n        user = None\n\n    ticket = Ticket.objects.create(\n        barcode=ticket_barcode,\n        email=email,\n        type=type_,\n        user=user,\n    )\n    ticket.save()\n\n    if user:\n        log.info('Ticket registered: %s and linked to user', ticket)\n    else:\n        log.info('Ticket registered: %s. Unclaimed', ticket)\n", "path": "wafer/tickets/views.py"}], "after_files": [{"content": "import json\nimport logging\n\nfrom django.conf import settings\nfrom django.contrib.auth import get_user_model\nfrom django.core.exceptions import PermissionDenied, ValidationError\nfrom django.core.urlresolvers import reverse\nfrom django.http import HttpResponse, Http404\nfrom django.views.decorators.csrf import csrf_exempt\nfrom django.views.decorators.http import require_POST\nfrom django.views.generic.edit import FormView\n\nfrom wafer.tickets.models import Ticket, TicketType\nfrom wafer.tickets.forms import TicketForm\n\nlog = logging.getLogger(__name__)\n\n\nclass ClaimView(FormView):\n    template_name = 'wafer.tickets/claim.html'\n    form_class = TicketForm\n\n    def get_context_data(self, **kwargs):\n        context = super(ClaimView, self).get_context_data(**kwargs)\n        context['can_claim'] = self.can_claim()\n        return context\n\n    def can_claim(self):\n        if settings.WAFER_REGISTRATION_MODE != 'ticket':\n            raise Http404('Ticket-based registration is not in use')\n        if not settings.WAFER_REGISTRATION_OPEN:\n            return False\n        return not self.request.user.userprofile.is_registered()\n\n    def form_valid(self, form):\n        if not self.can_claim():\n            raise ValidationError('User may not claim a ticket')\n        ticket = Ticket.objects.get(barcode=form.cleaned_data['barcode'])\n        ticket.user = self.request.user\n        ticket.save()\n        return super(ClaimView, self).form_valid(form)\n\n    def get_success_url(self):\n        return reverse(\n            'wafer_user_profile', args=(self.request.user.username,))\n\n\n@csrf_exempt\n@require_POST\ndef quicket_hook(request):\n    '''\n    Quicket.co.za can POST something like this when tickets are bought:\n    {\n      \"reference\": \"REF00123456\",\n      \"event_id\": 123,\n      \"event_name\": \"My Big Event\",\n      \"amount\": 0.00,\n      \"email\": \"demo@example.com\",\n      \"action\": \"checkout_started\",\n      // Options are \"checkout_started\",\"checkout_cancelled\",\"eft_pending\",\n      //             \"checkout_completed\"\n      \"tickets\": [\n        {\n          \"id\": 122,\n          \"attendee_name\": \"\",\n          \"attendee_email\": \"\",\n          \"ticket_type\": \"Free Ticket\",\n          \"price\": 0.00,\n          \"barcode\": 12345,\n        },\n        ...\n      ],\n    }\n    '''\n    if request.GET.get('secret') != settings.WAFER_TICKETS_SECRET:\n        raise PermissionDenied('Incorrect secret')\n\n    # This is required for python 3, and in theory fine on python 2\n    payload = json.loads(request.body.decode('utf8'))\n    for ticket in payload['tickets']:\n        import_ticket(ticket['barcode'], ticket['ticket_type'],\n                      ticket['attendee_email'])\n\n    return HttpResponse(\"Noted\\n\", content_type='text/plain')\n\n\ndef import_ticket(ticket_barcode, ticket_type, email):\n    if Ticket.objects.filter(barcode=ticket_barcode).exists():\n        log.debug('Ticket already registered: %s', ticket_barcode)\n        return\n\n    # truncate long ticket type names to length allowed by database\n    ticket_type = ticket_type[:TicketType.MAX_NAME_LENGTH]\n    type_, created = TicketType.objects.get_or_create(name=ticket_type)\n\n    UserModel = get_user_model()\n\n    try:\n        user = UserModel.objects.get(email=email, ticket=None)\n    except UserModel.DoesNotExist:\n        user = None\n    except UserModel.MultipleObjectsReturned:\n        # We're can't uniquely identify the user to associate this ticket\n        # with, so leave it for them to figure out via the 'claim ticket'\n        # interface\n        user = None\n\n    ticket = Ticket.objects.create(\n        barcode=ticket_barcode,\n        email=email,\n        type=type_,\n        user=user,\n    )\n    ticket.save()\n\n    if user:\n        log.info('Ticket registered: %s and linked to user', ticket)\n    else:\n        log.info('Ticket registered: %s. Unclaimed', ticket)\n", "path": "wafer/tickets/views.py"}]}