Shorten the form URL by compressing and b64 encoding it. In a real-world example, the baseline URL goes from 1086 characters to 620. This is good for the resulting QR barcode.

This commit is contained in:
Phil Elson 2021-03-10 17:50:22 +01:00
parent ce6b4a4420
commit eae08e81f9
2 changed files with 30 additions and 3 deletions

View file

@ -1,10 +1,12 @@
import datetime
import base64
import html
import json
import os
from pathlib import Path
import traceback
import uuid
import zlib
import jinja2
from tornado.web import Application, RequestHandler, StaticFileHandler
@ -131,6 +133,14 @@ class CalculatorForm(BaseRequestHandler):
self.finish(report)
class CompressedCalculatorFormInputs(BaseRequestHandler):
def get(self, compressed_args: str):
# Convert a base64 zlib encoded shortened URL into a non compressed
# URL, and redirect.
args = zlib.decompress(base64.b64decode(compressed_args)).decode()
self.redirect(f'/calculator?{args}')
class ReadmeHandler(BaseRequestHandler):
def get(self):
template = self.settings['template_environment'].get_template("userguide.html.j2")
@ -146,6 +156,7 @@ def make_app(debug=False, prefix='/calculator'):
calculator_static_dir = Path(__file__).absolute().parent / 'static'
urls = [
(r'/?', LandingPage),
(r'/c/(.*)', CompressedCalculatorFormInputs),
(r'/static/(.*)', StaticFileHandler, {'path': static_dir}),
(prefix + r'/?', CalculatorForm),
(prefix + r'/report', ConcentrationModel),

View file

@ -4,6 +4,7 @@ from datetime import datetime
import io
from pathlib import Path
import typing
import zlib
import qrcode
import urllib
@ -70,7 +71,22 @@ def calculate_report_data(model: models.ExposureModel):
def generate_qr_code(prefix, form: FormData):
form_dict = FormData.to_dict(form)
url = prefix + "?" + urllib.parse.urlencode(form_dict)
# Generate the calculator URL arguments that would be needed to re-create this
# form.
args = urllib.parse.urlencode(form_dict)
# Then zlib compress + base64 encode the string. To be inverted by the
# /c/ endpoint.
qr_url = prefix + "/c/" + base64.b64encode(
zlib.compress(args.encode())
).decode()
# We show the human-friendly URL when hovering over the link, but for now
# let's keep it the same as the QR URL to ensure everything continues to work
# as expected (it takes more effort to validate QR barcodes than it does links).
# url = prefix + "/calculator/?" + args
url = qr_url
qr = qrcode.QRCode(
version=1,
@ -78,7 +94,7 @@ def generate_qr_code(prefix, form: FormData):
box_size=10,
border=4,
)
qr.add_data(url)
qr.add_data(qr_url)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white").convert('RGB')
@ -272,7 +288,7 @@ def build_report(base_url: str, model: models.ExposureModel, form: FormData):
context.update(calculate_report_data(model))
alternative_scenarios = manufacture_alternative_scenarios(form)
context['alternative_scenarios'] = comparison_report(alternative_scenarios)
context['qr_code'] = generate_qr_code(f'{base_url}/calculator', form)
context['qr_code'] = generate_qr_code(base_url, form)
cara_templates = Path(__file__).parent.parent / "templates"
calculator_templates = Path(__file__).parent / "templates"