odstřel tvorby: relink – post
This commit is contained in:
		
							parent
							
								
									92c05342fb
								
							
						
					
					
						commit
						062f70e947
					
				
					 18 changed files with 418 additions and 779 deletions
				
			
		|  | @ -216,57 +216,57 @@ | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "add_cislo", | 		"codename": "add_cislo", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "cislo" | 		"ct_model": "cislo" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "change_cislo", | 		"codename": "change_cislo", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "cislo" | 		"ct_model": "cislo" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "delete_cislo", | 		"codename": "delete_cislo", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "cislo" | 		"ct_model": "cislo" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "view_cislo", | 		"codename": "view_cislo", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "cislo" | 		"ct_model": "cislo" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "add_clanek", | 		"codename": "add_clanek", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "clanek" | 		"ct_model": "clanek" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "change_clanek", | 		"codename": "change_clanek", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "clanek" | 		"ct_model": "clanek" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "delete_clanek", | 		"codename": "delete_clanek", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "clanek" | 		"ct_model": "clanek" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "view_clanek", | 		"codename": "view_clanek", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "clanek" | 		"ct_model": "clanek" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "add_deadline", | 		"codename": "add_deadline", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "deadline" | 		"ct_model": "deadline" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "change_deadline", | 		"codename": "change_deadline", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "deadline" | 		"ct_model": "deadline" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "view_deadline", | 		"codename": "view_deadline", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "deadline" | 		"ct_model": "deadline" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
|  | @ -371,22 +371,22 @@ | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "add_pohadka", | 		"codename": "add_pohadka", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "pohadka" | 		"ct_model": "pohadka" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "change_pohadka", | 		"codename": "change_pohadka", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "pohadka" | 		"ct_model": "pohadka" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "delete_pohadka", | 		"codename": "delete_pohadka", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "pohadka" | 		"ct_model": "pohadka" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "view_pohadka", | 		"codename": "view_pohadka", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "pohadka" | 		"ct_model": "pohadka" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
|  | @ -411,22 +411,22 @@ | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "add_problem", | 		"codename": "add_problem", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "problem" | 		"ct_model": "problem" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "change_problem", | 		"codename": "change_problem", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "problem" | 		"ct_model": "problem" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "delete_problem", | 		"codename": "delete_problem", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "problem" | 		"ct_model": "problem" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "view_problem", | 		"codename": "view_problem", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "problem" | 		"ct_model": "problem" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
|  | @ -441,22 +441,22 @@ | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "add_rocnik", | 		"codename": "add_rocnik", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "rocnik" | 		"ct_model": "rocnik" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "change_rocnik", | 		"codename": "change_rocnik", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "rocnik" | 		"ct_model": "rocnik" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "delete_rocnik", | 		"codename": "delete_rocnik", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "rocnik" | 		"ct_model": "rocnik" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "view_rocnik", | 		"codename": "view_rocnik", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "rocnik" | 		"ct_model": "rocnik" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
|  | @ -541,42 +541,42 @@ | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "add_tema", | 		"codename": "add_tema", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "tema" | 		"ct_model": "tema" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "change_tema", | 		"codename": "change_tema", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "tema" | 		"ct_model": "tema" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "delete_tema", | 		"codename": "delete_tema", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "tema" | 		"ct_model": "tema" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "view_tema", | 		"codename": "view_tema", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "tema" | 		"ct_model": "tema" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "add_uloha", | 		"codename": "add_uloha", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "uloha" | 		"ct_model": "uloha" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "change_uloha", | 		"codename": "change_uloha", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "uloha" | 		"ct_model": "uloha" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "delete_uloha", | 		"codename": "delete_uloha", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "uloha" | 		"ct_model": "uloha" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"codename": "view_uloha", | 		"codename": "view_uloha", | ||||||
| 		"ct_app_label": "seminar", | 		"ct_app_label": "tvorba", | ||||||
| 		"ct_model": "uloha" | 		"ct_model": "uloha" | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								odevzdavatko/migrations/0006_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								odevzdavatko/migrations/0006_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 21:34 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('odevzdavatko', '0005_tvorba_relink'), | ||||||
|  |         ('tvorba', '0003_tvorba_post'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |     ] | ||||||
							
								
								
									
										14
									
								
								personalni/migrations/0015_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								personalni/migrations/0015_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 21:35 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('personalni', '0014_tvorba_pre'), | ||||||
|  |         ('tvorba', '0003_tvorba_post'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |     ] | ||||||
							
								
								
									
										150
									
								
								seminar/migrations/0138_tvorba_delete.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								seminar/migrations/0138_tvorba_delete.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,150 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 14:03 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('tvorba', '0001_tvorba_create'), | ||||||
|  |         ('seminar', '0137_tvorba_unmanage'), | ||||||
|  |         ('odevzdavatko', '0005_tvorba_relink'), | ||||||
|  |         ('soustredeni', '0009_tvorba_relink5'), | ||||||
|  |         ('various', '0005_tvorba_relink'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='cislo', | ||||||
|  |             name='rocnik', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='clanek', | ||||||
|  |             name='cislo', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='clanek', | ||||||
|  |             name='problem_ptr', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='deadline', | ||||||
|  |             name='cislo', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='pohadka', | ||||||
|  |             name='autor', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='problem', | ||||||
|  |             name='autor', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='problem', | ||||||
|  |             name='garant', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='problem', | ||||||
|  |             name='nadproblem', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='problem', | ||||||
|  |             name='opravovatele', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='problem', | ||||||
|  |             name='polymorphic_ctype', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='problem', | ||||||
|  |             name='zamereni', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Problemy_Opravovatele', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='tema', | ||||||
|  |             name='problem_ptr', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='tema', | ||||||
|  |             name='rocnik', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='uloha', | ||||||
|  |             name='cislo_deadline', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='uloha', | ||||||
|  |             name='cislo_reseni', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='uloha', | ||||||
|  |             name='cislo_zadani', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='uloha', | ||||||
|  |             name='problem_ptr', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='zmrazenavysledkovka', | ||||||
|  |             name='deadline', | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='cislonode', | ||||||
|  |             name='cislo', | ||||||
|  |             field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='tvorba.cislo', verbose_name='číslo'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='pohadkanode', | ||||||
|  |             name='pohadka', | ||||||
|  |             field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='tvorba.pohadka', verbose_name='pohádka'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='rocniknode', | ||||||
|  |             name='rocnik', | ||||||
|  |             field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='tvorba.rocnik', verbose_name='ročník'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='temavcislenode', | ||||||
|  |             name='tema', | ||||||
|  |             field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tvorba.tema', verbose_name='téma v čísle'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='ulohavzoraknode', | ||||||
|  |             name='uloha', | ||||||
|  |             field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.PROTECT, to='tvorba.uloha', verbose_name='úloha'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='ulohazadaninode', | ||||||
|  |             name='uloha', | ||||||
|  |             field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.PROTECT, to='tvorba.uloha', verbose_name='úloha'), | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Cislo', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Clanek', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Deadline', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Pohadka', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Problem', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Rocnik', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Tema', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Uloha', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='ZmrazenaVysledkovka', | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										14
									
								
								seminar/migrations/0139_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								seminar/migrations/0139_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 21:35 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('seminar', '0138_tvorba_delete'), | ||||||
|  |         ('tvorba', '0003_tvorba_post'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |     ] | ||||||
|  | @ -15,3 +15,9 @@ from tvorba.models import ZmrazenaVysledkovka, Deadline, Cislo, Rocnik, Pohadka, | ||||||
| from soustredeni.models import generate_filename_konfera | from soustredeni.models import generate_filename_konfera | ||||||
| # migr. 0001 | # migr. 0001 | ||||||
| from odevzdavatko.models import generate_filename | from odevzdavatko.models import generate_filename | ||||||
|  | # migr. 0031, 0032, 0081 | ||||||
|  | from tvorba.models import cislo_pdf_filename | ||||||
|  | # migr. 0082 | ||||||
|  | from tvorba.models import cislo_png_filename | ||||||
|  | # migr 0100 (hack) | ||||||
|  | import tvorba.models as tvorba | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ from .pomocne import Text | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
| from seminar.models import tvorba as am | import tvorba.models as am | ||||||
| 
 | 
 | ||||||
| class TreeNode(PolymorphicModel): | class TreeNode(PolymorphicModel): | ||||||
| 	class Meta: | 	class Meta: | ||||||
|  |  | ||||||
|  | @ -1,40 +1,7 @@ | ||||||
| import datetime |  | ||||||
| import os | import os | ||||||
| import subprocess |  | ||||||
| import pathlib |  | ||||||
| import tempfile |  | ||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| from django.contrib.sites.shortcuts import get_current_site |  | ||||||
| from django.db import models |  | ||||||
| from django.db.models import Q |  | ||||||
| from django.template.loader import render_to_string |  | ||||||
| from django.utils import timezone |  | ||||||
| from django.conf import settings |  | ||||||
| from django.urls import reverse |  | ||||||
| from django.core.cache import cache |  | ||||||
| from django.core.exceptions import ObjectDoesNotExist, ValidationError |  | ||||||
| from django.core.files.storage import FileSystemStorage | from django.core.files.storage import FileSystemStorage | ||||||
| from django.utils.text import get_valid_filename |  | ||||||
| from django.utils.functional import cached_property |  | ||||||
| 
 |  | ||||||
| from solo.models import SingletonModel |  | ||||||
| from taggit.managers import TaggableManager |  | ||||||
| 
 |  | ||||||
| from reversion import revisions as reversion |  | ||||||
| 
 |  | ||||||
| from tvorba.utils import roman, aktivniResitele |  | ||||||
| from treenode import treelib |  | ||||||
| 
 |  | ||||||
| from unidecode import unidecode # Používám pro získání ID odkazu (ještě je to někde po někom zakomentované) |  | ||||||
| 
 |  | ||||||
| from polymorphic.models import PolymorphicModel |  | ||||||
| 
 |  | ||||||
| from django.core.mail import EmailMessage |  | ||||||
| 
 |  | ||||||
| from personalni.models import Prijemce, Organizator |  | ||||||
| 
 |  | ||||||
| from .base import SeminarModelBase |  | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
|  | @ -45,701 +12,3 @@ class OverwriteStorage(FileSystemStorage): | ||||||
| 		if self.exists(name): | 		if self.exists(name): | ||||||
| 			os.remove(os.path.join(self.location,name)) | 			os.remove(os.path.join(self.location,name)) | ||||||
| 		return super().get_available_name(name,max_length) | 		return super().get_available_name(name,max_length) | ||||||
| 
 |  | ||||||
| @reversion.register(ignore_duplicates=True) |  | ||||||
| class Rocnik(SeminarModelBase): |  | ||||||
| 
 |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_rocniky' |  | ||||||
| 		verbose_name = 'Ročník' |  | ||||||
| 		verbose_name_plural = 'Ročníky' |  | ||||||
| 		ordering = ['-rocnik'] |  | ||||||
| 		managed = False |  | ||||||
| 
 |  | ||||||
| 	# Interní ID |  | ||||||
| 	id = models.AutoField(primary_key = True) |  | ||||||
| 
 |  | ||||||
| 	prvni_rok = models.IntegerField('první rok', db_index=True, unique=True) |  | ||||||
| 
 |  | ||||||
| 	rocnik = models.IntegerField('číslo ročníku', db_index=True, unique=True) |  | ||||||
| 
 |  | ||||||
| 	exportovat = models.BooleanField('export do AESOPa', db_column='exportovat', default=False, |  | ||||||
| 			help_text='Exportuje se jen podle tohoto flagu (ne veřejnosti),' |  | ||||||
| 			' a to jen čísla s veřejnou výsledkovkou') |  | ||||||
| 
 |  | ||||||
| 	# má OneToOneField s: |  | ||||||
| 	# RocnikNode |  | ||||||
| 
 |  | ||||||
| 	def __str__(self): |  | ||||||
| 		return '{} ({}/{})'.format(self.rocnik, self.prvni_rok, self.prvni_rok+1) |  | ||||||
| 
 |  | ||||||
| 	# Ročník v římských číslech |  | ||||||
| 	def roman(self): |  | ||||||
| 		return roman(int(self.rocnik)) |  | ||||||
| 
 |  | ||||||
| 	def verejne(self): |  | ||||||
| 		return len(self.verejna_cisla()) > 0 |  | ||||||
| 	verejne.boolean = True |  | ||||||
| 	verejne.short_description = 'Veřejný (jen dle čísel)' |  | ||||||
| 
 |  | ||||||
| 	def neverejna_cisla(self): |  | ||||||
| 		vc = [c for c in self.cisla.all() if not c.verejne()] |  | ||||||
| 		vc.sort(key=lambda c: c.poradi) |  | ||||||
| 		return vc |  | ||||||
| 
 |  | ||||||
| 	def verejna_cisla(self): |  | ||||||
| 		vc = [c for c in self.cisla.all() if c.verejne()] |  | ||||||
| 		vc.sort(key=lambda c: c.poradi) |  | ||||||
| 		return vc |  | ||||||
| 
 |  | ||||||
| 	def posledni_verejne_cislo(self): |  | ||||||
| 		vc = self.verejna_cisla() |  | ||||||
| 		return vc[-1] if vc else None |  | ||||||
| 
 |  | ||||||
| 	def verejne_vysledkovky_cisla(self): |  | ||||||
| 		vc = list(self.cisla.filter(deadline_v_cisle__verejna_vysledkovka=True).distinct()) |  | ||||||
| 		vc.sort(key=lambda c: c.poradi) |  | ||||||
| 		return vc |  | ||||||
| 
 |  | ||||||
| 	def posledni_zverejnena_vysledkovka_cislo(self): |  | ||||||
| 		vc = self.verejne_vysledkovky_cisla() |  | ||||||
| 		return vc[-1] if vc else None |  | ||||||
| 
 |  | ||||||
| 	def druhy_rok(self): |  | ||||||
| 		return self.prvni_rok + 1 |  | ||||||
| 
 |  | ||||||
| 	def verejne_url(self): |  | ||||||
| 		return reverse('seminar_rocnik', kwargs={'rocnik': self.rocnik}) |  | ||||||
| 
 |  | ||||||
| 	@classmethod |  | ||||||
| 	def cached_rocnik(cls, r_id): |  | ||||||
| 		name = 'rocnik_%s' % (r_id, ) |  | ||||||
| 		c = cache.get(name) |  | ||||||
| 		if c is None: |  | ||||||
| 			c = cls.objects.get(id=r_id) |  | ||||||
| 			cache.set(name, c, 300) |  | ||||||
| 		return c |  | ||||||
| 		 |  | ||||||
| 	def save(self, *args, **kwargs): |  | ||||||
| 		super().save(*args, **kwargs) |  | ||||||
| 		# *Node.save() aktualizuje název *Nodu. |  | ||||||
| 		try: |  | ||||||
| 			self.rocniknode.save() |  | ||||||
| 		except ObjectDoesNotExist: |  | ||||||
| 			# Neexistující *Node nemá smysl aktualizovat. |  | ||||||
| 			pass |  | ||||||
| 
 |  | ||||||
| def cislo_pdf_filename(self, filename): |  | ||||||
| 	rocnik = str(self.rocnik.rocnik) |  | ||||||
| 	return pathlib.Path('cislo', 'pdf', rocnik, '{}-{}.pdf'.format(rocnik, self.poradi)) |  | ||||||
| 
 |  | ||||||
| def cislo_png_filename(self, filename): |  | ||||||
| 	rocnik = str(self.rocnik.rocnik) |  | ||||||
| 	return pathlib.Path('cislo', 'png', rocnik, '{}-{}.png'.format(rocnik, self.poradi)) |  | ||||||
| 
 |  | ||||||
| @reversion.register(ignore_duplicates=True) |  | ||||||
| class Cislo(SeminarModelBase): |  | ||||||
| 
 |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_cisla' |  | ||||||
| 		verbose_name = 'Číslo' |  | ||||||
| 		verbose_name_plural = 'Čísla' |  | ||||||
| 		ordering = ['-rocnik__rocnik', '-poradi'] |  | ||||||
| 		managed = False |  | ||||||
| 
 |  | ||||||
| 	# Interní ID |  | ||||||
| 	id = models.AutoField(primary_key = True) |  | ||||||
| 
 |  | ||||||
| 	rocnik = models.ForeignKey(Rocnik, verbose_name='ročník', related_name='cisla_old', |  | ||||||
| 		db_index=True,on_delete=models.PROTECT) |  | ||||||
| 
 |  | ||||||
| 	poradi = models.CharField('název čísla', max_length=32, db_index=True, |  | ||||||
| 		help_text='Většinou jen "1", vyjímečně "7-8", lexikograficky určuje pořadí v ročníku!') |  | ||||||
| 
 |  | ||||||
| 	datum_vydani = models.DateField('datum vydání', blank=True, null=True, |  | ||||||
| 		help_text='Datum vydání finální verze') |  | ||||||
| 
 |  | ||||||
| 	verejne_db = models.BooleanField('číslo zveřejněno', |  | ||||||
| 		db_column='verejne', default=False) |  | ||||||
| 
 |  | ||||||
| 	poznamka = models.TextField('neveřejná poznámka', blank=True, |  | ||||||
| 		help_text='Neveřejná poznámka k číslu (plain text)') |  | ||||||
| 
 |  | ||||||
| 	pdf = models.FileField('pdf', upload_to=cislo_pdf_filename, null=True, blank=True, |  | ||||||
| 		help_text='PDF čísla, které si mohou řešitelé stáhnout', storage=OverwriteStorage()) |  | ||||||
| 
 |  | ||||||
| 	titulka_nahled = models.ImageField('Obrázek titulní strany', upload_to=cislo_png_filename, null=True, blank=True, |  | ||||||
| 		help_text='Obrázek titulní strany, generuje se automaticky') |  | ||||||
| 
 |  | ||||||
| 	# má OneToOneField s: |  | ||||||
| 	# CisloNode |  | ||||||
| 
 |  | ||||||
| 	def kod(self): |  | ||||||
| 		return '%s.%s' % (self.rocnik.rocnik, self.poradi) |  | ||||||
| 	kod.short_description = 'Kód čísla' |  | ||||||
| 
 |  | ||||||
| 	def __str__(self): |  | ||||||
| 		# Potenciální DB HOG, pokud by se ročník necachoval |  | ||||||
| 		r = Rocnik.cached_rocnik(self.rocnik_id) |  | ||||||
| 		return '{}.{}'.format(r.rocnik, self.poradi) |  | ||||||
| 
 |  | ||||||
| 	def verejne(self): |  | ||||||
| 		return self.verejne_db |  | ||||||
| 	verejne.boolean = True |  | ||||||
| 
 |  | ||||||
| 	def verejne_url(self): |  | ||||||
| 		return reverse('seminar_cislo', kwargs={'rocnik': self.rocnik.rocnik, 'cislo': self.poradi}) |  | ||||||
| 
 |  | ||||||
| 	def absolute_url(self): |  | ||||||
| 		return "https://" + str(get_current_site(None)) + self.verejne_url() |  | ||||||
| 
 |  | ||||||
| 	def nasledujici(self): |  | ||||||
| 		"Vrací None, pokud je toto poslední" |  | ||||||
| 		return self.relativni_v_rocniku(1) |  | ||||||
| 
 |  | ||||||
| 	def predchozi(self): |  | ||||||
| 		"Vrací None, pokud je toto první" |  | ||||||
| 		return self.relativni_v_rocniku(-1) |  | ||||||
| 
 |  | ||||||
| 	def relativni_v_rocniku(self, rel_index): |  | ||||||
| 		"Číslo o `index` dále v ročníku. None pokud neexistuje." |  | ||||||
| 		cs = self.rocnik.cisla.order_by('poradi').all() |  | ||||||
| 		i = list(cs).index(self) + rel_index |  | ||||||
| 		if (i < 0) or (i >= len(cs)): |  | ||||||
| 			return None |  | ||||||
| 		return cs[i] |  | ||||||
| 
 |  | ||||||
| 	def vygeneruj_nahled(self): |  | ||||||
| 		VYSKA = 594 |  | ||||||
| 		sirka = int(VYSKA*210/297) |  | ||||||
| 		if not self.pdf: |  | ||||||
| 			return |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 		# Pokud obrázek neexistuje nebo není aktuální, vytvoř jej |  | ||||||
| 		if not self.titulka_nahled or os.path.getmtime(self.titulka_nahled.path) < os.path.getmtime(self.pdf.path): |  | ||||||
| 			png_filename = pathlib.Path(tempfile.mkdtemp(), 'nahled.png') |  | ||||||
| 
 |  | ||||||
| 			subprocess.run([ |  | ||||||
| 				"gs", |  | ||||||
| 				"-sstdout=%stderr", |  | ||||||
| 				"-dSAFER", |  | ||||||
| 				"-dNOPAUSE", |  | ||||||
| 				"-dBATCH", |  | ||||||
| 				"-dNOPROMPT", |  | ||||||
| 				"-sDEVICE=png16m", |  | ||||||
| 				"-r300x300", |  | ||||||
| 				"-dFirstPage=1d", |  | ||||||
| 				"-dLastPage=1d", |  | ||||||
| 				"-sOutputFile=" + str(png_filename), |  | ||||||
| 				"-f%s" % self.pdf.path |  | ||||||
| 				], |  | ||||||
| 				check=True, |  | ||||||
| 				capture_output=True |  | ||||||
| 			) |  | ||||||
| 
 |  | ||||||
| 			with open(png_filename,'rb') as f: |  | ||||||
| 				self.titulka_nahled.save('',f,True) |  | ||||||
| 
 |  | ||||||
| 			png_filename.unlink() |  | ||||||
| 			png_filename.parent.rmdir() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	@classmethod |  | ||||||
| 	def get(cls, rocnik, cislo): |  | ||||||
| 		try: |  | ||||||
| 			r = Rocnik.objects.get(rocnik=rocnik) |  | ||||||
| 			c = r.cisla.get(poradi=cislo) |  | ||||||
| 		except ObjectDoesNotExist: |  | ||||||
| 			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.absolute_url() |  | ||||||
| 
 |  | ||||||
| 		poslat_z_mailu = 'zadani@mam.mff.cuni.cz' |  | ||||||
| 		predmet = 'Vyšlo číslo {}'.format(self.kod()) |  | ||||||
| 		# TODO Možná nechceme všem psát „Ahoj“, např. příjemcům… |  | ||||||
| 		text_mailu = 'Ahoj,\n' \ |  | ||||||
| 			   'na adrese {} najdete nejnovější číslo.\n' \ |  | ||||||
| 			   'Vaše M&M\n'.format(odkaz) |  | ||||||
| 
 |  | ||||||
| 		predmet_prvni = 'Právě vyšlo 1. číslo M&M, pomoz nám ho poslat dál!' |  | ||||||
| 		text_mailu_prvni = 'Milý řešiteli,\n'\ |  | ||||||
| 			'právě jsme na našem webu zveřejnili první číslo {}. ročníku, najdeš ho na tomto odkazu: {}.\n\n'\ |  | ||||||
| 			'Doufáme, že tě M&M baví, a byli bychom rádi, kdyby mohlo dělat radost i dalším středoškolákům. Máme na tebe proto jednu prosbu. Sdílej prosím odkaz alespoň s jedním svým kamarádem, který by mohl mít o řešení M&M zájem. Je to pro nás moc důležité a velmi nám tím pomůžeš. Díky!\n\n'\ |  | ||||||
| 			'Organizátoři M&M\n'.format(self.rocnik.rocnik, odkaz) |  | ||||||
| 
 |  | ||||||
| 		predmet_resitel = predmet_prvni if self.poradi == "1" else predmet |  | ||||||
| 		text_mailu_resitel = text_mailu_prvni if self.poradi == "1" else text_mailu |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 		# Prijemci e-mailu |  | ||||||
| 		resitele_vsichni = aktivniResitele(self).filter(zasilat_cislo_emailem=True) |  | ||||||
| 
 |  | ||||||
| 		def posli(subject, text, resitele): |  | ||||||
| 			emaily = map(lambda resitel: resitel.osoba.email, resitele) |  | ||||||
| 
 |  | ||||||
| 			email = EmailMessage( |  | ||||||
| 				subject=subject, |  | ||||||
| 				body=text, |  | ||||||
| 				from_email=poslat_z_mailu, |  | ||||||
| 				bcc=list(emaily) |  | ||||||
| 				#bcc = příjemci skryté kopie |  | ||||||
| 			) |  | ||||||
| 
 |  | ||||||
| 			email.send() |  | ||||||
| 
 |  | ||||||
| 		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(predmet_resitel, text_mailu_resitel + paticka, resitele_vsichni.filter(zasilat_cislo_papirove=False)) |  | ||||||
| 		posli(predmet_resitel, text_mailu_resitel + '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.filter(zasilat_cislo_papirove=True)) |  | ||||||
| 
 |  | ||||||
| 		paticka_prijemce = "---\nPokud tyto e-maily nechcete nadále dostávat, prosíme, ozvěte se nám na mam@matfyz.cz." |  | ||||||
| 		posli(predmet, text_mailu + paticka_prijemce, Prijemce.objects.filter(zasilat_cislo_emailem=True)) |  | ||||||
| 
 |  | ||||||
| 	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() |  | ||||||
| 		except ObjectDoesNotExist: |  | ||||||
| 			# Neexistující *Node nemá smysl aktualizovat, ale je potřeba ho naopak vyrobit |  | ||||||
| 			logger.warning(f'Číslo {self} nemělo ČísloNode, vyrábím…') |  | ||||||
| 			from seminar.models.treenode import CisloNode |  | ||||||
| 			CisloNode.objects.create(cislo=self) |  | ||||||
| 
 |  | ||||||
| 	def zlomovy_deadline_pro_papirove_cislo(self): |  | ||||||
| 		prvni_deadline = Deadline.objects.filter(Q(typ=Deadline.TYP_PRVNI) | Q(typ=Deadline.TYP_PRVNI_A_SOUS), cislo=self).first() |  | ||||||
| 		if prvni_deadline is None: |  | ||||||
| 			posledni_deadline = self.posledni_deadline |  | ||||||
| 			if posledni_deadline is None: |  | ||||||
| 				# TODO promyslet, co se má stát tady |  | ||||||
| 				return Deadline.objects.filter(Q(cislo__poradi__lt=self.poradi, cislo__rocnik=self.rocnik) | Q(cislo__rocnik__rocnik__lt=self.rocnik.rocnik)).order_by("deadline").last() |  | ||||||
| 			return posledni_deadline |  | ||||||
| 		return prvni_deadline |  | ||||||
| 
 |  | ||||||
| 	@property |  | ||||||
| 	def posledni_deadline(self): |  | ||||||
| 		return self.deadline_v_cisle.all().order_by("deadline").last() |  | ||||||
| 
 |  | ||||||
| class Deadline(SeminarModelBase): |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_deadliny' |  | ||||||
| 		verbose_name = 'Deadline' |  | ||||||
| 		verbose_name_plural = 'Deadliny' |  | ||||||
| 		ordering = ['deadline'] |  | ||||||
| 		managed = False |  | ||||||
| 
 |  | ||||||
| 	def __init__(self, *args, **kwargs): |  | ||||||
| 		super().__init__(*args, **kwargs) |  | ||||||
| 		self.__original_verejna_vysledkovka = self.verejna_vysledkovka |  | ||||||
| 
 |  | ||||||
| 	id = models.AutoField(primary_key=True) |  | ||||||
| 
 |  | ||||||
| 	# V ročníku < 26 nastaveno na datetime.datetime.combine(datetime.date(1994 + cislo.rocnik.rocnik, 6, int(cislo.poradi[0])), datetime.time.min) |  | ||||||
| 	deadline = models.DateTimeField(blank=False, default=timezone.make_aware(datetime.datetime.combine(timezone.now(), datetime.time.max))) |  | ||||||
| 
 |  | ||||||
| 	cislo = models.ForeignKey(Cislo, verbose_name='deadline v čísle', |  | ||||||
| 		related_name='deadline_v_cisle_old', blank=False, |  | ||||||
| 		on_delete=models.CASCADE) |  | ||||||
| 
 |  | ||||||
| 	TYP_CISLA = 'cisla' |  | ||||||
| 	TYP_PRVNI_A_SOUS = 'prvniasous' |  | ||||||
| 	TYP_PRVNI = 'prvni' |  | ||||||
| 	TYP_SOUS = 'sous' |  | ||||||
| 	TYP_CHOICES = [ |  | ||||||
| 		(TYP_CISLA, 'Deadline celého čísla'), |  | ||||||
| 		(TYP_PRVNI, 'První deadline'), |  | ||||||
| 		(TYP_PRVNI_A_SOUS, 'Sousový a první deadline'), |  | ||||||
| 		(TYP_SOUS, 'Sousový deadline'), |  | ||||||
| 	] |  | ||||||
| 	CHOICES_MAP = dict(TYP_CHOICES) |  | ||||||
| 	typ = models.CharField('typ deadlinu', max_length=32, |  | ||||||
| 							choices=TYP_CHOICES, blank=False) |  | ||||||
| 
 |  | ||||||
| 	verejna_vysledkovka = models.BooleanField('veřejná výsledkovka', |  | ||||||
| 											  db_column='verejna_vysledkovka', |  | ||||||
| 											  default=False) |  | ||||||
| 
 |  | ||||||
| 	def __str__(self): |  | ||||||
| 		return self.CHOICES_MAP[self.typ] + " " + str(self.cislo) |  | ||||||
| 
 |  | ||||||
| 	def save(self, *args, **kwargs): |  | ||||||
| 		super().save(*args, **kwargs) |  | ||||||
| 		if self.verejna_vysledkovka and not self.__original_verejna_vysledkovka: |  | ||||||
| 			self.vygeneruj_vysledkovku() |  | ||||||
| 		if not self.verejna_vysledkovka and hasattr(self, "vysledkovka_v_deadlinu"): |  | ||||||
| 			self.vysledkovka_v_deadlinu.delete() |  | ||||||
| 
 |  | ||||||
| 	def vygeneruj_vysledkovku(self): |  | ||||||
| 		from vysledkovky.utils import VysledkovkaCisla |  | ||||||
| 		if hasattr(self, "vysledkovka_v_deadlinu"): |  | ||||||
| 			self.vysledkovka_v_deadlinu.delete() |  | ||||||
| 		vysledkovka = VysledkovkaCisla(self.cislo, jen_verejne=True, do_deadlinu=self) |  | ||||||
| 		if len(vysledkovka.radky_vysledkovky) != 0: |  | ||||||
| 			ZmrazenaVysledkovka.objects.create( |  | ||||||
| 				deadline=self, |  | ||||||
| 				html=render_to_string( |  | ||||||
| 					"vysledkovky/vysledkovka_cisla.html", |  | ||||||
| 					context={"vysledkovka": vysledkovka, "oznaceni_vysledkovky": self.id} |  | ||||||
| 				) |  | ||||||
| 			) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ZmrazenaVysledkovka(SeminarModelBase): |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_vysledkovky' |  | ||||||
| 		verbose_name = 'Zmražená výsledkovka' |  | ||||||
| 		verbose_name_plural = 'Zmražené výsledkovky' |  | ||||||
| 		managed = False |  | ||||||
| 
 |  | ||||||
| 	deadline = models.OneToOneField( |  | ||||||
| 		Deadline, |  | ||||||
| 		on_delete=models.CASCADE, |  | ||||||
| 		primary_key=True, |  | ||||||
| 		related_name="vysledkovka_v_deadlinu_old" |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	html = models.TextField(null=False, blank=False) |  | ||||||
| 
 |  | ||||||
| class Problemy_Opravovatele(SeminarModelBase): |  | ||||||
| 	"""Jen vazebná tabulka pro opravovatele. |  | ||||||
| 
 |  | ||||||
| 	Ona stejně existovala, při přesunu mezi aplikacemi jen potřebujeme zajistit nepřejmenování DB tabulky. |  | ||||||
| 	Proto taky nepotřebuje žádná specifika, ze :py:class:SeminarModelBase: dědí ze zvyku než že by to k něčemu kdy měo být. |  | ||||||
| 	""" |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_problemy_opravovatele' |  | ||||||
| 		managed = False |  | ||||||
| 	 |  | ||||||
| 	id = models.AutoField(primary_key = True) |  | ||||||
| 
 |  | ||||||
| 	problem = models.ForeignKey('Problem', on_delete=models.CASCADE, related_name='awawa1_old') |  | ||||||
| 	organizator = models.ForeignKey(Organizator, on_delete=models.CASCADE, related_name='awawa2_old') |  | ||||||
| 
 |  | ||||||
| @reversion.register(ignore_duplicates=True) |  | ||||||
| # Pozor na následující řádek. *Nekrmit, asi kouše!* |  | ||||||
| class Problem(SeminarModelBase,PolymorphicModel): |  | ||||||
| 
 |  | ||||||
| 	class Meta: |  | ||||||
| 		# Není abstraktní, protože se na něj jinak nedají dělat ForeignKeys. |  | ||||||
| 		# TODO: Udělat to polymorfní (pomocí django-polymorphic), abychom dostali  |  | ||||||
| 		# po těch vazbách přímo tu úlohu/témátko vč. fieldů, které nejsou součástí  |  | ||||||
| 		# modelu Problem? |  | ||||||
| 
 |  | ||||||
| 		#abstract = True |  | ||||||
| 		db_table = 'seminar_problemy' |  | ||||||
| 		verbose_name = 'Problém' |  | ||||||
| 		verbose_name_plural = 'Problémy' |  | ||||||
| 		ordering = ['nazev'] |  | ||||||
| 		managed = False |  | ||||||
| 
 |  | ||||||
| 	# Interní ID |  | ||||||
| 	id = models.AutoField(primary_key = True) |  | ||||||
| 
 |  | ||||||
| 	# Název |  | ||||||
| 	nazev = models.CharField('název', max_length=256) # Zveřejnitelný na stránky |  | ||||||
| 
 |  | ||||||
| 	# Problém má podproblémy |  | ||||||
| 	nadproblem = models.ForeignKey('self', verbose_name='nadřazený problém', |  | ||||||
| 		related_name='podproblem_old', null=True, blank=True, |  | ||||||
| 		on_delete=models.SET_NULL) |  | ||||||
| 
 |  | ||||||
| 	STAV_NAVRH = 'navrh' |  | ||||||
| 	STAV_ZADANY = 'zadany' |  | ||||||
| 	STAV_VYRESENY = 'vyreseny' |  | ||||||
| 	STAV_SMAZANY = 'smazany' |  | ||||||
| 	STAV_CHOICES = [ |  | ||||||
| 		(STAV_NAVRH, 'Návrh'), |  | ||||||
| 		(STAV_ZADANY, 'Zadaný'), |  | ||||||
| 		(STAV_VYRESENY, 'Vyřešený'), |  | ||||||
| 		(STAV_SMAZANY, 'Smazaný'), |  | ||||||
| 		] |  | ||||||
| 	stav = models.CharField('stav problému', max_length=32, choices=STAV_CHOICES, blank=False, default=STAV_NAVRH) |  | ||||||
| 	# Téma je taky Problém, takže má stavy, "zadané" témátko je aktuálně otevřené a dá se k němu něco poslat (řešení nebo článek) |  | ||||||
| 
 |  | ||||||
| 	zamereni = TaggableManager(verbose_name='zaměření', related_name='zamereni_old', |  | ||||||
| 		help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True) |  | ||||||
| 
 |  | ||||||
| 	poznamka = models.TextField('org poznámky (HTML)', blank=True, |  | ||||||
| 		help_text='Neveřejný návrh úlohy, návrh řešení, text zadání, poznámky ...') |  | ||||||
| 
 |  | ||||||
| 	autor = models.ForeignKey(Organizator, verbose_name='autor problému', |  | ||||||
| 		related_name='autor_problemu_%(class)s_old', null=True, blank=True, |  | ||||||
| 		on_delete=models.SET_NULL) |  | ||||||
| 
 |  | ||||||
| 	garant = models.ForeignKey(Organizator, verbose_name='garant zadaného problému', |  | ||||||
| 		related_name='garant_problemu_%(class)s_old', null=True, blank=True, |  | ||||||
| 		on_delete=models.SET_NULL) |  | ||||||
| 
 |  | ||||||
| 	opravovatele = models.ManyToManyField(Organizator, verbose_name='opravovatelé', |  | ||||||
| 		blank=True, related_name='opravovatele_%(class)s_old', through=Problemy_Opravovatele) |  | ||||||
| 
 |  | ||||||
| 	kod = models.CharField('lokální kód', max_length=32, blank=True, default='', |  | ||||||
| 		help_text='Číslo/kód úlohy v čísle nebo kód tématu/článku/seriálu v ročníku') |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	vytvoreno = models.DateTimeField('vytvořeno', default=timezone.now, blank=True, editable=False) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	def __str__(self): |  | ||||||
| 		return self.nazev |  | ||||||
| 
 |  | ||||||
| 	# Implicitini implementace, jednotlivé dědící třídy si přepíšou |  | ||||||
| 	@cached_property |  | ||||||
| 	def kod_v_rocniku(self): |  | ||||||
| 		if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY: |  | ||||||
| 			if self.nadproblem: |  | ||||||
| 				return self.nadproblem.kod_v_rocniku+".{}".format(self.kod) |  | ||||||
| 			return str(self.kod) |  | ||||||
| 		logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") |  | ||||||
| 		return f'<Není zadaný: {self.kod}>' |  | ||||||
| 
 |  | ||||||
| #	def verejne(self): |  | ||||||
| #		# aktuálně podle stavu problému |  | ||||||
| #		# FIXME pro některé problémy možná chceme override |  | ||||||
| #		# FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.  |  | ||||||
| #		# Je to tak správně? Podle aktuální představy ano. |  | ||||||
| #		stav_verejny = False |  | ||||||
| #		if self.stav == 'zadany' or self.stav == 'vyreseny': |  | ||||||
| #			stav_verejny = True |  | ||||||
| #			print("stav_verejny: {}".format(stav_verejny))		 |  | ||||||
| # |  | ||||||
| #		cislo_verejne = False |  | ||||||
| #		cislonode = self.cislo_node() |  | ||||||
| #		if cislonode is None: |  | ||||||
| #			# problém nemá vlastní node, veřejnost posuzujeme jen podle stavu |  | ||||||
| #			print("empty node")		 |  | ||||||
| #			return stav_verejny |  | ||||||
| #		else:	 |  | ||||||
| #			cislo_zadani = cislonode.cislo |  | ||||||
| #			if (cislo_zadani and cislo_zadani.verejne()): |  | ||||||
| #				print("cislo: {}".format(cislo_zadani)) |  | ||||||
| #				cislo_verejne = True |  | ||||||
| #			print("stav_verejny: {}".format(stav_verejny))		 |  | ||||||
| #			print("cislo_verejne: {}".format(cislo_verejne))		 |  | ||||||
| #			return (stav_verejny and cislo_verejne) |  | ||||||
| #	verejne.boolean = True |  | ||||||
| 
 |  | ||||||
| 	def verejne_url(self): |  | ||||||
| 		return reverse('seminar_problem', kwargs={'pk': self.id}) |  | ||||||
| 
 |  | ||||||
| 	def admin_url(self): |  | ||||||
| 			return reverse('admin:seminar_problem_change', args=(self.id, )) |  | ||||||
| 
 |  | ||||||
| 	@cached_property |  | ||||||
| 	def hlavni_problem(self): |  | ||||||
| 		""" Pro daný problém vrátí jeho nejvyšší nadproblém.""" |  | ||||||
| 		problem = self |  | ||||||
| 		while not (problem.nadproblem is None): |  | ||||||
| 			problem = problem.nadproblem |  | ||||||
| 		return problem |  | ||||||
| 
 |  | ||||||
| # FIXME - k úloze |  | ||||||
| 	def body_v_zavorce(self): |  | ||||||
| 		"""Vrať string s body v závorce jsou-li u problému vyplněné, jinak '' |  | ||||||
| 
 |  | ||||||
| 		Je-li desetinná část nulová, nezobrazuj ji. |  | ||||||
| 		""" |  | ||||||
| 		pocet_bodu = None |  | ||||||
| 		if self.body: |  | ||||||
| 			b = self.body |  | ||||||
| 			pocet_bodu = int(b) if int(b) == b else b |  | ||||||
| 		return "({}\u2009b)".format(pocet_bodu) if self.body else "" |  | ||||||
| 
 |  | ||||||
| class Tema(Problem): |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_temata' |  | ||||||
| 		verbose_name = 'Téma' |  | ||||||
| 		verbose_name_plural = 'Témata' |  | ||||||
| 		managed = False |  | ||||||
| 	 |  | ||||||
| 	TEMA_TEMA = 'tema' |  | ||||||
| 	TEMA_SERIAL = 'serial' |  | ||||||
| 	TEMA_CHOICES = [ |  | ||||||
| 		(TEMA_TEMA, 'Téma'), |  | ||||||
| 		(TEMA_SERIAL, 'Seriál'), |  | ||||||
| 		] |  | ||||||
| 	tema_typ = models.CharField('Typ tématu', max_length=16, choices=TEMA_CHOICES,  |  | ||||||
| 		blank=False, default=TEMA_TEMA) |  | ||||||
| 
 |  | ||||||
| 	rocnik = models.ForeignKey(Rocnik, verbose_name='ročník',related_name='temata_old',blank=True, null=True, |  | ||||||
| 		on_delete=models.PROTECT) |  | ||||||
| 
 |  | ||||||
| 	abstrakt = models.TextField('Abstrakt na rozcestník', blank=True) |  | ||||||
| 	obrazek = models.ImageField('Obrázek na rozcestník', null=True, blank=True) |  | ||||||
| 
 |  | ||||||
| 	@cached_property |  | ||||||
| 	def kod_v_rocniku(self): |  | ||||||
| 		if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY: |  | ||||||
| 			if self.nadproblem: |  | ||||||
| 				return self.nadproblem.kod_v_rocniku+".t{}".format(self.kod) |  | ||||||
| 			return 't'+self.kod |  | ||||||
| 		logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") |  | ||||||
| 		return f'<Není zadaný: {self.kod}>' |  | ||||||
| 
 |  | ||||||
| 	def save(self, *args, **kwargs): |  | ||||||
| 		super().save(*args, **kwargs) |  | ||||||
| 		# *Node.save() aktualizuje název *Nodu. |  | ||||||
| 		for tvcn in self.temavcislenode_set.all(): |  | ||||||
| 			tvcn.save() |  | ||||||
| 
 |  | ||||||
| 	def cislo_node(self): |  | ||||||
| 		tema_node_set = self.temavcislenode_set.all() |  | ||||||
| 		tema_cisla_vyskyt = [] |  | ||||||
| 		from seminar.models.treenode import CisloNode |  | ||||||
| 		for tn in tema_node_set: |  | ||||||
| 			tema_cisla_vyskyt.append( |  | ||||||
| 				treelib.get_upper_node_of_type(tn, CisloNode).cislo) |  | ||||||
| 		tema_cisla_vyskyt.sort(key=lambda x:x.datum_vydani) |  | ||||||
| 		prvni_zadani = tema_cisla_vyskyt[0] |  | ||||||
| 		return prvni_zadani.cislonode |  | ||||||
| 
 |  | ||||||
| class Clanek(Problem): |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_clanky' |  | ||||||
| 		verbose_name = 'Článek' |  | ||||||
| 		verbose_name_plural = 'Články' |  | ||||||
| 		managed = False |  | ||||||
| 	 |  | ||||||
| 	cislo = models.ForeignKey(Cislo, blank=True, null=True, on_delete=models.PROTECT, |  | ||||||
| 		verbose_name='číslo vydání', related_name='vydane_clanky_old') |  | ||||||
| 	 |  | ||||||
| 	strana = models.PositiveIntegerField(verbose_name="první strana", blank=True, null=True) |  | ||||||
| 
 |  | ||||||
| 	@cached_property |  | ||||||
| 	def kod_v_rocniku(self): |  | ||||||
| 		if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY: |  | ||||||
| # Nemělo by být potřeba |  | ||||||
| #			if self.nadproblem: |  | ||||||
| #				return self.nadproblem.kod_v_rocniku+".c{}".format(self.kod) |  | ||||||
| 			return "c" + self.kod |  | ||||||
| 		logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") |  | ||||||
| 		return f'<Není zadaný: {self.kod}>' |  | ||||||
| 	 |  | ||||||
| 	def node(self): |  | ||||||
| 		return None |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Uloha(Problem): |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_ulohy' |  | ||||||
| 		verbose_name = 'Úloha' |  | ||||||
| 		verbose_name_plural = 'Úlohy' |  | ||||||
| 		managed = False |  | ||||||
| 	 |  | ||||||
| 	cislo_zadani = models.ForeignKey(Cislo, verbose_name='číslo zadání', blank=True,  |  | ||||||
| 		null=True, related_name='zadane_ulohy_old', on_delete=models.PROTECT) |  | ||||||
| 	 |  | ||||||
| 	cislo_deadline = models.ForeignKey(Cislo, verbose_name='číslo deadlinu', blank=True,  |  | ||||||
| 		null=True, related_name='deadlinove_ulohy_old', on_delete=models.PROTECT) |  | ||||||
| 
 |  | ||||||
| 	cislo_reseni = models.ForeignKey(Cislo, verbose_name='číslo řešení', blank=True,  |  | ||||||
| 		null=True, related_name='resene_ulohy_old', |  | ||||||
| 		help_text='Číslo s řešením úlohy, jen pro úlohy', |  | ||||||
| 		on_delete=models.PROTECT) |  | ||||||
| 
 |  | ||||||
| 	max_body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='maximum bodů',  |  | ||||||
| 		blank=True, null=True) |  | ||||||
| 
 |  | ||||||
| 	# má OneToOneField s: |  | ||||||
| 	# UlohaZadaniNode |  | ||||||
| 	# UlohaVzorakNode |  | ||||||
| 
 |  | ||||||
| 	@cached_property |  | ||||||
| 	def kod_v_rocniku(self): |  | ||||||
| 		if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY: |  | ||||||
| 			return f"{self.cislo_zadani.poradi}.{self.kod}" |  | ||||||
| 		logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") |  | ||||||
| 		return f'<Není zadaný: {self.kod}>' |  | ||||||
| 
 |  | ||||||
| 	def save(self, *args, **kwargs): |  | ||||||
| 		super().save(*args, **kwargs) |  | ||||||
| 		# *Node.save() aktualizuje název *Nodu. |  | ||||||
| 		try: |  | ||||||
| 			self.ulohazadaninode.save() |  | ||||||
| 		except ObjectDoesNotExist: |  | ||||||
| 			# Neexistující *Node nemá smysl aktualizovat. |  | ||||||
| 			pass |  | ||||||
| 		try: |  | ||||||
| 			self.ulohavzoraknode.save() |  | ||||||
| 		except ObjectDoesNotExist: |  | ||||||
| 			# Neexistující *Node nemá smysl aktualizovat. |  | ||||||
| 			pass |  | ||||||
| 
 |  | ||||||
| 	def cislo_node(self): |  | ||||||
| 		zadani_node = self.ulohazadaninode |  | ||||||
| 		from seminar.models.treenode import CisloNode |  | ||||||
| 		return treelib.get_upper_node_of_type(zadani_node, CisloNode) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def aux_generate_filename(self, filename): |  | ||||||
| 	"""Pomocná funkce generující ošetřený název souboru v adresáři s datem""" |  | ||||||
| 	clean = get_valid_filename( |  | ||||||
| 		unidecode(filename.replace('/', '-').replace('\0', '')) |  | ||||||
| 	) |  | ||||||
| 	datedir = timezone.now().strftime('%Y-%m') |  | ||||||
| 	fname = "{}/{}".format( |  | ||||||
| 		timezone.now().strftime('%Y-%m-%d-%H:%M'), |  | ||||||
| 		clean) |  | ||||||
| 	return os.path.join(datedir, fname) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Pohadka(SeminarModelBase): |  | ||||||
| 	"""Kus pohádky před/za úlohou v čísle""" |  | ||||||
| 
 |  | ||||||
| 	class Meta: |  | ||||||
| 		db_table = 'seminar_pohadky' |  | ||||||
| 		verbose_name = 'Pohádka' |  | ||||||
| 		verbose_name_plural = 'Pohádky' |  | ||||||
| 		ordering = ['vytvoreno'] |  | ||||||
| 		managed = False |  | ||||||
| 
 |  | ||||||
| 	# Interní ID |  | ||||||
| 	id = models.AutoField(primary_key=True) |  | ||||||
| 
 |  | ||||||
| 	autor = models.ForeignKey( |  | ||||||
| 		Organizator, |  | ||||||
| 		verbose_name="Autor pohádky", |  | ||||||
| 
 |  | ||||||
| 		# Při nahrávání z TeXu není vyplnění vyžadováno, v adminu je |  | ||||||
| 		null=True, |  | ||||||
| 		blank=False, |  | ||||||
| 		on_delete=models.SET_NULL, |  | ||||||
| 		related_name='awawa3_old', |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	vytvoreno = models.DateTimeField( |  | ||||||
| 		'Vytvořeno', |  | ||||||
| 		default=timezone.now, |  | ||||||
| 		blank=True, |  | ||||||
| 		editable=False |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	# má OneToOneField s: |  | ||||||
| 	# PohadkaNode |  | ||||||
| 
 |  | ||||||
| 	def __str__(self): |  | ||||||
| 		uryvek = self.text if len(self.text) < 50 else self.text[:(50-3)]+"..." |  | ||||||
| 		return uryvek |  | ||||||
| 
 |  | ||||||
| 	def save(self, *args, **kwargs): |  | ||||||
| 		super().save(*args, **kwargs) |  | ||||||
| 		# *Node.save() aktualizuje název *Nodu. |  | ||||||
| 		try: |  | ||||||
| 			self.pohadkanode.save() |  | ||||||
| 		except ObjectDoesNotExist: |  | ||||||
| 			# Neexistující *Node nemá smysl aktualizovat. |  | ||||||
| 			pass |  | ||||||
|  |  | ||||||
|  | @ -12,11 +12,14 @@ class Migration(migrations.Migration): | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
|     operations = [ |     operations = [ | ||||||
|         migrations.AlterField( |         ## Konferu zmigrujeme jinak, kvůli <https://code.djangoproject.com/ticket/23521> jí nejde přepsat někde ve stavu `bases`. | ||||||
|             model_name='konfera', |         ## Proto si ji unmanagujeme a vyrobíme celou znovu, to by nemělo vadit (zvlášť když t.č. v DB žádná instance Konfery není). | ||||||
|             name='problem_ptr', |         ## (Šlo by `SeparateStateAndData`, což v principu děláme taky ale ty migrace jsou lehce čitelnější a o poznání konzistentnější.) | ||||||
|             field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tvorba.problem'), |         #migrations.AlterField( | ||||||
|         ), |         #    model_name='konfera', | ||||||
|  |         #    name='problem_ptr', | ||||||
|  |         #    field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tvorba.problem'), | ||||||
|  |         #), | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='soustredeni', |             model_name='soustredeni', | ||||||
|             name='rocnik', |             name='rocnik', | ||||||
|  |  | ||||||
							
								
								
									
										17
									
								
								soustredeni/migrations/0006_tvorba_relink2.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								soustredeni/migrations/0006_tvorba_relink2.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 19:37 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('soustredeni', '0005_tvorba_relink'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='konfera', | ||||||
|  |             options={'managed': False, 'verbose_name': 'Konfera', 'verbose_name_plural': 'Konfery'}, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										15
									
								
								soustredeni/migrations/0007_tvorba_relink3.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								soustredeni/migrations/0007_tvorba_relink3.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 19:38 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('soustredeni', '0006_tvorba_relink2'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='Konfera', | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										34
									
								
								soustredeni/migrations/0008_tvorba_relink4.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								soustredeni/migrations/0008_tvorba_relink4.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 19:45 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations,models | ||||||
|  | import django.db.models.deletion | ||||||
|  | import soustredeni.models | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('soustredeni', '0007_tvorba_relink3'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name='Konfera', | ||||||
|  |             fields=[ | ||||||
|  |                 ('problem_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tvorba.problem')), | ||||||
|  |                 ('anotace', models.TextField(blank=True, help_text='Popis, o čem bude konfera.', verbose_name='anotace')), | ||||||
|  |                 ('abstrakt', models.TextField(blank=True, help_text='Abstrakt konfery tak, jak byl uveden ve sborníku', verbose_name='abstrakt')), | ||||||
|  |                 ('typ_prezentace', models.CharField(choices=[('veletrh', 'Veletrh (postery)'), ('prezentace', 'Prezentace (přednáška)')], default='veletrh', max_length=16, verbose_name='typ prezentace')), | ||||||
|  |                 ('prezentace', models.FileField(blank=True, help_text='Prezentace nebo fotka posteru', upload_to=soustredeni.models.generate_filename_konfera, verbose_name='prezentace')), | ||||||
|  |                 ('materialy', models.FileField(blank=True, help_text='Další materiály ke konfeře zabalené do jednoho souboru', upload_to=soustredeni.models.generate_filename_konfera, verbose_name='materialy')), | ||||||
|  |                 ('soustredeni', models.ForeignKey(to='soustredeni.soustredeni', verbose_name='soustředění', on_delete=models.SET_NULL, null=True, related_name='konfery')), | ||||||
|  |                 ('ucastnici', models.ManyToManyField(help_text='Seznam účastníků konfery', through='soustredeni.Konfery_Ucastnici', to='personalni.resitel', verbose_name='účastníci konfery')), | ||||||
|  |             ], | ||||||
|  |             options={ | ||||||
|  |                 'verbose_name': 'Konfera', | ||||||
|  |                 'verbose_name_plural': 'Konfery', | ||||||
|  |                 'db_table': 'seminar_konfera', | ||||||
|  |                 'managed': False, | ||||||
|  |             }, | ||||||
|  |             bases=('tvorba.problem',), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										17
									
								
								soustredeni/migrations/0009_tvorba_relink5.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								soustredeni/migrations/0009_tvorba_relink5.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 20:03 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('soustredeni', '0008_tvorba_relink4'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='konfera', | ||||||
|  |             options={'verbose_name': 'Konfera', 'verbose_name_plural': 'Konfery'}, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										14
									
								
								soustredeni/migrations/0010_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								soustredeni/migrations/0010_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 21:35 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('soustredeni', '0009_tvorba_relink5'), | ||||||
|  |         ('tvorba', '0003_tvorba_post'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |     ] | ||||||
							
								
								
									
										54
									
								
								tvorba/migrations/0002_tvorba_manage.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								tvorba/migrations/0002_tvorba_manage.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 21:29 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('tvorba', '0001_tvorba_create'), | ||||||
|  |         ('seminar', '0138_tvorba_delete'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='cislo', | ||||||
|  |             options={'ordering': ['-rocnik__rocnik', '-poradi'], 'verbose_name': 'Číslo', 'verbose_name_plural': 'Čísla'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='clanek', | ||||||
|  |             options={'verbose_name': 'Článek', 'verbose_name_plural': 'Články'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='deadline', | ||||||
|  |             options={'ordering': ['deadline'], 'verbose_name': 'Deadline', 'verbose_name_plural': 'Deadliny'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='pohadka', | ||||||
|  |             options={'ordering': ['vytvoreno'], 'verbose_name': 'Pohádka', 'verbose_name_plural': 'Pohádky'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='problem', | ||||||
|  |             options={'ordering': ['nazev'], 'verbose_name': 'Problém', 'verbose_name_plural': 'Problémy'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='problemy_opravovatele', | ||||||
|  |             options={}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='rocnik', | ||||||
|  |             options={'ordering': ['-rocnik'], 'verbose_name': 'Ročník', 'verbose_name_plural': 'Ročníky'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='tema', | ||||||
|  |             options={'verbose_name': 'Téma', 'verbose_name_plural': 'Témata'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='uloha', | ||||||
|  |             options={'verbose_name': 'Úloha', 'verbose_name_plural': 'Úlohy'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='zmrazenavysledkovka', | ||||||
|  |             options={'verbose_name': 'Zmražená výsledkovka', 'verbose_name_plural': 'Zmražené výsledkovky'}, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										13
									
								
								tvorba/migrations/0003_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tvorba/migrations/0003_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 21:34 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('tvorba', '0002_tvorba_manage'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |     ] | ||||||
|  | @ -31,7 +31,8 @@ from polymorphic.models import PolymorphicModel | ||||||
| 
 | 
 | ||||||
| from django.core.mail import EmailMessage | from django.core.mail import EmailMessage | ||||||
| 
 | 
 | ||||||
| from seminar.models import SeminarModelBase, OverwriteStorage | from seminar.models.base import SeminarModelBase | ||||||
|  | from seminar.models.tvorba import OverwriteStorage | ||||||
| from personalni.models import Prijemce, Organizator | from personalni.models import Prijemce, Organizator | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
|  | @ -44,7 +45,6 @@ class Rocnik(SeminarModelBase): | ||||||
| 		verbose_name = 'Ročník' | 		verbose_name = 'Ročník' | ||||||
| 		verbose_name_plural = 'Ročníky' | 		verbose_name_plural = 'Ročníky' | ||||||
| 		ordering = ['-rocnik'] | 		ordering = ['-rocnik'] | ||||||
| 		managed = False |  | ||||||
| 
 | 
 | ||||||
| 	# Interní ID | 	# Interní ID | ||||||
| 	id = models.AutoField(primary_key = True) | 	id = models.AutoField(primary_key = True) | ||||||
|  | @ -132,7 +132,6 @@ class Cislo(SeminarModelBase): | ||||||
| 		verbose_name = 'Číslo' | 		verbose_name = 'Číslo' | ||||||
| 		verbose_name_plural = 'Čísla' | 		verbose_name_plural = 'Čísla' | ||||||
| 		ordering = ['-rocnik__rocnik', '-poradi'] | 		ordering = ['-rocnik__rocnik', '-poradi'] | ||||||
| 		managed = False |  | ||||||
| 
 | 
 | ||||||
| 	# Interní ID | 	# Interní ID | ||||||
| 	id = models.AutoField(primary_key = True) | 	id = models.AutoField(primary_key = True) | ||||||
|  | @ -321,7 +320,6 @@ class Deadline(SeminarModelBase): | ||||||
| 		verbose_name = 'Deadline' | 		verbose_name = 'Deadline' | ||||||
| 		verbose_name_plural = 'Deadliny' | 		verbose_name_plural = 'Deadliny' | ||||||
| 		ordering = ['deadline'] | 		ordering = ['deadline'] | ||||||
| 		managed = False |  | ||||||
| 
 | 
 | ||||||
| 	def __init__(self, *args, **kwargs): | 	def __init__(self, *args, **kwargs): | ||||||
| 		super().__init__(*args, **kwargs) | 		super().__init__(*args, **kwargs) | ||||||
|  | @ -384,7 +382,6 @@ class ZmrazenaVysledkovka(SeminarModelBase): | ||||||
| 		db_table = 'seminar_vysledkovky' | 		db_table = 'seminar_vysledkovky' | ||||||
| 		verbose_name = 'Zmražená výsledkovka' | 		verbose_name = 'Zmražená výsledkovka' | ||||||
| 		verbose_name_plural = 'Zmražené výsledkovky' | 		verbose_name_plural = 'Zmražené výsledkovky' | ||||||
| 		managed = False |  | ||||||
| 
 | 
 | ||||||
| 	deadline = models.OneToOneField( | 	deadline = models.OneToOneField( | ||||||
| 		Deadline, | 		Deadline, | ||||||
|  | @ -403,7 +400,6 @@ class Problemy_Opravovatele(SeminarModelBase): | ||||||
| 	""" | 	""" | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		db_table = 'seminar_problemy_opravovatele' | 		db_table = 'seminar_problemy_opravovatele' | ||||||
| 		managed = False |  | ||||||
| 	 | 	 | ||||||
| 	id = models.AutoField(primary_key = True) | 	id = models.AutoField(primary_key = True) | ||||||
| 
 | 
 | ||||||
|  | @ -425,7 +421,6 @@ class Problem(SeminarModelBase,PolymorphicModel): | ||||||
| 		verbose_name = 'Problém' | 		verbose_name = 'Problém' | ||||||
| 		verbose_name_plural = 'Problémy' | 		verbose_name_plural = 'Problémy' | ||||||
| 		ordering = ['nazev'] | 		ordering = ['nazev'] | ||||||
| 		managed = False |  | ||||||
| 
 | 
 | ||||||
| 	# Interní ID | 	# Interní ID | ||||||
| 	id = models.AutoField(primary_key = True) | 	id = models.AutoField(primary_key = True) | ||||||
|  | @ -543,7 +538,6 @@ class Tema(Problem): | ||||||
| 		db_table = 'seminar_temata' | 		db_table = 'seminar_temata' | ||||||
| 		verbose_name = 'Téma' | 		verbose_name = 'Téma' | ||||||
| 		verbose_name_plural = 'Témata' | 		verbose_name_plural = 'Témata' | ||||||
| 		managed = False |  | ||||||
| 	 | 	 | ||||||
| 	TEMA_TEMA = 'tema' | 	TEMA_TEMA = 'tema' | ||||||
| 	TEMA_SERIAL = 'serial' | 	TEMA_SERIAL = 'serial' | ||||||
|  | @ -591,7 +585,6 @@ class Clanek(Problem): | ||||||
| 		db_table = 'seminar_clanky' | 		db_table = 'seminar_clanky' | ||||||
| 		verbose_name = 'Článek' | 		verbose_name = 'Článek' | ||||||
| 		verbose_name_plural = 'Články' | 		verbose_name_plural = 'Články' | ||||||
| 		managed = False |  | ||||||
| 	 | 	 | ||||||
| 	cislo = models.ForeignKey(Cislo, blank=True, null=True, on_delete=models.PROTECT, | 	cislo = models.ForeignKey(Cislo, blank=True, null=True, on_delete=models.PROTECT, | ||||||
| 		verbose_name='číslo vydání', related_name='vydane_clanky') | 		verbose_name='číslo vydání', related_name='vydane_clanky') | ||||||
|  | @ -617,7 +610,6 @@ class Uloha(Problem): | ||||||
| 		db_table = 'seminar_ulohy' | 		db_table = 'seminar_ulohy' | ||||||
| 		verbose_name = 'Úloha' | 		verbose_name = 'Úloha' | ||||||
| 		verbose_name_plural = 'Úlohy' | 		verbose_name_plural = 'Úlohy' | ||||||
| 		managed = False |  | ||||||
| 	 | 	 | ||||||
| 	cislo_zadani = models.ForeignKey(Cislo, verbose_name='číslo zadání', blank=True,  | 	cislo_zadani = models.ForeignKey(Cislo, verbose_name='číslo zadání', blank=True,  | ||||||
| 		null=True, related_name='zadane_ulohy', on_delete=models.PROTECT) | 		null=True, related_name='zadane_ulohy', on_delete=models.PROTECT) | ||||||
|  | @ -680,7 +672,6 @@ class Pohadka(SeminarModelBase): | ||||||
| 		verbose_name = 'Pohádka' | 		verbose_name = 'Pohádka' | ||||||
| 		verbose_name_plural = 'Pohádky' | 		verbose_name_plural = 'Pohádky' | ||||||
| 		ordering = ['vytvoreno'] | 		ordering = ['vytvoreno'] | ||||||
| 		managed = False |  | ||||||
| 
 | 
 | ||||||
| 	# Interní ID | 	# Interní ID | ||||||
| 	id = models.AutoField(primary_key=True) | 	id = models.AutoField(primary_key=True) | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								various/migrations/0006_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								various/migrations/0006_tvorba_post.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | # Generated by Django 4.2.16 on 2024-10-30 21:35 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('various', '0005_tvorba_relink'), | ||||||
|  |         ('tvorba', '0003_tvorba_post'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |     ] | ||||||
		Loading…
	
		Reference in a new issue
	
	 Pavel 'LEdoian' Turinsky
						Pavel 'LEdoian' Turinsky