Browse Source

Přidání tagu {% maillink %}

Vyrábí odkazy, které vedou na poslání mailu.

Psal jsem to spíš po paměti, nejsem si jistý, že to takhle je přesně
podle příslušného RFC, ale jako PoC dobrý a když to nebude fungovat, tak
se implementace opraví.

Všimněte si, že to je otestované, takže když někdo opraví testy
(=předpis chování), tak je pak snadné z diffu a všeho odvodit úpravu.

V Django dokumentaci se píše něco o tom, že by se měl použít spíš
`format_html` a `conditional_escape`, ale zatím jsem to víc nezkoumal.

Je žádoucí z tagu {% maillink %} odddělit i tag {% mailurl %}, který by
vracel samotnou URL. Obojí dává smysl umět (speciálně bastlení odkazů z
URL je stejně strašně nepřehledné, takže je lepší to zavřít do {%
maillink %} a nikdy nevidět), ale zatím to oddělené není… (Ale jsou na
to testy, takže by se mělo aspoň dát poznat, že rozdělení nerozbije
chování.)
maillink_dev_ledoian^2
Pavel 'LEdoian' Turinsky 2 years ago
parent
commit
6994db438b
  1. 0
      various/templatetags/__init__.py
  2. 30
      various/templatetags/mail.py
  3. 43
      various/tests.py

0
various/templatetags/__init__.py

30
various/templatetags/mail.py

@ -0,0 +1,30 @@
from django import template
from django.utils.safestring import mark_safe
from urllib.request import quote as urlencode
register = template.Library()
@register.simple_tag
def maillink(text: str, subject=None, body=None, to=[], attrs=None):
"""TODO: Dokumentace"""
if isinstance(to, str):
to = [to]
assert isinstance(to, list)
parts = [
f'mailto:{str.join(",", to)}',
]
if len(to) < 1:
raise ValueError('Cannot mail to empty set of people')
if subject:
parts.append(f'subject={urlencode(subject)}')
if body:
parts.append(f'body={urlencode(body)}')
if len(parts) > 1:
url = parts[0] + '?' + str.join('&', parts[1:])
else:
url = parts[0]
if not attrs: attrs = ''
mezera = ' '*bool(attrs)
full_link = f'<a href="{url}"{mezera}{attrs}>{text}</a>'
return mark_safe(full_link)

43
various/tests.py

@ -1,3 +1,44 @@
from django.test import TestCase
# TODO: Možná vyrobit separátní soubory v tests/… než mít všechny testy v jednom souboru?
from various.templatetags.mail import maillink
# Create your tests here.
class MailTagsTest(TestCase):
"""Testuje template tagy ohledně mailů."""
def test_maillink(self):
# Tohle nedává smysl dělit do víc funkcí, bylo by v nich víc boilerplatu než užitečného kódu.
self.assertEquals(maillink('Hello', to='some@body.test'), r'<a href="mailto:some@body.test">Hello</a>')
self.assertEquals(maillink('Hello', to=['some@body.test']), r'<a href="mailto:some@body.test">Hello</a>')
self.assertEquals(
maillink('Hello', to=['alice@test.test', 'bob@jinde.test']),
r'<a href="mailto:alice@test.test,bob@jinde.test">Hello</a>',
)
self.assertEquals(
maillink('Hello', to='some@body.test', attrs='class="trida" id="id"'),
r'<a href="mailto:some@body.test" class="trida" id="id">Hello</a>',
)
# Následující test toho testuje moc zároveň, měly by předcházet dedikované testy… (kašlu na ně :-P)
self.assertEquals(
maillink('Text odkazu', to='prijemce@wtf.test', subject="Předmět", body="Čau"),
r'<a href="mailto:prijemce@wtf.test?subject=P%C5%99edm%C4%9Bt&body=%C4%8Cau">Text odkazu</a>',
)
self.assertRaises(ValueError, lambda: maillink('Nemám příjemce'))
self.assertRaises(TypeError, lambda: maillink()) # Nemá text, takže to shodí python
def test_render_in_template(self):
# Pomocná funkce: vykreslí template do stringu
# Ref: https://stackoverflow.com/a/1690879
def render_template(template, context=None):
from django.template import Template, Context
context = context or {}
context = Context(context)
return Template(template).render(context)
template=(
r'{% load mail %}'
# TODO: Vyzkoušet i víc adresátů. (Nepamatuji si z hlavy syntaxi…)
r'{% maillink "Text" to="alice@test.test" subject="Oprava řešení" %}'
)
self.assertEquals(
render_template(template),
r'<a href="mailto:alice@test.test?subject=Oprava%20%C5%99e%C5%A1en%C3%AD">Text</a>',
)

Loading…
Cancel
Save