From dfc66991f4efe2bfec0b8564c3de431fd8ec6dcf Mon Sep 17 00:00:00 2001 From: Phil Elson Date: Tue, 10 Aug 2021 17:34:37 +0200 Subject: [PATCH] Move QR generation to the browser, saving some time and effort on the server. --- cara/apps/calculator/report_generator.py | 23 ++++----------- cara/apps/calculator/static/js/pdf.js | 29 ------------------- .../templates/base/calculator.report.html.j2 | 16 ++++++---- cara/tests/apps/calculator/test_webapp.py | 16 +++++----- requirements.txt | 1 - setup.py | 1 - 6 files changed, 24 insertions(+), 62 deletions(-) delete mode 100644 cara/apps/calculator/static/js/pdf.js diff --git a/cara/apps/calculator/report_generator.py b/cara/apps/calculator/report_generator.py index 773481f3..2f55e3eb 100644 --- a/cara/apps/calculator/report_generator.py +++ b/cara/apps/calculator/report_generator.py @@ -1,17 +1,15 @@ import concurrent.futures import base64 import dataclasses -from datetime import datetime, timedelta +from datetime import datetime import io +import json import typing import urllib import zlib -import loky import jinja2 import numpy as np -import qrcode -import json from cara import models from ... import monte_carlo as mc @@ -123,7 +121,7 @@ def calculate_report_data(model: models.ExposureModel): } -def generate_qr_code(base_url, calculator_prefix, form: FormData): +def generate_permalink(base_url, calculator_prefix, form: FormData): form_dict = FormData.to_dict(form, strip_defaults=True) # Generate the calculator URL arguments that would be needed to re-create this @@ -136,20 +134,9 @@ def generate_qr_code(base_url, calculator_prefix, form: FormData): qr_url = f"{base_url}/_c/{compressed_args}" url = f"{base_url}{calculator_prefix}?{args}" - qr = qrcode.QRCode( - version=1, - error_correction=qrcode.constants.ERROR_CORRECT_H, - box_size=10, - border=4, - ) - qr.add_data(qr_url) - qr.make(fit=True) - img = qr.make_image(fill_color="black", back_color="white").convert('RGB') - return { - 'image': img2base64(_img2bytes(img)), 'link': url, - 'qr_url': qr_url, + 'shortened': qr_url, } @@ -313,7 +300,7 @@ class ReportGenerator: context['alternative_scenarios'] = comparison_report( alternative_scenarios, scenario_sample_times, executor_factory=executor_factory, ) - context['qr_code'] = generate_qr_code(base_url, self.calculator_prefix, form) + context['permalink'] = generate_permalink(base_url, self.calculator_prefix, form) context['calculator_prefix'] = self.calculator_prefix context['scale_warning'] = { 'level': 'yellow-2', diff --git a/cara/apps/calculator/static/js/pdf.js b/cara/apps/calculator/static/js/pdf.js deleted file mode 100644 index 6afb4fea..00000000 --- a/cara/apps/calculator/static/js/pdf.js +++ /dev/null @@ -1,29 +0,0 @@ -function generate_pdf_version(qr_link) { - const pdf_version = this.document.getElementById("body"); - - // PDF styling - var opt = { - filename: 'myfile.pdf', - image: { type: 'jpeg', quality: 0.98 }, - html2canvas: { scale: 2, width: 1200, windowWidth: 1200 }, - enableLinks: false, - jsPDF: { - unit: 'pt', - format: 'letter', - orientation: 'portrait', - }, - pagebreak: { mode: '', avoid: '.break-avoid' }, - }; - html2pdf().set(opt).from(pdf_version).toPdf().get('pdf').then(function(pdf) { - var totalPages = pdf.internal.getNumberOfPages(); - pdf.setPage(1); - pdf.link(530, 25, 60, 60, { url: qr_link }); //Hyperlink to reproduce results - - for (i = 1; i <= totalPages; i++) { - pdf.setPage(i); - pdf.setFontSize(10); - pdf.setTextColor(150); - pdf.text('Page ' + i + ' of ' + totalPages, (pdf.internal.pageSize.getWidth() / 2.25), (pdf.internal.pageSize.getHeight() - 10)); - } - }).save(); -}; \ No newline at end of file diff --git a/cara/apps/calculator/templates/base/calculator.report.html.j2 b/cara/apps/calculator/templates/base/calculator.report.html.j2 index 146478dc..128dd21d 100644 --- a/cara/apps/calculator/templates/base/calculator.report.html.j2 +++ b/cara/apps/calculator/templates/base/calculator.report.html.j2 @@ -24,8 +24,6 @@

Created {{ creation_date }} using CARA calculator version v{{ form.calculator_version }}

- {# To be replaced by "Generate PDF" #} - {% endblock report_header %} @@ -162,10 +160,10 @@
- +

- Click the QR code to regenerate the report and get a shareable link.
Alternatively, scan to regenerate the report.
Mobile-friendly app coming soon! + Click the QR code to regenerate the report and get a shareable link.
Alternatively, scan to regenerate the report.

@@ -433,11 +431,19 @@
{% endblock disclaimer_container %} - + + + diff --git a/cara/tests/apps/calculator/test_webapp.py b/cara/tests/apps/calculator/test_webapp.py index 40b75595..09bc104c 100644 --- a/cara/tests/apps/calculator/test_webapp.py +++ b/cara/tests/apps/calculator/test_webapp.py @@ -4,7 +4,7 @@ import pytest import tornado.testing import cara.apps.calculator -from cara.apps.calculator.report_generator import generate_qr_code +from cara.apps.calculator.report_generator import generate_permalink _TIMEOUT = 20. @@ -97,26 +97,26 @@ class TestOpenApp(tornado.testing.AsyncHTTPTestCase): assert response.code == 404 -async def test_qrcode_urls(http_server_client, baseline_form): +async def test_permalink_urls(http_server_client, baseline_form): base_url = 'proto://hostname/prefix' - qr_data = generate_qr_code(base_url, "/calculator", baseline_form) + permalink_data = generate_permalink(base_url, "/calculator", baseline_form) expected = f'{base_url}/calculator?exposed_coffee_break_option={baseline_form.exposed_coffee_break_option}&' - assert qr_data['link'].startswith(expected) + assert permalink_data['link'].startswith(expected) # We should get a 200 for the link. - response = await http_server_client.fetch(qr_data['link'].replace(base_url, '')) + response = await http_server_client.fetch(permalink_data['link'].replace(base_url, '')) assert response.code == 200 # And a 302 for the QR url itself. The redirected URL should be the same as # in the link. - assert qr_data['qr_url'].startswith(base_url) + assert permalink_data['shortened'].startswith(base_url) response = await http_server_client.fetch( - qr_data['qr_url'].replace(base_url, ''), + permalink_data['shortened'].replace(base_url, ''), max_redirects=0, raise_error=False, ) assert response.code == 302 - assert response.headers['Location'] == qr_data['link'].replace(base_url, '') + assert response.headers['Location'] == permalink_data['link'].replace(base_url, '') async def test_invalid_compressed_url(http_server_client, baseline_form): diff --git a/requirements.txt b/requirements.txt index 457a69b7..724bf5cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -62,7 +62,6 @@ pyparsing==2.4.7 pyrsistent==0.18.0 python-dateutil==2.8.2 pyzmq==22.1.0 -qrcode==7.2 requests==2.26.0 requests-unixsocket==0.2.0 scikit-learn==0.24.2 diff --git a/setup.py b/setup.py index 6be0d0f9..704f923c 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,6 @@ REQUIREMENTS: dict = { 'numpy', 'psutil', 'python-dateutil', - 'qrcode[pil]', 'scipy', 'sklearn', 'timezonefinder',