import base64
import binascii
import functools
from django.conf import settings
from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.core.signing import BadSignature, Signer
from django.http import HttpResponse
from django.views.decorators.cache import cache_page
from django.views.decorators.http import condition
from qr_code.qrcode import constants
from qr_code.qrcode.maker import make_qr_code_image
from qr_code.qrcode.utils import QRCodeOptions
from qr_code.qrcode.serve import (
get_url_protection_options,
get_qr_url_protection_token,
qr_code_etag,
qr_code_last_modified,
allows_external_request_from_user,
)
def cache_qr_code():
"""
Decorator that caches the requested page if a settings named 'QR_CODE_CACHE_ALIAS' exists and is not empty or None.
"""
def decorator(view_func):
@functools.wraps(view_func)
def _wrapped_view(request, *view_args, **view_kwargs):
cache_enabled = int(request.GET.get("cache_enabled", 1)) == 1
if cache_enabled and hasattr(settings, "QR_CODE_CACHE_ALIAS") and settings.QR_CODE_CACHE_ALIAS:
# We found a cache alias for storing the generate qr code and cache is enabled, use it to cache the
# page.
timeout = settings.CACHES[settings.QR_CODE_CACHE_ALIAS]["TIMEOUT"]
key_prefix = "token={}.user_pk={}".format(
request.GET.get("url_signature_enabled") or constants.DEFAULT_URL_SIGNATURE_ENABLED,
request.user.pk,
)
response = cache_page(timeout, cache=settings.QR_CODE_CACHE_ALIAS, key_prefix=key_prefix)(view_func)(
request, *view_args, **view_kwargs
)
else:
# No cache alias for storing the generated qr code, call the view as is.
response = (view_func)(request, *view_args, **view_kwargs)
return response
return _wrapped_view
return decorator
@condition(etag_func=qr_code_etag, last_modified_func=qr_code_last_modified)
@cache_qr_code()
def serve_qr_code_image(request) -> HttpResponse:
"""Serve an image that represents the requested QR code.
IMPORTANT NOTE: Each boolean option mentioned below (value True/False) must be passed as `