diff --git a/seminar/urls.py b/seminar/urls.py
index 777b40a4..125b1082 100644
--- a/seminar/urls.py
+++ b/seminar/urls.py
@@ -1,6 +1,7 @@
from django.urls import path, include, re_path
from . import views
from personalni.utils import org_required
+import various.views
urlpatterns = [
# path('aktualni/temata/', views.TemataRozcestnikView),
@@ -67,7 +68,7 @@ urlpatterns = [
),
path(
'stav',
- org_required(views.StavDatabazeView),
+ org_required(various.views.StavDatabazeView),
name='stav_databaze'
),
path(
diff --git a/seminar/utils.py b/seminar/utils.py
deleted file mode 100644
index 11a5ab30..00000000
--- a/seminar/utils.py
+++ /dev/null
@@ -1,96 +0,0 @@
-
-import datetime
-
-from django.contrib.contenttypes.models import ContentType
-
-from personalni.models import Resitel
-from tvorba.models import Clanek
-from treenode.models import CisloNode
-import treenode.treelib as t
-
-
-def histogram(seznam):
- d = {}
- for i in seznam:
- if i not in d:
- d[i] = 0
- d[i] += 1
- return d
-
-
-def seznam_problemu():
- """Funkce pro hledání nekonzistencí v databázi a dalších nežádoucích stavů webu/databáze.
-
- Nijak nesouvisí s Problémy zadanými řešitelům."""
- # FIXME: přejmenovat funkci?
- # FIXME: Tak, jak je napsaná, asi spíš patří někam k views a ne do utils (?)
- problemy = []
-
- # Pomocna fce k formatovani problemovych hlasek
- def prb(cls, msg, objs=None):
- s = '%s: %s' % (cls.__name__, msg)
- if objs:
- s += ' ['
- for o in objs:
- try:
- url = o.admin_url()
- except:
- url = None
- if url:
- s += '%s, ' % (url, o.pk,)
- else:
- s += '%s, ' % (o.pk,)
- s = s[:-2] + ']'
- problemy.append(s)
-
- # Duplicita jmen
- jmena = {}
- for r in Resitel.objects.all():
- j = r.osoba.plne_jmeno()
- if j not in jmena:
- jmena[j] = []
- jmena[j].append(r)
- for j in jmena:
- if len(jmena[j]) > 1:
- prb(Resitel, 'Duplicitní jméno "%s"' % (j,), jmena[j])
-
- # Data maturity a narození
- for r in Resitel.objects.all():
- if not r.rok_maturity:
- prb(Resitel, 'Neznámý rok maturity', [r])
- if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10):
- prb(Resitel, 'Podezřelé datum maturity', [r])
- if r.osoba.datum_narozeni and (
- r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12):
- prb(Resitel, 'Podezřelé datum narození', [r])
-# if not r.email:
-# prb(Resitel, u'Neznámý email', [r])
-
- ## Kontroly konzistence databáze a TreeNodů
-
- # Články
- for clanek in Clanek.objects.all():
- # získáme řešení svázané se článkem a z něj node ve stromě
- reseni = clanek.reseni_set
- if (reseni.count() != 1):
- raise ValueError("Článek k sobě má nejedno řešení!")
- r = reseni.first()
- clanek_node = r.text_cely # vazba na ReseniNode z Reseni
- # content type je věc pomáhající rozeznávat různé typy objektů v django-polymorphic
- # protože isinstance vrátí vždy jen TreeNode
- # https://django-polymorphic.readthedocs.io/en/stable/migrating.html
- cislonode_ct = ContentType.objects.get_for_model(CisloNode)
- node = clanek_node
- while node is not None:
- node_ct = node.polymorphic_ctype
- if node_ct == cislonode_ct: # dostali jsme se k CisloNode
- # zkontrolujeme, že stromové číslo odpovídá atributu
- # .cislonode je opačná vazba k treenode_ptr, abychom z TreeNode dostali
- # CisloNode
- if clanek.cislo != node.cislonode.cislo:
- prb(Clanek, "Číslo otištění uložené u článku nesedí s "
- "číslem otištění podle struktury treenodů.", [clanek])
- break
- node = t.get_parent(node)
-
- return problemy
diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py
index 10ab3116..41b33188 100644
--- a/seminar/views/views_all.py
+++ b/seminar/views/views_all.py
@@ -14,7 +14,6 @@ from seminar.models.nastaveni import Nastaveni
from personalni.models import Resitel, Organizator
from seminar.models.novinky import Novinky
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
-from seminar import utils
from treenode import treelib
import treenode.templatetags as tnltt
import treenode.serializers as vr
@@ -658,26 +657,6 @@ class ClankyResitelView(generic.ListView):
# queryset = Problem.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod')
-### Status
-
-def StavDatabazeView(request):
-# nastaveni = Nastaveni.objects.get()
- problemy = utils.seznam_problemu()
- muzi = Resitel.objects.filter(osoba__pohlavi_muz=True)
- zeny = Resitel.objects.filter(osoba__pohlavi_muz=False)
- return render(request, 'seminar/stav_databaze.html',
- {
-# 'nastaveni': nastaveni,
- 'problemy': problemy,
-
- 'resitele': Resitel.objects.all(),
- 'muzi': muzi,
- 'zeny': zeny,
- 'jmena_muzu': utils.histogram([r.osoba.jmeno for r in muzi]),
- 'jmena_zen': utils.histogram([r.osoba.jmeno for r in zeny]),
- })
-
-
# Interní, nemá se nikdy objevit v urls (jinak to účastníci vytrolí)
def formularOKView(request, text='', dalsi_odkazy: Sequence[tuple[str, str]] = ()):
template_name = 'seminar/formular_ok.html'
diff --git a/various/utils.py b/various/utils.py
index de483cb2..3122c040 100644
--- a/various/utils.py
+++ b/various/utils.py
@@ -1,4 +1,8 @@
+import datetime
+
from django import views as DjangoViews
+from django.contrib.contenttypes.models import ContentType
+
bez_diakritiky = ({}
# FIXME: funguje jen pro český a slovenský text, jinak jsou špatně
@@ -81,3 +85,98 @@ def viewMethodSwitch(get, post):
return thePostView(request, *args, **kwargs)
return NewView.as_view()
+
+
+def histogram(seznam):
+ d = {}
+ for i in seznam:
+ if i not in d:
+ d[i] = 0
+ d[i] += 1
+ return d
+
+
+def seznam_problemu():
+ """Funkce pro hledání nekonzistencí v databázi a dalších nežádoucích stavů webu/databáze.
+
+ Nijak nesouvisí s Problémy zadanými řešitelům."""
+ # FIXME: přejmenovat funkci?
+ # FIXME: Tak, jak je napsaná, asi spíš patří někam k views a ne do utils (?)
+
+ # Importy tady, aby various.utils zůstalo čisté od ostatních částí mamwebu
+ # obrana proti cyklickým importům...
+ from personalni.models import Resitel
+ from tvorba.models import Clanek
+ from treenode.models import CisloNode
+ import treenode.treelib as t
+
+ problemy = []
+
+ # Pomocna fce k formatovani problemovych hlasek
+ def prb(cls, msg, objs=None):
+ s = '%s: %s' % (cls.__name__, msg)
+ if objs:
+ s += ' ['
+ for o in objs:
+ try:
+ url = o.admin_url()
+ except:
+ url = None
+ if url:
+ s += '%s, ' % (url, o.pk,)
+ else:
+ s += '%s, ' % (o.pk,)
+ s = s[:-2] + ']'
+ problemy.append(s)
+
+ # Duplicita jmen
+ jmena = {}
+ for r in Resitel.objects.all():
+ j = r.osoba.plne_jmeno()
+ if j not in jmena:
+ jmena[j] = []
+ jmena[j].append(r)
+ for j in jmena:
+ if len(jmena[j]) > 1:
+ prb(Resitel, 'Duplicitní jméno "%s"' % (j,), jmena[j])
+
+ # Data maturity a narození
+ for r in Resitel.objects.all():
+ if not r.rok_maturity:
+ prb(Resitel, 'Neznámý rok maturity', [r])
+ if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10):
+ prb(Resitel, 'Podezřelé datum maturity', [r])
+ if r.osoba.datum_narozeni and (
+ r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12):
+ prb(Resitel, 'Podezřelé datum narození', [r])
+ # if not r.email:
+ # prb(Resitel, u'Neznámý email', [r])
+
+ ## Kontroly konzistence databáze a TreeNodů
+
+ # Články
+ for clanek in Clanek.objects.all():
+ # získáme řešení svázané se článkem a z něj node ve stromě
+ reseni = clanek.reseni_set
+ if (reseni.count() != 1):
+ raise ValueError("Článek k sobě má nejedno řešení!")
+ r = reseni.first()
+ clanek_node = r.text_cely # vazba na ReseniNode z Reseni
+ # content type je věc pomáhající rozeznávat různé typy objektů v django-polymorphic
+ # protože isinstance vrátí vždy jen TreeNode
+ # https://django-polymorphic.readthedocs.io/en/stable/migrating.html
+ cislonode_ct = ContentType.objects.get_for_model(CisloNode)
+ node = clanek_node
+ while node is not None:
+ node_ct = node.polymorphic_ctype
+ if node_ct == cislonode_ct: # dostali jsme se k CisloNode
+ # zkontrolujeme, že stromové číslo odpovídá atributu
+ # .cislonode je opačná vazba k treenode_ptr, abychom z TreeNode dostali
+ # CisloNode
+ if clanek.cislo != node.cislonode.cislo:
+ prb(Clanek, "Číslo otištění uložené u článku nesedí s "
+ "číslem otištění podle struktury treenodů.", [clanek])
+ break
+ node = t.get_parent(node)
+
+ return problemy
diff --git a/various/views.py b/various/views.py
index 91ea44a2..48cc435f 100644
--- a/various/views.py
+++ b/various/views.py
@@ -1,3 +1,25 @@
from django.shortcuts import render
-# Create your views here.
+from various import utils
+from personalni.models import Resitel
+
+
+def StavDatabazeView(request):
+ # nastaveni = Nastaveni.objects.get()
+ problemy = utils.seznam_problemu()
+ muzi = Resitel.objects.filter(osoba__pohlavi_muz=True)
+ zeny = Resitel.objects.filter(osoba__pohlavi_muz=False)
+ return render(
+ request,
+ 'seminar/stav_databaze.html',
+ {
+ # 'nastaveni': nastaveni,
+ 'problemy': problemy,
+
+ 'resitele': Resitel.objects.all(),
+ 'muzi': muzi,
+ 'zeny': zeny,
+ 'jmena_muzu': utils.histogram([r.osoba.jmeno for r in muzi]),
+ 'jmena_zen': utils.histogram([r.osoba.jmeno for r in zeny]),
+ }
+ )