Use the compressed URL only for the QR code, and always present the full URL to the user/browser.
This commit is contained in:
parent
eae08e81f9
commit
e6fb1b9374
7 changed files with 80 additions and 33 deletions
|
|
@ -88,8 +88,6 @@ class ConcentrationModel(BaseRequestHandler):
|
|||
|
||||
try:
|
||||
form = model_generator.FormData.from_dict(requested_model_config)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as err:
|
||||
if self.settings.get("debug", False):
|
||||
import traceback
|
||||
|
|
@ -137,7 +135,11 @@ 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()
|
||||
try:
|
||||
args = zlib.decompress(base64.b64decode(compressed_args)).decode()
|
||||
except Exception as err: # noqa
|
||||
self.set_status(400)
|
||||
return self.finish("Invalid calculator data: it seems incomplete. Was there an error copying & pasting the URL?")
|
||||
self.redirect(f'/calculator?{args}')
|
||||
|
||||
|
||||
|
|
@ -156,7 +158,7 @@ def make_app(debug=False, prefix='/calculator'):
|
|||
calculator_static_dir = Path(__file__).absolute().parent / 'static'
|
||||
urls = [
|
||||
(r'/?', LandingPage),
|
||||
(r'/c/(.*)', CompressedCalculatorFormInputs),
|
||||
(r'/_c/(.*)', CompressedCalculatorFormInputs),
|
||||
(r'/static/(.*)', StaticFileHandler, {'path': static_dir}),
|
||||
(prefix + r'/?', CalculatorForm),
|
||||
(prefix + r'/report', ConcentrationModel),
|
||||
|
|
|
|||
|
|
@ -77,16 +77,11 @@ def generate_qr_code(prefix, form: FormData):
|
|||
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(
|
||||
# /_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
|
||||
url = prefix + "/calculator?" + args
|
||||
|
||||
qr = qrcode.QRCode(
|
||||
version=1,
|
||||
|
|
@ -101,6 +96,7 @@ def generate_qr_code(prefix, form: FormData):
|
|||
return {
|
||||
'image': img2base64(_img2bytes(img)),
|
||||
'link': url,
|
||||
'qr_url': qr_url,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
13
cara/tests/apps/calculator/conftest.py
Normal file
13
cara/tests/apps/calculator/conftest.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import pytest
|
||||
|
||||
from cara.apps.calculator import model_generator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def baseline_form_data():
|
||||
return model_generator.baseline_raw_form_data()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def baseline_form(baseline_form_data):
|
||||
return model_generator.FormData.from_dict(baseline_form_data)
|
||||
|
|
@ -6,15 +6,6 @@ from cara import models
|
|||
from cara import data
|
||||
import numpy as np
|
||||
|
||||
@pytest.fixture
|
||||
def baseline_form_data():
|
||||
return model_generator.baseline_raw_form_data()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def baseline_form(baseline_form_data):
|
||||
return model_generator.FormData.from_dict(baseline_form_data)
|
||||
|
||||
|
||||
def test_model_from_dict(baseline_form_data):
|
||||
form = model_generator.FormData.from_dict(baseline_form_data)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,8 @@
|
|||
import pytest
|
||||
|
||||
from cara.apps.calculator import model_generator
|
||||
from cara.apps.calculator import report_generator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def baseline_form_data():
|
||||
return model_generator.baseline_raw_form_data()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def baseline_form(baseline_form_data):
|
||||
return model_generator.FormData.from_dict(baseline_form_data)
|
||||
|
||||
|
||||
def test_generate_report(baseline_form):
|
||||
model = baseline_form.build_model()
|
||||
|
||||
|
|
@ -32,4 +21,4 @@ def test_generate_report(baseline_form):
|
|||
],
|
||||
)
|
||||
def test_readable_minutes(test_input, expected):
|
||||
assert report_generator.readable_minutes(test_input) == expected
|
||||
assert report_generator.readable_minutes(test_input) == expected
|
||||
|
|
|
|||
54
cara/tests/apps/calculator/test_webapp.py
Normal file
54
cara/tests/apps/calculator/test_webapp.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import pytest
|
||||
|
||||
from cara.apps.calculator import make_app
|
||||
from cara.apps.calculator.report_generator import generate_qr_code
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app():
|
||||
return make_app()
|
||||
|
||||
|
||||
async def test_homepage(http_server_client):
|
||||
response = await http_server_client.fetch('/')
|
||||
assert response.code == 200
|
||||
|
||||
|
||||
async def test_calculator(http_server_client):
|
||||
# Both with and without a trailing slash.
|
||||
response = await http_server_client.fetch('/calculator')
|
||||
assert response.code == 200
|
||||
|
||||
response = await http_server_client.fetch('/calculator/')
|
||||
assert response.code == 200
|
||||
|
||||
|
||||
async def test_qrcode_urls(http_server_client, baseline_form):
|
||||
prefix = 'proto://hostname/prefix'
|
||||
qr_data = generate_qr_code(prefix, baseline_form)
|
||||
expected = f'{prefix}/calculator?activity_type=office&air_changes=0.0'
|
||||
assert qr_data['link'].startswith(expected)
|
||||
|
||||
# We should get a 200 for the link.
|
||||
response = await http_server_client.fetch(qr_data['link'].replace(prefix, ''))
|
||||
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(prefix)
|
||||
response = await http_server_client.fetch(
|
||||
qr_data['qr_url'].replace(prefix, ''),
|
||||
max_redirects=0,
|
||||
raise_error=False,
|
||||
)
|
||||
assert response.code == 302
|
||||
assert response.headers['Location'] == qr_data['link'].replace(prefix, '')
|
||||
|
||||
|
||||
async def test_invalid_compressed_url(http_server_client, baseline_form):
|
||||
response = await http_server_client.fetch(
|
||||
'/_c/invalid-data',
|
||||
max_redirects=0,
|
||||
raise_error=False,
|
||||
)
|
||||
assert response.code == 400
|
||||
2
setup.py
2
setup.py
|
|
@ -71,6 +71,8 @@ setup(
|
|||
'all': [req for reqs in REQUIREMENTS.values() for req in reqs],
|
||||
},
|
||||
package_data={'cara': [
|
||||
'apps/templates/*.j2',
|
||||
'apps/calculator/templates/*.j2',
|
||||
'apps/calculator/*',
|
||||
'apps/calculator/*/*',
|
||||
'apps/calculator/*/*/*'
|
||||
|
|
|
|||
Loading…
Reference in a new issue