Merge pull request 'Tag pro odkazy na poslání mailu' (!22) from maillink into master
Reviewed-on: #22
This commit is contained in:
		
						commit
						cac034149f
					
				
					 5 changed files with 121 additions and 4 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| {% extends "base.html" %} | {% extends "base.html" %} | ||||||
| {% load static %} | {% load static %} | ||||||
| {% load deadliny %} | {% load deadliny %} | ||||||
|  | {% load mail %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block content %} | ||||||
| 
 | 
 | ||||||
|  | @ -14,7 +15,14 @@ | ||||||
| 
 | 
 | ||||||
| {% if edit %} | {% if edit %} | ||||||
|   <p>Řešitelé: |   <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. #} | ||||||
|  |     ({% 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> |   </p> | ||||||
| {% else %} | {% else %} | ||||||
|   <p>Řešitelé: {{ object.resitele.all | join:", " }}</p> |   <p>Řešitelé: {{ object.resitele.all | join:", " }}</p> | ||||||
|  |  | ||||||
|  | @ -235,8 +235,12 @@ class DetailReseniView(DetailView): | ||||||
| 	def get_context_data(self, **kw): | 	def get_context_data(self, **kw): | ||||||
| 		self.check_access() | 		self.check_access() | ||||||
| 		ctx = super().get_context_data(**kw) | 		ctx = super().get_context_data(**kw) | ||||||
| 		hodnoceni = self.aktualni_hodnoceni() | 		detaily_hodnoceni = self.aktualni_hodnoceni() | ||||||
| 		ctx["hodnoceni"] = 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 | 		return ctx | ||||||
| 
 | 
 | ||||||
| 	def get(self, request, *args, **kwargs): | 	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 | 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') | ||||||
|  | 		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