Repository: TabbycatDebate/tabbycat

Issue:
Include QR code in private URL distribution pages
It is a bit odd to hand people a physical item directing them to the internet, but typing a random string is not really user-friendly. QR codes that directs to the URL could be added to the URL sheets for ease of use. The type of barcode that is in use can't encode as long a string, but a QR code is recognized to be scanned to lead to a website and seems to be well supported by phones.

This may require another dependency to generate these codes; `jsBarcode` can't generate them.


Discussion:
As the pages are handed out to the public, wouldn't it be `public ui`? :)
The difficulty here is the enormous amount of pages that are generated. Even for the "minimal" example, that is 92 pages to render. As a result, it stalls when trying to print. (Safari isn't slow, but it messes up the page breaks). The solution could be to render as PDF server-side, for the document to be downloaded. This would avoid browser problems, but finding a library that is suitable may pose a challenge.

Resolving patch:
diff --git a/tabbycat/printing/views.py b/tabbycat/printing/views.py
--- a/tabbycat/printing/views.py
+++ b/tabbycat/printing/views.py
@@ -1,5 +1,8 @@
 import json
 
+import qrcode
+from qrcode.image import svg
+
 from django.db.models import Q
 from django.utils.translation import gettext as _
 from django.views.generic.base import TemplateView
@@ -15,6 +18,7 @@
 from tournaments.mixins import (CurrentRoundMixin, OptionalAssistantTournamentPageMixin,
                                 RoundMixin, TournamentMixin)
 from tournaments.models import Tournament
+from utils.misc import reverse_tournament
 from utils.mixins import AdministratorMixin
 from venues.models import VenueCategory
 
@@ -280,16 +284,28 @@ class PrintableRandomisedURLs(TournamentMixin, AdministratorMixin, TemplateView)
 
     template_name = 'randomised_url_sheets.html'
 
+    def add_urls(self, participants):
+        for participant in participants:
+            url = reverse_tournament('privateurls-person-index', self.tournament, kwargs={'url_key': participant['url_key']})
+            abs_url = self.request.build_absolute_uri(url)
+            qr_code = qrcode.make(abs_url, image_factory=svg.SvgPathImage)
+
+            participant['url'] = abs_url
+            participant['qr'] = ' '.join(qr_code._generate_subpaths())
+
+        return participants
+
     def get_context_data(self, **kwargs):
-        kwargs['tournament_slug'] = self.tournament.slug
 
         if not self.tournament.pref('share_adjs'):
-            kwargs['parts'] = self.tournament.participants.filter(
-                url_key__isnull=False).select_related(
-                'speaker', 'speaker__team', 'adjudicator__institution',
-                'adjudicator')
+            participants = self.tournament.participants.filter(url_key__isnull=False)
         else:
-            kwargs['parts'] = Person.objects.filter(Q(speaker__team__tournament=self.tournament) | Q(adjudicator__tournament__isnull=True) & Q(url_key__isnull=False))
+            participants = Person.objects.filter(
+                Q(speaker__team__tournament=self.tournament) | Q(adjudicator__tournament__isnull=True) & Q(url_key__isnull=False))
+
+        participants_array = list(participants.select_related('speaker', 'speaker__team', 'adjudicator__institution', 'adjudicator')
+            .values('name', 'speaker__team__short_name', 'adjudicator__institution__code', 'url_key'))
+        kwargs['parts'] = self.add_urls(participants_array)
 
         kwargs['exists'] = self.tournament.participants.filter(url_key__isnull=False).exists()
 


Test patch: