WIP: Nástroj pro plošné vyrábění problémů #17
					 22 changed files with 376 additions and 385 deletions
				
			
		|  | @ -12,7 +12,7 @@ from django.contrib import admin | ||||||
| from reversion.admin import VersionAdmin | from reversion.admin import VersionAdmin | ||||||
| from korektury.models import KorekturovanePDF | from korektury.models import KorekturovanePDF | ||||||
| 
 | 
 | ||||||
| from django.core.mail import send_mail | from django.core.mail import EmailMessage | ||||||
| from django.urls import reverse | from django.urls import reverse | ||||||
| 
 | 
 | ||||||
| # Register your models here. | # Register your models here. | ||||||
|  | @ -64,6 +64,11 @@ Popis souboru: | ||||||
| S pozdravem a korekturám zdar! | S pozdravem a korekturám zdar! | ||||||
| Korekturovátko | Korekturovátko | ||||||
| ''' | ''' | ||||||
| 			send_mail(predmet,text,odesilatel,[prijemce]) | 			EmailMessage( | ||||||
|  | 				subject=predmet, | ||||||
|  | 				body=text, | ||||||
|  | 				from_email=odesilatel, | ||||||
|  | 				to=[prijemce], | ||||||
|  | 			).send() | ||||||
| 
 | 
 | ||||||
| admin.site.register(KorekturovanePDF, KorekturovanePDFAdmin) | admin.site.register(KorekturovanePDF, KorekturovanePDFAdmin) | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ from django.views import generic | ||||||
| from django.utils.translation import ugettext as _ | from django.utils.translation import ugettext as _ | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.http import HttpResponseForbidden | from django.http import HttpResponseForbidden | ||||||
| from django.core.mail import send_mail | from django.core.mail import EmailMessage | ||||||
| from django.db.models import Count,Q | from django.db.models import Count,Q | ||||||
| 
 | 
 | ||||||
| from .models import Oprava,Komentar,KorekturovanePDF, Organizator | from .models import Oprava,Komentar,KorekturovanePDF, Organizator | ||||||
|  | @ -207,7 +207,12 @@ class KorekturyView(generic.TemplateView): | ||||||
| 			print("---- Konec upozornění") | 			print("---- Konec upozornění") | ||||||
| 			return | 			return | ||||||
| 
 | 
 | ||||||
| 		send_mail(subject, text, from_email, list(emails)) | 		EmailMessage( | ||||||
|  | 			subject=subject, | ||||||
|  | 			body=text, | ||||||
|  | 			from_email=from_email, | ||||||
|  | 			to=list(emails), | ||||||
|  | 		).send() | ||||||
| 
 | 
 | ||||||
| 	def get_context_data(self, **kwargs): | 	def get_context_data(self, **kwargs): | ||||||
| 		context = super().get_context_data(**kwargs) | 		context = super().get_context_data(**kwargs) | ||||||
|  |  | ||||||
|  | @ -8,3 +8,4 @@ ensure_venv | ||||||
| ./manage.py testdata | ./manage.py testdata | ||||||
| ./manage.py loaddata data/* | ./manage.py loaddata data/* | ||||||
| make/sync_prod_flatpages | make/sync_prod_flatpages | ||||||
|  | ./manage.py load_org_permissions deploy_v2/admin_org_prava.json | ||||||
|  |  | ||||||
|  | @ -170,6 +170,22 @@ | ||||||
| 	rotace_a_posun($('.container'), randomUhel()); | 	rotace_a_posun($('.container'), randomUhel()); | ||||||
| 	</script> | 	</script> | ||||||
| 	{% endif %} | 	{% endif %} | ||||||
|  |   {% if april == 2023 %} | ||||||
|  |     <script> | ||||||
|  | {#  By https://stackoverflow.com/a/34559316  #} | ||||||
|  |       function walkText(node) { | ||||||
|  |         if (node.nodeType == 3) { | ||||||
|  |           node.data = node.data.replace(/M&M/g, "M💘M"); | ||||||
|  |         } | ||||||
|  |         if (node.nodeType == 1 && node.nodeName != "SCRIPT") { | ||||||
|  |           for (var i = 0; i < node.childNodes.length; i++) { | ||||||
|  |             walkText(node.childNodes[i]); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       walkText(document.body); | ||||||
|  |     </script> | ||||||
|  |   {% endif %} | ||||||
| 	{% render_block "js" %} | 	{% render_block "js" %} | ||||||
|   </body> |   </body> | ||||||
| </html> | </html> | ||||||
|  |  | ||||||
|  | @ -2,12 +2,24 @@ | ||||||
| {% load static %} | {% load static %} | ||||||
| {% load deadliny %} | {% load deadliny %} | ||||||
| {% load mail %} | {% load mail %} | ||||||
|  | {% load jmena %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block content %} | ||||||
| 
 | 
 | ||||||
|   {% if edit %} |   {% if edit %} | ||||||
|     <script src="{% static 'odevzdavatko/dynamic_formsets_for_detail.js' %}"></script> |     <script src="{% static 'odevzdavatko/dynamic_formsets_for_detail.js' %}"></script> | ||||||
|     <script src="{% static 'odevzdavatko/check_for_detail.js' %}"></script> |     <script src="{% static 'odevzdavatko/check_for_detail.js' %}"></script> | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |       $(document).ready(function () { | ||||||
|  |         const zaskrtavatko = document.getElementById('pridat-jmena-resitelu'); | ||||||
|  |         zaskrtavatko.addEventListener('change', () => { | ||||||
|  |           for (var priloha of document.getElementsByClassName("reseni-ke-stazeni")) { | ||||||
|  |             let new_download = zaskrtavatko.checked ? priloha.dataset.altFilename : ''; | ||||||
|  |             priloha.setAttribute('download', new_download); | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  |     </script> | ||||||
|   {% endif %} |   {% endif %} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -40,11 +52,20 @@ | ||||||
| <tr><th>Soubor</th><th>Řešitelova poznámka</th><th>Datum</th></tr> | <tr><th>Soubor</th><th>Řešitelova poznámka</th><th>Datum</th></tr> | ||||||
| {% for priloha in object.prilohy.all %} | {% for priloha in object.prilohy.all %} | ||||||
| <tr> | <tr> | ||||||
| 	<td><a href="{{ priloha.soubor.url }}" download>{{ priloha.split | last }}</a></td> |   <td><a class='reseni-ke-stazeni'  | ||||||
|  |          href="{{ priloha.soubor.url }}" | ||||||
|  |          download | ||||||
|  |          data-alt-filename="{{object.resitele.first.osoba | jmeno_jako_prefix }}_{{ object.id }}_{{ priloha.split | last}}" | ||||||
|  |          >{{ priloha.split | last }}</a></td> | ||||||
| 	<td>{{ priloha.res_poznamka }}</td> | 	<td>{{ priloha.res_poznamka }}</td> | ||||||
| 	<td>{{ priloha.vytvoreno }}</td></tr> | 	<td>{{ priloha.vytvoreno }}</td></tr> | ||||||
| {% endfor %} | {% endfor %} | ||||||
| </table> | </table> | ||||||
|  | {% if edit %} {# FIXME: tohle nesouvisí s editací, ale s tím, jestli je člověk org… #} | ||||||
|  |   <br> | ||||||
|  |   <input type=checkbox id="pridat-jmena-resitelu"> | ||||||
|  |   <label class="field-label" for="pridat-jmena-resitelu">Uvést jméno řešitele v názvu souboru při stažení.</label> | ||||||
|  | {% endif %} | ||||||
| {% else %} | {% else %} | ||||||
| <p>Žádné přílohy</p> | <p>Žádné přílohy</p> | ||||||
| {% endif %} | {% endif %} | ||||||
|  |  | ||||||
							
								
								
									
										0
									
								
								odevzdavatko/templatetags/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								odevzdavatko/templatetags/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										9
									
								
								odevzdavatko/templatetags/jmena.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								odevzdavatko/templatetags/jmena.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | from django import template | ||||||
|  | register = template.Library() | ||||||
|  | 
 | ||||||
|  | from personalni.utils import normalizuj_jmeno | ||||||
|  | import seminar.models as m # jen kvůli typové anotaci… | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def jmeno_jako_prefix(o: m.Osoba): | ||||||
|  | 	return normalizuj_jmeno(o).replace(' ', '_') | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| from django.core.exceptions import PermissionDenied | from django.core.exceptions import PermissionDenied | ||||||
| from django.views.generic import ListView, DetailView, FormView | from django.views.generic import ListView, DetailView, FormView | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin | from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
| from django.core.mail import send_mail | from django.core.mail import EmailMessage | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| from django.views.generic import ListView, DetailView, FormView, CreateView | from django.views.generic import ListView, DetailView, FormView, CreateView | ||||||
| from django.views.generic.list import MultipleObjectTemplateResponseMixin,MultipleObjectMixin | from django.views.generic.list import MultipleObjectTemplateResponseMixin,MultipleObjectMixin | ||||||
|  | @ -449,11 +449,11 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | ||||||
| 		seznam = "problému " + str(problemy[0]) if len(problemy) == 1 else 'následujícím problémům:\n' + ', \n'.join(map(str, problemy)) | 		seznam = "problému " + str(problemy[0]) if len(problemy) == 1 else 'následujícím problémům:\n' + ', \n'.join(map(str, problemy)) | ||||||
| 		seznam_do_subjectu = "problému " + str(problemy[0]) + ("" if len(problemy) == 1 else f" (a dalším { len(problemy) - 1 })") | 		seznam_do_subjectu = "problému " + str(problemy[0]) + ("" if len(problemy) == 1 else f" (a dalším { len(problemy) - 1 })") | ||||||
| 
 | 
 | ||||||
| 		send_mail( | 		EmailMessage( | ||||||
| 			subject="Nové řešení k " + seznam_do_subjectu, | 			subject="Nové řešení k " + seznam_do_subjectu, | ||||||
| 			message=f"Řešitel{ '' if resitel.pohlavi_muz else 'ka' } { resitel } právě nahrál{'' if resitel.pohlavi_muz else 'a' } nové řešení k { seznam }.\n\nHurá do opravování: { self.object.absolute_url() }", | 			body=f"Řešitel{ '' if resitel.pohlavi_muz else 'ka' } { resitel } právě nahrál{'' if resitel.pohlavi_muz else 'a' } nové řešení k { seznam }.\n\nHurá do opravování: { self.object.absolute_url() }", | ||||||
| 			from_email="submitovatko@mam.mff.cuni.cz", # FIXME: Chceme to mít radši tady, nebo v nastavení? | 			from_email="submitovatko@mam.mff.cuni.cz", # FIXME: Chceme to mít radši tady, nebo v nastavení? | ||||||
| 			recipient_list=list(prijemci), | 			to=list(prijemci), | ||||||
| 		) | 		).send() | ||||||
| 
 | 
 | ||||||
| 		return formularOKView(self.request, text='Řešení úspěšně odevzdáno') | 		return formularOKView(self.request, text='Řešení úspěšně odevzdáno') | ||||||
|  |  | ||||||
|  | @ -25,107 +25,86 @@ class TelInput(forms.TextInput): | ||||||
| 	input_pattern="^[+]?[()/0-9. -]{9,}$" | 	input_pattern="^[+]?[()/0-9. -]{9,}$" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PrihlaskaForm(PasswordResetForm): | class UdajeForm(forms.Form): | ||||||
| 	username = forms.CharField(label='Přihlašovací jméno',  | 	username = None | ||||||
| 			max_length=256,  | 	err_logger = logging.getLogger('seminar.prihlaska.problem') | ||||||
| 			required=True, |  | ||||||
| 			help_text='Tímto jménem se následně budeš přihlašovat pro odevzdání řešení a další činnosti v semináři') |  | ||||||
| 
 | 
 | ||||||
| 	jmeno = forms.CharField(label='Jméno', max_length=256, required=True) | 	jmeno = forms.CharField(label='Jméno', max_length=256, required=True) | ||||||
| 	prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False) | 	prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False) | ||||||
| 	prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) | 	prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) | ||||||
| 	pohlavi_muz = forms.ChoiceField(label='Pohlaví', | 	pohlavi_muz = forms.ChoiceField(label='Pohlaví', choices=((True, 'muž'), (False, 'žena')), required=True) | ||||||
| 			choices = ((True,'muž'),(False,'žena')), required=True) |  | ||||||
| 	email = forms.EmailField(label='E-mail', max_length=256, required=True) | 	email = forms.EmailField(label='E-mail', max_length=256, required=True) | ||||||
| 	telefon = forms.CharField(widget=TelInput(), label='Telefon', max_length=256, required=False) | 	telefon = forms.CharField(widget=TelInput(), label='Telefon', max_length=256, required=False) | ||||||
| 	datum_narozeni = forms.DateField(widget=DateInput(), label='Datum narození', required=False) | 	datum_narozeni = forms.DateField(widget=DateInput(), label='Datum narození', required=False) | ||||||
| 	ulice = forms.CharField(label='Ulice a číslo popisné', max_length=256, required=False) | 	ulice = forms.CharField(label='Ulice a číslo popisné', max_length=256, required=False) | ||||||
| 	mesto = forms.CharField(label='Město', max_length=256, required=False) | 	mesto = forms.CharField(label='Město', max_length=256, required=False) | ||||||
| 	psc = forms.CharField(label='PSČ', max_length=32, required=False) | 	psc = forms.CharField(label='PSČ', max_length=32, required=False) | ||||||
| 	stat = forms.ChoiceField(label='Stát',  | 	stat = forms.ChoiceField(label='Stát', choices=(('CZ', 'Česká republika'), ('SK', 'Slovenská republika'), ('other', 'Jiné')), required=False) | ||||||
| 			choices = (('CZ', 'Česká Republika'), |  | ||||||
| 				('SK', 'Slovenská Republika'), |  | ||||||
| 				('other', 'Jiné')), |  | ||||||
| 			required=False) |  | ||||||
| 	stat_text = forms.CharField(label='Stát', max_length=256, required=False) | 	stat_text = forms.CharField(label='Stát', max_length=256, required=False) | ||||||
| 
 | 
 | ||||||
| 	skola = forms.ModelChoiceField(label="Škola", | 	skola = forms.ModelChoiceField( | ||||||
|  | 		label="Škola", | ||||||
| 		queryset=Skola.objects.all(), | 		queryset=Skola.objects.all(), | ||||||
| 		widget=autocomplete.ModelSelect2( | 		widget=autocomplete.ModelSelect2( | ||||||
| 			url='autocomplete_skola', | 			url='autocomplete_skola', | ||||||
| 			attrs = {'data-placeholder--id': '-1', | 			attrs={ | ||||||
|  | 				'data-placeholder--id': '-1', | ||||||
| 				'data-placeholder--text': '---', | 				'data-placeholder--text': '---', | ||||||
| 				'data-allow-clear': 'true'}) | 				'data-allow-clear': 'true' | ||||||
| 			,required=False) | 			} | ||||||
|  | 		), | ||||||
|  | 		required=False, | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	skola_nazev = forms.CharField(label='Název školy', max_length=256, required=False) | 	skola_nazev = forms.CharField(label='Název školy', max_length=256, required=False) | ||||||
| 	skola_adresa = forms.CharField(label='Adresa školy', max_length=256, required=False) | 	skola_adresa = forms.CharField(label='Adresa školy', max_length=256, required=False) | ||||||
| 
 | 
 | ||||||
| #	trida = forms.CharField(label='Třída',max_length=10, required=True) |  | ||||||
| 
 |  | ||||||
| 	rok_maturity = forms.IntegerField( | 	rok_maturity = forms.IntegerField( | ||||||
| 		label='Rok maturity', | 		label='Rok maturity', | ||||||
| 		min_value=date.today().year, | 		min_value=date.today().year, | ||||||
| 		max_value=date.today().year+8, | 		max_value=date.today().year+8, | ||||||
| 		required=True) | 		required=True, | ||||||
| 	zasilat = forms.ChoiceField(label='Kam zasílat čísla',choices = Resitel.ZASILAT_CHOICES, required=True) | 	) | ||||||
| 	zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat e-mailem upozornění na vydání nového čísla', required=False) |  | ||||||
| 
 | 
 | ||||||
| 	jak_se_dozvedeli = forms.CharField(widget=forms.Textarea({"rows": 3, "cols": 20}), label='Jak ses o M&M dozvěděl(a)? (Nechceš-li odpovídat, napiš „nechci uvést“.)', required=True) | 	zasilat = forms.ChoiceField(label='Kam zasílat (odměny, pozvánky, případně čísla nebo propagační materiály)', choices=[it for it in Resitel.ZASILAT_CHOICES if it[0] != Resitel.ZASILAT_NIKAM], required=True, initial=Resitel.ZASILAT_DOMU) | ||||||
| 
 | 	zasilat_cislo_papirove = forms.BooleanField(label='Chci dostávat čísla poštou (zasílání není zpoplatněno)', required=False, initial=False) | ||||||
| 	gdpr = forms.BooleanField(label='Souhlasím se zpracováním osobních údajů', required=True) | 	zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat e-mailem upozornění na vydání nového čísla', required=False, initial=True) | ||||||
| 	spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False) | 	spam = forms.BooleanField(label='Souhlasím se zasíláním propagačních materiálů od MFF UK', required=False) | ||||||
| 	 |  | ||||||
| 	def clean_username(self): |  | ||||||
| 		err_logger = logging.getLogger('seminar.prihlaska.problem') |  | ||||||
| 		username = self.cleaned_data.get('username') |  | ||||||
| 		try: |  | ||||||
| 			User.objects.get(username=username) |  | ||||||
| 			msg = "Username {} exists".format(username) |  | ||||||
| 			err_logger.info(msg) |  | ||||||
| 			raise forms.ValidationError('Přihlašovací jméno je již použito') |  | ||||||
| 
 |  | ||||||
| 		except ObjectDoesNotExist: |  | ||||||
| 			pass |  | ||||||
| 		return username |  | ||||||
| 
 |  | ||||||
| 	def clean_email(self): |  | ||||||
| 		err_logger = logging.getLogger('seminar.prihlaska.problem') |  | ||||||
| 		email = self.cleaned_data.get('email') |  | ||||||
| 		try: |  | ||||||
| 			osoba = Osoba.objects.get(email=email) |  | ||||||
| 			msg = "Email {} exists".format(email) |  | ||||||
| 			if osoba.user is not None: |  | ||||||
| 				err_logger.info(msg) |  | ||||||
| 				raise forms.ValidationError('E-mail je již použit') |  | ||||||
| 			else: |  | ||||||
| 				msg += ', but currently has no User, so allowing registration.' |  | ||||||
| 				err_logger.info(msg) |  | ||||||
| 
 |  | ||||||
| 		except ObjectDoesNotExist: |  | ||||||
| 			pass |  | ||||||
| 		return email |  | ||||||
| 
 | 
 | ||||||
| 	def clean_prezdivka_resitele(self): | 	def clean_prezdivka_resitele(self): | ||||||
| 		prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele') | 		prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele') | ||||||
| 		if prezdivka_resitele == '': | 		if prezdivka_resitele == '': | ||||||
| 			return prezdivka_resitele | 			return prezdivka_resitele | ||||||
| 		if Resitel.objects.filter(prezdivka_resitele=prezdivka_resitele).count() > 0: | 		if Resitel.objects.filter(prezdivka_resitele=prezdivka_resitele).exclude(osoba__user__username=self.username).count() > 0: | ||||||
| 			raise forms.ValidationError('Přezdívka je již použita') | 			raise forms.ValidationError('Přezdívka je již použita') | ||||||
| 		return prezdivka_resitele | 		return prezdivka_resitele | ||||||
| 
 | 
 | ||||||
|  | 	def clean_email(self): | ||||||
|  | 		email = self.cleaned_data.get('email') | ||||||
|  | 		try: | ||||||
|  | 			osoba = Osoba.objects.exclude(user__username=self.username).get(email=email) | ||||||
|  | 			msg = "Email {} exists".format(email) | ||||||
|  | 			if osoba.user is not None: | ||||||
|  | 				self.err_logger.info(msg) | ||||||
|  | 				raise forms.ValidationError('E-mail je již použit') | ||||||
|  | 			else: | ||||||
|  | 				msg += ', but currently has no User, so allowing registration.' | ||||||
|  | 				self.err_logger.info(msg) | ||||||
|  | 
 | ||||||
|  | 		except ObjectDoesNotExist: | ||||||
|  | 			pass | ||||||
|  | 		return email | ||||||
|  | 
 | ||||||
| 	def clean_zasilat(self): | 	def clean_zasilat(self): | ||||||
| 		zasilat = self.cleaned_data.get('zasilat') | 		zasilat = self.cleaned_data.get('zasilat') | ||||||
| 		ulice = self.cleaned_data.get('ulice') | 		ulice = self.cleaned_data.get('ulice') | ||||||
| 		if zasilat == Resitel.ZASILAT_DOMU and ulice == "": | 		if zasilat == Resitel.ZASILAT_DOMU and ulice == "": | ||||||
| 			raise forms.ValidationError('Nevyplněná adresa bydliště, nelze zasílat čísla domů.') | 			raise forms.ValidationError('Nevyplněná adresa bydliště, nelze zasílat domů.') | ||||||
| 		return zasilat | 		return zasilat | ||||||
| 
 | 
 | ||||||
| 	def clean(self): | 	def clean(self): | ||||||
| 		super().clean() | 		super().clean() | ||||||
| 
 | 
 | ||||||
| 		err_logger = logging.getLogger('seminar.prihlaska.problem') |  | ||||||
| 
 |  | ||||||
| 		data = self.cleaned_data | 		data = self.cleaned_data | ||||||
| 		if data.get('stat') != 'other' and data.get('stat_text') != '': | 		if data.get('stat') != 'other' and data.get('stat_text') != '': | ||||||
| 			self.add_error('stat',forms.ValidationError('Nelze mít vybraný stát z menu a zároven zapsaný textem')) | 			self.add_error('stat',forms.ValidationError('Nelze mít vybraný stát z menu a zároven zapsaný textem')) | ||||||
|  | @ -140,106 +119,41 @@ class PrihlaskaForm(PasswordResetForm): | ||||||
| 				self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy')) | 				self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy')) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ProfileEditForm(forms.Form): | 
 | ||||||
| 	username = forms.CharField(label='Přihlašovací jméno', | 
 | ||||||
|  | class PrihlaskaForm(PasswordResetForm, UdajeForm): | ||||||
|  | 	username = forms.CharField( | ||||||
|  | 		label='Přihlašovací jméno', | ||||||
| 		max_length=256, | 		max_length=256, | ||||||
| 			required=False, | 		required=True, | ||||||
| 			disabled=True) | 		help_text='Tímto jménem se následně budeš přihlašovat pro odevzdání řešení a další činnosti v semináři', | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	jmeno = forms.CharField(label='Jméno', max_length=256, required=True) | 	jak_se_dozvedeli = forms.CharField(widget=forms.Textarea({"rows": 3, "cols": 20}), label='Jak ses o M&M dozvěděl(a)? (Nechceš-li odpovídat, napiš „nechci uvést“.)', required=True) | ||||||
| 	prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False) |  | ||||||
| 	prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) |  | ||||||
| 	pohlavi_muz = forms.ChoiceField(label='Pohlaví', |  | ||||||
| 			choices = ((True,'muž'),(False,'žena')), required=True) |  | ||||||
| 	email = forms.EmailField(label='E-mail',max_length=256, required=True) |  | ||||||
| 	telefon = forms.CharField(widget=TelInput(),label='Telefon',max_length=256, required=False) |  | ||||||
| 	datum_narozeni = forms.DateField(widget=DateInput(),label='Datum narození', required=False) |  | ||||||
| 	ulice = forms.CharField(label='Ulice', max_length=256, required=False) |  | ||||||
| 	mesto = forms.CharField(label='Město', max_length=256, required=False) |  | ||||||
| 	psc = forms.CharField(label='PSČ', max_length=32, required=False) |  | ||||||
| 	stat = forms.ChoiceField(label='Stát',  |  | ||||||
| 			choices = (('CZ', 'Česká republika'), |  | ||||||
| 				('SK', 'Slovenská republika'), |  | ||||||
| 				('other', 'Jiné')), |  | ||||||
| 			required=False) |  | ||||||
| 	stat_text = forms.CharField(label='Stát', max_length=256, required=False) |  | ||||||
| 
 | 
 | ||||||
| 	skola = forms.ModelChoiceField(label="Škola", | 	gdpr = forms.BooleanField(label='Souhlasím se zpracováním osobních údajů', required=True) | ||||||
| 		queryset=Skola.objects.all(), |  | ||||||
| 		widget=autocomplete.ModelSelect2( |  | ||||||
| 			url='autocomplete_skola', |  | ||||||
| 			attrs = {'data-placeholder--id': '-1', |  | ||||||
| 				'data-placeholder--text' : '---', |  | ||||||
| 				'data-allow-clear': 'true'}) |  | ||||||
| 			,required=False) |  | ||||||
| 	 | 	 | ||||||
| 	skola_nazev = forms.CharField(label='Název školy', max_length=256, required=False) | 	def clean_username(self): | ||||||
| 	skola_adresa = forms.CharField(label='Adresa školy', max_length=256, required=False) | 		username = self.cleaned_data.get('username') | ||||||
| 
 |  | ||||||
| #	trida = forms.CharField(label='Třída',max_length=10, required=True) |  | ||||||
| 
 |  | ||||||
| 	rok_maturity = forms.IntegerField( |  | ||||||
| 		label='Rok maturity',  |  | ||||||
| 		min_value=date.today().year,  |  | ||||||
| 		max_value=date.today().year+8, |  | ||||||
| 		required=True) |  | ||||||
| 	zasilat = forms.ChoiceField(label='Kam zasílat čísla',choices = Resitel.ZASILAT_CHOICES, required=True) |  | ||||||
| 	zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat email s upozorněním na vydání nového čísla', required=False) |  | ||||||
| 
 |  | ||||||
| 	spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False) |  | ||||||
| #	def clean_username(self): |  | ||||||
| #		err_logger = logging.getLogger('seminar.prihlaska.problem') |  | ||||||
| #		username = self.cleaned_data.get('username') |  | ||||||
| #		try: |  | ||||||
| #			User.objects.get(username=username) |  | ||||||
| #			msg = "Username {} exists".format(username) |  | ||||||
| #			err_logger.info(msg) |  | ||||||
| #			raise forms.ValidationError('Přihlašovací jméno je již použito') |  | ||||||
| # |  | ||||||
| #		except ObjectDoesNotExist: |  | ||||||
| #			pass |  | ||||||
| #		return username |  | ||||||
| # |  | ||||||
| 
 |  | ||||||
| 	def clean_prezdivka_resitele(self): |  | ||||||
| 		prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele') |  | ||||||
| 		if prezdivka_resitele == '': |  | ||||||
| 			return prezdivka_resitele |  | ||||||
| 		if Resitel.objects.filter(prezdivka_resitele=prezdivka_resitele).exclude(osoba__user__username=self.username).count() > 0: |  | ||||||
| 			raise forms.ValidationError('Přezdívka je již použita') |  | ||||||
| 		return prezdivka_resitele |  | ||||||
| 
 |  | ||||||
| 	def clean_email(self): |  | ||||||
| 		err_logger = logging.getLogger('seminar.prihlaska.problem') |  | ||||||
| 		email = self.cleaned_data.get('email') |  | ||||||
| 		try: | 		try: | ||||||
| 			Osoba.objects.exclude(user__username=self.username).get(email=email) | 			User.objects.get(username=username) | ||||||
| 			msg = "Email {} exists (in edit)".format(email) | 			msg = "Username {} exists".format(username) | ||||||
| 			err_logger.info(msg) | 			self.err_logger.info(msg) | ||||||
| 			raise forms.ValidationError('Email je již použit') | 			raise forms.ValidationError('Přihlašovací jméno je již použito') | ||||||
| 
 | 
 | ||||||
| 		except ObjectDoesNotExist: | 		except ObjectDoesNotExist: | ||||||
| 			pass | 			pass | ||||||
| 		return email | 		return username | ||||||
| 	#def clean(self): |  | ||||||
| 	#	super().clean() |  | ||||||
| 	#	 |  | ||||||
| 	#	err_logger = logging.getLogger('seminar.prihlaska.problem') |  | ||||||
| 
 | 
 | ||||||
| 	#	data = self.cleaned_data | 
 | ||||||
| 	#	if data.get('password') != data.get('password_check'): | class ProfileEditForm(UdajeForm): | ||||||
| 	#		self.add_error('password_check',forms.ValidationError('Hesla se neshodují')) | 	err_logger = logging.getLogger('seminar.edit.problem') | ||||||
| 	#	if data.get('stat') != '' and data.get('stat_text') != '': | 	username = forms.CharField( | ||||||
| 	#		self.add_error('stat',forms.ValidationError('Nelze mít vybraný stát z menu a zároven zapsaný textem')) | 		label='Přihlašovací jméno', | ||||||
| 	#	if data.get('skola') and (data.get('skola_nazev') or data.get('skola_adresa')): | 		max_length=256, | ||||||
| 	#		self.add_error('skola',forms.ValidationError('Pokud je škola v seznamu, nevypisujte ji ručně, pokud není, zrušte výběr ze seznamu (křížek vpravo)')) | 		required=False, | ||||||
| 	#	if not data.get('skola'): | 		disabled=True, | ||||||
| 	#		if data.get('skola_nazev')=='' and data.get('skola_adresa')=='': | 	) | ||||||
| 	#			self.add_error('skola',forms.ValidationError('Je nutné vyplnit školu')) |  | ||||||
| 	#		elif data.get('skola_nazev')=='': |  | ||||||
| 	#			self.add_error('skola_nazev',forms.ValidationError('Je nutné vyplnit název školy')) |  | ||||||
| 	#		elif data.get('skola_adresa')=='': |  | ||||||
| 	#			self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy')) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PoMaturiteProfileEditForm(ProfileEditForm): | class PoMaturiteProfileEditForm(ProfileEditForm): | ||||||
|  |  | ||||||
|  | @ -1,109 +1,19 @@ | ||||||
| {% extends "base.html" %} | {% extends "base.html" %} | ||||||
| {% load static %} | {% load static %} | ||||||
| 
 | 
 | ||||||
| {% block script %} |  | ||||||
|     <script src="{% static 'personalni/prihlaska.js' %}"></script> |  | ||||||
| {% endblock %} |  | ||||||
| 
 |  | ||||||
| <!-- |  | ||||||
| 
 |  | ||||||
| # pro přidání políčka do formuláře je potřeba |  | ||||||
| # - mít v modelu tu položku, kterou chci upravovat |  | ||||||
| # - přidat do views (prihlaskaView, resitelEditView) |  | ||||||
| # - přidat do forms |  | ||||||
| # - includovat do html |  | ||||||
| 
 |  | ||||||
| --> |  | ||||||
| 
 |  | ||||||
| {% block content %} | {% block content %} | ||||||
| <h1> | <h1> | ||||||
|   {% block nadpis1a %} |   {% block nadpis1a %} | ||||||
|    Změna osobních údajů |    Změna osobních údajů | ||||||
|   {% endblock %} |   {% endblock %} | ||||||
| </h1> | </h1> | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | <p><a href="{% url 'reset_password' %}">Změnit heslo</a></p> | ||||||
|  | 
 | ||||||
| <form action="{% url 'seminar_resitel_edit' %}" method="post"> | <form action="{% url 'seminar_resitel_edit' %}" method="post"> | ||||||
|  {% csrf_token %} |   {% include "personalni/udaje/udaje.html"%} | ||||||
|  {{form.non_field_errors}} |  | ||||||
| 
 |  | ||||||
| <hr> |  | ||||||
| 
 |  | ||||||
|      <h4> |  | ||||||
|       Přihlašovací údaje |  | ||||||
|      </h4> |  | ||||||
|      <table class="form"> |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.username %} |  | ||||||
|      </table> |  | ||||||
|      <p><a href="{% url 'reset_password' %}"> |  | ||||||
|         Změnit heslo |  | ||||||
|      </a></p> |  | ||||||
| 
 |  | ||||||
| <hr> |  | ||||||
| 
 |  | ||||||
|     <h4> |  | ||||||
|      Osobní údaje |  | ||||||
|     </h4> |  | ||||||
|       <table class="form"> |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.jmeno %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.prezdivka_resitele %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.prijmeni %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.pohlavi_muz%} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.email %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.telefon %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.datum_narozeni %} |  | ||||||
|      </table> |  | ||||||
| 
 |  | ||||||
|   <hr> |  | ||||||
| 
 |  | ||||||
|     <h4> |  | ||||||
|       Bydliště |  | ||||||
|     </h4> |  | ||||||
|       <table class="form"> |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.ulice %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.mesto %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.psc %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.stat %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.stat_text id="id_li_stat_text"%} |  | ||||||
|      </table> |  | ||||||
| 
 |  | ||||||
|  <hr> |  | ||||||
| 
 |  | ||||||
|     <h4> |  | ||||||
|      Škola |  | ||||||
|     </h4> |  | ||||||
|      <table class="form"> |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.skola %} |  | ||||||
|        <tr><td colspan="2" ><button id="id_skola_text_button" type="button">Škola není v seznamu</button></td></tr> |  | ||||||
|        <tr><td id="id_li_skola_vypln" colspan="2">Vyplň prosím celý název a adresu školy.</td></tr> |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.skola_nazev id="id_li_skola_nazev" %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.skola_adresa id="id_li_skola_adresa" %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.rok_maturity %} |  | ||||||
|      </table> |  | ||||||
| 
 |  | ||||||
|  <hr> |  | ||||||
| 
 |  | ||||||
|     <h4> |  | ||||||
|      Pošta |  | ||||||
|     </h4> |  | ||||||
|      <table class="form"> |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat %} |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_emailem %} |  | ||||||
|      </table> |  | ||||||
| 
 |  | ||||||
|  <hr> |  | ||||||
| 
 |  | ||||||
|     <h4> |  | ||||||
|      Zasílání propagačních materiálů |  | ||||||
|     </h4> |  | ||||||
|      <table class="form"> |  | ||||||
|        {% include "personalni/udaje/prihlaska_field.html" with field=form.spam %} |  | ||||||
|      </table> |  | ||||||
| 
 |  | ||||||
|  <hr> |  | ||||||
| 
 |  | ||||||
|   <input type="submit" value="Změnit"> |   <input type="submit" value="Změnit"> | ||||||
| </form> | </form> | ||||||
| <script> | 
 | ||||||
| $("#id_stat").on("change",addrCountryChanged); |  | ||||||
| $("#id_skola_text_button").on("click",schoolNotInList); |  | ||||||
| </script> |  | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
|  | @ -5,16 +5,6 @@ | ||||||
|     <script src="{% static 'personalni/prihlaska.js' %}"></script> |     <script src="{% static 'personalni/prihlaska.js' %}"></script> | ||||||
| {% endblock %} | {% endblock %} | ||||||
| 
 | 
 | ||||||
| <!-- |  | ||||||
| 
 |  | ||||||
| # pro přidání políčka do formuláře je potřeba |  | ||||||
| # - mít v modelu tu položku, kterou chci upravovat |  | ||||||
| # - přidat do views (prihlaskaView, resitelEditView) |  | ||||||
| # - přidat do forms |  | ||||||
| # - includovat do html |  | ||||||
| 
 |  | ||||||
| --> |  | ||||||
| 
 |  | ||||||
| {% block content %} | {% block content %} | ||||||
| <h1> | <h1> | ||||||
|   {% block nadpis1a %} |   {% block nadpis1a %} | ||||||
|  | @ -25,73 +15,7 @@ | ||||||
| <p><b>Tučně</b> popsaná pole jsou povinná.</p> | <p><b>Tučně</b> popsaná pole jsou povinná.</p> | ||||||
| 
 | 
 | ||||||
| <form action="{% url 'seminar_prihlaska' %}" method="post"> | <form action="{% url 'seminar_prihlaska' %}" method="post"> | ||||||
|   {% csrf_token %} |   {% include "personalni/udaje/udaje.html" %} | ||||||
|   {{form.non_field_errors}} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| <hr> |  | ||||||
|          <h4> |  | ||||||
|           Přihlašovací údaje |  | ||||||
|          </h4> |  | ||||||
|          <table class="form"> |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.username %} |  | ||||||
| {#           {% include "personalni/udaje/prihlaska_field.html" with field=form.password %}#} |  | ||||||
| {#           {% include "personalni/udaje/prihlaska_field.html" with field=form.password_check %}#} |  | ||||||
|          </table> |  | ||||||
| 
 |  | ||||||
| <hr> |  | ||||||
| 
 |  | ||||||
|         <h4> |  | ||||||
|          Osobní údaje |  | ||||||
|         </h4> |  | ||||||
|           <table class="form"> |  | ||||||
|             {% include "personalni/udaje/prihlaska_field.html" with field=form.jmeno %} |  | ||||||
|             {% include "personalni/udaje/prihlaska_field.html" with field=form.prezdivka_resitele %} |  | ||||||
|             {% include "personalni/udaje/prihlaska_field.html" with field=form.prijmeni %} |  | ||||||
|             {% include "personalni/udaje/prihlaska_field.html" with field=form.pohlavi_muz%} |  | ||||||
|             {% include "personalni/udaje/prihlaska_field.html" with field=form.email %} |  | ||||||
|             {% include "personalni/udaje/prihlaska_field.html" with field=form.telefon %} |  | ||||||
|             {% include "personalni/udaje/prihlaska_field.html" with field=form.datum_narozeni %} |  | ||||||
|          </table> |  | ||||||
| 
 |  | ||||||
| <hr> |  | ||||||
| 
 |  | ||||||
|         <h4> |  | ||||||
|           Bydliště |  | ||||||
|         </h4> |  | ||||||
|           <table class="form"> |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.ulice %} |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.mesto %} |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.psc %} |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.stat %} |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.stat_text id="id_li_stat_text"%} |  | ||||||
|          </table> |  | ||||||
| 
 |  | ||||||
| <hr> |  | ||||||
| 
 |  | ||||||
|         <h4> |  | ||||||
|          Škola |  | ||||||
|         </h4> |  | ||||||
|          <table class="form"> |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.skola %} |  | ||||||
|              <tr><td colspan="2" ><button id="id_skola_text_button" type="button">Škola není v seznamu</button></td><td>(Prosíme, zkuste ji najít, téměř jistě ji v seznamu máme. Školy se dobře hledají podle příjmení lidí v jejich názvu, podle ulice, případně název ulice <i>mezera</i> město, atd. Nezadávejte slova, která se často zkracují – gymnázium, střední odborná škola, křestní jména…)</td></tr> |  | ||||||
|            <tr><td id="id_li_skola_vypln" colspan="2">Vyplň prosím celý název a adresu školy.</td></tr> |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.skola_nazev id="id_li_skola_nazev" %} |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.skola_adresa id="id_li_skola_adresa" %} |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.rok_maturity %} |  | ||||||
|          </table> |  | ||||||
| 
 |  | ||||||
| <hr> |  | ||||||
| 
 |  | ||||||
|         <h4> |  | ||||||
|          Pošta |  | ||||||
|         </h4> |  | ||||||
|          <table class="form"> |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat %} |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_emailem %} |  | ||||||
|          </table> |  | ||||||
|  <hr> |  | ||||||
| 
 |  | ||||||
|   <h4> |   <h4> | ||||||
|     GDPR |     GDPR | ||||||
|   </h4> |   </h4> | ||||||
|  | @ -100,17 +24,6 @@ | ||||||
|     {% include "personalni/udaje/prihlaska_field.html" with field=form.gdpr %} |     {% include "personalni/udaje/prihlaska_field.html" with field=form.gdpr %} | ||||||
|   </table> |   </table> | ||||||
| 
 | 
 | ||||||
| <hr> |  | ||||||
| 
 |  | ||||||
|         <h4> |  | ||||||
|          Zasílání propagačních materiálů |  | ||||||
|         </h4> |  | ||||||
|          <table class="form"> |  | ||||||
|            {% include "personalni/udaje/prihlaska_field.html" with field=form.spam %} |  | ||||||
|          </table> |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   <hr> |   <hr> | ||||||
| 
 | 
 | ||||||
|   <h4> |   <h4> | ||||||
|  | @ -120,14 +33,8 @@ | ||||||
|     {% include "personalni/udaje/prihlaska_field.html" with field=form.jak_se_dozvedeli %} |     {% include "personalni/udaje/prihlaska_field.html" with field=form.jak_se_dozvedeli %} | ||||||
|   </table> |   </table> | ||||||
| 
 | 
 | ||||||
| 
 |   <hr> | ||||||
| 
 | 
 | ||||||
|   <input type="submit" value="Odeslat"> |   <input type="submit" value="Odeslat"> | ||||||
| </form> | </form> | ||||||
| <script> |  | ||||||
| $("#id_stat").on("change",addrCountryChanged); |  | ||||||
| $("#id_skola_text_button").on("click",schoolNotInList); |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
							
								
								
									
										75
									
								
								personalni/templates/personalni/udaje/udaje.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								personalni/templates/personalni/udaje/udaje.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,75 @@ | ||||||
|  | {% load static %} | ||||||
|  | 
 | ||||||
|  | {% block script %} | ||||||
|  |   <script src="{% static 'personalni/prihlaska.js' %}"></script> | ||||||
|  | {% endblock %} | ||||||
|  | 
 | ||||||
|  | {% csrf_token %} | ||||||
|  | {{form.non_field_errors}} | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | <h4> | ||||||
|  |   Přihlašovací údaje | ||||||
|  | </h4> | ||||||
|  | <table class="form"> | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.username %} | ||||||
|  | </table> | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | 
 | ||||||
|  | <h4> | ||||||
|  |   Osobní údaje | ||||||
|  | </h4> | ||||||
|  | <table class="form"> | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.jmeno %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.prezdivka_resitele %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.prijmeni %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.pohlavi_muz%} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.email %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.telefon %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.datum_narozeni %} | ||||||
|  | </table> | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | 
 | ||||||
|  | <h4> | ||||||
|  |   Škola | ||||||
|  | </h4> | ||||||
|  | <table class="form"> | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.skola %} | ||||||
|  |   <tr><td colspan="2" ><button id="id_skola_text_button" type="button">Škola není v seznamu</button></td><td>(Prosíme, zkuste ji najít, téměř jistě ji v seznamu máme. Školy se dobře hledají podle příjmení lidí v jejich názvu, podle ulice, případně název ulice <i>mezera</i> město, atd. Nezadávejte slova, která se často zkracují – gymnázium, střední odborná škola, křestní jména…)</td></tr> | ||||||
|  |   <tr><td id="id_li_skola_vypln" colspan="2">Vyplň prosím celý název a adresu školy.</td></tr> | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.skola_nazev id="id_li_skola_nazev" %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.skola_adresa id="id_li_skola_adresa" %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.rok_maturity %} | ||||||
|  | </table> | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | 
 | ||||||
|  | <h4> | ||||||
|  |   Pošta | ||||||
|  | </h4> | ||||||
|  | <table class="form"> | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_emailem %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_papirove %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.spam %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat %} | ||||||
|  | </table> | ||||||
|  | <hr> | ||||||
|  | <h4> | ||||||
|  |   Bydliště (povinné při volbě „domů“) | ||||||
|  | </h4> | ||||||
|  | <table class="form"> | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.ulice %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.mesto %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.psc %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.stat %} | ||||||
|  |   {% include "personalni/udaje/prihlaska_field.html" with field=form.stat_text id="id_li_stat_text"%} | ||||||
|  | </table> | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | 
 | ||||||
|  | <script> | ||||||
|  |   $("#id_stat").on("change",addrCountryChanged); | ||||||
|  |   $("#id_skola_text_button").on("click",schoolNotInList); | ||||||
|  | </script> | ||||||
							
								
								
									
										11
									
								
								personalni/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								personalni/utils.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | import seminar.models as m | ||||||
|  | from various.utils import bez_diakritiky_translate | ||||||
|  | import re | ||||||
|  | 
 | ||||||
|  | def normalizuj_jmeno(o: m.Osoba) -> str: | ||||||
|  | 	# FIXME: Možná není potřeba vázat na model? | ||||||
|  | 	cele_jmeno = f'{o.jmeno} {o.prijmeni}' | ||||||
|  | 	cele_jmeno = cele_jmeno.translate(bez_diakritiky_translate) | ||||||
|  | 	cele_jmeno = re.sub(r'[^a-zA-Z- ]', '', cele_jmeno) | ||||||
|  | 	return cele_jmeno | ||||||
|  | 
 | ||||||
|  | @ -165,6 +165,7 @@ def resitelEditView(request): | ||||||
| 				resitel_edit.rok_maturity = fcd['rok_maturity'] | 				resitel_edit.rok_maturity = fcd['rok_maturity'] | ||||||
| 				resitel_edit.zasilat = fcd['zasilat'] | 				resitel_edit.zasilat = fcd['zasilat'] | ||||||
| 				resitel_edit.zasilat_cislo_emailem = fcd['zasilat_cislo_emailem'] | 				resitel_edit.zasilat_cislo_emailem = fcd['zasilat_cislo_emailem'] | ||||||
|  | 				resitel_edit.zasilat_cislo_papirove = fcd['zasilat_cislo_papirove'] | ||||||
| 				if fcd.get('skola'): | 				if fcd.get('skola'): | ||||||
| 					resitel_edit.skola = fcd['skola'] | 					resitel_edit.skola = fcd['skola'] | ||||||
| 				else: | 				else: | ||||||
|  | @ -264,10 +265,11 @@ def prihlaskaView(request): | ||||||
| 					err_logger.warning(f'Zaregistrovala se osoba s kolizním jménem. ID osob: {[o.id for o in kolize]}') | 					err_logger.warning(f'Zaregistrovala se osoba s kolizním jménem. ID osob: {[o.id for o in kolize]}') | ||||||
| 
 | 
 | ||||||
| 				r = s.Resitel( | 				r = s.Resitel( | ||||||
| 					prezdivka_resitele=fcd['prezdivka_resitele'], | 					prezdivka_resitele=fcd['prezdivka_resitele'] if fcd['prezdivka_resitele'] != "" else None, | ||||||
| 					rok_maturity = fcd['rok_maturity'], | 					rok_maturity = fcd['rok_maturity'], | ||||||
| 					zasilat = fcd['zasilat'], | 					zasilat = fcd['zasilat'], | ||||||
| 					zasilat_cislo_emailem = fcd['zasilat_cislo_emailem'] | 					zasilat_cislo_emailem = fcd['zasilat_cislo_emailem'], | ||||||
|  | 					zasilat_cislo_papirove = fcd['zasilat_cislo_papirove'], | ||||||
| 					) | 					) | ||||||
| 
 | 
 | ||||||
| 				if fcd.get('skola'): | 				if fcd.get('skola'): | ||||||
|  | @ -284,7 +286,7 @@ def prihlaskaView(request): | ||||||
| 				except m.Resitel.DoesNotExist: | 				except m.Resitel.DoesNotExist: | ||||||
| 					# Stejný trik: | 					# Stejný trik: | ||||||
| 					orig_resitel = r | 					orig_resitel = r | ||||||
| 				resitel_attrs = ['skola', 'rok_maturity', 'zasilat', 'zasilat_cislo_emailem'] | 				resitel_attrs = ['skola', 'rok_maturity', 'zasilat', 'zasilat_cislo_emailem', 'zasilat_cislo_papirove'] | ||||||
| 				for attr in resitel_attrs: | 				for attr in resitel_attrs: | ||||||
| 					new = getattr(r, attr) | 					new = getattr(r, attr) | ||||||
| 					old = getattr(orig_resitel, attr) | 					old = getattr(orig_resitel, attr) | ||||||
|  | @ -345,6 +347,7 @@ def dataResiteluCsvResponse(queryset, columns=None, with_header=True): | ||||||
| 		'rok_maturity', | 		'rok_maturity', | ||||||
| 		'zasilat', | 		'zasilat', | ||||||
| 		'zasilat_cislo_emailem', | 		'zasilat_cislo_emailem', | ||||||
|  | 		'zasilat_cislo_papirove', | ||||||
| 		'osoba__datum_registrace', | 		'osoba__datum_registrace', | ||||||
| 		'osoba__datum_souhlasu_udaje', | 		'osoba__datum_souhlasu_udaje', | ||||||
| 		'osoba__datum_souhlasu_zasilani', | 		'osoba__datum_souhlasu_zasilani', | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								seminar/migrations/0112_prijemce_zasilat_cislo_emailem.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								seminar/migrations/0112_prijemce_zasilat_cislo_emailem.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | # Generated by Django 2.2.28 on 2023-04-17 18:38 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('seminar', '0111_nikam2nezasilat_papirove'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='prijemce', | ||||||
|  |             name='zasilat_cislo_emailem', | ||||||
|  |             field=models.BooleanField(default=False, help_text='True pokud chce příjemce dostávat číslo emailem', verbose_name='zasílat číslo emailem'), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										42
									
								
								seminar/migrations/0113_resitel_zasilat_cislo_papirove.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								seminar/migrations/0113_resitel_zasilat_cislo_papirove.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | # Generated by Django 2.2.28 on 2023-03-13 22:02 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | 
 | ||||||
|  | ZASILAT_DOMU = 'domu' | ||||||
|  | ZASILAT_DO_SKOLY = 'do_skoly' | ||||||
|  | ZASILAT_NIKAM = 'nikam' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def default_zasilat_papirove(apps, schema_editor): | ||||||
|  |     Resitel = apps.get_model('seminar', 'Resitel') | ||||||
|  | 
 | ||||||
|  |     for resitel in Resitel.objects.all(): | ||||||
|  |         resitel.zasilat_cislo_papirove = resitel.zasilat != ZASILAT_NIKAM | ||||||
|  |         if resitel.zasilat == ZASILAT_NIKAM: | ||||||
|  |             resitel.zasilat = ZASILAT_DOMU if resitel.osoba.ulice else ZASILAT_DO_SKOLY | ||||||
|  |         resitel.save() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def vrat_nikam(apps, schema_editor): | ||||||
|  |     Resitel = apps.get_model('seminar', 'Resitel') | ||||||
|  | 
 | ||||||
|  |     for resitel in Resitel.objects.all(): | ||||||
|  |         if not resitel.zasilat_cislo_papirove: | ||||||
|  |             resitel.zasilat = ZASILAT_NIKAM | ||||||
|  |             resitel.save() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('seminar', '0112_prijemce_zasilat_cislo_emailem'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='resitel', | ||||||
|  |             name='zasilat_cislo_papirove', | ||||||
|  |             field=models.BooleanField(default=True, help_text='True pokud chce řešitel dostávat číslo papírově', verbose_name='zasílat číslo papírově'), | ||||||
|  |         ), | ||||||
|  |         migrations.RunPython(default_zasilat_papirove, vrat_nikam), | ||||||
|  |     ] | ||||||
|  | @ -192,6 +192,8 @@ class Prijemce(SeminarModelBase): | ||||||
| 		help_text='Které osobě či na jakou adresu se mají zasílat čísla', | 		help_text='Které osobě či na jakou adresu se mají zasílat čísla', | ||||||
| 		on_delete=models.CASCADE) | 		on_delete=models.CASCADE) | ||||||
| 
 | 
 | ||||||
|  | 	zasilat_cislo_emailem = models.BooleanField('zasílat číslo emailem', help_text='True pokud chce příjemce dostávat číslo emailem', default=False) | ||||||
|  | 
 | ||||||
| 	# FIXME: možná chceme něco jako vazbu na osobu XOR školu a počet kusů k zaslání | 	# FIXME: možná chceme něco jako vazbu na osobu XOR školu a počet kusů k zaslání | ||||||
| 	# FIXME: a možná taky posílání na mail a možná taky přes něj chceme posílat i řešitelům | 	# FIXME: a možná taky posílání na mail a možná taky přes něj chceme posílat i řešitelům | ||||||
| 
 | 
 | ||||||
|  | @ -236,6 +238,8 @@ class Resitel(SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 	zasilat_cislo_emailem = models.BooleanField('zasílat číslo emailem', help_text='True pokud chce řešitel dostávat číslo emailem', default=False) | 	zasilat_cislo_emailem = models.BooleanField('zasílat číslo emailem', help_text='True pokud chce řešitel dostávat číslo emailem', default=False) | ||||||
| 
 | 
 | ||||||
|  | 	zasilat_cislo_papirove = models.BooleanField('zasílat číslo papírově', help_text='True pokud chce řešitel dostávat číslo papírově', default=True) | ||||||
|  | 
 | ||||||
| 	poznamka = models.TextField('neveřejná poznámka', blank=True, | 	poznamka = models.TextField('neveřejná poznámka', blank=True, | ||||||
| 		help_text='Neveřejná poznámka k řešiteli (plain text)') | 		help_text='Neveřejná poznámka k řešiteli (plain text)') | ||||||
| 
 | 
 | ||||||
|  | @ -402,6 +406,7 @@ class Organizator(SeminarModelBase): | ||||||
| 		editable=False | 		editable=False | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
|  | 	# Ne, date to nebude. SQLite: invalid literal for int() with base 10: b'17 23:00:00' | ||||||
| 	organizuje_od = models.DateTimeField('Organizuje od', blank=True, null=True) | 	organizuje_od = models.DateTimeField('Organizuje od', blank=True, null=True) | ||||||
| 	 | 	 | ||||||
| 	organizuje_do = models.DateTimeField('Organizuje do', blank=True, null=True) | 	organizuje_do = models.DateTimeField('Organizuje do', blank=True, null=True) | ||||||
|  |  | ||||||
|  | @ -265,6 +265,7 @@ class Cislo(SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 		poslat_z_mailu = 'zadani@mam.mff.cuni.cz' | 		poslat_z_mailu = 'zadani@mam.mff.cuni.cz' | ||||||
| 		predmet = 'Vyšlo číslo {}'.format(self.kod()) | 		predmet = 'Vyšlo číslo {}'.format(self.kod()) | ||||||
|  | 		# TODO Možná nechceme všem psát „Ahoj“, např. příjemcům… | ||||||
| 		text_mailu = 'Ahoj,\n' \ | 		text_mailu = 'Ahoj,\n' \ | ||||||
| 			   'na adrese {} najdete nejnovější číslo.\n' \ | 			   'na adrese {} najdete nejnovější číslo.\n' \ | ||||||
| 			   'Vaše M&M\n'.format(odkaz) | 			   'Vaše M&M\n'.format(odkaz) | ||||||
|  | @ -288,9 +289,14 @@ class Cislo(SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 			email.send() | 			email.send() | ||||||
| 
 | 
 | ||||||
| 		posli(text_mailu, resitele_vsichni.filter(zasilat=pm.Resitel.ZASILAT_NIKAM)) | 		paticka = "---\nK odběru těchto e-mailů jste se přihlásili na stránkách https://mam.matfyz.cz. Z odběru se lze odhlásit na https://mam.matfyz.cz/resitel/osobni-udaje/" | ||||||
| 		posli(text_mailu + 'P. S. Také by vám brzy měla přijít papírová verze. Připomínáme, že pokud papírovou verzi čísla nevyužijete, můžete v https://mam.mff.cuni.cz/resitel/osobni-udaje/ zaškrtnout, abychom vám ji neposílali. Děkujeme. (Čísla vždy můžete nalézt v našem archivu a dál vám budou chodit e-mailem.)\n', | 
 | ||||||
| 			  resitele_vsichni.exclude(zasilat=pm.Resitel.ZASILAT_NIKAM)) | 		posli(text_mailu + paticka, resitele_vsichni.filter(zasilat=pm.Resitel.zasilat_cislo_papirove)) | ||||||
|  | 		posli(text_mailu + 'P. S. Brzy budeme též rozesílat papírovou verzi čísla. Připomínáme, že pokud papírovou verzi čísla nevyužijete, můžete v https://mam.mff.cuni.cz/resitel/osobni-udaje/ zaškrtnout, abychom vám ji neposílali. Čísla vždy můžete nalézt v našem archivu a dál vám budou chodit e-mailem. Děkujeme.\n' + paticka, | ||||||
|  | 			  resitele_vsichni.exclude(zasilat=pm.Resitel.zasilat_cislo_papirove)) | ||||||
|  | 
 | ||||||
|  | 		paticka_prijemce = "---\nPokud tyto e-maily nechcete nadále dostávat, prosíme, ozvěte se nám na mam@matfyz.cz." | ||||||
|  | 		posli(text_mailu + paticka_prijemce, pm.Prijemce.objects.filter(zasilat_cislo_emailem=True)) | ||||||
| 
 | 
 | ||||||
| 	def save(self, *args, **kwargs): | 	def save(self, *args, **kwargs): | ||||||
| 		super().save(*args, **kwargs) | 		super().save(*args, **kwargs) | ||||||
|  |  | ||||||
|  | @ -100,6 +100,7 @@ | ||||||
| 	{% with o=r.osoba %} | 	{% with o=r.osoba %} | ||||||
| 	{% with s=r.skola %} | 	{% with s=r.skola %} | ||||||
| 	{% spaceless %} | 	{% spaceless %} | ||||||
|  | 	{% if r.zasilat_cislo_papirove %} | ||||||
| 	{% if r.zasilat == "do_skoly" %}  | 	{% if r.zasilat == "do_skoly" %}  | ||||||
| 		{% if o.stat == "CZ" %} | 		{% if o.stat == "CZ" %} | ||||||
| \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{s.nazev|sloz}}{{s.ulice|sloz}}{{s.psc|sloz}}{{s.mesto|sloz}}{{''|sloz}} | \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{s.nazev|sloz}}{{s.ulice|sloz}}{{s.psc|sloz}}{{s.mesto|sloz}}{{''|sloz}} | ||||||
|  | @ -115,6 +116,7 @@ | ||||||
| 		{% endif %} | 		{% endif %} | ||||||
| 	{% else %} | 	{% else %} | ||||||
| 	{% endif %} | 	{% endif %} | ||||||
|  | 	{% endif %} | ||||||
| 	{% endspaceless %} | 	{% endspaceless %} | ||||||
| 	{% endwith %} | 	{% endwith %} | ||||||
| 	{% endwith %} | 	{% endwith %} | ||||||
|  |  | ||||||
|  | @ -265,7 +265,7 @@ def merge_resitele(cilovy, zdrojovy): | ||||||
| 	# Postup: | 	# Postup: | ||||||
| 	# Sjednotit / upravit informace cílového řešitele | 	# Sjednotit / upravit informace cílového řešitele | ||||||
| 	print('Upravuji data modelu') | 	print('Upravuji data modelu') | ||||||
| 	fieldy_shoda = ['skola', 'rok_maturity', 'zasilat', 'zasilat_cislo_emailem'] | 	fieldy_shoda = ['skola', 'rok_maturity', 'zasilat', 'zasilat_cislo_emailem', 'zasilat_cislo_papirove'] | ||||||
| 	 | 	 | ||||||
| 	for f in fieldy_shoda: | 	for f in fieldy_shoda: | ||||||
| 		zf = getattr(zdrojovy, f) | 		zf = getattr(zdrojovy, f) | ||||||
|  |  | ||||||
|  | @ -7,6 +7,11 @@ Used to distinguish testing emails from production ones.""" | ||||||
| from django.core.mail.backends.smtp import EmailBackend as DjangoSMTPBackend | from django.core.mail.backends.smtp import EmailBackend as DjangoSMTPBackend | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| 
 | 
 | ||||||
|  | def omezovatko_poctu_mailu(maily:list, maximum:int) -> str: | ||||||
|  | 	if len(maily) <= maximum: return str(maily) | ||||||
|  | 	# Aspoň zhruba simulujeme tisk pole… | ||||||
|  | 	return '[' + ", ".join(f"'{mail}'" for mail in maily[:maximum - 1]) + f', … ({len(maily)} e-mailů) ]' | ||||||
|  | 
 | ||||||
| class PrefixingMailBackend(DjangoSMTPBackend): | class PrefixingMailBackend(DjangoSMTPBackend): | ||||||
| 	# method _send is not probably meant to be monkey_patched, so we patch send_messages instead. | 	# method _send is not probably meant to be monkey_patched, so we patch send_messages instead. | ||||||
| 	def send_messages(self, messages): | 	def send_messages(self, messages): | ||||||
|  | @ -16,10 +21,13 @@ class PrefixingMailBackend(DjangoSMTPBackend): | ||||||
| 
 | 
 | ||||||
| 			if message.from_email != settings.SERVER_EMAIL: | 			if message.from_email != settings.SERVER_EMAIL: | ||||||
| 				message.subject = prefix + ' ' + message.subject | 				message.subject = prefix + ' ' + message.subject | ||||||
|  | 				to = omezovatko_poctu_mailu(message.to, 3) | ||||||
|  | 				cc = omezovatko_poctu_mailu(message.cc, 3) | ||||||
|  | 				bcc = omezovatko_poctu_mailu(message.bcc, 3) | ||||||
| 				message.body = f"""Bylo by posláno na e-maily: | 				message.body = f"""Bylo by posláno na e-maily: | ||||||
| 	To: {message.to} | 	To: {to} | ||||||
| 	Cc: {message.cc} | 	Cc: {cc} | ||||||
| 	Bcc: {message.bcc} | 	Bcc: {bcc} | ||||||
| """+ "\n\n" + message.body | """+ "\n\n" + message.body | ||||||
| 				message.to = settings.TESTOVACI_EMAILOVA_KONFERENCE | 				message.to = settings.TESTOVACI_EMAILOVA_KONFERENCE | ||||||
| 				message.cc = [] | 				message.cc = [] | ||||||
|  |  | ||||||
							
								
								
									
										33
									
								
								various/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								various/utils.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | ||||||
|  | bez_diakritiky = ({} | ||||||
|  | 	# FIXME: funguje jen pro český a slovenský text, jinak jsou špatně | ||||||
|  | 	# transliterace. Potenciální řešení: | ||||||
|  | 	# https://stackoverflow.com/questions/517923/what-is-the-best-way-to-remove-accents-normalize-in-a-python-unicode-string | ||||||
|  | 	# (ale přidává to další závislosti…) | ||||||
|  | 
 | ||||||
|  | 	# Tisknutelné ASCII | ||||||
|  | 	| {chr(a): chr(a) for a in range(32, 126+1)} | ||||||
|  | 	 | ||||||
|  | 	# České, slovenské a blízké diakritiky a divnoznaky | ||||||
|  | 	| { x: 'a' for x in 'áÁäÄ'} | ||||||
|  | 	| { x: 'c' for x in 'čČ'} | ||||||
|  | 	| { x: 'd' for x in 'ďĎ'} | ||||||
|  | 	| { x: 'e' for x in 'éÉěĚëË'} | ||||||
|  | 	| { x: 'i' for x in 'íÍ'} | ||||||
|  | 	| { x: 'l' for x in 'ľĽĺĹ'} | ||||||
|  | 	| { x: 'n' for x in 'ňŇ'} | ||||||
|  | 	| { x: 'o' for x in 'óÓöÖôÔ'} | ||||||
|  | 	| { x: 'r' for x in 'řŘŕŔ'} | ||||||
|  | 	| { x: 's' for x in 'šŠßẞ'} | ||||||
|  | 	| { x: 't' for x in 'ťŤ'} | ||||||
|  | 	| { x: 'u' for x in 'úÚůŮ'} | ||||||
|  | 	| { x: 'y' for x in 'ýÝ'} | ||||||
|  | 	| { x: 'z' for x in 'žŽ'} | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | # Tabulka pro str.translate | ||||||
|  | class _bez_diakritiky_translate: | ||||||
|  | 	def __getitem__(self, it): | ||||||
|  | 		return ord(bez_diakritiky.get(chr(it), None)) | ||||||
|  | bez_diakritiky_translate = _bez_diakritiky_translate() | ||||||
|  | 
 | ||||||
|  | # TODO: testy? | ||||||
		Loading…
	
		Reference in a new issue