Merge branch 'data_migrations' into test
This commit is contained in:
		
						commit
						f7a234b0c6
					
				
					 18 changed files with 323 additions and 250 deletions
				
			
		|  | @ -334,7 +334,7 @@ | ||||||
| 			"inmenu": true, | 			"inmenu": true, | ||||||
| 			"insitetree": true, | 			"insitetree": true, | ||||||
| 			"parent": 3, | 			"parent": 3, | ||||||
| 			"sort_order": 33, | 			"sort_order": 43, | ||||||
| 			"title": "Výsledková listina", | 			"title": "Výsledková listina", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_aktualni_vysledky", | 			"url": "seminar_aktualni_vysledky", | ||||||
|  | @ -695,13 +695,13 @@ | ||||||
| 			"alias": null, | 			"alias": null, | ||||||
| 			"description": "", | 			"description": "", | ||||||
| 			"hidden": false, | 			"hidden": false, | ||||||
| 			"hint": "To, co ŘEŠITELÉ poslali", | 			"hint": "", | ||||||
| 			"inbreadcrumbs": true, | 			"inbreadcrumbs": true, | ||||||
| 			"inmenu": true, | 			"inmenu": true, | ||||||
| 			"insitetree": true, | 			"insitetree": true, | ||||||
| 			"parent": 21, | 			"parent": 21, | ||||||
| 			"sort_order": 38, | 			"sort_order": 37, | ||||||
| 			"title": "Došlá řešení", | 			"title": "Odevzdaná řešení", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "odevzdavatko_tabulka", | 			"url": "odevzdavatko_tabulka", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
|  | @ -724,7 +724,7 @@ | ||||||
| 			"inmenu": true, | 			"inmenu": true, | ||||||
| 			"insitetree": true, | 			"insitetree": true, | ||||||
| 			"parent": 21, | 			"parent": 21, | ||||||
| 			"sort_order": 42, | 			"sort_order": 38, | ||||||
| 			"title": "Odhlásit se", | 			"title": "Odhlásit se", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "logout", | 			"url": "logout", | ||||||
|  | @ -832,5 +832,29 @@ | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
| 		"pk": 42 | 		"pk": 42 | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"fields": { | ||||||
|  | 			"access_guest": false, | ||||||
|  | 			"access_loggedin": false, | ||||||
|  | 			"access_perm_type": 1, | ||||||
|  | 			"access_permissions": [], | ||||||
|  | 			"access_restricted": false, | ||||||
|  | 			"alias": null, | ||||||
|  | 			"description": "", | ||||||
|  | 			"hidden": false, | ||||||
|  | 			"hint": "", | ||||||
|  | 			"inbreadcrumbs": true, | ||||||
|  | 			"inmenu": true, | ||||||
|  | 			"insitetree": true, | ||||||
|  | 			"parent": 3, | ||||||
|  | 			"sort_order": 33, | ||||||
|  | 			"title": "Aktuální ročník", | ||||||
|  | 			"tree": 1, | ||||||
|  | 			"url": "seminar_aktualni_rocnik", | ||||||
|  | 			"urlaspattern": true | ||||||
|  | 		}, | ||||||
|  | 		"model": "sitetree.treeitem", | ||||||
|  | 		"pk": 43 | ||||||
| 	} | 	} | ||||||
| ] | ] | ||||||
|  | @ -44,6 +44,7 @@ STATICFILES_FINDERS = ( | ||||||
| 
 | 
 | ||||||
| # Where redirect for login required services | # Where redirect for login required services | ||||||
| LOGIN_URL = 'login' | LOGIN_URL = 'login' | ||||||
|  | LOGIN_REDIRECT_URL = 'profil' | ||||||
| 
 | 
 | ||||||
| # Modules configuration | # Modules configuration | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1149,11 +1149,13 @@ div.gdpr { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* tabulka odevzdaných řešení */ | /* tabulka odevzdaných řešení */ | ||||||
| .dosla_reseni tr th { |  | ||||||
| 	text-align: center; |  | ||||||
| } |  | ||||||
| .dosla_reseni tr th, .dosla_reseni tr td { | .dosla_reseni tr th, .dosla_reseni tr td { | ||||||
| 	border: 1px solid black; | 	border: 1px solid black; | ||||||
| 	padding: 1px 10px 1px 10px; | 	padding: 1px 10px 1px 10px; | ||||||
| 	border-collapse: collapse; | 	border-collapse: collapse; | ||||||
|  | 	text-align: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .dosla_reseni tr td#problem { | ||||||
|  | 	text-align: left; | ||||||
| } | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								mamweb/static/images/MSMT_logo_bez_textu_black.eps
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mamweb/static/images/MSMT_logo_bez_textu_black.eps
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB | 
|  | @ -409,7 +409,7 @@ | ||||||
|       </g> |       </g> | ||||||
|     </a> |     </a> | ||||||
|     <a |     <a | ||||||
|        href="/aktualni/temata/" |        href="/aktualni/zadani/" | ||||||
|        id="temata" |        id="temata" | ||||||
|        transform="matrix(0.70138313,0,0,0.7462289,-192.38886,20.298351)"> |        transform="matrix(0.70138313,0,0,0.7462289,-192.38886,20.298351)"> | ||||||
|       <g |       <g | ||||||
|  | @ -439,7 +439,7 @@ | ||||||
|       </g> |       </g> | ||||||
|     </a> |     </a> | ||||||
|     <a |     <a | ||||||
|        href="/aktualni/temata/" |        href="/aktualni/zadani/" | ||||||
|        id="a74" |        id="a74" | ||||||
|        transform="matrix(0.70138313,0,0,0.7462289,-192.38886,20.298351)"> |        transform="matrix(0.70138313,0,0,0.7462289,-192.38886,20.298351)"> | ||||||
|       <g |       <g | ||||||
|  | @ -469,7 +469,7 @@ | ||||||
|       </g> |       </g> | ||||||
|     </a> |     </a> | ||||||
|     <a |     <a | ||||||
|        href="/aktualni/temata/" |        href="/aktualni/zadani/" | ||||||
|        id="a80" |        id="a80" | ||||||
|        transform="matrix(0.70138313,0,0,0.7462289,-192.38886,20.298351)"> |        transform="matrix(0.70138313,0,0,0.7462289,-192.38886,20.298351)"> | ||||||
|       <g |       <g | ||||||
|  | @ -499,7 +499,7 @@ | ||||||
|       </g> |       </g> | ||||||
|     </a> |     </a> | ||||||
|     <a |     <a | ||||||
|        href="/aktualni/temata/" |        href="/aktualni/zadani/" | ||||||
|        id="a86" |        id="a86" | ||||||
|        transform="matrix(0.70138313,0,0,0.7462289,-192.38886,20.298351)"> |        transform="matrix(0.70138313,0,0,0.7462289,-192.38886,20.298351)"> | ||||||
|       <g |       <g | ||||||
|  |  | ||||||
| Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB | 
|  | @ -9,6 +9,7 @@ from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni | ||||||
| #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | ||||||
| from .ovvpfile import OvvpFile | from .ovvpfile import OvvpFile | ||||||
| from seminar import views | from seminar import views | ||||||
|  | from seminar.views import vysledkovka | ||||||
| from seminar.utils import aktivniResitele | from seminar.utils import aktivniResitele | ||||||
| 
 | 
 | ||||||
| class ExportIndexView(generic.View): | class ExportIndexView(generic.View): | ||||||
|  | @ -78,8 +79,8 @@ class ExportRocnikView(generic.View): | ||||||
| 		rocnik = get_object_or_404(Rocnik, prvni_rok=pr, exportovat=True) | 		rocnik = get_object_or_404(Rocnik, prvni_rok=pr, exportovat=True) | ||||||
| 		cislo = rocnik.posledni_zverejnena_vysledkovka_cislo() | 		cislo = rocnik.posledni_zverejnena_vysledkovka_cislo() | ||||||
| 		resitele = aktivniResitele(cislo, True) | 		resitele = aktivniResitele(cislo, True) | ||||||
| 		slovnik_body = views.secti_body_za_rocnik(cislo, resitele) | 		slovnik_body = vysledkovka.secti_body_za_rocnik(cislo, resitele, False) | ||||||
| 		_, setrizeni_resitele, setrizene_body = views.setrid_resitele_a_body(slovnik_body) | 		_, setrizeni_resitele, body = vysledkovka.setrid_resitele_a_body(slovnik_body) | ||||||
| 
 | 
 | ||||||
| 		of = default_ovvpfile('MaM.rocnik', rocnik) | 		of = default_ovvpfile('MaM.rocnik', rocnik) | ||||||
| 		of.headers['comment'] = u'MaM-Web export aktivnich resitelu rocniku {rocnik} do cisla {cislo}'.format(rocnik=rocnik, cislo=cislo) | 		of.headers['comment'] = u'MaM-Web export aktivnich resitelu rocniku {rocnik} do cisla {cislo}'.format(rocnik=rocnik, cislo=cislo) | ||||||
|  |  | ||||||
|  | @ -142,28 +142,6 @@ class PrihlaskaForm(forms.Form): | ||||||
| 			elif data.get('skola_adresa')=='': | 			elif data.get('skola_adresa')=='': | ||||||
| 				self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy')) | 				self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy')) | ||||||
| 
 | 
 | ||||||
| # Editační formulář bez řešitele. |  | ||||||
| class ProfileEditFormPoMaturite(forms.Form): |  | ||||||
| 	username = forms.CharField(label='Přihlašovací jméno', |  | ||||||
| 			max_length=256, |  | ||||||
| 			required=True) |  | ||||||
| 
 |  | ||||||
| 	jmeno = forms.CharField(label='Jméno', max_length=256, required=True) |  | ||||||
| 	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) |  | ||||||
| 
 | 
 | ||||||
| class ProfileEditForm(forms.Form): | class ProfileEditForm(forms.Form): | ||||||
| 	username = forms.CharField(label='Přihlašovací jméno',  | 	username = forms.CharField(label='Přihlašovací jméno',  | ||||||
|  | @ -203,7 +181,7 @@ class ProfileEditForm(forms.Form): | ||||||
| 
 | 
 | ||||||
| 	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 a řešení',choices = Resitel.ZASILAT_CHOICES, required=True) | 	zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True) | ||||||
|  | @ -255,6 +233,11 @@ class ProfileEditForm(forms.Form): | ||||||
| 	#		elif data.get('skola_adresa')=='': | 	#		elif data.get('skola_adresa')=='': | ||||||
| 	#			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 PoMaturiteProfileEditForm(ProfileEditForm): | ||||||
|  | 	rok_maturity = forms.IntegerField( | ||||||
|  | 		label='Rok maturity', | ||||||
|  | 		required=True) | ||||||
|  | 
 | ||||||
| class VlozReseniForm(forms.Form): | class VlozReseniForm(forms.Form): | ||||||
| 	#FIXME jen podproblémy daného problému | 	#FIXME jen podproblémy daného problému | ||||||
| 	problem = forms.ModelChoiceField(label='Problém',queryset=m.Problem.objects.all()) | 	problem = forms.ModelChoiceField(label='Problém',queryset=m.Problem.objects.all()) | ||||||
|  | @ -284,16 +267,16 @@ class VlozReseniForm(forms.Form): | ||||||
| 	#forma = models.CharField('forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False, | 	#forma = models.CharField('forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False, | ||||||
| 	#	 default=FORMA_EMAIL) | 	#	 default=FORMA_EMAIL) | ||||||
| 
 | 
 | ||||||
| 	poznamka = forms.CharField(label='Neveřejná poznámka')	 | 	poznamka = forms.CharField(label='Neveřejná poznámka', required=False) | ||||||
| 	#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šení (plain text)') | 	#	help_text='Neveřejná poznámka k řešení (plain text)') | ||||||
| 
 | 
 | ||||||
| 	#TODO body do cisla | 	#TODO body do cisla | ||||||
| 	#TODO prilohy | 	#TODO prilohy | ||||||
| 
 | 
 | ||||||
| 	def __init__(self, *args, **kwargs): | 	##def __init__(self, *args, **kwargs): | ||||||
| 		super().__init__(*args, **kwargs) | 	##	super().__init__(*args, **kwargs) | ||||||
| 		#self.fields['favorite_color'] = forms.ChoiceField(choices=[(color.id, color.name) for color in Resitel.objects.all()]) | 	##	#self.fields['favorite_color'] = forms.ChoiceField(choices=[(color.id, color.name) for color in Resitel.objects.all()]) | ||||||
| 
 | 
 | ||||||
| class NahrajReseniForm(forms.ModelForm): | class NahrajReseniForm(forms.ModelForm): | ||||||
| 	class Meta: | 	class Meta: | ||||||
|  |  | ||||||
|  | @ -525,17 +525,17 @@ class Cislo(SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 	datum_vydani = models.DateField('datum vydání', blank=True, null=True, | 	datum_vydani = models.DateField('datum vydání', blank=True, null=True, | ||||||
| 		help_text='Datum vydání finální verze') | 		help_text='Datum vydání finální verze') | ||||||
| 
 |   | ||||||
| 	datum_deadline = models.DateField('datum deadline', blank=True, null=True, |  | ||||||
| 		help_text='Datum pro příjem řešení úloh zadaných v tomto čísle') |  | ||||||
| 
 |  | ||||||
| 	datum_preddeadline = models.DateField('datum předdeadline', blank=True, null=True, |  | ||||||
| 		help_text='Datum pro příjem řešení, která se otisknou v dalším čísle') |  | ||||||
| 
 |  | ||||||
| 	datum_deadline_soustredeni = models.DateField( | 	datum_deadline_soustredeni = models.DateField( | ||||||
| 		'datum deadline soustředění', | 		'datum deadline soustředění', | ||||||
| 		blank=True, null=True, | 		blank=True, null=True, | ||||||
| 		help_text='Datum pro příjem řešení pro účast na soustředění') | 		help_text='Datum pro příjem řešení pro účast na soustředění') | ||||||
|  |   | ||||||
|  | 	datum_preddeadline = models.DateField('datum předdeadline', blank=True, null=True, | ||||||
|  | 		help_text='Datum pro příjem řešení, která se otisknou v dalším čísle') | ||||||
|  | 
 | ||||||
|  | 	datum_deadline = models.DateField('datum deadline', blank=True, null=True, | ||||||
|  | 		help_text='Datum pro příjem řešení úloh zadaných v tomto čísle') | ||||||
| 
 | 
 | ||||||
| 	verejne_db = models.BooleanField('číslo zveřejněno', | 	verejne_db = models.BooleanField('číslo zveřejněno', | ||||||
| 		db_column='verejne', default=False) | 		db_column='verejne', default=False) | ||||||
|  |  | ||||||
|  | @ -3,6 +3,15 @@ | ||||||
| {% load deadliny %} | {% load deadliny %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block content %} | ||||||
|  | <h3>Označení deadlinů</h3> | ||||||
|  | <ul> | ||||||
|  | 	<li>Ⓢ deadline pro účast na soustředění</li> | ||||||
|  | 	<li>♲ 1. deadline</li> | ||||||
|  | 	<li>✓ 2. deadline</li> | ||||||
|  | </ul> | ||||||
|  | 
 | ||||||
|  | <br> | ||||||
|  | 
 | ||||||
| {% for rocnik, hodnoceni in podle_rocniku %} | {% for rocnik, hodnoceni in podle_rocniku %} | ||||||
| <h1>Ročník {{ rocnik }}</h1> | <h1>Ročník {{ rocnik }}</h1> | ||||||
| <table class="dosla_reseni"> | <table class="dosla_reseni"> | ||||||
|  | @ -14,12 +23,15 @@ | ||||||
| 	</tr> | 	</tr> | ||||||
| 	{% for hodn in hodnoceni %} | 	{% for hodn in hodnoceni %} | ||||||
| 	<tr> | 	<tr> | ||||||
| 		<td>{{ hodn.reseni.cas_doruceni }}</td> | 		<td>{{ hodn.reseni.cas_doruceni | date:"d.m.Y H:i"}}</td> | ||||||
| 		<td>{{ hodn.problem }}</td> | 		<td id="problem"><span title="{{ hodn.problem.nazev }}">{{ hodn.problem.nazev | zkrat_nazev_problemu }}</span></td> | ||||||
| 		<td>{{ hodn.body|default_if_none:"---" }}</td> | 		<td>{{ hodn.body|default_if_none:"---" }}</td> | ||||||
| 		<td>{{ hodn.reseni.cas_doruceni | deadline_html }}</td> | 		<td>{{ hodn.reseni.cas_doruceni | deadline_html }}</td> | ||||||
| 	</tr> | 	</tr> | ||||||
| 	{% endfor %} | 	{% endfor %} | ||||||
| </table> | </table> | ||||||
|  | 
 | ||||||
|  | <br> | ||||||
|  | 
 | ||||||
| {% endfor %} | {% endfor %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
|  | @ -61,7 +61,6 @@ | ||||||
|        {% include "seminar/profil/prihlaska_field.html" with field=form.stat_text id="id_li_stat_text"%} |        {% include "seminar/profil/prihlaska_field.html" with field=form.stat_text id="id_li_stat_text"%} | ||||||
|      </table> |      </table> | ||||||
| 
 | 
 | ||||||
| {% if not po_maturite %} {# Vysloužilým účastníkům skrýt editaci školy apod. #} |  | ||||||
|  <hr> |  <hr> | ||||||
| 
 | 
 | ||||||
|     <h4> |     <h4> | ||||||
|  | @ -96,7 +95,6 @@ | ||||||
|      </table> |      </table> | ||||||
| 
 | 
 | ||||||
|  <hr> |  <hr> | ||||||
| {% endif %} |  | ||||||
| 
 | 
 | ||||||
|     <input type="submit" value="Změnit"> |     <input type="submit" value="Změnit"> | ||||||
| </form> | </form> | ||||||
|  |  | ||||||
|  | @ -8,6 +8,10 @@ | ||||||
|     Přihlášení |     Přihlášení | ||||||
|   {% endblock %}{% endblock %} |   {% endblock %}{% endblock %} | ||||||
| </h1> | </h1> | ||||||
|  | {# Obšlehnuto z Admina :-) #} | ||||||
|  | {% if user.is_authenticated %} | ||||||
|  | <p>K této stránce nejspíš nemáte přístup. Můžete se zkusit přihlásit jako uživatel, který přístup má.</p> | ||||||
|  | {% endif %} | ||||||
| <form action="{% url 'login' %}" method="post"> | <form action="{% url 'login' %}" method="post"> | ||||||
|   {% csrf_token %} |   {% csrf_token %} | ||||||
|   <table class="form"> |   <table class="form"> | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ register = template.Library() | ||||||
| 
 | 
 | ||||||
| @register.filter(name='deadline') | @register.filter(name='deadline') | ||||||
| def deadline_text(datum): | def deadline_text(datum): | ||||||
|  | 	if deadline(datum) is None: | ||||||
|  | 		return 'Neznámý deadline' | ||||||
| 	typ, cislo, dl = deadline(datum) | 	typ, cislo, dl = deadline(datum) | ||||||
| 	strings = { | 	strings = { | ||||||
| 		TypDeadline.PredDeadline: f"1. deadline čísla {cislo} ({dl})", | 		TypDeadline.PredDeadline: f"1. deadline čísla {cislo} ({dl})", | ||||||
|  | @ -15,16 +17,20 @@ def deadline_text(datum): | ||||||
| 
 | 
 | ||||||
| @register.filter(name='deadline_kratseji') | @register.filter(name='deadline_kratseji') | ||||||
| def deadline_kratsi_text(datum): | def deadline_kratsi_text(datum): | ||||||
|  | 	if deadline(datum) is None: | ||||||
|  | 		return 'NONE' | ||||||
| 	typ, cislo, dl = deadline(datum) | 	typ, cislo, dl = deadline(datum) | ||||||
| 	strings = { | 	strings = { | ||||||
| 		TypDeadline.PredDeadline: f"1. deadline {cislo}", | 		TypDeadline.PredDeadline: f"{cislo} ♲", | ||||||
| 		TypDeadline.SousDeadline: f"Soustřeďkový deadline {cislo}", | 		TypDeadline.SousDeadline: f"{cislo} Ⓢ", | ||||||
| 		TypDeadline.FinalDeadline: f"Finální deadline {cislo}", | 		TypDeadline.FinalDeadline: f"{cislo} ✓", | ||||||
| 		} | 		} | ||||||
| 	return strings[typ] | 	return strings[typ] | ||||||
| 
 | 
 | ||||||
| @register.filter(name='deadline_html') | @register.filter(name='deadline_html') | ||||||
| def deadline_html(datum): | def deadline_html(datum): | ||||||
|  | 	if deadline(datum) is None: | ||||||
|  | 		return 'Neznámý deadline' | ||||||
| 	typ, _, _ = deadline(datum) | 	typ, _, _ = deadline(datum) | ||||||
| 	text = deadline_kratsi_text(datum) | 	text = deadline_kratsi_text(datum) | ||||||
| 	classes = { | 	classes = { | ||||||
|  | @ -33,3 +39,12 @@ def deadline_html(datum): | ||||||
| 		TypDeadline.FinalDeadline: 'final_deadline', | 		TypDeadline.FinalDeadline: 'final_deadline', | ||||||
| 		} | 		} | ||||||
| 	return mark_safe(f'<span class="{classes[typ]}">{text}</span>') | 	return mark_safe(f'<span class="{classes[typ]}">{text}</span>') | ||||||
|  | 
 | ||||||
|  | @register.filter(name='zkrat_nazev_problemu') | ||||||
|  | def zkrat_nazev_problemu(nazev): | ||||||
|  | 	if len(nazev) > 10: | ||||||
|  | 		if nazev[9] == " ": | ||||||
|  | 			nazev = nazev[:9] + "..." | ||||||
|  | 		else: | ||||||
|  | 			nazev = nazev[:10] + "..." | ||||||
|  | 	return nazev | ||||||
|  |  | ||||||
|  | @ -144,3 +144,6 @@ class DeadlineTestCase(TestCase): | ||||||
| 	def test_deadline_pro_datetime(self): | 	def test_deadline_pro_datetime(self): | ||||||
| 		"""Testuje, že i pro datetime dostáváme správné deadliny""" | 		"""Testuje, že i pro datetime dostáváme správné deadliny""" | ||||||
| 		self.skipTest('Chybí implementace testu') | 		self.skipTest('Chybí implementace testu') | ||||||
|  | 
 | ||||||
|  | 	def test_moc_pozdni_deadline(self): | ||||||
|  | 		self.assertIsNone(deadline(date.max)) | ||||||
|  |  | ||||||
|  | @ -61,6 +61,7 @@ urlpatterns = [ | ||||||
| 	path('aktualni/zadani/', views.AktualniZadaniView, name='seminar_aktualni_zadani'), | 	path('aktualni/zadani/', views.AktualniZadaniView, name='seminar_aktualni_zadani'), | ||||||
| 	#path('aktualni/temata/', views.ZadaniTemataView, name='seminar_temata'), | 	#path('aktualni/temata/', views.ZadaniTemataView, name='seminar_temata'), | ||||||
| 	path('aktualni/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_aktualni_vysledky'), | 	path('aktualni/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_aktualni_vysledky'), | ||||||
|  | 	path('aktualni/rocnik/', views.AktualniRocnikRedirectView.as_view(), name='seminar_aktualni_rocnik'), | ||||||
| 	path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'), | 	path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'), | ||||||
| 
 | 
 | ||||||
| 	# Clanky | 	# Clanky | ||||||
|  | @ -133,7 +134,9 @@ urlpatterns = [ | ||||||
| 
 | 
 | ||||||
| 	path('prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), | 	path('prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), | ||||||
| 	path('prihlasit/', views.LoginView.as_view(), name='login'), | 	path('prihlasit/', views.LoginView.as_view(), name='login'), | ||||||
|  | 	path('login/', RedirectView.as_view(pattern_name='login', permanent=True, query_string=True)), | ||||||
| 	path('odhlasit/', views.LogoutView.as_view(), name='logout'), | 	path('odhlasit/', views.LogoutView.as_view(), name='logout'), | ||||||
|  | 	path('logout/', RedirectView.as_view(pattern_name='login', permanent=True, query_string=True)), | ||||||
| 	path('resitel/', resitel_required(views.ResitelView.as_view()), name='seminar_resitel'), | 	path('resitel/', resitel_required(views.ResitelView.as_view()), name='seminar_resitel'), | ||||||
| 	path('resitel/odevzdana_reseni/', resitel_required(views.PrehledOdevzdanychReseni.as_view()), name='seminar_resitel_odevzdana_reseni'), | 	path('resitel/odevzdana_reseni/', resitel_required(views.PrehledOdevzdanychReseni.as_view()), name='seminar_resitel_odevzdana_reseni'), | ||||||
| 	path('reset-hesla/', views.PasswordResetView.as_view(), name='reset_password'), | 	path('reset-hesla/', views.PasswordResetView.as_view(), name='reset_password'), | ||||||
|  |  | ||||||
|  | @ -14,11 +14,15 @@ from django.core.exceptions import ObjectDoesNotExist | ||||||
| from enum import Enum | from enum import Enum | ||||||
| from enum import auto | from enum import auto | ||||||
| 
 | 
 | ||||||
|  | import logging | ||||||
|  | 
 | ||||||
| import seminar.models as m | import seminar.models as m | ||||||
| import seminar.treelib as t | import seminar.treelib as t | ||||||
| 
 | 
 | ||||||
| org_required = permission_required('auth.org', raise_exception=True) | logger = logging.getLogger(__name__) | ||||||
| resitel_required = permission_required('auth.resitel', raise_exception=True) | 
 | ||||||
|  | org_required = permission_required('auth.org') | ||||||
|  | resitel_required = permission_required('auth.resitel') | ||||||
| User = get_user_model() | User = get_user_model() | ||||||
| # Není to úplně hezké, ale budeme doufat, že to je funkční... | # Není to úplně hezké, ale budeme doufat, že to je funkční... | ||||||
| User.je_org = property(lambda self: self.has_perm('auth.org')) | User.je_org = property(lambda self: self.has_perm('auth.org')) | ||||||
|  | @ -312,11 +316,12 @@ def deadline_v_rocniku(datum, rocnik): | ||||||
| 		if datum <= dl[2]: | 		if datum <= dl[2]: | ||||||
| 			# První takový deadline je ten nejtěsnější | 			# První takový deadline je ten nejtěsnější | ||||||
| 			return dl | 			return dl | ||||||
|  | 	logger.error(f'Pro datum {datum} v ročníku {rocnik} neexistuje deadline.') | ||||||
| 
 | 
 | ||||||
| def deadline(datum): | def deadline(datum): | ||||||
| 	"""Funkce pro dohledání, ke kterému deadlinu se datum váže. | 	"""Funkce pro dohledání, ke kterému deadlinu se datum váže. | ||||||
| 	 | 	 | ||||||
| 	Vrací trojici (TypDeadline, Cislo, datumDeadline: date). | 	Vrací trojici (TypDeadline, Cislo, datumDeadline: date). Pokud se deadline nenajde, vrátí None | ||||||
| 	""" | 	""" | ||||||
| 
 | 
 | ||||||
| 	if isinstance(datum, datetime.datetime): | 	if isinstance(datum, datetime.datetime): | ||||||
|  | @ -338,9 +343,12 @@ def deadline(datum): | ||||||
| 		# Seznam čísel je potřeba ručně setřídit chronologicky, protože Model říká, že se řadí od nejnovějšího | 		# Seznam čísel je potřeba ručně setřídit chronologicky, protože Model říká, že se řadí od nejnovějšího | ||||||
| 		posledni_deadline_drivejsiho_rocniku = m.Cislo.objects.filter(rocnik=drivejsi_rocnik, datum_deadline__isnull=False).order_by('poradi').last().datum_deadline | 		posledni_deadline_drivejsiho_rocniku = m.Cislo.objects.filter(rocnik=drivejsi_rocnik, datum_deadline__isnull=False).order_by('poradi').last().datum_deadline | ||||||
| 
 | 
 | ||||||
|  | 	logger.debug(f'Nalezené ročníky: {drivejsi_rocnik}, {pozdejsi_rocnik}') | ||||||
| 	if drivejsi_rocnik is not None and datum <= posledni_deadline_drivejsiho_rocniku: | 	if drivejsi_rocnik is not None and datum <= posledni_deadline_drivejsiho_rocniku: | ||||||
|  | 		logger.debug(f'Hledám v dřívějším ročníku: {drivejsi_rocnik}') | ||||||
| 		return deadline_v_rocniku(datum, drivejsi_rocnik) | 		return deadline_v_rocniku(datum, drivejsi_rocnik) | ||||||
| 	else: | 	else: | ||||||
|  | 		logger.debug(f'Hledám v pozdějším ročníku: {pozdejsi_rocnik}') | ||||||
| 		return deadline_v_rocniku(datum, pozdejsi_rocnik) | 		return deadline_v_rocniku(datum, pozdejsi_rocnik) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -257,7 +257,7 @@ class PrehledOdevzdanychReseni(ListView): | ||||||
| 		# Ročník určujeme podle čísla, do jehož deadlinu došlo řešení. | 		# Ročník určujeme podle čísla, do jehož deadlinu došlo řešení. | ||||||
| 		# Chceme to mít seřazené, takže místo comphrerehsion ručně postavíme pole polí. Django templates neumí použít OrderedDict :-/ | 		# Chceme to mít seřazené, takže místo comphrerehsion ručně postavíme pole polí. Django templates neumí použít OrderedDict :-/ | ||||||
| 		podle_rocniku = [] | 		podle_rocniku = [] | ||||||
| 		for rocnik, hodnoceni in groupby(ctx['object_list'], lambda ho: deadline(ho.reseni.cas_doruceni)[1].rocnik): | 		for rocnik, hodnoceni in groupby(ctx['object_list'], lambda ho: deadline(ho.reseni.cas_doruceni)[1].rocnik if deadline(ho.reseni.cas_doruceni) is not None else None): | ||||||
| 			podle_rocniku.append((rocnik, list(hodnoceni))) | 			podle_rocniku.append((rocnik, list(hodnoceni))) | ||||||
| 		ctx['podle_rocniku'] = reversed(podle_rocniku) # Od nejnovějšího ročníku | 		ctx['podle_rocniku'] = reversed(podle_rocniku) # Od nejnovějšího ročníku | ||||||
| 		# TODO: Umožnit stažení / zobrazení řešení | 		# TODO: Umožnit stažení / zobrazení řešení | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect | ||||||
| from django.db.models import Q, Sum, Count | from django.db.models import Q, Sum, Count | ||||||
| from django.views.decorators.csrf import ensure_csrf_cookie | from django.views.decorators.csrf import ensure_csrf_cookie | ||||||
| from django.views.generic.edit import FormView, CreateView | from django.views.generic.edit import FormView, CreateView | ||||||
| from django.views.generic.base import TemplateView | from django.views.generic.base import TemplateView, RedirectView | ||||||
| from django.contrib.auth import authenticate, login, get_user_model, logout | from django.contrib.auth import authenticate, login, get_user_model, logout | ||||||
| from django.contrib.auth import views as auth_views | from django.contrib.auth import views as auth_views | ||||||
| from django.contrib.auth.models import User, Permission | from django.contrib.auth.models import User, Permission | ||||||
|  | @ -26,7 +26,7 @@ import seminar.models as m | ||||||
| from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci | from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci | ||||||
| #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | ||||||
| from seminar import utils, treelib | from seminar import utils, treelib | ||||||
| from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm, ProfileEditFormPoMaturite | from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm, PoMaturiteProfileEditForm | ||||||
| import seminar.forms as f | import seminar.forms as f | ||||||
| import seminar.templatetags.treenodes as tnltt | import seminar.templatetags.treenodes as tnltt | ||||||
| import seminar.views.views_rest as vr | import seminar.views.views_rest as vr | ||||||
|  | @ -1026,7 +1026,20 @@ class ResitelView(LoginRequiredMixin,generic.DetailView): | ||||||
| class AddSolutionView(LoginRequiredMixin, FormView): | class AddSolutionView(LoginRequiredMixin, FormView): | ||||||
| 	template_name = 'seminar/org/vloz_reseni.html' | 	template_name = 'seminar/org/vloz_reseni.html' | ||||||
| 	form_class = f.VlozReseniForm | 	form_class = f.VlozReseniForm | ||||||
| 	success_url = '/' | 
 | ||||||
|  | 	def form_valid(self, form): | ||||||
|  | 		data = form.cleaned_data | ||||||
|  | 		nove_reseni = m.Reseni.objects.create( | ||||||
|  | 			cas_doruceni=data['cas_doruceni'], | ||||||
|  | 			forma=data['forma'], | ||||||
|  | 			poznamka=data['poznamka'], | ||||||
|  | 			) | ||||||
|  | 		nove_reseni.resitele.add(data['resitel']) | ||||||
|  | 		nove_reseni.problem.add(data['problem']) | ||||||
|  | 		nove_reseni.save() | ||||||
|  | 		# Chtěl jsem, aby bylo vidět, že se to uložilo, tak přesměrovávám na profil. | ||||||
|  | 		return redirect(reverse('profil')) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class NahrajReseniView(LoginRequiredMixin, CreateView): | class NahrajReseniView(LoginRequiredMixin, CreateView): | ||||||
| 	model = s.Reseni | 	model = s.Reseni | ||||||
|  | @ -1095,21 +1108,21 @@ def resitelEditView(request): | ||||||
| 	user_edit = osoba_edit.user | 	user_edit = osoba_edit.user | ||||||
| 	## Vytvoření slovníku, kterým předvyplním formulář  | 	## Vytvoření slovníku, kterým předvyplním formulář  | ||||||
| 	prefill_1=model_to_dict(user_edit) | 	prefill_1=model_to_dict(user_edit) | ||||||
| 	if resitel_edit and resitel_edit.rok_maturity >= date.today().year: | 	if resitel_edit: | ||||||
| 		prefill_2=model_to_dict(resitel_edit) | 		prefill_2=model_to_dict(resitel_edit) | ||||||
| 		prefill_1.update(prefill_2) | 		prefill_1.update(prefill_2) | ||||||
| 	prefill_3=model_to_dict(osoba_edit) | 	prefill_3=model_to_dict(osoba_edit) | ||||||
| 	prefill_1.update(prefill_3) | 	prefill_1.update(prefill_3) | ||||||
| 	if 'datum_narozeni' in prefill_1: | 	if 'datum_narozeni' in prefill_1: | ||||||
| 		prefill_1['datum_narozeni'] = str(prefill_1['datum_narozeni']) | 		prefill_1['datum_narozeni'] = str(prefill_1['datum_narozeni']) | ||||||
| 	if resitel_edit and resitel_edit.rok_maturity < date.today().year: | 	if 'rok_maturity' not in prefill_1 or prefill_1['rok_maturity'] < date.today().year: | ||||||
| 		form = ProfileEditFormPoMaturite(initial=prefill_1) | 		form = PoMaturiteProfileEditForm(initial=prefill_1) | ||||||
| 	else: | 	else: | ||||||
| 		form = ProfileEditForm(initial=prefill_1) | 		form = ProfileEditForm(initial=prefill_1) | ||||||
| 	## Změna údajů a jejich uložení | 	## Změna údajů a jejich uložení | ||||||
| 	if request.method == 'POST': | 	if request.method == 'POST': | ||||||
| 		if resitel_edit and resitel_edit.rok_maturity < date.today().year: | 		if 'rok_maturity' not in prefill_1 or prefill_1['rok_maturity'] < date.today().year: | ||||||
| 			form = ProfileEditFormPoMaturite(request.POST) | 			form = PoMaturiteProfileEditForm(request.POST) | ||||||
| 		else: | 		else: | ||||||
| 			form = ProfileEditForm(request.POST) | 			form = ProfileEditForm(request.POST) | ||||||
| 		if form.is_valid(): | 		if form.is_valid(): | ||||||
|  | @ -1133,7 +1146,7 @@ def resitelEditView(request): | ||||||
| 				## Neznámá země | 				## Neznámá země | ||||||
| 				msg = "Unknown country {}".format(fcd['stat_text']) | 				msg = "Unknown country {}".format(fcd['stat_text']) | ||||||
| 
 | 
 | ||||||
| 			if resitel_edit and resitel_edit.rok_maturity >= date.today().year: | 			if resitel_edit: | ||||||
| 				## Změny v řešiteli | 				## Změny v řešiteli | ||||||
| 				resitel_edit.skola = fcd['skola'] | 				resitel_edit.skola = fcd['skola'] | ||||||
| 				resitel_edit.rok_maturity = fcd['rok_maturity'] | 				resitel_edit.rok_maturity = fcd['rok_maturity'] | ||||||
|  | @ -1149,7 +1162,7 @@ def resitelEditView(request): | ||||||
| 			return formularOKView(request) | 			return formularOKView(request) | ||||||
| 	else: | 	else: | ||||||
| 		## Stránka před odeslaním formuláře = předvyplněný formulář | 		## Stránka před odeslaním formuláře = předvyplněný formulář | ||||||
| 		return render(request, 'seminar/profil/edit.html', {'form': form, 'po_maturite': resitel_edit and resitel_edit.rok_maturity < date.today().year}) | 		return render(request, 'seminar/profil/edit.html', {'form': form}) | ||||||
| 
 | 
 | ||||||
| def prihlaskaView(request): | def prihlaskaView(request): | ||||||
| 	generic_logger = logging.getLogger('seminar.prihlaska') | 	generic_logger = logging.getLogger('seminar.prihlaska') | ||||||
|  | @ -1230,12 +1243,6 @@ class LoginView(auth_views.LoginView): | ||||||
| 	# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL | 	# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL | ||||||
| 	template_name = 'seminar/profil/login.html' | 	template_name = 'seminar/profil/login.html' | ||||||
| 
 | 
 | ||||||
| 	# Přesměrovací URL má být v kontextu: |  | ||||||
| 	def get_context_data(self, **kwargs): |  | ||||||
| 		ctx = super().get_context_data(**kwargs) |  | ||||||
| 		ctx['next'] = reverse('profil') |  | ||||||
| 		return ctx |  | ||||||
| 
 |  | ||||||
| class LogoutView(auth_views.LogoutView): | class LogoutView(auth_views.LogoutView): | ||||||
| 	# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL | 	# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL | ||||||
| 	template_name = 'seminar/profil/logout.html' | 	template_name = 'seminar/profil/logout.html' | ||||||
|  | @ -1327,3 +1334,11 @@ class JakResitView(generic.ListView): | ||||||
|      |      | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		return None | 		return None | ||||||
|  | 
 | ||||||
|  | class AktualniRocnikRedirectView(RedirectView): | ||||||
|  | 	permanent=False | ||||||
|  | 	pattern_name = 'seminar_rocnik' | ||||||
|  | 
 | ||||||
|  | 	def get_redirect_url(self, *args, **kwargs): | ||||||
|  | 		aktualni_rocnik = m.Nastaveni.get_solo().aktualni_rocnik.rocnik | ||||||
|  | 		return super().get_redirect_url(rocnik=aktualni_rocnik, *args, **kwargs) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jonas Havelka
						Jonas Havelka