Merge branch 'data_migrations' into odevzdavatko
This commit is contained in:
		
						commit
						a8f91e1222
					
				
					 21 changed files with 946 additions and 835 deletions
				
			
		
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							|  | @ -34,8 +34,8 @@ install_web: venv_check | |||
| 	pip install --upgrade setuptools | ||||
| 	# Instalace závislostí webu | ||||
| 	pip install -r requirements.txt --upgrade | ||||
| 	# Po vygenerování testdat spusť  ./manage.py loaddata sitetree_new.json, ať máš menu | ||||
| 	# Pro synchronizaci flatpages spusť make sync_prod_flatpages | ||||
| 	# Po vygenerování testdat spusť  ./manage.py loaddata data/*, ať máš menu a další modely | ||||
| :x | ||||
| 
 | ||||
| install_venv: | ||||
| 	${VENV} ${VENV_PATH} | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										12
									
								
								fix_json.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								fix_json.py
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #!/usr/bin/python3 | ||||
| 
 | ||||
| import json | ||||
| import argparse | ||||
| 
 | ||||
| parser = argparse.ArgumentParser() | ||||
| parser.add_argument("input", type=argparse.FileType('r', encoding='utf-8')) | ||||
| parser.add_argument('output', type=argparse.FileType('w', encoding='utf-8')) | ||||
| args = parser.parse_args() | ||||
| 
 | ||||
| data = json.load(args.input) | ||||
| json.dump(data, args.output, ensure_ascii=False, sort_keys=True, indent='\t') | ||||
|  | @ -186,7 +186,7 @@ class KorekturyView(generic.TemplateView): | |||
| 		if email: | ||||
| 			emails.discard(email) | ||||
| 
 | ||||
| 		if not settings.SEND_EMAIL_NOTIFICATIONS: | ||||
| 		if not settings.POSLI_MAILOVOU_NOTIFIKACI: | ||||
| 			print("Poslal bych upozornění na tyto adresy: ", " ".join(emails)) | ||||
| 			return | ||||
| 
 | ||||
|  |  | |||
|  | @ -308,4 +308,4 @@ CISLO_IMG_DIR = os.path.join('cislo', 'img') | |||
| 
 | ||||
| 
 | ||||
| # E-MAIL NOTIFICATIONS | ||||
| SEND_EMAIL_NOTIFICATIONS = False | ||||
| POSLI_MAILOVOU_NOTIFIKACI = False | ||||
|  |  | |||
|  | @ -66,4 +66,4 @@ LOGGING['handlers']['registration_error_log']['filename'] = '/home/mam-web/logs/ | |||
| 
 | ||||
| 
 | ||||
| # E-MAIL NOTIFICATIONS | ||||
| SEND_EMAIL_NOTIFICATIONS = True | ||||
| POSLI_MAILOVOU_NOTIFIKACI = True | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 476 KiB | 
|  | @ -31,6 +31,10 @@ | |||
|       src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> | ||||
|     </script> | ||||
| 
 | ||||
|     {# Případné skripty widgetů formulářů #} | ||||
|     {% if form %} | ||||
|         {{form.media}} | ||||
|     {% endif %} | ||||
|     {# script specifický pro stránku #} | ||||
|     {% block script %}{% endblock %} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,14 @@ | |||
| from django.contrib import admin | ||||
| from django.contrib.auth.models import Permission | ||||
| from django.db import models | ||||
| from django.forms import widgets | ||||
| 
 | ||||
| from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter | ||||
| from reversion.admin import VersionAdmin | ||||
| from django_reverse_admin import ReverseModelAdmin | ||||
| from solo.admin import SingletonModelAdmin | ||||
| 
 | ||||
| 
 | ||||
| # Todo: reversion | ||||
| 
 | ||||
| import seminar.models as m | ||||
|  | @ -14,8 +17,6 @@ admin.site.register(m.Skola) | |||
| admin.site.register(m.Prijemce) | ||||
| admin.site.register(m.Rocnik) | ||||
| admin.site.register(m.Cislo) | ||||
| admin.site.register(m.Organizator) | ||||
| admin.site.register(m.Soustredeni) | ||||
| 
 | ||||
| @admin.register(m.Osoba) | ||||
| class OsobaAdmin(admin.ModelAdmin): | ||||
|  | @ -42,7 +43,14 @@ class OsobaAdmin(admin.ModelAdmin): | |||
| 			org.save() | ||||
| 	udelej_orgem.short_description = "Udělej vybraných osob organizátory" | ||||
| 
 | ||||
| @admin.register(m.Organizator) | ||||
| class OrganizatorAdmin(admin.ModelAdmin): | ||||
| 	search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'prezdivka'] | ||||
| 			 | ||||
| @admin.register(m.Resitel) | ||||
| class ResitelAdmin(admin.ModelAdmin): | ||||
| 	search_fields = ['jmeno', 'prijmeni', 'prezdivka'] | ||||
| 	ordering = ('osoba__jmeno','osoba__prijmeni') | ||||
| 
 | ||||
| @admin.register(m.Problem) | ||||
| class ProblemAdmin(PolymorphicParentModelAdmin): | ||||
|  | @ -74,15 +82,55 @@ class KonferaAdmin(PolymorphicChildModelAdmin): | |||
| 	base_model = m.Konfera | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| 
 | ||||
| class TextAdminInline(admin.TabularInline): | ||||
| 	model = m.Text | ||||
| 	formfield_overrides = { | ||||
| 		models.TextField: {'widget': widgets.TextInput} | ||||
| 	} | ||||
| 	exclude = ['text_zkraceny_set','text_zkraceny'] | ||||
| 
 | ||||
| admin.site.register(m.Text) | ||||
| 
 | ||||
| class ResitelInline(admin.TabularInline): | ||||
| 	model = m.Resitel | ||||
| 	extra = 1 | ||||
| admin.site.register(m.Resitel) | ||||
| 
 | ||||
| class SoustredeniUcastniciInline(admin.TabularInline): | ||||
| 	model = m.Soustredeni_Ucastnici | ||||
| 	extra = 1 | ||||
| 	fields = ['resitel','poznamka'] | ||||
| 	autocomplete_fields = ['resitel'] | ||||
| 	ordering = ['resitel__osoba__jmeno', 'resitel__osoba__prijmeni'] | ||||
| 	formfield_overrides = { | ||||
| 		models.TextField: {'widget': widgets.TextInput} | ||||
| 	} | ||||
| 
 | ||||
| 	def get_queryset(self,request): | ||||
| 		qs = super().get_queryset(request) | ||||
| 		return qs.select_related('resitel','soustredeni') | ||||
| 
 | ||||
| class SoustredeniOrganizatoriInline(admin.TabularInline): | ||||
| 	model = m.Soustredeni.organizatori.through | ||||
| 	extra = 1 | ||||
| 	fields = ['organizator','poznamka'] | ||||
| 	autocomplete_fields = ['organizator'] | ||||
| 	ordering = ['organizator__osoba__jmeno','organizator__prijmeni'] | ||||
| 	formfield_overrides = { | ||||
| 		models.TextField: {'widget': widgets.TextInput} | ||||
| 	} | ||||
| 
 | ||||
| 	def get_queryset(self,request): | ||||
| 		qs = super().get_queryset(request) | ||||
| 		return qs.select_related('organizator', 'soustredeni') | ||||
| 
 | ||||
| 
 | ||||
| @admin.register(m.Soustredeni) | ||||
| class SoustredeniAdmin(admin.ModelAdmin): | ||||
| 	model = m.Soustredeni | ||||
| 	inline_type = 'tabular' | ||||
| 	inlines = [SoustredeniUcastniciInline, SoustredeniOrganizatoriInline] | ||||
| 
 | ||||
| 
 | ||||
| class PrilohaReseniInline(admin.TabularInline): | ||||
| 	model = m.PrilohaReseni | ||||
|  | @ -92,6 +140,7 @@ admin.site.register(m.PrilohaReseni) | |||
| class Reseni_ResiteleInline(admin.TabularInline): | ||||
| 	model = m.Reseni_Resitele | ||||
| 
 | ||||
| 
 | ||||
| @admin.register(m.Reseni) | ||||
| class ReseniAdmin(ReverseModelAdmin): | ||||
| 	base_model = m.Reseni | ||||
|  | @ -106,7 +155,6 @@ admin.site.register(m.Hodnoceni) | |||
| admin.site.register(m.Pohadka) | ||||
| admin.site.register(m.Obrazek) | ||||
| 
 | ||||
| 
 | ||||
| # Polymorfismus pro stromy | ||||
| # TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html | ||||
| 
 | ||||
|  |  | |||
|  | @ -184,7 +184,7 @@ class ProfileEditForm(forms.Form): | |||
| 		max_value=date.today().year+8, | ||||
| 		required=True) | ||||
| 	zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',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=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): | ||||
|  |  | |||
|  | @ -31,6 +31,8 @@ from unidecode import unidecode # Používám pro získání ID odkazu (ještě | |||
| 
 | ||||
| from polymorphic.models import PolymorphicModel | ||||
| 
 | ||||
| from django.core.mail import EmailMessage | ||||
| from seminar.utils import aktivniResitele | ||||
| 
 | ||||
| class SeminarModelBase(models.Model): | ||||
| 
 | ||||
|  | @ -624,9 +626,43 @@ class Cislo(SeminarModelBase): | |||
| 			return None | ||||
| 		return c | ||||
| 
 | ||||
| 	def __init__(self, *args, **kwargs): | ||||
| 		super().__init__(*args, **kwargs) | ||||
| 		self.__original_verejne = self.verejne_db | ||||
| 
 | ||||
| 	def posli_cislo_mailem(self): | ||||
| 		# parametry e-mailu | ||||
| 		odkaz = self.get_absolute_url() | ||||
| 
 | ||||
| 		poslat_z_mailu = 'zadani@mam.mff.cuni.cz' | ||||
| 		predmet = 'Vyšlo číslo {}'.format(self.kod()) | ||||
| 		text_mailu = 'Ahoj,\n' \ | ||||
| 			   'na adrese {} najdete nejnovější číslo.\n' \ | ||||
| 			   'Vaše M&M\n'.format(odkaz) | ||||
| 
 | ||||
| 		# Prijemci e-mailu | ||||
| 		emaily = map(lambda r: r.osoba.email, filter(lambda r: r.zasilat_cislo_emailem, aktivniResitele(self))) | ||||
| 
 | ||||
| 		if not settings.POSLI_MAILOVOU_NOTIFIKACI: | ||||
| 			print("Poslal bych upozornění na tyto adresy: ", " ".join(emaily)) | ||||
| 			return | ||||
| 
 | ||||
| 		email = EmailMessage( | ||||
| 			subject=predmet, | ||||
| 			body=text_mailu, | ||||
| 			from_email=poslat_z_mailu, | ||||
| 			bcc=list(emaily) | ||||
| 			#bcc = příjemci skryté kopie | ||||
| 		) | ||||
| 
 | ||||
| 		email.send() | ||||
| 
 | ||||
| 	def save(self, *args, **kwargs): | ||||
| 		super().save(*args, **kwargs) | ||||
| 		self.vygeneruj_nahled() | ||||
| 		# Při zveřejnění pošle mail | ||||
| 		if self.verejne_db and not self.__original_verejne: | ||||
| 			self.posli_cislo_mailem() | ||||
| 		# *Node.save() aktualizuje název *Nodu. | ||||
| 		try: | ||||
| 			self.cislonode.save() | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								seminar/static/images/no-picture.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								seminar/static/images/no-picture.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 86 KiB | 
|  | @ -32,7 +32,7 @@ | |||
|         {% if c.titulka_nahled %} | ||||
|         <img src="{{ c.titulka_nahled.url }}" alt="{{ c.kod }}" height=180px> | ||||
|         {% else %} | ||||
|         <img src="" alt="no image" height=180px> | ||||
|         {% load static %} <img src="{% static 'images/no-picture.png' %}" height=180px alt="no-picture"> | ||||
|         {% endif %} | ||||
|       </div> | ||||
| 
 | ||||
|  |  | |||
|  | @ -58,6 +58,7 @@ | |||
| <h2><strong>Soustředění</strong></h2> | ||||
| 
 | ||||
| <ul> | ||||
| 	<li><a href="/admin/seminar/soustredeni/add/">přidat soustředění</a></li> | ||||
| 	<li><strong>přednášky</strong> | ||||
| 
 | ||||
| 	<ul> | ||||
|  |  | |||
|  | @ -2,8 +2,6 @@ | |||
| {% load staticfiles %} | ||||
| 
 | ||||
| {% block script %} | ||||
|     <!--script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script!--> | ||||
|     {{form.media}} | ||||
|     <script src="{% static 'seminar/prihlaska.js' %}"></script> | ||||
| {% endblock %} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,8 +1,6 @@ | |||
| {% extends "base.html" %} | ||||
| {% load staticfiles %} | ||||
| {% block script %} | ||||
|     <!--script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script!--> | ||||
|     {{form.media}} | ||||
|     <script src="{% static 'seminar/dynamic_formsets.js' %}"></script> | ||||
| {% endblock %} | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,8 +2,6 @@ | |||
| {% load staticfiles %} | ||||
| 
 | ||||
| {% block script %} | ||||
|     <!--script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script!--> | ||||
|     {{form.media}} | ||||
|     <script src="{% static 'seminar/prihlaska.js' %}"></script> | ||||
| {% endblock %} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,12 @@ | |||
| <script> | ||||
| function preddeadline() { | ||||
|   alert("Řešení, která nám přijdou do tohoto deadlinu, se pokusíme opravit co nejdříve, abyste měli ještě šanci si je ještě opravit před definitivním deadlinem čísla."); | ||||
| } | ||||
| function sousdeadline() { | ||||
|   alert("Body za řešení, která nám přijdou do tohoto deadlinu, se ještě započítají pro účast na připravovaném soustředění."); | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| {% extends 'base.html' %} | ||||
| 
 | ||||
| {% load humanize %} | ||||
|  | @ -8,7 +17,17 @@ | |||
| 
 | ||||
| {% if nejblizsi_deadline %} | ||||
| <div class="odpocet"> | ||||
| 	<p><b><big>Do konce <a href="/zadani/aktualni/">odeslání řešení</a> {% if typ_deadline == 'soustredeni' %}(pro účast na soustředění) {% elif typ_deadline == 'preddeadline' %}(pro otištění došlých řešení) {% endif %}zbývá: | ||||
| 	<p><b><big>Do | ||||
|   {% if typ_deadline == 'soustredeni' %} | ||||
|   <a href="" onClick="sousdeadline()" | ||||
|      title="Body za řešení, která nám přijdou do tohoto deadlinu, se ještě započítají pro účast na připravovaném soustředění."> | ||||
|      deadlinu</a> odeslání <a href="/zadani/aktualni/">řešení | ||||
|   </a> pro účast na soustředění | ||||
| 
 | ||||
|   {% elif typ_deadline == 'preddeadline' %} <a href="" onClick="preddeadline()" | ||||
|   title="Řešení, která nám přijdou do tohoto deadlinu, se pokusíme opravit co nejdříve, abyste měli ještě šanci si je ještě opravit před definitivním deadlinem čísla.">1. deadlinu</a> aktuálního <a href="/zadani/aktualni/">čísla</a>  | ||||
|   {% else %} deadlinu aktuálního <a href="/zadani/aktualni/">čísla</a>  | ||||
|   {% endif %}zbývá: | ||||
|       {{nejblizsi_deadline|timeuntil}}</big></b></p> | ||||
| </div> | ||||
| {% endif %} | ||||
|  |  | |||
|  | @ -13,8 +13,8 @@ urlpatterns = [ | |||
| 	path('co-je-MaM/organizatori/organizovali/', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'), | ||||
| 
 | ||||
| 	# Archiv | ||||
| 	path('archiv/rocniky/', views.ArchivView.as_view(), name="seninar_archiv_rocniky"), | ||||
| 	path('archiv/temata/', views.ArchivTemataView.as_view(), name="seninar_archiv_temata"), | ||||
| 	path('archiv/rocniky/', views.ArchivView.as_view(), name="seminar_archiv_rocniky"), | ||||
| 	path('archiv/temata/', views.ArchivTemataView.as_view(), name="seminar_archiv_temata"), | ||||
| 
 | ||||
| 	path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'), | ||||
| 	path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='seminar_cislo'), | ||||
|  | @ -63,7 +63,7 @@ urlpatterns = [ | |||
| 	path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'), | ||||
| 
 | ||||
| 	# Clanky | ||||
| 	path('clanky/resitel/', views.ClankyResitelView.as_view(), name='clanky_resitel'), | ||||
| 	path('archiv/clanky/', views.ClankyResitelView.as_view(), name='clanky_resitel'), | ||||
| 	#path('clanky/org/', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'), | ||||
| 
 | ||||
| 	# Aesop | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| from dal import autocomplete | ||||
| from django.shortcuts import get_object_or_404 | ||||
| from django.db.models import Q | ||||
| 
 | ||||
| import seminar.models as m | ||||
| from .helpers import LoginRequiredAjaxMixin | ||||
|  |  | |||
|  | @ -568,6 +568,8 @@ class TitulniStranaView(generic.ListView): | |||
| 
 | ||||
| 		try: | ||||
| 			nejblizsi_deadline = sorted(filter(lambda dl: dl[0] is not None and dl[0] >= date.today(), [deadline_soustredeni, preddeadline, deadline]))[0] | ||||
| 			if nejblizsi_deadline[0] == deadline_soustredeni[0]: | ||||
| 				nejblizsi_deadline = deadline_soustredeni | ||||
| 		except IndexError: | ||||
| 			nejblizsi_deadline = (None, None) # neni zadna aktualni deadline | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Pavel "LEdoian" Turinsky
						Pavel "LEdoian" Turinsky