"""Template tags of the config app."""
from json import dumps
from os.path import basename, splitext
from typing import Dict, List
from urllib.parse import urljoin as join
from urllib.request import Request, urlopen
from django.core.cache import cache
from django.core.serializers.json import DjangoJSONEncoder
from django.template.defaultfilters import register, slice_filter
from django.utils.html import format_html
from django.utils.safestring import mark_safe
[docs]@register.filter
def urljoin(origin: str, pathname: str) -> str:
"""
A template filter used to join URL parts.
:param origin: The origin of the URL.
:param pathname: The pathname of the URL.
:return: The URL joined via :func:`~urllib.parse.urljoin`.
"""
return join(origin, pathname)
[docs]@register.filter(is_safe=True)
def jsonld(value: Dict, element_id: str) -> str:
"""
Generate a JSON-LD script tag.
:param value: A JSON-LD dictionary.
:param element_id: The id of the element.
:return: An HTML ``<script>`` element.
.. seealso:: :tag:`json_script template tag <json-script>`
"""
sep = (',', ':')
# Escape special HTML characters for JSON output
escapes = {ord('>'): '\\u003E', ord('<'): '\\u003C', ord('&'): '\\u0026'}
jstr = dumps(value, cls=DjangoJSONEncoder, indent=None, separators=sep)
return format_html(
'<script id="{}" type="application/ld+json">{}</script>',
element_id, mark_safe(jstr.translate(escapes)) # nosec: B308
)
[docs]@register.filter
def vslice(value: List, var: int) -> List:
"""
Filter used to dynamically :tag:`slice` a list.
:param value: The original list.
:param var: The end of the slice.
:return: The sliced list.
"""
return slice_filter(value, f':{var:d}')
[docs]@register.filter
def get_type(link: str) -> str:
"""
Get the type of an image given its URL.
:param link: The link to the image file.
:return: The mime type of the image.
"""
if (key := 'type.' + basename(link.lower())) in cache:
return cache.get(key) # pragma: no cover
try:
# Disallow non-HTTP(S) schemes
if not link.startswith(('http://', 'https://')):
raise Exception('Invalid scheme')
request = Request(link, method='HEAD')
with urlopen(request) as response: # nosec: B310
type_ = response.info().get_content_type()
cache.add(key, type_)
return type_
except Exception:
return {
'.apng': 'image/apng',
'.bmp': 'image/bmp',
'.gif': 'image/gif',
'.heic': 'image/heic',
'.heif': 'image/heif',
'.ico': 'image/x-icon',
'.icon': 'image/x-icon',
'.j2k': 'image/jp2',
'.jfif': 'image/jpeg',
'.jls': 'image/jls',
'.jp2': 'image/jp2',
'.jpeg': 'image/jpeg',
'.jpf': 'image/jpx',
'.jpg': 'image/jpeg',
'.jpm': 'image/jpm',
'.jpx': 'image/jpx',
'.jxl': 'image/jxl',
'.jxr': 'image/jxr',
'.jxs': 'image/jxs',
'.png': 'image/png',
'.svg': 'image/svg+xml',
'.tif': 'image/tiff',
'.tiff': 'image/tiff',
'.webp': 'image/webp'
}.get(splitext(link.lower())[-1], 'image/jpeg')
__all__ = ['urljoin', 'vslice', 'jsonld', 'get_type']