Replace qrcode generator with template tag

This commit is contained in:
Paul Konstantin Gerke 2022-08-25 23:56:18 +02:00
parent abcd832591
commit e238563b53
4 changed files with 112 additions and 27 deletions

View File

@ -86,22 +86,6 @@ class Settings(models.Model):
Token.objects.get(user=self.user).delete() Token.objects.get(user=self.user).delete()
return Token.objects.get_or_create(user=self.user)[0] 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 @property
def dashboard_refresh_rate_milliseconds(self): def dashboard_refresh_rate_milliseconds(self):
""" """

View File

@ -1,5 +1,5 @@
{% extends 'babybuddy/page.html' %} {% extends 'babybuddy/page.html' %}
{% load i18n widget_tweaks %} {% load i18n widget_tweaks babybuddy_tags %}
{% block title %}{% trans "User Settings" %}{% endblock %} {% block title %}{% trans "User Settings" %}{% endblock %}
@ -87,7 +87,12 @@
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label">{% trans "Login QR code" %}</label> <label class="col-sm-2 col-form-label">{% trans "Login QR code" %}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<img src="data:image/png;base64,{{ login_qr_code_png }}"> {% url 'babybuddy:root-router' as relative_root_url %}
{% make_absolute_url relative_root_url as absolute_root_url %}
<img src="{% qrcodepng stripwhitespace %}
BABYBUDDY-LOGIN:{"url":"{{ absolute_root_url }}","api_key":"{{ user.settings.api_key }}"}
{% endqrcodepng %}">
</div> </div>
</div> </div>
</fieldset> </fieldset>

View File

@ -1,8 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import io
import base64
from multiprocessing.sharedctypes import Value
from django import template from django import template
from django.apps import apps from django.apps import apps
from django.utils import timezone from django.utils import timezone
from django.utils.translation import to_locale, get_language from django.utils.translation import to_locale, get_language
from django.template.defaultfilters import stringfilter
from core.models import Child from core.models import Child
@ -55,3 +60,102 @@ def get_child_count():
@register.simple_tag() @register.simple_tag()
def get_current_timezone(): def get_current_timezone():
return timezone.get_current_timezone_name() 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)

View File

@ -164,20 +164,12 @@ class UserSettings(LoginRequiredMixin, View):
def get(self, request): def get(self, request):
settings = request.user.settings 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( return render(
request, request,
self.template_name, self.template_name,
{ {
"form_user": self.form_user_class(instance=request.user), "form_user": self.form_user_class(instance=request.user),
"form_settings": self.form_settings_class( "form_settings": self.form_settings_class(instance=settings),
instance=settings
),
"login_qr_code_png": base64_png.decode(),
}, },
) )