From e238563b53f76315201a74f2fb9f6bbc927f6005 Mon Sep 17 00:00:00 2001 From: Paul Konstantin Gerke Date: Thu, 25 Aug 2022 23:56:18 +0200 Subject: [PATCH] Replace qrcode generator with template tag --- babybuddy/models.py | 16 --- .../babybuddy/user_settings_form.html | 9 +- babybuddy/templatetags/babybuddy_tags.py | 104 ++++++++++++++++++ babybuddy/views.py | 10 +- 4 files changed, 112 insertions(+), 27 deletions(-) diff --git a/babybuddy/models.py b/babybuddy/models.py index 7b4c42d1..2631ba03 100644 --- a/babybuddy/models.py +++ b/babybuddy/models.py @@ -86,22 +86,6 @@ class Settings(models.Model): Token.objects.get(user=self.user).delete() return Token.objects.get_or_create(user=self.user)[0] - def generate_login_qr_code_png(self, page_root: str) -> bytes: - json_data = { - "url": page_root, - "api_key": str(self.api_key()), - } - qr_code_data = r"BABYBUDDY-LOGIN:" + json.dumps(json_data) - - qr = qrcode.QRCode(border=1, box_size=5) - qr.add_data(qr_code_data) - qr.make(fit=True) - image = qr.make_image() - - bytesio = io.BytesIO() - image.save(bytesio, format="png") - return bytesio.getbuffer() - @property def dashboard_refresh_rate_milliseconds(self): """ diff --git a/babybuddy/templates/babybuddy/user_settings_form.html b/babybuddy/templates/babybuddy/user_settings_form.html index 17c6b175..7ac8901b 100644 --- a/babybuddy/templates/babybuddy/user_settings_form.html +++ b/babybuddy/templates/babybuddy/user_settings_form.html @@ -1,5 +1,5 @@ {% extends 'babybuddy/page.html' %} -{% load i18n widget_tweaks %} +{% load i18n widget_tweaks babybuddy_tags %} {% block title %}{% trans "User Settings" %}{% endblock %} @@ -87,7 +87,12 @@
- + {% url 'babybuddy:root-router' as relative_root_url %} + {% make_absolute_url relative_root_url as absolute_root_url %} + +
diff --git a/babybuddy/templatetags/babybuddy_tags.py b/babybuddy/templatetags/babybuddy_tags.py index dc5f6cab..e9f62b0d 100644 --- a/babybuddy/templatetags/babybuddy_tags.py +++ b/babybuddy/templatetags/babybuddy_tags.py @@ -1,8 +1,13 @@ # -*- coding: utf-8 -*- +import io +import base64 +from multiprocessing.sharedctypes import Value + from django import template from django.apps import apps from django.utils import timezone from django.utils.translation import to_locale, get_language +from django.template.defaultfilters import stringfilter from core.models import Child @@ -55,3 +60,102 @@ def get_child_count(): @register.simple_tag() def get_current_timezone(): return timezone.get_current_timezone_name() + + +@register.simple_tag() +def inline_png_qrcode(qr_code_data, border=1, box_size=5): + import qrcode + + qr = qrcode.QRCode(border=border, box_size=box_size) + qr.add_data(qr_code_data) + qr.make(fit=True) + image = qr.make_image() + + bytesio = io.BytesIO() + image.save(bytesio, format="png") + base64_data = base64.b64encode(bytesio.getbuffer()).decode() + return f"data:image/png;base64,{base64_data}" + + +@register.simple_tag(takes_context=True) +def make_absolute_url(context, url): + request = context["request"] + abs_url = request.build_absolute_uri(url) + return abs_url + + +class QrCodeNode(template.Node): + def __init__(self, nodelist, strip, border, box_size) -> None: + super().__init__() + self.__nodelist = nodelist + self.__strip = strip + self.__border = border + self.__box_size = box_size + + def render(self, context): + contents = "" + for node in self.__nodelist: + contents += node.render(context) + if self.__strip: + contents = contents.strip() + + import qrcode + + qr = qrcode.QRCode(border=self.__border, box_size=self.__box_size) + qr.add_data(contents) + qr.make(fit=True) + image = qr.make_image() + + bytesio = io.BytesIO() + image.save(bytesio, format="png") + base64_data = base64.b64encode(bytesio.getbuffer()).decode() + return f"data:image/png;base64,{base64_data}" + + +@register.tag_function +def qrcodepng(parser, token): + contents = token.split_contents() + params = contents[1:] + + def get_parameter(name: str, value_type=None): + search_for = name + if value_type is not None: + search_for += "=" + + for p in params: + if p.startswith(search_for): + if value_type is None: + if p != search_for: + continue + params.remove(p) + return True + else: + str_value = p[len(search_for) :] + print("AHAGAGAG", str_value) + try: + result = value_type(str_value) + except ValueError: + raise template.TemplateSyntaxError( + f"Invalid parameter '{p}' does " + f"not have type '{value_type}'" + ) + else: + params.remove(p) + return result + + if value_type is None: + return False + return None + + strip = get_parameter("stripwhitespace") + border = get_parameter("border", int) or 1 + box_size = get_parameter("box_size", int) or 5 + + if params: + raise template.TemplateSyntaxError( + f"Unkown arguments for qrcode template tag: {', '.join(params)}" + ) + + nodelist = parser.parse(("endqrcodepng",)) + parser.delete_first_token() + return QrCodeNode(nodelist, strip, border, box_size) diff --git a/babybuddy/views.py b/babybuddy/views.py index 0d34a957..c2ad4cda 100644 --- a/babybuddy/views.py +++ b/babybuddy/views.py @@ -164,20 +164,12 @@ class UserSettings(LoginRequiredMixin, View): def get(self, request): settings = request.user.settings - page_root = request.build_absolute_uri(reverse("babybuddy:root-router")) - base64_png = base64.b64encode( - settings.generate_login_qr_code_png(page_root) - ) - return render( request, self.template_name, { "form_user": self.form_user_class(instance=request.user), - "form_settings": self.form_settings_class( - instance=settings - ), - "login_qr_code_png": base64_png.decode(), + "form_settings": self.form_settings_class(instance=settings), }, )