diff --git a/seminar/forms.py b/seminar/forms.py
index 29e6607e..b28beeb9 100644
--- a/seminar/forms.py
+++ b/seminar/forms.py
@@ -123,23 +123,10 @@ class PrihlaskaForm(forms.Form):
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,
- help_text='Tímto jménem se následně budeš přihlašovat pro odevzdání řešení a další činnosti v semináři')
- password = forms.CharField(
- label='Heslo',
- max_length=256,
- required=False,
- widget=forms.PasswordInput())
- password_check = forms.CharField(
- label='Ověření hesla',
- max_length=256,
- required=False,
- widget=forms.PasswordInput())
+ required=True)
jmeno = forms.CharField(label='Jméno', max_length=256, required=True)
prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True)
@@ -178,7 +165,6 @@ class EditForm(forms.Form):
max_value=date.today().year+8,
required=True)
zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True)
- gdpr = forms.BooleanField(label='Souhlasím se zpracováním osobních údajů', 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')
diff --git a/seminar/migrations/0072_auto_20191204_2257.py b/seminar/migrations/0072_auto_20191204_2257.py
new file mode 100644
index 00000000..f96b670a
--- /dev/null
+++ b/seminar/migrations/0072_auto_20191204_2257.py
@@ -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é'),
+ ),
+ ]
diff --git a/seminar/models.py b/seminar/models.py
index 691c04af..60bc361e 100644
--- a/seminar/models.py
+++ b/seminar/models.py
@@ -21,9 +21,9 @@ from taggit.managers import TaggableManager
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
@@ -620,7 +620,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
id = models.AutoField(primary_key = True)
# 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
nadproblem = models.ForeignKey('self', verbose_name='nadřazený problém',
@@ -785,8 +785,11 @@ class Text(SeminarModelBase):
for tn in self.textnode_set.all():
tn.save()
-
-
+ def __str__(self):
+ parser = FirstTagParser()
+ parser.feed(str(self.na_web))
+ return parser.firstTag
+
class Uloha(Problem):
class Meta:
db_table = 'seminar_ulohy'
@@ -1238,8 +1241,15 @@ class TreeNode(PolymorphicModel):
on_delete=models.SET_NULL,
verbose_name="další element na stejné úrovni")
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",
- blank=False, null=True)
+ help_text = "Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode",
+ 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):
print("{}TreeNode({})".format(" "*indent,self.id))
@@ -1247,7 +1257,27 @@ class TreeNode(PolymorphicModel):
self.first_child.print_tree(indent=indent+2)
if self.succ:
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):
if self.nazev:
return self.nazev
@@ -1283,6 +1313,9 @@ class CisloNode(TreeNode):
def aktualizuj_nazev(self):
self.nazev = "CisloNode: "+str(self.cislo)
+ def getOdkazStr(self):
+ return "Číslo " + str(self.cislo)
+
class MezicisloNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_mezicislo'
@@ -1304,6 +1337,8 @@ class MezicisloNode(TreeNode):
else:
print("!!!!! Nějaké neidentifikované mezičíslo !!!!!")
self.nazev = "MezicisloNode: Neidentifikovatelné mezičíslo!"
+ def getOdkazStr(self):
+ return "Obsah dostupný pouze na webu"
class TemaVCisleNode(TreeNode):
""" Obsahuje příspěvky k tématu v daném čísle """
@@ -1318,6 +1353,9 @@ class TemaVCisleNode(TreeNode):
def aktualizuj_nazev(self):
self.nazev = "TemaVCisleNode: "+str(self.tema)
+ def getOdkazStr(self):
+ return str(self.tema)
+
class KonferaNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_konfera'
@@ -1346,6 +1384,10 @@ class ClanekNode(TreeNode):
def aktualizuj_nazev(self):
self.nazev = "ClanekNode: "+str(self.clanek)
+ def getOdkazStr(self):
+ return str(self.clanek)
+
+
class UlohaZadaniNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_uloha_zadani'
@@ -1360,6 +1402,10 @@ class UlohaZadaniNode(TreeNode):
def aktualizuj_nazev(self):
self.nazev = "UlohaZadaniNode: "+str(self.uloha)
+ def getOdkazStr(self):
+ return str(self.uloha)
+
+
class PohadkaNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_pohadka'
@@ -1387,6 +1433,10 @@ class UlohaVzorakNode(TreeNode):
def aktualizuj_nazev(self):
self.nazev = "UlohaVzorakNode: "+str(self.uloha)
+ def getOdkazStr(self):
+ return str(self.uloha)
+
+
class TextNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_obsah'
@@ -1399,6 +1449,10 @@ class TextNode(TreeNode):
def aktualizuj_nazev(self):
self.nazev = "TextNode: "+str(self.text)
+ def getOdkazStr(self):
+ return str(self.text)
+
+
## FIXME: Logiku přesunout do views.
#class VysledkyBase(SeminarModelBase):
#
diff --git a/seminar/templates/seminar/edit.html b/seminar/templates/seminar/edit.html
index cc039301..3f3e0d99 100644
--- a/seminar/templates/seminar/edit.html
+++ b/seminar/templates/seminar/edit.html
@@ -20,10 +20,6 @@
Přihlašovací údaje
{% include "seminar/prihlaska_field.html" with field=form.username %}
-
- {% include "seminar/prihlaska_field.html" with field=form.password %}
-
- {% include "seminar/prihlaska_field.html" with field=form.password_check %}
Osobní údaje
@@ -68,9 +64,6 @@
{% include "seminar/prihlaska_field.html" with field=form.rok_maturity %}
{% include "seminar/prihlaska_field.html" with field=form.zasilat %}
-
- {% include "seminar/gdpr.html" %}
- {% include "seminar/prihlaska_field.html" with field=form.gdpr %}
{% include "seminar/prihlaska_field.html" with field=form.spam %}
diff --git a/seminar/templates/seminar/tematka/rozcestnik.html b/seminar/templates/seminar/tematka/rozcestnik.html
new file mode 100644
index 00000000..abec82dd
--- /dev/null
+++ b/seminar/templates/seminar/tematka/rozcestnik.html
@@ -0,0 +1,14 @@
+{% for tematko in tematka %}
+{{tematko.nazev}}
+{{tematko.abstrakt}}
+
+ {% for cislo in tematko.cisla %}
+ - {{cislo.0.0}} -> /{{tematko.kod}}/#{{cislo.0.1}}
+
+ {% for odkaz in cislo.1 %}
+ - {{odkaz.0}} -> /{{tematko.kod}}/#{{odkaz.1}}
+ {% endfor %}
+
+ {% endfor %}
+
+{% endfor %}
diff --git a/seminar/testutils.py b/seminar/testutils.py
index 204c0ea6..f378e725 100644
--- a/seminar/testutils.py
+++ b/seminar/testutils.py
@@ -380,7 +380,8 @@ def gen_temata(rnd, rocniky, rocnik_cisla, organizatori):
kod=str(n),
# atributy třídy Téma
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))
for i in range(ci, konec_tematu+1):
diff --git a/seminar/urls.py b/seminar/urls.py
index 5f534020..213494f6 100644
--- a/seminar/urls.py
+++ b/seminar/urls.py
@@ -8,6 +8,9 @@ from django.contrib.auth import views as auth_views
staff_member_required = user_passes_test(lambda u: u.is_staff)
urlpatterns = [
+ path('tematka/', views.TemataRozcestnikView),
+ path('tematko//', views.TematkoView),
+
# REDIRECTy
path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')),
diff --git a/seminar/utils.py b/seminar/utils.py
index 75092384..d910a5b6 100644
--- a/seminar/utils.py
+++ b/seminar/utils.py
@@ -2,9 +2,18 @@
import datetime
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)
+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):
d = {}
for i in seznam:
diff --git a/seminar/views.py b/seminar/views.py
index 46571927..ccbb2d00 100644
--- a/seminar/views.py
+++ b/seminar/views.py
@@ -16,7 +16,8 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
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 . import utils
from .unicodecsv import UnicodeWriter
@@ -74,6 +75,91 @@ def ZadaniTemataView(request):
}
)
+#TODO na příště - implementovat DFS, které vrátí seznam objektů, jejich hloubku a objekt, který chci zobrazit,
+#TODO na příště - rozmyslet, jak zobrazovat objekty - u každého Nodu se objekt, na který ukazuje jmenuje jinak, zavést metodu, která se u každé subclassy bude jmenovat stejně? __str__
+#TODO na příště - v jaké formě předávat templatu? Jak řešit rozbalovací tagy?
+#TODO na příště - implementace vpisování rozbalovacích tagů, vytvořit si nový objekt, který bude mít stejnou metodu jako objekty, které mají node, která bude vracet vhodný tag a prostě ji přidat do seznamu?
+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):
+ neco
+
+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})
+
#def ZadaniAktualniVysledkovkaView(request):
# nastaveni = get_object_or_404(Nastaveni)
@@ -1028,15 +1114,16 @@ def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, 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(osoba_edit)
+ prefill_1=model_to_dict(user_edit)
prefill_2=model_to_dict(resitel_edit)
- prefill_3=model_to_dict(user_edit)
+ prefill_3=model_to_dict(osoba_edit)
prefill_1.update(prefill_2)
prefill_1.update(prefill_3)
form = EditForm(initial=prefill_1)
@@ -1044,7 +1131,35 @@ def resitelEditView(request):
if request.method == 'POST':
form = EditForm(request.POST)
if form.is_valid():
- osoba_edit.prijmeni = 'NOVOTA'
+ ## 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: