Merge branch 'data_migrations' of gimli.ms.mff.cuni.cz:/akce/mam/git/mamweb into data_migrations
This commit is contained in:
commit
0425e368ed
17 changed files with 705 additions and 38 deletions
|
@ -87,3 +87,5 @@ LOGGING = {
|
||||||
|
|
||||||
# set to 'DEBUG' for EXTRA verbose output
|
# set to 'DEBUG' for EXTRA verbose output
|
||||||
# LOGGING['handlers']['console']['level'] = 'INFO'
|
# LOGGING['handlers']['console']['level'] = 'INFO'
|
||||||
|
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||||
|
|
|
@ -27,6 +27,7 @@ django-crispy-forms
|
||||||
django-imagekit
|
django-imagekit
|
||||||
django-polymorphic
|
django-polymorphic
|
||||||
django-sitetree
|
django-sitetree
|
||||||
|
django_reverse_admin
|
||||||
|
|
||||||
# Comments
|
# Comments
|
||||||
akismet==1.0.1
|
akismet==1.0.1
|
||||||
|
|
|
@ -1,20 +1,33 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
|
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
|
||||||
|
from reversion.admin import VersionAdmin
|
||||||
|
from django_reverse_admin import ReverseModelAdmin
|
||||||
|
|
||||||
# Todo: reversion
|
# Todo: reversion
|
||||||
|
|
||||||
import seminar.models as m
|
import seminar.models as m
|
||||||
|
|
||||||
admin.site.register(m.Osoba)
|
|
||||||
admin.site.register(m.Skola)
|
admin.site.register(m.Skola)
|
||||||
admin.site.register(m.Prijemce)
|
admin.site.register(m.Prijemce)
|
||||||
admin.site.register(m.Resitel)
|
|
||||||
admin.site.register(m.Rocnik)
|
admin.site.register(m.Rocnik)
|
||||||
admin.site.register(m.Cislo)
|
admin.site.register(m.Cislo)
|
||||||
admin.site.register(m.Organizator)
|
admin.site.register(m.Organizator)
|
||||||
admin.site.register(m.Soustredeni)
|
admin.site.register(m.Soustredeni)
|
||||||
|
|
||||||
|
@admin.register(m.Osoba)
|
||||||
|
class OsobaAdmin(admin.ModelAdmin):
|
||||||
|
actions = ['synchronizuj_maily']
|
||||||
|
|
||||||
|
def synchronizuj_maily(self, request, queryset):
|
||||||
|
for o in queryset:
|
||||||
|
if o.user is not None:
|
||||||
|
u = o.user
|
||||||
|
u.email = o.email
|
||||||
|
u.save()
|
||||||
|
self.message_user(request, "E-maily synchronizovány.")
|
||||||
|
synchronizuj_maily.short_description = "Synchronizuj vybraným osobám e-maily do uživatelů"
|
||||||
|
|
||||||
@admin.register(m.Problem)
|
@admin.register(m.Problem)
|
||||||
class ProblemAdmin(PolymorphicParentModelAdmin):
|
class ProblemAdmin(PolymorphicParentModelAdmin):
|
||||||
base_model = m.Problem
|
base_model = m.Problem
|
||||||
|
@ -39,11 +52,35 @@ class UlohaAdmin(PolymorphicChildModelAdmin):
|
||||||
base_model = m.Uloha
|
base_model = m.Uloha
|
||||||
show_in_index = True
|
show_in_index = True
|
||||||
|
|
||||||
|
class TextAdminInline(admin.TabularInline):
|
||||||
|
model = m.Text
|
||||||
|
exclude = ['text_zkraceny_set','text_zkraceny']
|
||||||
admin.site.register(m.Text)
|
admin.site.register(m.Text)
|
||||||
admin.site.register(m.Reseni)
|
|
||||||
admin.site.register(m.Hodnoceni)
|
class ResitelInline(admin.TabularInline):
|
||||||
|
model = m.Resitel
|
||||||
|
extra = 1
|
||||||
|
admin.site.register(m.Resitel)
|
||||||
|
|
||||||
|
class PrilohaReseniInline(admin.TabularInline):
|
||||||
|
model = m.PrilohaReseni
|
||||||
|
extra = 1
|
||||||
admin.site.register(m.PrilohaReseni)
|
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
|
||||||
|
inline_type = 'tabular'
|
||||||
|
inline_reverse = ['text_cely','resitele']
|
||||||
|
exclude = ['text_zkraceny', 'text_zkraceny_set']
|
||||||
|
inlines = [PrilohaReseniInline]
|
||||||
|
# FAIL in template
|
||||||
|
# inlines = [PrilohaReseniInline,Reseni_ResiteleInline]
|
||||||
|
|
||||||
|
admin.site.register(m.Hodnoceni)
|
||||||
admin.site.register(m.Pohadka)
|
admin.site.register(m.Pohadka)
|
||||||
admin.site.register(m.Konfera)
|
admin.site.register(m.Konfera)
|
||||||
admin.site.register(m.Obrazek)
|
admin.site.register(m.Obrazek)
|
||||||
|
@ -68,6 +105,17 @@ class TreeNodeAdmin(PolymorphicParentModelAdmin):
|
||||||
m.TextNode,
|
m.TextNode,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
actions = ['aktualizuj_nazvy']
|
||||||
|
|
||||||
|
# XXX: nejspíš je to totální DB HOG, nechcete to použít moc často.
|
||||||
|
def aktualizuj_nazvy(self, request, queryset):
|
||||||
|
newqs = queryset.get_real_instances()
|
||||||
|
for tn in newqs:
|
||||||
|
tn.aktualizuj_nazev()
|
||||||
|
tn.save()
|
||||||
|
self.message_user(request, "Názvy aktualizovány.")
|
||||||
|
aktualizuj_nazvy.short_description = "Aktualizuj vybraným TreeNodům názvy"
|
||||||
|
|
||||||
@admin.register(m.RocnikNode)
|
@admin.register(m.RocnikNode)
|
||||||
class RocnikNodeAdmin(PolymorphicChildModelAdmin):
|
class RocnikNodeAdmin(PolymorphicChildModelAdmin):
|
||||||
base_model = m.RocnikNode
|
base_model = m.RocnikNode
|
||||||
|
|
|
@ -121,3 +121,92 @@ class PrihlaskaForm(forms.Form):
|
||||||
self.add_error('skola_nazev',forms.ValidationError('Je nutné vyplnit název školy'))
|
self.add_error('skola_nazev',forms.ValidationError('Je nutné vyplnit název školy'))
|
||||||
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 EditForm(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(label='Telefon',max_length=256, required=False)
|
||||||
|
datum_narozeni = forms.DateField(label='Datum narození', required=False)
|
||||||
|
ulice = forms.CharField(label='Ulice', max_length=256, required=False)
|
||||||
|
mesto = forms.CharField(label='Město', max_length=256, required=False)
|
||||||
|
psc = forms.CharField(label='PSČ', max_length=32, required=False)
|
||||||
|
stat = forms.ChoiceField(label='Stát',
|
||||||
|
choices = (('CZ', 'Česká Republika'),
|
||||||
|
('SK', 'Slovenská Republika'),
|
||||||
|
('other', 'Jiné')),
|
||||||
|
required=False)
|
||||||
|
stat_text = forms.CharField(label='Stát', max_length=256, required=False)
|
||||||
|
|
||||||
|
skola = forms.ModelChoiceField(label="Škola",
|
||||||
|
queryset=Skola.objects.all(),
|
||||||
|
widget=autocomplete.ModelSelect2(
|
||||||
|
url='autocomplete_skola',
|
||||||
|
attrs = {'data-placeholder--id': '-1',
|
||||||
|
'data-placeholder--text' : '---',
|
||||||
|
'data-allow-clear': 'true'})
|
||||||
|
,required=False)
|
||||||
|
|
||||||
|
skola_nazev = forms.CharField(label='Název školy', max_length=256, required=False)
|
||||||
|
skola_adresa = forms.CharField(label='Adresa školy', max_length=256, required=False)
|
||||||
|
|
||||||
|
# trida = forms.CharField(label='Třída',max_length=10, required=True)
|
||||||
|
|
||||||
|
rok_maturity = forms.IntegerField(
|
||||||
|
label='Rok maturity',
|
||||||
|
min_value=date.today().year,
|
||||||
|
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)
|
||||||
|
spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
|
||||||
|
# def clean_username(self):
|
||||||
|
# err_logger = logging.getLogger('seminar.prihlaska.problem')
|
||||||
|
# username = self.cleaned_data.get('username')
|
||||||
|
# try:
|
||||||
|
# User.objects.get(username=username)
|
||||||
|
# msg = "Username {} exists".format(username)
|
||||||
|
# err_logger.info(msg)
|
||||||
|
# raise forms.ValidationError('Přihlašovací jméno je již použito')
|
||||||
|
#
|
||||||
|
# except ObjectDoesNotExist:
|
||||||
|
# pass
|
||||||
|
# return username
|
||||||
|
#
|
||||||
|
# def clean_email(self):
|
||||||
|
# err_logger = logging.getLogger('seminar.prihlaska.problem')
|
||||||
|
# email = self.cleaned_data.get('email')
|
||||||
|
# try:
|
||||||
|
# Osoba.objects.get(email=email)
|
||||||
|
# msg = "Email {} exists".format(email)
|
||||||
|
# err_logger.info(msg)
|
||||||
|
# raise forms.ValidationError('Email je již použit')
|
||||||
|
#
|
||||||
|
# except ObjectDoesNotExist:
|
||||||
|
# pass
|
||||||
|
# return email
|
||||||
|
#def clean(self):
|
||||||
|
# super().clean()
|
||||||
|
#
|
||||||
|
# err_logger = logging.getLogger('seminar.prihlaska.problem')
|
||||||
|
|
||||||
|
# data = self.cleaned_data
|
||||||
|
# if data.get('password') != data.get('password_check'):
|
||||||
|
# self.add_error('password_check',forms.ValidationError('Hesla se neshodují'))
|
||||||
|
# if data.get('stat') != '' and data.get('stat_text') != '':
|
||||||
|
# self.add_error('stat',forms.ValidationError('Nelze mít vybraný stát z menu a zároven zapsaný textem'))
|
||||||
|
# if data.get('skola') and (data.get('skola_nazev') or data.get('skola_adresa')):
|
||||||
|
# self.add_error('skola',forms.ValidationError('Pokud je škola v seznamu, nevypisujte ji ručně, pokud není, zrušte výběr ze seznamu (křížek vpravo)'))
|
||||||
|
# if not data.get('skola'):
|
||||||
|
# if data.get('skola_nazev')=='' and data.get('skola_adresa')=='':
|
||||||
|
# self.add_error('skola',forms.ValidationError('Je nutné vyplnit školu'))
|
||||||
|
# elif data.get('skola_nazev')=='':
|
||||||
|
# self.add_error('skola_nazev',forms.ValidationError('Je nutné vyplnit název školy'))
|
||||||
|
# elif data.get('skola_adresa')=='':
|
||||||
|
# self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy'))
|
||||||
|
|
23
seminar/migrations/0072_auto_20191204_2257.py
Normal file
23
seminar/migrations/0072_auto_20191204_2257.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 2.2.7 on 2019-12-04 21:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('seminar', '0071_remove_nastaveni_aktualni_rocnik'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='treenode',
|
||||||
|
name='srolovatelne',
|
||||||
|
field=models.BooleanField(blank=True, help_text='Bude na stránce témátka možnost tuto položku skrýt', null=True, verbose_name='Srolovatelné'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='treenode',
|
||||||
|
name='zajimave',
|
||||||
|
field=models.BooleanField(default=False, help_text='Zobrazí se daná věc na rozcestníku témátek', verbose_name='Zajímavé'),
|
||||||
|
),
|
||||||
|
]
|
22
seminar/migrations/0073_copy_osoba_email_to_user_email.py
Normal file
22
seminar/migrations/0073_copy_osoba_email_to_user_email.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 2.2.9 on 2020-01-15 21:28
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
def copy_mails(apps, schema_editor):
|
||||||
|
Osoba = apps.get_model('seminar', 'Osoba')
|
||||||
|
|
||||||
|
for o in Osoba.objects.all():
|
||||||
|
if o.user is not None:
|
||||||
|
u = o.user
|
||||||
|
u.email = o.email
|
||||||
|
u.save()
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('seminar', '0072_auto_20191204_2257'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(copy_mails, migrations.RunPython.noop)
|
||||||
|
]
|
|
@ -21,9 +21,9 @@ from taggit.managers import TaggableManager
|
||||||
|
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
from seminar.utils import roman
|
from seminar.utils import roman, FirstTagParser # Pro získání úryvku z TextNode
|
||||||
|
|
||||||
from unidecode import unidecode
|
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 polymorphic.models import PolymorphicModel
|
||||||
|
|
||||||
|
@ -130,6 +130,17 @@ class Osoba(SeminarModelBase):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.plne_jmeno()
|
return self.plne_jmeno()
|
||||||
|
|
||||||
|
# Overridujeme save Osoby, aby když si změní e-mail, aby se projevil i v
|
||||||
|
# Userovi (a tak se dal poslat mail s resetem hesla)
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if self.user is not None:
|
||||||
|
u = self.user
|
||||||
|
# U svatého tučňáka, prosím ať tohle funguje.
|
||||||
|
# (Takhle se kódit asi nemá...)
|
||||||
|
u.email = self.email
|
||||||
|
u.save()
|
||||||
|
super().save()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Mělo by být částečně vytaženo z Aesopa
|
# Mělo by být částečně vytaženo z Aesopa
|
||||||
# viz https://ovvp.mff.cuni.cz/wiki/aesop/export-skol.
|
# viz https://ovvp.mff.cuni.cz/wiki/aesop/export-skol.
|
||||||
|
@ -620,7 +631,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
|
||||||
id = models.AutoField(primary_key = True)
|
id = models.AutoField(primary_key = True)
|
||||||
|
|
||||||
# Název
|
# Název
|
||||||
nazev = models.CharField('název', max_length=256)
|
nazev = models.CharField('název', max_length=256) # Zveřejnitelný na stránky
|
||||||
|
|
||||||
# Problém má podproblémy
|
# Problém má podproblémy
|
||||||
nadproblem = models.ForeignKey('self', verbose_name='nadřazený problém',
|
nadproblem = models.ForeignKey('self', verbose_name='nadřazený problém',
|
||||||
|
@ -785,8 +796,11 @@ class Text(SeminarModelBase):
|
||||||
for tn in self.textnode_set.all():
|
for tn in self.textnode_set.all():
|
||||||
tn.save()
|
tn.save()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
parser = FirstTagParser()
|
||||||
|
parser.feed(str(self.na_web))
|
||||||
|
return parser.firstTag
|
||||||
|
|
||||||
class Uloha(Problem):
|
class Uloha(Problem):
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'seminar_ulohy'
|
db_table = 'seminar_ulohy'
|
||||||
|
@ -885,7 +899,7 @@ class Reseni(SeminarModelBase):
|
||||||
# Konfera
|
# Konfera
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{}: {}".format(self.resitel.osoba.plne_jmeno(), self.problem.nazev)
|
return "{}({}): {}({})".format(self.resitele.first(),len(self.resitele.all()), self.problem.first() ,len(self.problem.all()))
|
||||||
# NOTE: Potenciální DB HOG (bez select_related)
|
# NOTE: Potenciální DB HOG (bez select_related)
|
||||||
|
|
||||||
## Pravdepodobne uz nebude potreba:
|
## Pravdepodobne uz nebude potreba:
|
||||||
|
@ -1239,8 +1253,15 @@ class TreeNode(PolymorphicModel):
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
verbose_name="další element na stejné úrovni")
|
verbose_name="další element na stejné úrovni")
|
||||||
nazev = models.TextField("název tohoto node",
|
nazev = models.TextField("název tohoto node",
|
||||||
help_text = "Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode",
|
help_text = "Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode",
|
||||||
blank=False, null=True)
|
blank=False,
|
||||||
|
null=True) # Nezveřejnitelný název na stránky - pouze do adminu
|
||||||
|
zajimave = models.BooleanField(default = False,
|
||||||
|
verbose_name = "Zajímavé",
|
||||||
|
help_text = "Zobrazí se daná věc na rozcestníku témátek")
|
||||||
|
srolovatelne = models.BooleanField(null = True, blank = True,
|
||||||
|
verbose_name = "Srolovatelné",
|
||||||
|
help_text = "Bude na stránce témátka možnost tuto položku skrýt")
|
||||||
|
|
||||||
def print_tree(self,indent=0):
|
def print_tree(self,indent=0):
|
||||||
print("{}TreeNode({})".format(" "*indent,self.id))
|
print("{}TreeNode({})".format(" "*indent,self.id))
|
||||||
|
@ -1248,7 +1269,27 @@ class TreeNode(PolymorphicModel):
|
||||||
self.first_child.print_tree(indent=indent+2)
|
self.first_child.print_tree(indent=indent+2)
|
||||||
if self.succ:
|
if self.succ:
|
||||||
self.succ.print_tree(indent=indent)
|
self.succ.print_tree(indent=indent)
|
||||||
|
|
||||||
|
def getOdkazStr(self): # String na rozcestník
|
||||||
|
return self.first_child.getOdkazStr()
|
||||||
|
|
||||||
|
def getOdkaz(self): # ID HTML tagu, na který se bude scrollovat #{{self.getOdkaz}}
|
||||||
|
# Jsem si vědom, že tu potenciálně vznikají kolize.
|
||||||
|
# Přijdou mi natolik nepravděpodobné, že je neřeším
|
||||||
|
# Chtěl jsem ale hezké odkazy
|
||||||
|
string = unidecode(self.getOdkazStr())
|
||||||
|
returnVal = ""
|
||||||
|
i = 0
|
||||||
|
while len(returnVal) < 16: # Max 15 znaků
|
||||||
|
if i == len(string):
|
||||||
|
break
|
||||||
|
if string[i] == " ":
|
||||||
|
returnVal += "-"
|
||||||
|
if string[i].isalnum():
|
||||||
|
returnVal += string[i].lower()
|
||||||
|
i += 1
|
||||||
|
return returnVal
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.nazev:
|
if self.nazev:
|
||||||
return self.nazev
|
return self.nazev
|
||||||
|
@ -1260,6 +1301,9 @@ class TreeNode(PolymorphicModel):
|
||||||
self.aktualizuj_nazev()
|
self.aktualizuj_nazev()
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def aktualizuj_nazev(self):
|
||||||
|
raise NotImplementedError("Pokus o aktualizaci názvu obecného TreeNode místo konkrétní instance")
|
||||||
|
|
||||||
class RocnikNode(TreeNode):
|
class RocnikNode(TreeNode):
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'seminar_nodes_rocnik'
|
db_table = 'seminar_nodes_rocnik'
|
||||||
|
@ -1284,6 +1328,9 @@ class CisloNode(TreeNode):
|
||||||
def aktualizuj_nazev(self):
|
def aktualizuj_nazev(self):
|
||||||
self.nazev = "CisloNode: "+str(self.cislo)
|
self.nazev = "CisloNode: "+str(self.cislo)
|
||||||
|
|
||||||
|
def getOdkazStr(self):
|
||||||
|
return "Číslo " + str(self.cislo)
|
||||||
|
|
||||||
class MezicisloNode(TreeNode):
|
class MezicisloNode(TreeNode):
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'seminar_nodes_mezicislo'
|
db_table = 'seminar_nodes_mezicislo'
|
||||||
|
@ -1305,6 +1352,8 @@ class MezicisloNode(TreeNode):
|
||||||
else:
|
else:
|
||||||
print("!!!!! Nějaké neidentifikované mezičíslo !!!!!")
|
print("!!!!! Nějaké neidentifikované mezičíslo !!!!!")
|
||||||
self.nazev = "MezicisloNode: Neidentifikovatelné mezičíslo!"
|
self.nazev = "MezicisloNode: Neidentifikovatelné mezičíslo!"
|
||||||
|
def getOdkazStr(self):
|
||||||
|
return "Obsah dostupný pouze na webu"
|
||||||
|
|
||||||
class TemaVCisleNode(TreeNode):
|
class TemaVCisleNode(TreeNode):
|
||||||
""" Obsahuje příspěvky k tématu v daném čísle """
|
""" Obsahuje příspěvky k tématu v daném čísle """
|
||||||
|
@ -1319,6 +1368,9 @@ class TemaVCisleNode(TreeNode):
|
||||||
def aktualizuj_nazev(self):
|
def aktualizuj_nazev(self):
|
||||||
self.nazev = "TemaVCisleNode: "+str(self.tema)
|
self.nazev = "TemaVCisleNode: "+str(self.tema)
|
||||||
|
|
||||||
|
def getOdkazStr(self):
|
||||||
|
return str(self.tema)
|
||||||
|
|
||||||
class KonferaNode(TreeNode):
|
class KonferaNode(TreeNode):
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'seminar_nodes_konfera'
|
db_table = 'seminar_nodes_konfera'
|
||||||
|
@ -1347,6 +1399,10 @@ class ClanekNode(TreeNode):
|
||||||
def aktualizuj_nazev(self):
|
def aktualizuj_nazev(self):
|
||||||
self.nazev = "ClanekNode: "+str(self.clanek)
|
self.nazev = "ClanekNode: "+str(self.clanek)
|
||||||
|
|
||||||
|
def getOdkazStr(self):
|
||||||
|
return str(self.clanek)
|
||||||
|
|
||||||
|
|
||||||
class UlohaZadaniNode(TreeNode):
|
class UlohaZadaniNode(TreeNode):
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'seminar_nodes_uloha_zadani'
|
db_table = 'seminar_nodes_uloha_zadani'
|
||||||
|
@ -1361,6 +1417,10 @@ class UlohaZadaniNode(TreeNode):
|
||||||
def aktualizuj_nazev(self):
|
def aktualizuj_nazev(self):
|
||||||
self.nazev = "UlohaZadaniNode: "+str(self.uloha)
|
self.nazev = "UlohaZadaniNode: "+str(self.uloha)
|
||||||
|
|
||||||
|
def getOdkazStr(self):
|
||||||
|
return str(self.uloha)
|
||||||
|
|
||||||
|
|
||||||
class PohadkaNode(TreeNode):
|
class PohadkaNode(TreeNode):
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'seminar_nodes_pohadka'
|
db_table = 'seminar_nodes_pohadka'
|
||||||
|
@ -1388,6 +1448,10 @@ class UlohaVzorakNode(TreeNode):
|
||||||
def aktualizuj_nazev(self):
|
def aktualizuj_nazev(self):
|
||||||
self.nazev = "UlohaVzorakNode: "+str(self.uloha)
|
self.nazev = "UlohaVzorakNode: "+str(self.uloha)
|
||||||
|
|
||||||
|
def getOdkazStr(self):
|
||||||
|
return str(self.uloha)
|
||||||
|
|
||||||
|
|
||||||
class TextNode(TreeNode):
|
class TextNode(TreeNode):
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'seminar_nodes_obsah'
|
db_table = 'seminar_nodes_obsah'
|
||||||
|
@ -1400,6 +1464,10 @@ class TextNode(TreeNode):
|
||||||
def aktualizuj_nazev(self):
|
def aktualizuj_nazev(self):
|
||||||
self.nazev = "TextNode: "+str(self.text)
|
self.nazev = "TextNode: "+str(self.text)
|
||||||
|
|
||||||
|
def getOdkazStr(self):
|
||||||
|
return str(self.text)
|
||||||
|
|
||||||
|
|
||||||
## FIXME: Logiku přesunout do views.
|
## FIXME: Logiku přesunout do views.
|
||||||
#class VysledkyBase(SeminarModelBase):
|
#class VysledkyBase(SeminarModelBase):
|
||||||
#
|
#
|
||||||
|
@ -1491,6 +1559,7 @@ class Nastaveni(SingletonModel):
|
||||||
aktualni_cislo = models.ForeignKey(Cislo, verbose_name='poslední vydané číslo',
|
aktualni_cislo = models.ForeignKey(Cislo, verbose_name='poslední vydané číslo',
|
||||||
null=False, on_delete=models.PROTECT)
|
null=False, on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
@property
|
||||||
def aktualni_rocnik(self):
|
def aktualni_rocnik(self):
|
||||||
return self.aktualni_cislo.rocnik
|
return self.aktualni_cislo.rocnik
|
||||||
|
|
||||||
|
@ -1534,3 +1603,35 @@ class Novinky(models.Model):
|
||||||
return '[' + str(self.datum) + '] ' + self.text[0:50]
|
return '[' + str(self.datum) + '] ' + self.text[0:50]
|
||||||
else:
|
else:
|
||||||
return '[' + str(self.datum) + '] '
|
return '[' + str(self.datum) + '] '
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME: Tohle nepatří do aplikace 'seminar'
|
||||||
|
# Nefunkční alternativa vestavěného Usera, který má jméno a mail v přidružené Osobě
|
||||||
|
# from django.contrib.auth.models import User as Django_User
|
||||||
|
#
|
||||||
|
# class Uzivatel(Django_User):
|
||||||
|
# class Meta:
|
||||||
|
# proxy = True
|
||||||
|
#
|
||||||
|
# @property
|
||||||
|
# def first_name(self):
|
||||||
|
# osoby = Osoba.objects.filter(user=self)
|
||||||
|
# if len(osoby) == 0:
|
||||||
|
# return None
|
||||||
|
# return osoby.first().krestni_jmeno
|
||||||
|
#
|
||||||
|
# @property
|
||||||
|
# def last_name(self):
|
||||||
|
# osoby = Osoba.objects.filter(user=self)
|
||||||
|
# if len(osoby) == 0:
|
||||||
|
# return None
|
||||||
|
# return osoby.first().prijmeni
|
||||||
|
#
|
||||||
|
# @property
|
||||||
|
# def email(self):
|
||||||
|
# osoby = Osoba.objects.filter(user=self)
|
||||||
|
# if len(osoby) == 0:
|
||||||
|
# return None
|
||||||
|
# return osoby.first().email
|
||||||
|
|
78
seminar/templates/seminar/edit.html
Normal file
78
seminar/templates/seminar/edit.html
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
{% extends "seminar/zadani/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/prihlaska.js' %}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>
|
||||||
|
{% block nadpis1a %}{% block nadpis1b %}
|
||||||
|
Změna osobních údajů
|
||||||
|
{% endblock %}{% endblock %}
|
||||||
|
</h1>
|
||||||
|
<form action="{% url 'seminar_resitel_edit' %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{form.non_field_errors}}
|
||||||
|
<ul class="form">
|
||||||
|
<li>
|
||||||
|
Přihlašovací údaje
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.username %}
|
||||||
|
</li><li>
|
||||||
|
Osobní údaje
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.jmeno %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.prijmeni %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.pohlavi_muz%}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.email %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.telefon %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.datum_narozeni %}
|
||||||
|
</li><li>
|
||||||
|
<hr>
|
||||||
|
Bydliště
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.ulice %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.mesto %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.psc %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.stat %}
|
||||||
|
</li>
|
||||||
|
<li id="id_li_stat_text">
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.stat_text %}
|
||||||
|
</li><li>
|
||||||
|
<hr>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.skola %}
|
||||||
|
</li><li>
|
||||||
|
<button id="id_skola_text_button" type="button">Škola není v seznamu</button>
|
||||||
|
</li>
|
||||||
|
<li id="id_li_skola_nazev">
|
||||||
|
Vyplň prosím celý název a adresu školy.<br>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.skola_nazev %}
|
||||||
|
</li>
|
||||||
|
<li id="id_li_skola_adresa">
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.skola_adresa %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.rok_maturity %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.zasilat %}
|
||||||
|
</li><li>
|
||||||
|
{% include "seminar/prihlaska_field.html" with field=form.spam %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<input type="submit" value="Změnit">
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
$("#id_stat").on("change",addrCountryChanged);
|
||||||
|
$("#id_skola_text_button").on("click",schoolNotInList);
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -8,20 +8,13 @@
|
||||||
Přihlášení
|
Přihlášení
|
||||||
{% endblock %}{% endblock %}
|
{% endblock %}{% endblock %}
|
||||||
</h1>
|
</h1>
|
||||||
{% if login_error %}
|
|
||||||
<span class="field_error">{{login_error}}<span>
|
|
||||||
{% endif %}
|
|
||||||
<form action="{% url 'login' %}" method="post">
|
<form action="{% url 'login' %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{form.non_field_errors}}
|
|
||||||
<ul class="form">
|
<ul class="form">
|
||||||
<li>
|
{{ form.as_ul }}
|
||||||
{% include "seminar/prihlaska_field.html" with field=form.username %}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
{% include "seminar/prihlaska_field.html" with field=form.password %}
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
{# Django si posílá jméno další stránky jako obsah formuláře a výchozí hodnota (mi přišlo, že) nejde změnit... #}
|
||||||
|
<input type="hidden" name='next' value="{{ next }}">
|
||||||
<input type="submit" value="Přihlásit">
|
<input type="submit" value="Přihlásit">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
18
seminar/templates/seminar/logout.html
Normal file
18
seminar/templates/seminar/logout.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends "seminar/zadani/base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>
|
||||||
|
{% block nadpis1a %}{% block nadpis1b %}
|
||||||
|
Odhlášení
|
||||||
|
{% endblock %}{% endblock %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
Byl jsi úspěšně odhlášen
|
||||||
|
{# Tohle by se asi mělo udělat přes kontext (title), ale kašlu na to, stejně je to jen jednojazyčná stránka #}
|
||||||
|
|
||||||
|
{# TODO: odkaz na znovupřihlášení? #}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
30
seminar/templates/seminar/org/obalkovani.html
Normal file
30
seminar/templates/seminar/org/obalkovani.html
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>
|
||||||
|
{% block nadpis1a %}{% block nadpis1b %}
|
||||||
|
Obálkování {{ cislo }}
|
||||||
|
{% endblock %}{% endblock %}
|
||||||
|
</h1>
|
||||||
|
<ul>
|
||||||
|
{% for reseni in object_list %}
|
||||||
|
{% ifchanged reseni.resitele %}
|
||||||
|
{% if not forloop.first %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
<h4>{% for resitel in reseni.resitele.all %}{{resitel.osoba}},{% endfor %}</h4>
|
||||||
|
<ul>
|
||||||
|
{% endifchanged %}
|
||||||
|
|
||||||
|
<li>Celkem {{reseni.hodnoceni__body__sum}} bodů z {{reseni.hodnoceni__count}} hodnocení
|
||||||
|
<ul>
|
||||||
|
{% for h in reseni.hodnoceni_set.all %}
|
||||||
|
<li> {{ h.problem }}: {{ h.body }}b </li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %}
|
14
seminar/templates/seminar/tematka/rozcestnik.html
Normal file
14
seminar/templates/seminar/tematka/rozcestnik.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% for tematko in tematka %}
|
||||||
|
<h1>{{tematko.nazev}}</h1>
|
||||||
|
<p>{{tematko.abstrakt}}</p>
|
||||||
|
<ul>
|
||||||
|
{% for cislo in tematko.cisla %}
|
||||||
|
<li><a href="/{{rocnik}}/t{{tematko.kod}}/#{{cislo.0.1}}">{{cislo.0.0}}</a></li>
|
||||||
|
<ul>
|
||||||
|
{% for odkaz in cislo.1 %}
|
||||||
|
<li><a href="/{{rocnik}}/t{{tematko.kod}}/#{{odkaz.1}}">{{odkaz.0}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
1
seminar/templates/seminar/tematka/toaletak.html
Normal file
1
seminar/templates/seminar/tematka/toaletak.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Stránká témátka
|
|
@ -380,7 +380,8 @@ def gen_temata(rnd, rocniky, rocnik_cisla, organizatori):
|
||||||
kod=str(n),
|
kod=str(n),
|
||||||
# atributy třídy Téma
|
# atributy třídy Téma
|
||||||
tema_typ=rnd.choice(Tema.TEMA_CHOICES)[0],
|
tema_typ=rnd.choice(Tema.TEMA_CHOICES)[0],
|
||||||
rocnik=rocnik
|
rocnik=rocnik,
|
||||||
|
abstrakt = "Abstrakt tematka {}".format(n)
|
||||||
)
|
)
|
||||||
konec_tematu = min(rnd.randint(ci, 7), len(cisla))
|
konec_tematu = min(rnd.randint(ci, 7), len(cisla))
|
||||||
for i in range(ci, konec_tematu+1):
|
for i in range(ci, konec_tematu+1):
|
||||||
|
|
|
@ -8,6 +8,9 @@ from django.contrib.auth import views as auth_views
|
||||||
staff_member_required = user_passes_test(lambda u: u.is_staff)
|
staff_member_required = user_passes_test(lambda u: u.is_staff)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('aktualni/temata/', views.TemataRozcestnikView),
|
||||||
|
path('<int:rocnik>/t<int:tematko>/', views.TematkoView),
|
||||||
|
|
||||||
# REDIRECTy
|
# REDIRECTy
|
||||||
path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')),
|
path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')),
|
||||||
|
|
||||||
|
@ -86,24 +89,30 @@ urlpatterns = [
|
||||||
path('stav',
|
path('stav',
|
||||||
staff_member_required(views.StavDatabazeView), name='stav_databaze'),
|
staff_member_required(views.StavDatabazeView), name='stav_databaze'),
|
||||||
path('cislo/<int:rocnik>.<int:cislo>/obalkovani',
|
path('cislo/<int:rocnik>.<int:cislo>/obalkovani',
|
||||||
staff_member_required(views.obalkovaniView), name='seminar_cislo_resitel_obalkovani'),
|
staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'),
|
||||||
path('cislo/<int:rocnik>.<int:cislo>/tex-download.json',
|
path('cislo/<int:rocnik>.<int:cislo>/tex-download.json',
|
||||||
staff_member_required(views.texDownloadView), name='seminar_tex_download'),
|
staff_member_required(views.texDownloadView), name='seminar_tex_download'),
|
||||||
path('soustredeni/<int:soustredeni>/obalky.pdf',
|
path('soustredeni/<int:soustredeni>/obalky.pdf',
|
||||||
staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'),
|
staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'),
|
||||||
|
|
||||||
path('tex-upload/login/', views.LoginView, name='seminar_login'),
|
path('tex-upload/login/', views.TeXUploadLoginView, name='seminar_login'),
|
||||||
path(
|
path(
|
||||||
'tex-upload/',
|
'tex-upload/',
|
||||||
staff_member_required(views.texUploadView),
|
staff_member_required(views.texUploadView),
|
||||||
name='seminar_tex_upload'
|
name='seminar_tex_upload'
|
||||||
),
|
),
|
||||||
|
path('org/vloz_body/<int:tema>/',
|
||||||
|
staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'),
|
||||||
path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'),
|
path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'),
|
||||||
path('auth/login/', views.loginView, name='login'),
|
path('auth/login/', views.LoginView.as_view(), name='login'),
|
||||||
path('auth/logout/', views.logoutView, name='logout'),
|
path('auth/logout/', views.LogoutView.as_view(), name='logout'),
|
||||||
path('auth/resitel/', views.ResitelView.as_view(), name='seminar_resitel'),
|
path('auth/resitel/', views.ResitelView.as_view(), name='seminar_resitel'),
|
||||||
path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'),
|
path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'),
|
||||||
path('auth/reset_password', views.resetPasswordView, name='reset_password'),
|
path('auth/reset_password/', views.PasswordResetView.as_view(), name='reset_password'),
|
||||||
|
path('auth/change_password/', views.PasswordChangeView.as_view(), name='change_password'),
|
||||||
|
path('auth/reset_password_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'),
|
||||||
|
path('auth/reset_password_confirm/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
|
||||||
|
path('auth/reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'),
|
||||||
path('auth/resitel_edit', views.resitelEditView, name='seminar_resitel_edit'),
|
path('auth/resitel_edit', views.resitelEditView, name='seminar_resitel_edit'),
|
||||||
path('', views.TitulniStranaView.as_view(), name='titulni_strana'),
|
path('', views.TitulniStranaView.as_view(), name='titulni_strana'),
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,18 @@
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
staff_member_required = user_passes_test(lambda u: u.is_staff)
|
staff_member_required = user_passes_test(lambda u: u.is_staff)
|
||||||
|
|
||||||
|
class FirstTagParser(HTMLParser):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.firstTag = None
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
def handle_data(self, data):
|
||||||
|
if self.firstTag == None:
|
||||||
|
self.firstTag = data
|
||||||
|
|
||||||
def histogram(seznam):
|
def histogram(seznam):
|
||||||
d = {}
|
d = {}
|
||||||
for i in seznam:
|
for i in seznam:
|
||||||
|
|
244
seminar/views.py
244
seminar/views.py
|
@ -2,24 +2,26 @@
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse,reverse_lazy
|
||||||
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
|
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect
|
from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect
|
||||||
from django.db.models import Q
|
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.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.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from dal import autocomplete
|
from dal import autocomplete
|
||||||
|
|
||||||
from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola
|
import seminar.models as s
|
||||||
|
from .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 . import utils
|
from . import utils
|
||||||
from .unicodecsv import UnicodeWriter
|
from .unicodecsv import UnicodeWriter
|
||||||
from .forms import PrihlaskaForm, LoginForm
|
from .forms import PrihlaskaForm, LoginForm, EditForm
|
||||||
|
|
||||||
from datetime import timedelta, date, datetime
|
from datetime import timedelta, date, datetime
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -43,6 +45,45 @@ def verejna_temata(rocnik):
|
||||||
"""
|
"""
|
||||||
return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod')
|
return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod')
|
||||||
|
|
||||||
|
def temata_v_rocniku(rocnik):
|
||||||
|
return Problem.objects.filter(typ=Problem.TYP_TEMA, rocnik=rocnik)
|
||||||
|
|
||||||
|
def get_problemy_k_tematu(tema):
|
||||||
|
return Problemy.objects.filter(nadproblem = tema)
|
||||||
|
|
||||||
|
|
||||||
|
class VlozBodyView(generic.ListView):
|
||||||
|
template_name = 'seminar/org/vloz_body.html'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
self.tema = get_object_or_404(Problem,id=self.kwargs['tema'])
|
||||||
|
print(self.tema)
|
||||||
|
self.problemy = Problem.objects.filter(nadproblem = self.tema)
|
||||||
|
print(self.problemy)
|
||||||
|
self.reseni = Reseni.objects.filter(problem__in=self.problemy)
|
||||||
|
print(self.reseni)
|
||||||
|
return self.reseni
|
||||||
|
|
||||||
|
|
||||||
|
class ObalkovaniView(generic.ListView):
|
||||||
|
template_name = 'seminar/org/obalkovani.html'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
rocnik = get_object_or_404(Rocnik,rocnik=self.kwargs['rocnik'])
|
||||||
|
cislo = get_object_or_404(Cislo,rocnik=rocnik,poradi=self.kwargs['cislo'])
|
||||||
|
self.cislo = cislo
|
||||||
|
self.hodnoceni = s.Hodnoceni.objects.filter(cislo_body=cislo)
|
||||||
|
self.reseni = Reseni.objects.filter(hodnoceni__in = self.hodnoceni).annotate(Sum('hodnoceni__body')).annotate(Count('hodnoceni')).order_by('resitele__osoba')
|
||||||
|
return self.reseni
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(ObalkovaniView, self).get_context_data(**kwargs)
|
||||||
|
print(self.cislo)
|
||||||
|
context['cislo'] = self.cislo
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def AktualniZadaniView(request):
|
def AktualniZadaniView(request):
|
||||||
nastaveni = get_object_or_404(Nastaveni)
|
nastaveni = get_object_or_404(Nastaveni)
|
||||||
|
@ -73,6 +114,99 @@ def ZadaniTemataView(request):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO Napsat tuto funkci znovu rekurzivně podle Jethrorad. Potom se podívat, jak lehce se dá modifikovat pro Rozcestník. Pokud lehce, rozšířit ji. Pokud složitě - použít tuhle
|
||||||
|
def vytahniZLesaSeznam(tematko, koren, pouze_zajimave=False):
|
||||||
|
returnVal = []
|
||||||
|
|
||||||
|
stack = []
|
||||||
|
stack.append((koren.first_child, 0, False)) #Tuple of node, depth and relevance
|
||||||
|
|
||||||
|
while len(stack) > 0:
|
||||||
|
wn, wd, wr = stack.pop()
|
||||||
|
|
||||||
|
if wn.succ != None:
|
||||||
|
stack.append((wn.succ, wd, wr))
|
||||||
|
if isinstance(wn, s.TemaVCisleNode):
|
||||||
|
print("TEMA")
|
||||||
|
print(wn.tema.id)
|
||||||
|
print(tematko.id)
|
||||||
|
if wn.tema.id == tematko.id:
|
||||||
|
returnVal.append((posledni_cislo, 0))
|
||||||
|
print("PRIDANO")
|
||||||
|
wr = True
|
||||||
|
wd = 1
|
||||||
|
|
||||||
|
if wn.srolovatelne:
|
||||||
|
tagOpen = s.Text(na_web = "Otevírací srolovací tag")
|
||||||
|
tagOpenNode = s.TextNode(text = tagOpen)
|
||||||
|
tagClose = s.Text(na_web = "Zavírací srolovací tag")
|
||||||
|
tagCloseNode = s.TextNode(text = tagClose)
|
||||||
|
stack.append((tagCloseNode, wd, True))
|
||||||
|
|
||||||
|
if wn.first_child != None:
|
||||||
|
stack.append((wn.first_child, wd + 1, wr))
|
||||||
|
|
||||||
|
if isinstance(wn, s.CisloNode):
|
||||||
|
posledni_cislo = wn
|
||||||
|
print(wn)
|
||||||
|
|
||||||
|
if wr:
|
||||||
|
print("ZAJIMAVE")
|
||||||
|
if pouze_zajimave:
|
||||||
|
if not wn.zajimave:
|
||||||
|
continue
|
||||||
|
returnVal.append((wn, wd))
|
||||||
|
return returnVal
|
||||||
|
|
||||||
|
def TematkoView(request, rocnik, tematko):
|
||||||
|
nastaveni = s.Nastaveni.objects.first()
|
||||||
|
rocnik_object = s.Rocnik.objects.filter(rocnik=rocnik)
|
||||||
|
tematko_object = s.Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko)
|
||||||
|
seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode)
|
||||||
|
for node, depth in seznam:
|
||||||
|
if node.isinstance(node, s.KonferaNode):
|
||||||
|
raise Exception("Not implemented yet")
|
||||||
|
if node.isinstance(node, s.PohadkaNode): # Mohu ignorovat, má pod sebou
|
||||||
|
pass
|
||||||
|
|
||||||
|
return render(request, 'seminar/tematka/toaletak.html', {})
|
||||||
|
|
||||||
|
|
||||||
|
def TemataRozcestnikView(request):
|
||||||
|
print("=============================================")
|
||||||
|
nastaveni = s.Nastaveni.objects.first()
|
||||||
|
tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik())
|
||||||
|
tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku
|
||||||
|
for tematko_object in tematka_objects:
|
||||||
|
print("AKTUALNI TEMATKO")
|
||||||
|
print(tematko_object.id)
|
||||||
|
odkazy = vytahniZLesaSeznam(tematko_object, nastaveni.aktualni_rocnik().rocniknode, pouze_zajimave = True) #Odkazy jsou tuply (node, depth) v listu
|
||||||
|
print(odkazy)
|
||||||
|
cisla = [] # List tuplů (nazev cisla, list odkazů)
|
||||||
|
vcisle = []
|
||||||
|
cislo = None
|
||||||
|
for odkaz in odkazy:
|
||||||
|
if odkaz[1] == 0:
|
||||||
|
if cislo != None:
|
||||||
|
cisla.append((cislo, vcisle))
|
||||||
|
cislo = (odkaz[0].getOdkazStr(), odkaz[0].getOdkaz())
|
||||||
|
vcisle = []
|
||||||
|
else:
|
||||||
|
print(odkaz[0].getOdkaz())
|
||||||
|
vcisle.append((odkaz[0].getOdkazStr(), odkaz[0].getOdkaz()))
|
||||||
|
if cislo != None:
|
||||||
|
cisla.append((cislo, vcisle))
|
||||||
|
|
||||||
|
print(cisla)
|
||||||
|
tematka.append({
|
||||||
|
"kod" : tematko_object.kod,
|
||||||
|
"nazev" : tematko_object.nazev,
|
||||||
|
"abstrakt" : tematko_object.abstrakt,
|
||||||
|
"obrazek": tematko_object.obrazek,
|
||||||
|
"cisla" : cisla
|
||||||
|
})
|
||||||
|
return render(request, 'seminar/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik})
|
||||||
|
|
||||||
|
|
||||||
#def ZadaniAktualniVysledkovkaView(request):
|
#def ZadaniAktualniVysledkovkaView(request):
|
||||||
# nastaveni = get_object_or_404(Nastaveni)
|
# nastaveni = get_object_or_404(Nastaveni)
|
||||||
|
@ -672,7 +806,7 @@ def obalkyView(request,resitele):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def obalkovaniView(request, rocnik, cislo):
|
def oldObalkovaniView(request, rocnik, cislo):
|
||||||
rocnik = Rocnik.objects.get(rocnik=rocnik)
|
rocnik = Rocnik.objects.get(rocnik=rocnik)
|
||||||
cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo)
|
cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo)
|
||||||
|
|
||||||
|
@ -809,7 +943,7 @@ def StavDatabazeView(request):
|
||||||
|
|
||||||
|
|
||||||
@ensure_csrf_cookie
|
@ensure_csrf_cookie
|
||||||
def LoginView(request):
|
def TeXUploadLoginView(request):
|
||||||
"""Pro přihlášení při nahrávání z texu"""
|
"""Pro přihlášení při nahrávání z texu"""
|
||||||
q = request.POST
|
q = request.POST
|
||||||
# nastavení cookie csrftoken
|
# nastavení cookie csrftoken
|
||||||
|
@ -1016,8 +1150,6 @@ class ResitelView(LoginRequiredMixin,generic.DetailView):
|
||||||
return Resitel.objects.get(osoba__user=self.request.user)
|
return Resitel.objects.get(osoba__user=self.request.user)
|
||||||
|
|
||||||
## Formulare
|
## Formulare
|
||||||
def resitelEditView(request):
|
|
||||||
pass
|
|
||||||
def resetPasswordView(request):
|
def resetPasswordView(request):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1054,6 +1186,59 @@ def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data):
|
||||||
logger.warn(msg)
|
logger.warn(msg)
|
||||||
gdpr_logger.warn(msg+", form:{}".format(form_data))
|
gdpr_logger.warn(msg+", form:{}".format(form_data))
|
||||||
|
|
||||||
|
from django.forms.models import model_to_dict
|
||||||
|
def resitelEditView(request):
|
||||||
|
err_logger = logging.getLogger('seminar.prihlaska.problem')
|
||||||
|
## Načtení objektu Osoba a Resitel, patrici k aktuálně přihlášenému uživately
|
||||||
|
u = request.user
|
||||||
|
osoba_edit = Osoba.objects.get(user=u)
|
||||||
|
resitel_edit = osoba_edit.resitel
|
||||||
|
user_edit = osoba_edit.user
|
||||||
|
## Vytvoření slovníku, kterým předvyplním formulář
|
||||||
|
prefill_1=model_to_dict(user_edit)
|
||||||
|
prefill_2=model_to_dict(resitel_edit)
|
||||||
|
prefill_3=model_to_dict(osoba_edit)
|
||||||
|
prefill_1.update(prefill_2)
|
||||||
|
prefill_1.update(prefill_3)
|
||||||
|
form = EditForm(initial=prefill_1)
|
||||||
|
## Změna údajů a jejich uložení
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = EditForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
## Změny v osobě
|
||||||
|
fcd = form.cleaned_data
|
||||||
|
osoba_edit.jmeno = fcd['jmeno']
|
||||||
|
osoba_edit.prijmeni = fcd['prijmeni']
|
||||||
|
osoba_edit.pohlavi_muz = fcd['pohlavi_muz']
|
||||||
|
osoba_edit.email = fcd['email']
|
||||||
|
osoba_edit.telefon = fcd['telefon']
|
||||||
|
osoba_edit.ulice = fcd['ulice']
|
||||||
|
osoba_edit.mesto = fcd['mesto']
|
||||||
|
osoba_edit.psc = fcd['psc']
|
||||||
|
## Změny v osobě s podmínkami
|
||||||
|
if fcd.get('spam',False):
|
||||||
|
osoba_edit.datum_souhlasu_zasilani = date.today()
|
||||||
|
if fcd.get('stat','') in ('CZ','SK'):
|
||||||
|
osoba_edit.stat = fcd['stat']
|
||||||
|
else:
|
||||||
|
## Neznámá země
|
||||||
|
msg = "Unknown country {}".format(fcd['stat_text'])
|
||||||
|
|
||||||
|
## Změny v řešiteli
|
||||||
|
resitel_edit.skola = fcd['skola']
|
||||||
|
resitel_edit.rok_maturity = fcd['rok_maturity']
|
||||||
|
resitel_edit.zasilat = fcd['zasilat']
|
||||||
|
if fcd.get('skola'):
|
||||||
|
resitel_edit.skola = fcd['skola']
|
||||||
|
else:
|
||||||
|
# Unknown school - log it
|
||||||
|
msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa'])
|
||||||
|
resitel_edit.save()
|
||||||
|
osoba_edit.save()
|
||||||
|
return HttpResponseRedirect('/thanks/')
|
||||||
|
else:
|
||||||
|
## Stránka před odeslaním formuláře = předvyplněný formulář
|
||||||
|
return render(request, 'seminar/edit.html', {'form': form})
|
||||||
|
|
||||||
def prihlaskaView(request):
|
def prihlaskaView(request):
|
||||||
generic_logger = logging.getLogger('seminar.prihlaska')
|
generic_logger = logging.getLogger('seminar.prihlaska')
|
||||||
|
@ -1159,3 +1344,46 @@ class SkolaAutocomplete(autocomplete.Select2QuerySetView):
|
||||||
# Q(user__last_name__isstartswith=query))
|
# Q(user__last_name__isstartswith=query))
|
||||||
#
|
#
|
||||||
# return qs
|
# return qs
|
||||||
|
|
||||||
|
# FIXME: Tohle asi vlastně vůbec nepatří do aplikace 'seminar'
|
||||||
|
class LoginView(auth_views.LoginView):
|
||||||
|
# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL
|
||||||
|
template_name = 'seminar/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('titulni_strana')
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
class LogoutView(auth_views.LogoutView):
|
||||||
|
# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL
|
||||||
|
template_name = 'seminar/logout.html'
|
||||||
|
# Pavel: Vůbec nevím, proč to s _lazy funguje, ale bez toho to bylo rozbité.
|
||||||
|
next_page = reverse_lazy('titulni_strana')
|
||||||
|
|
||||||
|
# "Chci resetovat heslo"
|
||||||
|
class PasswordResetView(auth_views.PasswordResetView):
|
||||||
|
#template_name = 'seminar/password_reset.html'
|
||||||
|
# TODO: vlastní email_template_name a subject_template_name a html_email_template_name
|
||||||
|
success_url = reverse_lazy('reset_password_done')
|
||||||
|
from_email = 'login@mam.mff.cuni.cz'
|
||||||
|
|
||||||
|
# "Poslali jsme e-mail (pokud bylo kam))"
|
||||||
|
class PasswordResetDoneView(auth_views.PasswordResetDoneView):
|
||||||
|
#template_name = 'seminar/password_reset_done.html'
|
||||||
|
pass
|
||||||
|
|
||||||
|
# "Vymysli si heslo"
|
||||||
|
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
|
||||||
|
#template_name = 'seminar/password_confirm_done.html'
|
||||||
|
success_url = reverse_lazy('reset_password_complete')
|
||||||
|
|
||||||
|
# "Heslo se asi změnilo."
|
||||||
|
class PasswordResetCompleteView(auth_views.PasswordResetCompleteView):
|
||||||
|
#template_name = 'seminar/password_complete_done.html'
|
||||||
|
pass
|
||||||
|
|
||||||
|
class PasswordChangeView(auth_views.PasswordChangeView):
|
||||||
|
#template_name = 'seminar/password_change.html'
|
||||||
|
success_url = reverse_lazy('titulni_strana')
|
||||||
|
|
Loading…
Reference in a new issue