Tag pro odkazy na poslání mailu #22
					 5 changed files with 121 additions and 4 deletions
				
			
		|  | @ -1,6 +1,7 @@ | |||
| {% extends "base.html" %} | ||||
| {% load static %} | ||||
| {% load deadliny %} | ||||
| {% load mail %} | ||||
| 
 | ||||
| {% block content %} | ||||
| 
 | ||||
|  | @ -14,7 +15,14 @@ | |||
| 
 | ||||
| {% if edit %} | ||||
|   <p>Řešitelé: | ||||
|     {% for r in object.resitele.all %}{{ r }} (<a href="mailto:{{ r.osoba.email }}?subject={{ "Oprava řešení M&M " | urlencode }}{{ object.problem.all.0.hlavni_problem | urlencode }}">{{ r.osoba.email }}</a>){% if forloop.revcounter0 != 0 %}, {% endif %}{% endfor %} | ||||
|   {% for r in object.resitele.all %} | ||||
|     {{ r }} | ||||
|     {# DjangoTemplates neumí spojovat řetězce (https://stackoverflow.com/q/4386168), tak si necháváme vyrobit subject mailu ve view. #} | ||||
| 
				
				zelvuska marked this conversation as resolved
				
					
					
						Outdated
					
				
			 | ||||
|     ({% maillink r.osoba.email to=r.osoba.email subject=predmetmailu %}){% if forloop.revcounter0 != 0 %}, {% endif %} | ||||
|   {% endfor %} | ||||
|   </p> | ||||
|   <p> | ||||
|     {% maillink "Poslat mail všem řešitelům" bcc=maily_vsech_resitelu subject=predmetmailu %} | ||||
|   </p> | ||||
| {% else %} | ||||
|   <p>Řešitelé: {{ object.resitele.all | join:", " }}</p> | ||||
|  |  | |||
|  | @ -235,8 +235,12 @@ class DetailReseniView(DetailView): | |||
| 	def get_context_data(self, **kw): | ||||
| 		self.check_access() | ||||
| 		ctx = super().get_context_data(**kw) | ||||
| 		hodnoceni = self.aktualni_hodnoceni() | ||||
| 		ctx["hodnoceni"] = hodnoceni | ||||
| 		detaily_hodnoceni = self.aktualni_hodnoceni() | ||||
| 		ctx["hodnoceni"] = detaily_hodnoceni | ||||
| 
 | ||||
| 		# Subject případného mailu (template neumí použitelně spojovat řetězce: https://stackoverflow.com/q/4386168) | ||||
| 		ctx["predmetmailu"] = "Oprava řešení M&M "+self.reseni.problem.first().hlavni_problem.nazev | ||||
| 		ctx["maily_vsech_resitelu"] = [y for x in self.reseni.resitele.all().values_list('osoba__email') for y in x] | ||||
| 		return ctx | ||||
| 
 | ||||
| 	def get(self, request, *args, **kwargs): | ||||
|  |  | |||
							
								
								
									
										0
									
								
								various/templatetags/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								various/templatetags/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										48
									
								
								various/templatetags/mail.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								various/templatetags/mail.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| 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 mailurl(*, subject=None, body=None, to=[], cc=[], bcc=[]): | ||||
| 	"""Tag na vytváření správně zakódované mailto: adresy | ||||
| 
 | ||||
| 	Ref: RFC 6068, <https://en.wikipedia.org/wiki/Mailto>""" | ||||
| 	if isinstance(to, str): | ||||
| 		to = [to] | ||||
| 	if isinstance(cc, str): | ||||
| 		cc = [cc] | ||||
| 	if isinstance(bcc, str): | ||||
| 		bcc = [bcc] | ||||
| 	assert isinstance(to, list) | ||||
| 	assert isinstance(cc, list) | ||||
| 	assert isinstance(bcc, list) | ||||
| 	# FIXME: adresa není správně zakódovaná, rozbije se to na adresách s divnými znaky | ||||
| 	parts = [ | ||||
| 		f'mailto:{str.join(",", to)}', | ||||
| 		] | ||||
| 	if len(to) + len(cc) + len(bcc) < 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(cc) > 0: | ||||
| 		parts.append(f'cc={str.join(",", cc)}') | ||||
| 	if len(bcc) > 0: | ||||
| 		parts.append(f'bcc={str.join(",", bcc)}') | ||||
| 	 | ||||
| 	if len(parts) > 1: | ||||
| 		url = parts[0] + '?' + str.join('&', parts[1:]) | ||||
| 	else: | ||||
| 		url = parts[0] | ||||
| 	return url | ||||
| 
 | ||||
| @register.simple_tag | ||||
| def maillink(text, subject=None, body=None, to=[], cc=[], bcc=[], attrs=None): | ||||
| 	url = mailurl(subject=subject, body=body, to=to, cc=cc, bcc=bcc) | ||||
| 	if not attrs: attrs = '' | ||||
| 	mezera = ' '*bool(attrs) | ||||
| 	full_link = f'<a href="{url}"{mezera}{attrs}>{text}</a>' | ||||
| 	return mark_safe(full_link) | ||||
|  | @ -1,3 +1,60 @@ | |||
| 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, mailurl | ||||
| 
 | ||||
| # 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_mailurl(self): | ||||
| 		self.assertEquals(mailurl(to='some@body.test'), r'mailto:some@body.test') | ||||
| 		self.assertEquals(mailurl(to=['some@body.test']), r'mailto:some@body.test') | ||||
| 		self.assertEquals(mailurl(to=['alice@test.test', 'bob@jinde.test']), r'mailto:alice@test.test,bob@jinde.test') | ||||
| 
				
				zelvuska marked this conversation as resolved
				
					
					
						Outdated
					
				
			 
				
					
						zelvuska
						commented  Není to tohle: https://docs.djangoproject.com/en/3.2/topics/templates/#django.template.loader.render_to_string Není to tohle:
from django.template.loader import render_to_string
https://docs.djangoproject.com/en/3.2/topics/templates/#django.template.loader.render_to_string
 
				
					
						zelvuska
						commented  Aha, to bere soubor… Aha, to bere soubor… | ||||
| 		self.assertEquals( | ||||
| 			mailurl(to='some@body.test', body='Tělo', subject='Předmět'), | ||||
| 			r'mailto:some@body.test?subject=P%C5%99edm%C4%9Bt&body=T%C4%9Blo', | ||||
| 			) | ||||
| 		self.assertRaises(ValueError, lambda: mailurl()) | ||||
| 
 | ||||
| 	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>', | ||||
| 			) | ||||
| 		 | ||||
| 		mailurltemplate = ( | ||||
| 			r'{% load mail %}' | ||||
| 			r'{% mailurl to="alice@test.test" subject="Čau Alice" %}' | ||||
| 			) | ||||
| 		self.assertEquals(render_template(mailurltemplate), r'mailto:alice@test.test?subject=%C4%8Cau%20Alice') | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	
Přemýšlím, jestli to nechce komentář, proč máme
mailsubjectgenerovaný ve view, když je to prakticky čistě prezentační záležitost… Názory?A možná v template komentář, kde se vzal mailsubject / co to je?
Template IMHO spíš komentář nepotřebuje. Je to evidentně subject mailu, a věci se typicky berou v kontextu (a v development toolbaru by měl být normálně vidět). Ta divná věc je to, že ho bastlíme ve view…
Ale možná by se mohl jmenovat česky, není důvod to tak neudělat (kromě toho, že jsem to nejspíš kódil v tramvaji a tam kódím většinou anglicky :-D)