diff --git a/seminar/utils.py b/seminar/utils.py index 14bc4ac2..d3e370f2 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -1,98 +1,6 @@ import datetime from django import views as DjangoViews -from django.contrib.contenttypes.models import ContentType - -import seminar.models as m -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 m.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(m.Resitel, 'Duplicitní jméno "%s"' % (j,), jmena[j]) - - # Data maturity a narození - for r in m.Resitel.objects.all(): - if not r.rok_maturity: - prb(m.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(m.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(m.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 m.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(m.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(m.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 - def viewMethodSwitch(get, post): """ diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 09914b0e..835ccce9 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -1,3 +1,4 @@ +from django.contrib.contenttypes.models import ContentType from django.shortcuts import get_object_or_404, render from django.http import HttpResponse from django.urls import reverse @@ -9,6 +10,8 @@ from django.db.models import Q, Sum, Count from django.views.generic.base import RedirectView from django.core.exceptions import PermissionDenied +from treenode.treelib import get_parent +from treenode.models import CisloNode from tvorba.models.problem import Problem from tvorba.models.tema import Tema from tvorba.models.clanek import Clanek @@ -21,7 +24,6 @@ from personalni.models.resitel import Resitel 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,10 +660,103 @@ class ClankyResitelView(generic.ListView): ### Status +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 > 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 > 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 = get_parent(node) + + return problemy + def StavDatabazeView(request): # nastaveni = Nastaveni.objects.get() - problemy = utils.seznam_problemu() + problemy = _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', @@ -672,8 +767,8 @@ def StavDatabazeView(request): '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]), + 'jmena_muzu': _histogram([r.osoba.jmeno for r in muzi]), + 'jmena_zen': _histogram([r.osoba.jmeno for r in zeny]), })