diff --git a/convert_spaces_to_tabs.sh b/convert_spaces_to_tabs.sh new file mode 100755 index 00000000..8f98f6ae --- /dev/null +++ b/convert_spaces_to_tabs.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +if test "$#" -lt 1 +then + echo "Usage: $0 file ..." + exit 2 +fi + +for file in "$@" +do + # Do the sed magic: keep replacing 4 spaces at the begining of line + sed -i -re ' + : loop + s/^( *) /\1 / + t loop + ' "$file" +done diff --git a/galerie/admin.py b/galerie/admin.py index 9ab2c3ba..98c83ea9 100644 --- a/galerie/admin.py +++ b/galerie/admin.py @@ -10,45 +10,45 @@ from autocomplete_light import shortcuts as autocomplete_light # akction def zverejnit_fotogalerii(modeladmin, request, queryset): - '''zverejni vybranou fotogalerii i jeji vsechny podgalerie''' - for galerie in queryset: - galerie.zobrazit = 0 - galerie.save() - zverejnit_fotogalerii(modeladmin, request, - Galerie.objects.filter(galerie_up = galerie)) - zverejnit_fotogalerii.short_description = 'Zveřejnit fotogalerie' + '''zverejni vybranou fotogalerii i jeji vsechny podgalerie''' + for galerie in queryset: + galerie.zobrazit = 0 + galerie.save() + zverejnit_fotogalerii(modeladmin, request, + Galerie.objects.filter(galerie_up = galerie)) + zverejnit_fotogalerii.short_description = 'Zveřejnit fotogalerie' def prepnout_fotogalerii_do_org_rezimu(modeladmin, request, queryset): - '''zneverjni vybranou fotogalerii i jeji vsechny podgalerie''' - for galerie in queryset: - galerie.zobrazit = 1 - galerie.save() - prepnout_fotogalerii_do_org_rezimu(modeladmin, request, - Galerie.objects.filter(galerie_up = galerie)) - prepnout_fotogalerii_do_org_rezimu.short_description = \ - 'Přepnout do režimu úprav (zneveřejní galerii)' + '''zneverjni vybranou fotogalerii i jeji vsechny podgalerie''' + for galerie in queryset: + galerie.zobrazit = 1 + galerie.save() + prepnout_fotogalerii_do_org_rezimu(modeladmin, request, + Galerie.objects.filter(galerie_up = galerie)) + prepnout_fotogalerii_do_org_rezimu.short_description = \ + 'Přepnout do režimu úprav (zneveřejní galerii)' class GalerieInline(admin.TabularInline): - model = Obrazek - fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag'] - readonly_fields = ['nazev', 'obrazek_maly_tag'] - formfield_overrides = { - models.TextField: {'widget': forms.TextInput}, - } + model = Obrazek + fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag'] + readonly_fields = ['nazev', 'obrazek_maly_tag'] + formfield_overrides = { + models.TextField: {'widget': forms.TextInput}, + } class ObrazekAdmin(admin.ModelAdmin): - list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag') - + list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag') + class GalerieAdmin(admin.ModelAdmin): - form = autocomplete_light.modelform_factory(Galerie, autocomplete_fields=['titulni_obrazek'], fields=['titulni_obrazek']) - model = Galerie - fields = ('zobrazit', 'nazev', 'titulni_obrazek', 'popis', 'galerie_up', 'soustredeni', 'poradi') - list_display = ('nazev', 'soustredeni', 'galerie_up', 'poradi', 'zobrazit', 'datum_zmeny') - inlines = [GalerieInline] - actions = [zverejnit_fotogalerii, prepnout_fotogalerii_do_org_rezimu] - save_on_top = True - ordering = ['galerie_up__nazev', 'poradi'] + form = autocomplete_light.modelform_factory(Galerie, autocomplete_fields=['titulni_obrazek'], fields=['titulni_obrazek']) + model = Galerie + fields = ('zobrazit', 'nazev', 'titulni_obrazek', 'popis', 'galerie_up', 'soustredeni', 'poradi') + list_display = ('nazev', 'soustredeni', 'galerie_up', 'poradi', 'zobrazit', 'datum_zmeny') + inlines = [GalerieInline] + actions = [zverejnit_fotogalerii, prepnout_fotogalerii_do_org_rezimu] + save_on_top = True + ordering = ['galerie_up__nazev', 'poradi'] admin.site.register(Obrazek, ObrazekAdmin) admin.site.register(Galerie, GalerieAdmin) diff --git a/galerie/forms.py b/galerie/forms.py index 1cadb3fc..e6666884 100644 --- a/galerie/forms.py +++ b/galerie/forms.py @@ -4,8 +4,8 @@ from django import forms from seminar.models import Soustredeni class KomentarForm(forms.Form): - komentar = forms.CharField(label = "Komentář:", max_length = 300, required=False) + komentar = forms.CharField(label = "Komentář:", max_length = 300, required=False) class NewGalerieForm(forms.Form): - nazev = forms.CharField(label = "Název galerie", max_length = 100) - #popis = forms.CharField(label = "Popis", required = False, max_length = 2000, widget = forms.Textarea) + nazev = forms.CharField(label = "Název galerie", max_length = 100) + #popis = forms.CharField(label = "Popis", required = False, max_length = 2000, widget = forms.Textarea) diff --git a/galerie/models.py b/galerie/models.py index 133551ec..4a90b131 100644 --- a/galerie/models.py +++ b/galerie/models.py @@ -14,109 +14,108 @@ VZDY=0 ORG=1 NIKDY=2 VIDITELNOST = ( - (VZDY, 'Vždy'), - (ORG, 'Organizátorům'), - (NIKDY, 'Nikdy'), + (VZDY, 'Vždy'), + (ORG, 'Organizátorům'), + (NIKDY, 'Nikdy'), ) # tyhle funkce jsou tady jen kvůli starým migracím, které se na ně odkazují # až se ty migrace někdy squashnou, tak by mělo být možné funkce smazat def obrazek_filename_maly(): - pass + pass def obrazek_filename_stredni(): - pass + pass def obrazek_filename_velky(): - pass + pass def obrazek_filename(self, filename): - gal = self.galerie - cislo_gal = force_unicode(gal.pk) + gal = self.galerie + cislo_gal = force_unicode(gal.pk) - # najdi kořenovou galerii - while (gal.galerie_up): - gal = gal.galerie_up + # najdi kořenovou galerii + while (gal.galerie_up): + gal = gal.galerie_up - # soustředění je v cestě jen pokud galerie pod nějaké patří - cesta = ( - ['Galerie'] + - (["soustredeni_" + force_unicode(gal.soustredeni.pk)] if gal.soustredeni else []) + - ["galerie_" + cislo_gal, force_unicode(self.nazev)] - ) + # soustředění je v cestě jen pokud galerie pod nějaké patří + cesta = ( + ['Galerie'] + + (["soustredeni_" + force_unicode(gal.soustredeni.pk)] if gal.soustredeni else []) + + ["galerie_" + cislo_gal, force_unicode(self.nazev)] + ) - return os.path.join(*cesta) + return os.path.join(*cesta) class Obrazek(models.Model): - obrazek_velky = models.ImageField(upload_to=obrazek_filename, - help_text = "Lze vložit libovolně velký obrázek. Ideální je, aby alespoň jeden rozměr měl alespoň 500px.") - obrazek_stredni = ImageSpecField(source='obrazek_velky', - processors=[Transpose(Transpose.AUTO), ResizeToFit(900, 675, upscale=False)], - options={'quality': 95}) - obrazek_maly = ImageSpecField(source='obrazek_velky', - processors=[Transpose(Transpose.AUTO), ResizeToFit(167, 167, upscale=False)], - options={'quality': 95}) - nazev = models.CharField('Název', max_length=50, blank=True, null=True) - popis = models.TextField('Popis', blank=True, null=True) - datum_vlozeni = models.DateTimeField('Datum vložení', auto_now_add=True) - galerie = models.ForeignKey('Galerie', blank=True, null=True) - poradi = models.IntegerField('Pořadí', blank=True, null=True) - - def __unicode__(self): - return unicode(self.obrazek_velky.name) - - class Meta: - verbose_name = 'Obrázek' - verbose_name_plural = 'Obrázky' - ordering = ['nazev'] - - def obrazek_maly_tag(self): - return u''.format(self.obrazek_maly.url) - obrazek_maly_tag.short_description = "Náhled" - obrazek_maly_tag.allow_tags = True - - def save(self, *args, **kwargs): - # obrázek potřebuje název, protože se z něj generuje cesta pro jeho uložení - # (a pak se podle něj taky řadí) - if self.nazev is None: - self.nazev = os.path.basename(self.obrazek_velky.name) - super(Obrazek, self).save(*args, **kwargs) - - + obrazek_velky = models.ImageField(upload_to=obrazek_filename, + help_text = "Lze vložit libovolně velký obrázek. Ideální je, aby alespoň jeden rozměr měl alespoň 500px.") + obrazek_stredni = ImageSpecField(source='obrazek_velky', + processors=[Transpose(Transpose.AUTO), ResizeToFit(900, 675, upscale=False)], + options={'quality': 95}) + obrazek_maly = ImageSpecField(source='obrazek_velky', + processors=[Transpose(Transpose.AUTO), ResizeToFit(167, 167, upscale=False)], + options={'quality': 95}) + nazev = models.CharField('Název', max_length=50, blank=True, null=True) + popis = models.TextField('Popis', blank=True, null=True) + datum_vlozeni = models.DateTimeField('Datum vložení', auto_now_add=True) + galerie = models.ForeignKey('Galerie', blank=True, null=True) + poradi = models.IntegerField('Pořadí', blank=True, null=True) + + def __unicode__(self): + return unicode(self.obrazek_velky.name) + + class Meta: + verbose_name = 'Obrázek' + verbose_name_plural = 'Obrázky' + ordering = ['nazev'] + + def obrazek_maly_tag(self): + return u''.format(self.obrazek_maly.url) + obrazek_maly_tag.short_description = "Náhled" + obrazek_maly_tag.allow_tags = True + + def save(self, *args, **kwargs): + # obrázek potřebuje název, protože se z něj generuje cesta pro jeho uložení + # (a pak se podle něj taky řadí) + if self.nazev is None: + self.nazev = os.path.basename(self.obrazek_velky.name) + super(Obrazek, self).save(*args, **kwargs) + class Galerie(models.Model): - nazev = models.CharField('Název', max_length=100) - datum_vytvoreni = models.DateTimeField('Datum vytvoření', auto_now_add = True) - datum_zmeny = models.DateTimeField('Datum poslední změny', auto_now = True) - popis = models.TextField('Popis', blank = True, null = True) - titulni_obrazek = models.ForeignKey(Obrazek, blank = True, null = True, related_name = "+", on_delete = models.SET_NULL) - zobrazit = models.IntegerField('Zobrazit?', default = ORG, choices = VIDITELNOST) - galerie_up = models.ForeignKey('Galerie', blank = True, null = True) - soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True) - poradi = models.IntegerField('Pořadí', blank = True, null = True) - - def __unicode__(self): - return self.nazev - class Meta: - verbose_name = 'Galerie' - verbose_name_plural = 'Galerie' - - #def link_na_preview(self): - #"""Odkaz na galerii, používá se v admin rozhranní. """ - #return 'Preview' % self.id - #link_na_preview.allow_tags = True - #link_na_preview.short_description = 'Zobrazit galerii' + nazev = models.CharField('Název', max_length=100) + datum_vytvoreni = models.DateTimeField('Datum vytvoření', auto_now_add = True) + datum_zmeny = models.DateTimeField('Datum poslední změny', auto_now = True) + popis = models.TextField('Popis', blank = True, null = True) + titulni_obrazek = models.ForeignKey(Obrazek, blank = True, null = True, related_name = "+", on_delete = models.SET_NULL) + zobrazit = models.IntegerField('Zobrazit?', default = ORG, choices = VIDITELNOST) + galerie_up = models.ForeignKey('Galerie', blank = True, null = True) + soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True) + poradi = models.IntegerField('Pořadí', blank = True, null = True) + + def __unicode__(self): + return self.nazev + class Meta: + verbose_name = 'Galerie' + verbose_name_plural = 'Galerie' + + #def link_na_preview(self): + #"""Odkaz na galerii, používá se v admin rozhranní. """ + #return 'Preview' % self.id + #link_na_preview.allow_tags = True + #link_na_preview.short_description = 'Zobrazit galerii' # - #def je_publikovano(self): - #"""Vraci True, pokud je tato galerie publikovana. """ - #if self.zobrazit == VZDY: - #return True - #if self.zobrazit == PODLE_CLANKU: - #for clanek in self.clanek_set.all(): - #if clanek.je_publikovano(): - #return True - #return False + #def je_publikovano(self): + #"""Vraci True, pokud je tato galerie publikovana. """ + #if self.zobrazit == VZDY: + #return True + #if self.zobrazit == PODLE_CLANKU: + #for clanek in self.clanek_set.all(): + #if clanek.je_publikovano(): + #return True + #return False # - #@staticmethod - #def publikovane_galerie(): - #"""Vraci galerie, ktere uz maji byt publikovane.""" - #clanky = Blog.models.Clanek.publikovane_clanky() - #return Galerie.objects.filter(Q(zobrazit=VZDY) | (Q(clanek__in=clanky) & Q(zobrazit=PODLE_CLANKU))).distinct() + #@staticmethod + #def publikovane_galerie(): + #"""Vraci galerie, ktere uz maji byt publikovane.""" + #clanky = Blog.models.Clanek.publikovane_clanky() + #return Galerie.objects.filter(Q(zobrazit=VZDY) | (Q(clanek__in=clanky) & Q(zobrazit=PODLE_CLANKU))).distinct() diff --git a/galerie/urls.py b/galerie/urls.py index 4b015e44..487ddc22 100644 --- a/galerie/urls.py +++ b/galerie/urls.py @@ -4,10 +4,10 @@ from django.conf.urls import include, url from . import views urlpatterns = [ - url(r'^(?P\d+)/$', views.nahled), - url(r'^(?P\d+)/(?P\d+)/$', views.detail), - url(r'^(?P\d+)/new/$', views.new_galerie), - url(r'^(?P\d+)/plus/(?P\d+)/$', views.plus_galerie), - url(r'^(?P\d+)/minus/(?P\d+)/$', views.minus_galerie), + url(r'^(?P\d+)/$', views.nahled), + url(r'^(?P\d+)/(?P\d+)/$', views.detail), + url(r'^(?P\d+)/new/$', views.new_galerie), + url(r'^(?P\d+)/plus/(?P\d+)/$', views.plus_galerie), + url(r'^(?P\d+)/minus/(?P\d+)/$', views.minus_galerie), ] diff --git a/galerie/views.py b/galerie/views.py index 46860810..729ac3b8 100644 --- a/galerie/views.py +++ b/galerie/views.py @@ -12,222 +12,221 @@ from seminar.models import Soustredeni from galerie.forms import KomentarForm, NewGalerieForm def zobrazit(galerie, request): - preview = False - if galerie.zobrazit >= 1: - if request.user.is_staff: - preview = True; - else: - raise Http404 - return preview + preview = False + if galerie.zobrazit >= 1: + if request.user.is_staff: + preview = True; + else: + raise Http404 + return preview def cesta_od_korene(g): - """Vrátí seznam galerií od kořene ke g""" - cesta = [] - while g != None: - cesta.append(g) - g = g.galerie_up - return reversed(cesta) + """Vrátí seznam galerií od kořene ke g""" + cesta = [] + while g != None: + cesta.append(g) + g = g.galerie_up + return reversed(cesta) def nahled(request, pk, soustredeni): - """Zobrazeni nahledu vsech fotek ve skupine.""" - galerie = get_object_or_404(Galerie, pk=pk) - - podgalerie = Galerie.objects.filter(galerie_up = galerie).order_by('poradi') - if not request.user.is_staff: - podgalerie = podgalerie.filter(zobrazit__lt=1) - - obrazky = Obrazek.objects.filter(galerie = galerie) - preview = zobrazit(galerie, request) - - sourozenci = [] - if galerie.galerie_up: - sourozenci = galerie.galerie_up.galerie_set.all().order_by('poradi') - if not request.user.is_staff: - sourozenci = sourozenci.filter(zobrazit__lt=1) - - predchozi = None - nasledujici = None - minuly = None - for g in sourozenci: - if g.pk == galerie.pk: - predchozi = minuly - if minuly != None and minuly.pk == galerie.pk: - nasledujici = g - break - minuly = g - - cesta = cesta_od_korene(galerie) - - return render(request, 'galerie/GalerieNahled.html', - {'galerie' : galerie, - 'podgalerie' : podgalerie, - 'obrazky' : obrazky, - 'preview' : preview, - 'cesta': cesta, - 'sourozenci': sourozenci, - 'predchozi': predchozi, - 'nasledujici': nasledujici, - }) + """Zobrazeni nahledu vsech fotek ve skupine.""" + galerie = get_object_or_404(Galerie, pk=pk) + + podgalerie = Galerie.objects.filter(galerie_up = galerie).order_by('poradi') + if not request.user.is_staff: + podgalerie = podgalerie.filter(zobrazit__lt=1) + + obrazky = Obrazek.objects.filter(galerie = galerie) + preview = zobrazit(galerie, request) + + sourozenci = [] + if galerie.galerie_up: + sourozenci = galerie.galerie_up.galerie_set.all().order_by('poradi') + if not request.user.is_staff: + sourozenci = sourozenci.filter(zobrazit__lt=1) + + predchozi = None + nasledujici = None + minuly = None + for g in sourozenci: + if g.pk == galerie.pk: + predchozi = minuly + if minuly != None and minuly.pk == galerie.pk: + nasledujici = g + break + minuly = g + + cesta = cesta_od_korene(galerie) + + return render(request, 'galerie/GalerieNahled.html', + {'galerie' : galerie, + 'podgalerie' : podgalerie, + 'obrazky' : obrazky, + 'preview' : preview, + 'cesta': cesta, + 'sourozenci': sourozenci, + 'predchozi': predchozi, + 'nasledujici': nasledujici, + }) def detail(request, pk, fotka, soustredeni): - """Zobrazeni nahledu fotky s id 'fotka'.""" - MAX_VYSKA = 900 - MAX_SIRKA = 900 - MAX_VYSKA_MALA = 100 - MAX_SIRKA_MALA = 200 - NAHLEDU = 1 - - galerie = get_object_or_404(Galerie, pk=pk) - preview = zobrazit(galerie, request) - obrazek = get_object_or_404(Obrazek, pk=fotka) - obrazky = galerie.obrazek_set.all() - - # vytvoreni a obslouzeni formulare - if request.method == 'POST': - form = KomentarForm(request.POST) - if form.is_valid(): - obrazek.popis = form.cleaned_data['komentar'] - obrazek.save() - else: - form = KomentarForm({'komentar': obrazek.popis}) - - # Poradi aktualniho obrazku v galerii/stitku. - for i in range(len(obrazky)): - if obrazky[i] == obrazek: - znacka = i - break - else: - # Obrazek neni v galerii/stitku. - raise Http404 - - - # Nacteni okolnich obrazku a galerii - # TODO vyjmout zjisteni predchozich a nasledujicich galerii - # a udelat z toho funkci, ktera se pouzije u nahledu - predchozi_galerie = None - nasledujici_galerie = None - obrazky_dalsi = obrazky[znacka+1:znacka+NAHLEDU+1] - if (znacka+1) > NAHLEDU: - obrazky_predchozi = obrazky[znacka-NAHLEDU:znacka] - else: - obrazky_predchozi = obrazky[0:znacka] - if galerie.poradi > 1: - predchozi_galerie = Galerie.objects.\ - filter(galerie_up=galerie.galerie_up).\ - filter(poradi=(galerie.poradi-1)) - if predchozi_galerie: - predchozi_galerie = predchozi_galerie[0] - else: - predchozi_galerie = None - if (znacka+1) == len(obrazky): - nasledujici_galerie = Galerie.objects.\ - filter(galerie_up=galerie.galerie_up).\ - filter(poradi=(galerie.poradi+1)) - if nasledujici_galerie: - nasledujici_galerie = nasledujici_galerie[0] - else: - nasledujici_galerie = None - - - - # Preskalovani obrazku do vybraneho prostoru. - vyska = obrazek.obrazek_stredni.height - sirka = obrazek.obrazek_stredni.width - if vyska > MAX_VYSKA: - sirka = sirka * MAX_VYSKA / vyska - vyska = MAX_VYSKA - if sirka > MAX_SIRKA: - vyska = vyska * MAX_SIRKA / sirka - sirka = MAX_SIRKA - - return render(request, 'galerie/Galerie.html', - {'galerie' : galerie, - 'predchozi_galerie' : predchozi_galerie, - 'nasledujici_galerie' : nasledujici_galerie, - 'obrazek' : obrazek, - 'vyska' : vyska, - 'sirka' : sirka, - 'obrazky_predchozi' : obrazky_predchozi, - 'obrazky_dalsi' : obrazky_dalsi, - 'preview' : preview, - 'form' : form, - 'cesta': cesta_od_korene(galerie), - }) + """Zobrazeni nahledu fotky s id 'fotka'.""" + MAX_VYSKA = 900 + MAX_SIRKA = 900 + MAX_VYSKA_MALA = 100 + MAX_SIRKA_MALA = 200 + NAHLEDU = 1 + + galerie = get_object_or_404(Galerie, pk=pk) + preview = zobrazit(galerie, request) + obrazek = get_object_or_404(Obrazek, pk=fotka) + obrazky = galerie.obrazek_set.all() + + # vytvoreni a obslouzeni formulare + if request.method == 'POST': + form = KomentarForm(request.POST) + if form.is_valid(): + obrazek.popis = form.cleaned_data['komentar'] + obrazek.save() + else: + form = KomentarForm({'komentar': obrazek.popis}) + + # Poradi aktualniho obrazku v galerii/stitku. + for i in range(len(obrazky)): + if obrazky[i] == obrazek: + znacka = i + break + else: + # Obrazek neni v galerii/stitku. + raise Http404 + + # Nacteni okolnich obrazku a galerii + # TODO vyjmout zjisteni predchozich a nasledujicich galerii + # a udelat z toho funkci, ktera se pouzije u nahledu + predchozi_galerie = None + nasledujici_galerie = None + obrazky_dalsi = obrazky[znacka+1:znacka+NAHLEDU+1] + if (znacka+1) > NAHLEDU: + obrazky_predchozi = obrazky[znacka-NAHLEDU:znacka] + else: + obrazky_predchozi = obrazky[0:znacka] + if galerie.poradi > 1: + predchozi_galerie = Galerie.objects.\ + filter(galerie_up=galerie.galerie_up).\ + filter(poradi=(galerie.poradi-1)) + if predchozi_galerie: + predchozi_galerie = predchozi_galerie[0] + else: + predchozi_galerie = None + if (znacka+1) == len(obrazky): + nasledujici_galerie = Galerie.objects.\ + filter(galerie_up=galerie.galerie_up).\ + filter(poradi=(galerie.poradi+1)) + if nasledujici_galerie: + nasledujici_galerie = nasledujici_galerie[0] + else: + nasledujici_galerie = None + + + + # Preskalovani obrazku do vybraneho prostoru. + vyska = obrazek.obrazek_stredni.height + sirka = obrazek.obrazek_stredni.width + if vyska > MAX_VYSKA: + sirka = sirka * MAX_VYSKA / vyska + vyska = MAX_VYSKA + if sirka > MAX_SIRKA: + vyska = vyska * MAX_SIRKA / sirka + sirka = MAX_SIRKA + + return render(request, 'galerie/Galerie.html', + {'galerie' : galerie, + 'predchozi_galerie' : predchozi_galerie, + 'nasledujici_galerie' : nasledujici_galerie, + 'obrazek' : obrazek, + 'vyska' : vyska, + 'sirka' : sirka, + 'obrazky_predchozi' : obrazky_predchozi, + 'obrazky_dalsi' : obrazky_dalsi, + 'preview' : preview, + 'form' : form, + 'cesta': cesta_od_korene(galerie), + }) def new_galerie(request, galerie, soustredeni): - # zjistime k jakemu soustredeni se vaze nove vytvarena galerie - soustredeni = get_object_or_404(Soustredeni, pk = soustredeni) - # pokud je parametr galerie 0, pak jde o hlavni galerii - # kdyz je nejaky jiny, pak je pk galerie pod kterou tu dalsi vytvarim - if int(galerie) == 0: - galerie_up = False - galerie_text = "Hlavní fotogalerie soustředění" - else: - galerie_up = get_object_or_404(Galerie, pk = int(galerie)) - galerie_text = "podgalerii ke galerii " + str(galerie_up) - - # obsluha formulare umoznujiciho multiple nahravani fotek - if request.method == 'POST': - form = NewGalerieForm(request.POST, request.FILES) - if form.is_valid(): - # vytvoreni nove galerie - gal = Galerie() - gal.nazev = form.cleaned_data['nazev'] - #gal.popis = form.cleaned_data['popis'] # popis nepouzivame - gal.zobrazit = 1 # galerie je v procesu vytvareni - ''' pokud je to podgalerie pridej nadrazenou galerii - a nadrazene soustredeni nechej volne, - pokud je to hlavni galerie, tak nadrazena galerie neexistuje, - ale v takovem pripade musi byt nadrazene soustredeni a ne jinak ''' - if galerie_up: - gal.galerie_up = galerie_up - else: - gal.soustredeni = soustredeni - if gal.galerie_up: - gal.poradi = int(len(gal.galerie_up.galerie_set.all())) + 1 - gal.save() - - # zpracovani obrazku v galerii - for obr in request.FILES.getlist('obr'): - o = Obrazek() - o.obrazek_velky = obr - o.nazev = str(obr) - o.galerie = gal - o.save() - - # presmerovani na prave vzniklou galerii - return HttpResponseRedirect('../../' + str(gal.pk)) - - else: - form = NewGalerieForm() - - - return render(request, 'galerie/GalerieNew.html', - { - 'form' : form, - 'soustredeni' : soustredeni, - 'galerie_text' : galerie_text, - }) + # zjistime k jakemu soustredeni se vaze nove vytvarena galerie + soustredeni = get_object_or_404(Soustredeni, pk = soustredeni) + # pokud je parametr galerie 0, pak jde o hlavni galerii + # kdyz je nejaky jiny, pak je pk galerie pod kterou tu dalsi vytvarim + if int(galerie) == 0: + galerie_up = False + galerie_text = "Hlavní fotogalerie soustředění" + else: + galerie_up = get_object_or_404(Galerie, pk = int(galerie)) + galerie_text = "podgalerii ke galerii " + str(galerie_up) + + # obsluha formulare umoznujiciho multiple nahravani fotek + if request.method == 'POST': + form = NewGalerieForm(request.POST, request.FILES) + if form.is_valid(): + # vytvoreni nove galerie + gal = Galerie() + gal.nazev = form.cleaned_data['nazev'] + #gal.popis = form.cleaned_data['popis'] # popis nepouzivame + gal.zobrazit = 1 # galerie je v procesu vytvareni + ''' pokud je to podgalerie pridej nadrazenou galerii + a nadrazene soustredeni nechej volne, + pokud je to hlavni galerie, tak nadrazena galerie neexistuje, + ale v takovem pripade musi byt nadrazene soustredeni a ne jinak ''' + if galerie_up: + gal.galerie_up = galerie_up + else: + gal.soustredeni = soustredeni + if gal.galerie_up: + gal.poradi = int(len(gal.galerie_up.galerie_set.all())) + 1 + gal.save() + + # zpracovani obrazku v galerii + for obr in request.FILES.getlist('obr'): + o = Obrazek() + o.obrazek_velky = obr + o.nazev = str(obr) + o.galerie = gal + o.save() + + # presmerovani na prave vzniklou galerii + return HttpResponseRedirect('../../' + str(gal.pk)) + + else: + form = NewGalerieForm() + + + return render(request, 'galerie/GalerieNew.html', + { + 'form' : form, + 'soustredeni' : soustredeni, + 'galerie_text' : galerie_text, + }) def plus_galerie(request, galerie, soustredeni, subgalerie): - galerie = get_object_or_404(Galerie, pk=subgalerie) - if galerie.poradi: - galerie.poradi += 1 - else: - galerie.poradi = int(len(galerie.galerie_up.galerie_set.all())) - galerie.save() - return HttpResponseRedirect('../../') + galerie = get_object_or_404(Galerie, pk=subgalerie) + if galerie.poradi: + galerie.poradi += 1 + else: + galerie.poradi = int(len(galerie.galerie_up.galerie_set.all())) + galerie.save() + return HttpResponseRedirect('../../') def minus_galerie(request, galerie, soustredeni, subgalerie): - galerie = get_object_or_404(Galerie, pk=subgalerie) - if galerie.poradi: - galerie.poradi -= 1 - else: - galerie.poradi = 1 - galerie.save() - return HttpResponseRedirect('../../') + galerie = get_object_or_404(Galerie, pk=subgalerie) + if galerie.poradi: + galerie.poradi -= 1 + else: + galerie.poradi = 1 + galerie.save() + return HttpResponseRedirect('../../') diff --git a/korektury/admin.py b/korektury/admin.py index 25b49e4e..79dfffb1 100644 --- a/korektury/admin.py +++ b/korektury/admin.py @@ -6,21 +6,21 @@ from korektury.models import KorekturovanePDF # Register your models here. class KorekturovanePDFAdmin(VersionAdmin): - readonly_fields = ['cas', 'stran'] + readonly_fields = ['cas', 'stran'] - def get_readonly_fields(self, request, obj=None): - if obj: - return self.readonly_fields + ['pdf'] - return self.readonly_fields + def get_readonly_fields(self, request, obj=None): + if obj: + return self.readonly_fields + ['pdf'] + return self.readonly_fields - fieldsets = [ - (None, - {'fields': - ['pdf', 'cas', 'org', 'stran', 'nazev', 'komentar']}), - # (u'PDF', {'fields': ['pdf']}), - ] - list_display = ['nazev', 'cas', 'stran', 'org'] - list_filter = [] - search_fields = [] + fieldsets = [ + (None, + {'fields': + ['pdf', 'cas', 'org', 'stran', 'nazev', 'komentar']}), + # (u'PDF', {'fields': ['pdf']}), + ] + list_display = ['nazev', 'cas', 'stran', 'org'] + list_filter = [] + search_fields = [] admin.site.register(KorekturovanePDF, KorekturovanePDFAdmin) diff --git a/korektury/forms.py b/korektury/forms.py index 676d6b3a..7385e687 100644 --- a/korektury/forms.py +++ b/korektury/forms.py @@ -1,13 +1,13 @@ from django import forms class OpravaForm(forms.Form): - text = forms.CharField(max_length=256) - autor = forms.CharField(max_length=20) - x = forms.IntegerField() - y = forms.IntegerField() - scroll = forms.CharField(max_length=256) - pdf = forms.CharField(max_length=256) - img_id = forms.CharField(max_length=256) - id = forms.CharField(max_length=256) - action = forms.CharField(max_length=256) + text = forms.CharField(max_length=256) + autor = forms.CharField(max_length=20) + x = forms.IntegerField() + y = forms.IntegerField() + scroll = forms.CharField(max_length=256) + pdf = forms.CharField(max_length=256) + img_id = forms.CharField(max_length=256) + id = forms.CharField(max_length=256) + action = forms.CharField(max_length=256) diff --git a/korektury/models.py b/korektury/models.py index 47094f89..ab9cf62f 100644 --- a/korektury/models.py +++ b/korektury/models.py @@ -17,171 +17,171 @@ from unidecode import unidecode def generate_filename(self, filename): - clean = get_valid_filename( - unidecode( - filename.replace('/', '-').replace('\0', '').replace(":", "_") - ) - ) - fname = "%s_%s" % ( - timezone.now().strftime('%Y-%m-%d-%H_%M'), - clean) - return os.path.join(settings.KOREKTURY_PDF_DIR, fname) + clean = get_valid_filename( + unidecode( + filename.replace('/', '-').replace('\0', '').replace(":", "_") + ) + ) + fname = "%s_%s" % ( + timezone.now().strftime('%Y-%m-%d-%H_%M'), + clean) + return os.path.join(settings.KOREKTURY_PDF_DIR, fname) #@reversion.register(ignore_duplicates=True) #@python_2_unicode_compatible class KorekturovanePDF(models.Model): - class Meta: - ordering = ['-cas'] - db_table = 'korekturovane_cislo' - verbose_name = u'PDF k opravám' - verbose_name_plural = u'PDF k opravám' - - #Interní ID - id = models.AutoField(primary_key = True) - - cas = models.DateTimeField(u'čas vložení PDF',default=timezone.now,help_text = 'Čas vložení PDF') - - nazev = models.CharField(u'název PDF',blank = True,max_length=50, help_text='Název (např. 22.1 verze 4) korekturovaného PDF') - - komentar = models.TextField(u'komentář k PDF',blank = True, help_text='Komentář ke korekturovanému PDF (např. na co se zaměřit)') - - pdf = models.FileField(u'PDF', upload_to = generate_filename) - - org = models.ForeignKey(Organizator, blank=True, - help_text='Zodpovědný organizátor za obsah', - null=True, - default=None) - - stran = models.IntegerField(u'počet stran', help_text='Počet stran PDF', - default=0) - STATUS_PRIDAVANI = 'pridavani' - STATUS_ZANASENI = 'zanaseni' - STATUS_ZASTARALE = 'zastarale' - STATUS_CHOICES = ( - (STATUS_PRIDAVANI, u'Přidávání korektur'), - (STATUS_ZANASENI, u'Korektury jsou zanášeny'), - (STATUS_ZASTARALE, u'Stará verze, nekorigovat'), - ) - status = models.CharField(u'stav PDF',max_length=16, choices=STATUS_CHOICES, blank=False, - default = STATUS_PRIDAVANI) - - - #TODO Nepovinný foreign key k číslu - - def get_prefix(self): - """Vrať řetězec, ke kterému se připojí číslo a .png""" - # vrátíme jméno souboru bez cesty - return os.path.basename(self.pdf.file.name) - - def convert(self): - """Vytvoří jedno png za každou stranu pdf a uloží se""" - dirname = os.path.join(settings.MEDIA_ROOT, settings.KOREKTURY_IMG_DIR) - if not os.path.exists(dirname): - os.mkdir(dirname) - self.stran = 0 - while True: - res = subprocess.call([ - "convert", - "-density", "180x180", - "-geometry", " 1024x1448", - "%s[%d]" % (self.pdf.path, self.stran), - os.path.join( - dirname, - "%s-%d.png" % (self.get_prefix(), self.stran) - ) - ]) - if res == 1: - break - self.stran += 1 - # Změnil se počet stran, ukládáme - super(KorekturovanePDF, self).save() - - def save(self): - # Pokud se nezmenilo PDF, tak nepregenerovavej nahledy - try: - original = KorekturovanePDF.objects.get(pk=self.pk) - if original.pdf == self.pdf: - super(KorekturovanePDF, self).save() - return - except ObjectDoesNotExist: - pass - # uložíme nahrávané pdf - super(KorekturovanePDF, self).save() - - # uložíme png a změněný počet stran - self.convert() + class Meta: + ordering = ['-cas'] + db_table = 'korekturovane_cislo' + verbose_name = u'PDF k opravám' + verbose_name_plural = u'PDF k opravám' + + #Interní ID + id = models.AutoField(primary_key = True) + + cas = models.DateTimeField(u'čas vložení PDF',default=timezone.now,help_text = 'Čas vložení PDF') + + nazev = models.CharField(u'název PDF',blank = True,max_length=50, help_text='Název (např. 22.1 verze 4) korekturovaného PDF') + + komentar = models.TextField(u'komentář k PDF',blank = True, help_text='Komentář ke korekturovanému PDF (např. na co se zaměřit)') + + pdf = models.FileField(u'PDF', upload_to = generate_filename) + + org = models.ForeignKey(Organizator, blank=True, + help_text='Zodpovědný organizátor za obsah', + null=True, + default=None) + + stran = models.IntegerField(u'počet stran', help_text='Počet stran PDF', + default=0) + STATUS_PRIDAVANI = 'pridavani' + STATUS_ZANASENI = 'zanaseni' + STATUS_ZASTARALE = 'zastarale' + STATUS_CHOICES = ( + (STATUS_PRIDAVANI, u'Přidávání korektur'), + (STATUS_ZANASENI, u'Korektury jsou zanášeny'), + (STATUS_ZASTARALE, u'Stará verze, nekorigovat'), + ) + status = models.CharField(u'stav PDF',max_length=16, choices=STATUS_CHOICES, blank=False, + default = STATUS_PRIDAVANI) + + + #TODO Nepovinný foreign key k číslu + + def get_prefix(self): + """Vrať řetězec, ke kterému se připojí číslo a .png""" + # vrátíme jméno souboru bez cesty + return os.path.basename(self.pdf.file.name) + + def convert(self): + """Vytvoří jedno png za každou stranu pdf a uloží se""" + dirname = os.path.join(settings.MEDIA_ROOT, settings.KOREKTURY_IMG_DIR) + if not os.path.exists(dirname): + os.mkdir(dirname) + self.stran = 0 + while True: + res = subprocess.call([ + "convert", + "-density", "180x180", + "-geometry", " 1024x1448", + "%s[%d]" % (self.pdf.path, self.stran), + os.path.join( + dirname, + "%s-%d.png" % (self.get_prefix(), self.stran) + ) + ]) + if res == 1: + break + self.stran += 1 + # Změnil se počet stran, ukládáme + super(KorekturovanePDF, self).save() + + def save(self): + # Pokud se nezmenilo PDF, tak nepregenerovavej nahledy + try: + original = KorekturovanePDF.objects.get(pk=self.pk) + if original.pdf == self.pdf: + super(KorekturovanePDF, self).save() + return + except ObjectDoesNotExist: + pass + # uložíme nahrávané pdf + super(KorekturovanePDF, self).save() + + # uložíme png a změněný počet stran + self.convert() @reversion.register(ignore_duplicates=True) @python_2_unicode_compatible class Oprava(models.Model): - class Meta: - db_table = 'opravy' - verbose_name = u'Oprava' - verbose_name_plural = u'Opravy' - ordering = ['y','x'] - - #Interní ID - id = models.AutoField(primary_key = True) - - pdf = models.ForeignKey(KorekturovanePDF, default=-1) - - strana = models.IntegerField(u'strana s opravou', help_text='Strana s opravou (od 0)') - - x = models.IntegerField(u'x-ová souřadnice bugu') - y = models.IntegerField(u'y-ová souřadnice bugu') - - STATUS_K_OPRAVE = 'k_oprave' - STATUS_OPRAVENO = 'opraveno' - STATUS_NENI_CHYBA = 'neni_chyba' - STATUS_K_ZANESENI = 'k_zaneseni' - STATUS_CHOICES = ( - (STATUS_K_OPRAVE, u'K opravě'), - (STATUS_OPRAVENO, u'Opraveno'), - (STATUS_NENI_CHYBA, u'Není chyba'), - (STATUS_K_ZANESENI, u'K zanesení do TeXu'), - ) - status = models.CharField(u'stav opravy',max_length=16, choices=STATUS_CHOICES, blank=False, - default = STATUS_K_OPRAVE) - - autor = models.ForeignKey(Organizator, blank = True, - help_text='Autor opravy', - null = True) - - text = models.TextField(u'text opravy',blank = True, help_text='Text opravy') - -# def __init__(self,dictionary): -# for k,v in dictionary.items(): -# setattr(self,k,v) - - def __str__(self): - return force_unicode(u'%s od %s: %s'%(self.status,self.autor,self.text)) + class Meta: + db_table = 'opravy' + verbose_name = u'Oprava' + verbose_name_plural = u'Opravy' + ordering = ['y','x'] + + #Interní ID + id = models.AutoField(primary_key = True) + + pdf = models.ForeignKey(KorekturovanePDF, default=-1) + + strana = models.IntegerField(u'strana s opravou', help_text='Strana s opravou (od 0)') + + x = models.IntegerField(u'x-ová souřadnice bugu') + y = models.IntegerField(u'y-ová souřadnice bugu') + + STATUS_K_OPRAVE = 'k_oprave' + STATUS_OPRAVENO = 'opraveno' + STATUS_NENI_CHYBA = 'neni_chyba' + STATUS_K_ZANESENI = 'k_zaneseni' + STATUS_CHOICES = ( + (STATUS_K_OPRAVE, u'K opravě'), + (STATUS_OPRAVENO, u'Opraveno'), + (STATUS_NENI_CHYBA, u'Není chyba'), + (STATUS_K_ZANESENI, u'K zanesení do TeXu'), + ) + status = models.CharField(u'stav opravy',max_length=16, choices=STATUS_CHOICES, blank=False, + default = STATUS_K_OPRAVE) + + autor = models.ForeignKey(Organizator, blank = True, + help_text='Autor opravy', + null = True) + + text = models.TextField(u'text opravy',blank = True, help_text='Text opravy') + +# def __init__(self,dictionary): +# for k,v in dictionary.items(): +# setattr(self,k,v) + + def __str__(self): + return force_unicode(u'%s od %s: %s'%(self.status,self.autor,self.text)) @reversion.register(ignore_duplicates=True) @python_2_unicode_compatible class Komentar(models.Model): - class Meta: - db_table = 'komentare' - verbose_name = u'Komentář k opravě' - verbose_name_plural = u'Komentáře k opravě' - ordering = ['cas'] - - #Interní ID - id = models.AutoField(primary_key = True) - - cas = models.DateTimeField(u'čas komentáře',default=timezone.now,help_text = 'Čas zadání komentáře') - - oprava = models.ForeignKey(Oprava) - autor = models.ForeignKey(Organizator, blank = True, - help_text = u'Autor komentáře', - null = True) - - text = models.TextField(u'text komentáře',blank = True, help_text='Text komentáře') - - def __str__(self): - return force_unicode(u'%s od %s: %s'%(self.cas,self.autor,self.text)) + class Meta: + db_table = 'komentare' + verbose_name = u'Komentář k opravě' + verbose_name_plural = u'Komentáře k opravě' + ordering = ['cas'] + + #Interní ID + id = models.AutoField(primary_key = True) + + cas = models.DateTimeField(u'čas komentáře',default=timezone.now,help_text = 'Čas zadání komentáře') + + oprava = models.ForeignKey(Oprava) + autor = models.ForeignKey(Organizator, blank = True, + help_text = u'Autor komentáře', + null = True) + + text = models.TextField(u'text komentáře',blank = True, help_text='Text komentáře') + + def __str__(self): + return force_unicode(u'%s od %s: %s'%(self.cas,self.autor,self.text)) diff --git a/korektury/urls.py b/korektury/urls.py index 2f131516..a1fe8469 100644 --- a/korektury/urls.py +++ b/korektury/urls.py @@ -6,7 +6,7 @@ from . import views staff_member_required = user_passes_test(lambda u: u.is_staff) urlpatterns = [ - url(r'^korektury/$', staff_member_required(views.KorekturyListView.as_view()), name='korektury-list'), - url(r'^korektury/(?P\d+)/$', staff_member_required(views.KorekturyView.as_view()), name='korektury'), - url(r'^korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), + url(r'^korektury/$', staff_member_required(views.KorekturyListView.as_view()), name='korektury-list'), + url(r'^korektury/(?P\d+)/$', staff_member_required(views.KorekturyView.as_view()), name='korektury'), + url(r'^korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), ] diff --git a/korektury/views.py b/korektury/views.py index c8abbd9e..fe2577bb 100644 --- a/korektury/views.py +++ b/korektury/views.py @@ -15,186 +15,186 @@ import os import unicodedata class KorekturyHelpView(generic.TemplateView): - template_name = 'korektury/help.html' + template_name = 'korektury/help.html' class KorekturyListView(generic.ListView): - model = KorekturovanePDF - template_name = 'korektury/seznam.html' + model = KorekturovanePDF + template_name = 'korektury/seznam.html' ### Korektury class KorekturyView(generic.TemplateView): - model = Oprava - template_name = 'korektury/opraf.html' - form_class = OpravaForm - - def post(self, request, *args, **kwargs): - form = self.form_class(request.POST) - q = request.POST - scroll = q.get('scroll') - - # prirazeni autora podle prihlaseni - autor_user = request.user - # pokud existuje ucet (user), ale neni to organizator = 403 - autor = Organizator.objects.filter(user=autor_user).first() - if not autor: - return HttpResponseForbidden() - - if not scroll: - scroll = 0 - - action = q.get('action') - if (action == ''): # Přidej - x = int(q.get('x')) - y = int(q.get('y')) - text = q.get('txt') - strana = int(q.get('img-id')[4:]) - pdf = KorekturovanePDF.objects.get(id=q.get('pdf')) - - op = Oprava(x=x,y=y, autor=autor, text=text, strana=strana,pdf = pdf) - op.save() - self.send_email_notification_komentar(op, autor, text) - elif (action == 'del'): - id = int(q.get('id')) - op = Oprava.objects.get(id=id) - op.delete() - elif (action == 'update'): - id = int(q.get('id')) - op = Oprava.objects.get(id=id) - text = q.get('txt') - op.autor = autor - op.text = text - op.save() - elif (action == 'undone'): - id = int(q.get('id')) - op = Oprava.objects.get(id=id) - op.status = op.STATUS_K_OPRAVE - op.save() - elif (action == 'done'): - id = int(q.get('id')) - op = Oprava.objects.get(id=id) - op.status = op.STATUS_OPRAVENO - op.save() - elif (action == 'ready'): - id = int(q.get('id')) - op = Oprava.objects.get(id=id) - op.status = op.STATUS_K_ZANESENI - op.save() - elif (action == 'wontfix'): - id = int(q.get('id')) - op = Oprava.objects.get(id=id) - op.status = op.STATUS_NENI_CHYBA - op.save() - elif (action == 'comment'): - id = int(q.get('id')) - op = Oprava.objects.get(id=id) - text = q.get('txt') - kom = Komentar(oprava=op,autor=autor,text=text) - kom.save() - self.send_email_notification_komentar(op, autor, text) - elif (action == 'update-comment'): - id = int(q.get('id')) - kom = Komentar.objects.get(id=id) - text = q.get('txt') - kom.text = text - kom.autor = autor - kom.save() - elif (action == 'del-comment'): - id = int(q.get('id')) - kom = Komentar.objects.get(id=id) - kom.delete() - elif (action == 'set-state'): - pdf = KorekturovanePDF.objects.get(id=q.get('pdf')) - if (q.get('state') == 'adding'): - pdf.status = pdf.STATUS_PRIDAVANI - elif (q.get('state') == 'comitting'): - pdf.status = pdf.STATUS_ZANASENI - elif (q.get('state') == 'deprecated'): - pdf.status = pdf.STATUS_ZASTARALE - pdf.save() - context = self.get_context_data() - context['scroll'] = scroll - context['autor'] = autor - return render(request, 'korektury/opraf.html',context) - - def send_email_notification_komentar(self, oprava, autor, text): - ''' Rozesle e-mail pri pridani komentare, - ktery obsahuje text komentare. - ''' - - # parametry e-mailu - odkaz = "https://mam.mff.cuni.cz/korektury/{}/".format(oprava.pdf.pk) - from_email = 'korekturovatko@mam.mff.cuni.cz' - subject = 'Nová korektura od {} v {}'.format(autor, - oprava.pdf.nazev) - text = u"Text komentáře:\n\n{}\n\n=== Konec textu komentáře ===\n\ - \nodkaz do korekturovátka: {}\n\ - \nVaše korekturovátko\n".format(text, odkaz) - - # Prijemci e-mailu - emails = set() - # e-mail autora korektury - email = oprava.autor.user.email - if email: - emails.add(email) - - # nalezeni e-mailu na autory komentaru - for komentar in oprava.komentar_set.all(): - email_komentujiciho = komentar.autor.user.email - if email_komentujiciho: - emails.add(email_komentujiciho) - - # zodpovedny org - if oprava.pdf.org: - email_zobpovedny = oprava.pdf.org.user.email - if email_zobpovedny: - emails.add(email_zobpovedny) - - # odstran e-mail autora opravy - email = autor.user.email - if email: - emails.discard(email) - - if not settings.SEND_EMAIL_NOTIFICATIONS: - print("Poslal bych upozornění na tyto adresy: ", " ".join(emails)) - return - - send_mail(subject, text, from_email, list(emails)) - - def get_context_data(self, **kwargs): - context = super(KorekturyView,self).get_context_data(**kwargs) - pdf = get_object_or_404(KorekturovanePDF, id=self.kwargs['pdf']) - context['pdf'] = pdf - context['img_prefix'] = pdf.get_prefix() - context['img_path'] = settings.KOREKTURY_IMG_DIR - context['img_indexes'] = range(pdf.stran) - context['form_oprava'] = OpravaForm() - opravy = Oprava.objects.filter(pdf=self.kwargs['pdf']) - zasluhy = {} - for o in opravy: - if o.autor in zasluhy: - zasluhy[o.autor]+=1 - else: - zasluhy[o.autor]=1 - o.komentare = o.komentar_set.all() - for k in o.komentare: - if k.autor in zasluhy: - zasluhy[k.autor] += 1 - else: - zasluhy[k.autor] = 1 - zasluhy = [ - {'autor': jmeno, 'pocet': pocet} - for (jmeno, pocet) in zasluhy.items() - ] - zasluhy.sort(key=lambda z: z['pocet'], reverse=True) - - strany = set(o.strana for o in opravy) - opravy_na_stranu = [{'strana': s, 'op_id': opravy.filter(strana=s)} for s in strany] - context['opravy_strany'] = opravy_na_stranu - - context['opravy'] = opravy - context['zasluhy'] = zasluhy - return context - - def form_valid(self,form): - return super(KorekturyView,self).form_valid(form) + model = Oprava + template_name = 'korektury/opraf.html' + form_class = OpravaForm + + def post(self, request, *args, **kwargs): + form = self.form_class(request.POST) + q = request.POST + scroll = q.get('scroll') + + # prirazeni autora podle prihlaseni + autor_user = request.user + # pokud existuje ucet (user), ale neni to organizator = 403 + autor = Organizator.objects.filter(user=autor_user).first() + if not autor: + return HttpResponseForbidden() + + if not scroll: + scroll = 0 + + action = q.get('action') + if (action == ''): # Přidej + x = int(q.get('x')) + y = int(q.get('y')) + text = q.get('txt') + strana = int(q.get('img-id')[4:]) + pdf = KorekturovanePDF.objects.get(id=q.get('pdf')) + + op = Oprava(x=x,y=y, autor=autor, text=text, strana=strana,pdf = pdf) + op.save() + self.send_email_notification_komentar(op, autor, text) + elif (action == 'del'): + id = int(q.get('id')) + op = Oprava.objects.get(id=id) + op.delete() + elif (action == 'update'): + id = int(q.get('id')) + op = Oprava.objects.get(id=id) + text = q.get('txt') + op.autor = autor + op.text = text + op.save() + elif (action == 'undone'): + id = int(q.get('id')) + op = Oprava.objects.get(id=id) + op.status = op.STATUS_K_OPRAVE + op.save() + elif (action == 'done'): + id = int(q.get('id')) + op = Oprava.objects.get(id=id) + op.status = op.STATUS_OPRAVENO + op.save() + elif (action == 'ready'): + id = int(q.get('id')) + op = Oprava.objects.get(id=id) + op.status = op.STATUS_K_ZANESENI + op.save() + elif (action == 'wontfix'): + id = int(q.get('id')) + op = Oprava.objects.get(id=id) + op.status = op.STATUS_NENI_CHYBA + op.save() + elif (action == 'comment'): + id = int(q.get('id')) + op = Oprava.objects.get(id=id) + text = q.get('txt') + kom = Komentar(oprava=op,autor=autor,text=text) + kom.save() + self.send_email_notification_komentar(op, autor, text) + elif (action == 'update-comment'): + id = int(q.get('id')) + kom = Komentar.objects.get(id=id) + text = q.get('txt') + kom.text = text + kom.autor = autor + kom.save() + elif (action == 'del-comment'): + id = int(q.get('id')) + kom = Komentar.objects.get(id=id) + kom.delete() + elif (action == 'set-state'): + pdf = KorekturovanePDF.objects.get(id=q.get('pdf')) + if (q.get('state') == 'adding'): + pdf.status = pdf.STATUS_PRIDAVANI + elif (q.get('state') == 'comitting'): + pdf.status = pdf.STATUS_ZANASENI + elif (q.get('state') == 'deprecated'): + pdf.status = pdf.STATUS_ZASTARALE + pdf.save() + context = self.get_context_data() + context['scroll'] = scroll + context['autor'] = autor + return render(request, 'korektury/opraf.html',context) + + def send_email_notification_komentar(self, oprava, autor, text): + ''' Rozesle e-mail pri pridani komentare, + ktery obsahuje text komentare. + ''' + + # parametry e-mailu + odkaz = "https://mam.mff.cuni.cz/korektury/{}/".format(oprava.pdf.pk) + from_email = 'korekturovatko@mam.mff.cuni.cz' + subject = 'Nová korektura od {} v {}'.format(autor, + oprava.pdf.nazev) + text = u"Text komentáře:\n\n{}\n\n=== Konec textu komentáře ===\n\ + \nodkaz do korekturovátka: {}\n\ + \nVaše korekturovátko\n".format(text, odkaz) + + # Prijemci e-mailu + emails = set() + # e-mail autora korektury + email = oprava.autor.user.email + if email: + emails.add(email) + + # nalezeni e-mailu na autory komentaru + for komentar in oprava.komentar_set.all(): + email_komentujiciho = komentar.autor.user.email + if email_komentujiciho: + emails.add(email_komentujiciho) + + # zodpovedny org + if oprava.pdf.org: + email_zobpovedny = oprava.pdf.org.user.email + if email_zobpovedny: + emails.add(email_zobpovedny) + + # odstran e-mail autora opravy + email = autor.user.email + if email: + emails.discard(email) + + if not settings.SEND_EMAIL_NOTIFICATIONS: + print("Poslal bych upozornění na tyto adresy: ", " ".join(emails)) + return + + send_mail(subject, text, from_email, list(emails)) + + def get_context_data(self, **kwargs): + context = super(KorekturyView,self).get_context_data(**kwargs) + pdf = get_object_or_404(KorekturovanePDF, id=self.kwargs['pdf']) + context['pdf'] = pdf + context['img_prefix'] = pdf.get_prefix() + context['img_path'] = settings.KOREKTURY_IMG_DIR + context['img_indexes'] = range(pdf.stran) + context['form_oprava'] = OpravaForm() + opravy = Oprava.objects.filter(pdf=self.kwargs['pdf']) + zasluhy = {} + for o in opravy: + if o.autor in zasluhy: + zasluhy[o.autor]+=1 + else: + zasluhy[o.autor]=1 + o.komentare = o.komentar_set.all() + for k in o.komentare: + if k.autor in zasluhy: + zasluhy[k.autor] += 1 + else: + zasluhy[k.autor] = 1 + zasluhy = [ + {'autor': jmeno, 'pocet': pocet} + for (jmeno, pocet) in zasluhy.items() + ] + zasluhy.sort(key=lambda z: z['pocet'], reverse=True) + + strany = set(o.strana for o in opravy) + opravy_na_stranu = [{'strana': s, 'op_id': opravy.filter(strana=s)} for s in strany] + context['opravy_strany'] = opravy_na_stranu + + context['opravy'] = opravy + context['zasluhy'] = zasluhy + return context + + def form_valid(self,form): + return super(KorekturyView,self).form_valid(form) diff --git a/prednasky/admin.py b/prednasky/admin.py index 99504ddf..2688fffc 100644 --- a/prednasky/admin.py +++ b/prednasky/admin.py @@ -10,91 +10,91 @@ from seminar.models import Soustredeni class Seznam_PrednaskaInline(admin.TabularInline): - model = Prednaska.seznamy.through - extra = 0 - - def prednaska__nazev(self, obj): - return mark_safe( - u"{}".format( - obj.prednaska.id, - escape(obj.prednaska.nazev) - ) - ) - - def prednaska__popis(self, obj): - return mark_safe( - u"
{}
".format( - escape(obj.prednaska.popis) - ) - ) - - def prednaska__anotace(self, obj): - return obj.prednaska.anotace - - def prednaska__org(self, obj): - return obj.prednaska.org - - def prednaska__obor(self, obj): - return obj.prednaska.obor - - prednaska__nazev.short_description = u'Přednáška' - prednaska__popis.short_description = u'Popis pro orgy' - prednaska__anotace.short_description = u'Anotace' - prednaska__org.short_description = u'Org' - prednaska__obor.short_description = u'Obor' - - readonly_fields = [ - 'prednaska__nazev', - 'prednaska__obor', - 'prednaska__org', - 'prednaska__popis', - 'prednaska__anotace', - ] - exclude = ['prednaska'] - - def has_add_permission(self, req): return False + model = Prednaska.seznamy.through + extra = 0 + + def prednaska__nazev(self, obj): + return mark_safe( + u"{}".format( + obj.prednaska.id, + escape(obj.prednaska.nazev) + ) + ) + + def prednaska__popis(self, obj): + return mark_safe( + u"
{}
".format( + escape(obj.prednaska.popis) + ) + ) + + def prednaska__anotace(self, obj): + return obj.prednaska.anotace + + def prednaska__org(self, obj): + return obj.prednaska.org + + def prednaska__obor(self, obj): + return obj.prednaska.obor + + prednaska__nazev.short_description = u'Přednáška' + prednaska__popis.short_description = u'Popis pro orgy' + prednaska__anotace.short_description = u'Anotace' + prednaska__org.short_description = u'Org' + prednaska__obor.short_description = u'Obor' + + readonly_fields = [ + 'prednaska__nazev', + 'prednaska__obor', + 'prednaska__org', + 'prednaska__popis', + 'prednaska__anotace', + ] + exclude = ['prednaska'] + + def has_add_permission(self, req): return False class SeznamAdmin(VersionAdmin): - list_display = ['soustredeni', 'stav'] - inlines = [Seznam_PrednaskaInline] + list_display = ['soustredeni', 'stav'] + inlines = [Seznam_PrednaskaInline] admin.site.register(Seznam, SeznamAdmin) class PrednaskaAdmin(VersionAdmin): - list_display = ['nazev', 'org', 'obor'] - list_filter = ['org', 'obor'] - search_fields = [] - filter_horizontal = ('seznamy', ) - - actions = ['move_to_soustredeni'] - - def move_to_soustredeni(self, request, queryset): - sous = Soustredeni.objects.first() - seznam = Seznam.objects.filter(soustredeni=sous, stav=STAV_NAVRH) - if len(seznam) == 0: - self.message_user( - request, - u"Není definován seznam pro aktuální soustředění, " - u"nic se neprovedlo", - messages.ERROR - ) - return - seznam = seznam[0] - for prednaska in queryset: - prednaska.seznamy.add(seznam) - prednaska.save() - - self.message_user( - request, - u"Vybrané přednášky ({}) přidány jako návrhy na nejbližší " - u"soustředění".format(len(queryset)) - ) - - move_to_soustredeni.short_description = ( - u"Přidat přednášky do návrhu na nejbližší soustředění" - ) + list_display = ['nazev', 'org', 'obor'] + list_filter = ['org', 'obor'] + search_fields = [] + filter_horizontal = ('seznamy', ) + + actions = ['move_to_soustredeni'] + + def move_to_soustredeni(self, request, queryset): + sous = Soustredeni.objects.first() + seznam = Seznam.objects.filter(soustredeni=sous, stav=STAV_NAVRH) + if len(seznam) == 0: + self.message_user( + request, + u"Není definován seznam pro aktuální soustředění, " + u"nic se neprovedlo", + messages.ERROR + ) + return + seznam = seznam[0] + for prednaska in queryset: + prednaska.seznamy.add(seznam) + prednaska.save() + + self.message_user( + request, + u"Vybrané přednášky ({}) přidány jako návrhy na nejbližší " + u"soustředění".format(len(queryset)) + ) + + move_to_soustredeni.short_description = ( + u"Přidat přednášky do návrhu na nejbližší soustředění" + ) admin.site.register(Prednaska, PrednaskaAdmin) diff --git a/prednasky/forms.py b/prednasky/forms.py index 969232e3..071d068e 100644 --- a/prednasky/forms.py +++ b/prednasky/forms.py @@ -2,7 +2,7 @@ from django import forms class NewPrednaskyForm(forms.Form): - ucastnik = forms.CharField(label = 'Tvoje jméno', max_length = 100) + ucastnik = forms.CharField(label = 'Tvoje jméno', max_length = 100) diff --git a/prednasky/models.py b/prednasky/models.py index e1e57eef..1cda462f 100644 --- a/prednasky/models.py +++ b/prednasky/models.py @@ -29,15 +29,15 @@ class Seznam(models.Model): stav = models.IntegerField('Stav',choices=STAV_CHOICES,default = STAV_NAVRH) def __str__(self): - return force_unicode("Seznam {}přednášek na {}".format("návrhů " - if self.stav == STAV_NAVRH else "", self.soustredeni)) + return force_unicode("Seznam {}přednášek na {}".format("návrhů " + if self.stav == STAV_NAVRH else "", self.soustredeni)) CHOICES_OBTIZNOST = ( - (1, 'Lehká'), - (2, 'Střední'), - (3, 'Těžká'), - ) + (1, 'Lehká'), + (2, 'Střední'), + (3, 'Těžká'), + ) CHOICES_BODY = ( (-1, '-1'), @@ -82,5 +82,5 @@ class Hlasovani(models.Model): def __str__(self): return force_unicode("{} dal {} bodů {} v seznamu {}".format(self.ucastnik, - self.body, self.prednaska, self.seznam)) + self.body, self.prednaska, self.seznam)) diff --git a/prednasky/urls.py b/prednasky/urls.py index 94fcccdb..e00abea4 100644 --- a/prednasky/urls.py +++ b/prednasky/urls.py @@ -6,10 +6,10 @@ from . import views staff_member_required = user_passes_test(lambda u: u.is_staff) urlpatterns = [ - url(r'^prednasky/$', views.newPrednaska), - url(r'^prednasky/hotovo$', views.Prednaska_hotovo), - url(r'^prednasky/metaseznam_prednasek$', staff_member_required(views.MetaSeznamListView.as_view()), name='metaseznam-list'), - url(r'^prednasky/seznam_prednasek/(?P\d+)/$', staff_member_required(views.SeznamListView.as_view()), name='seznam-list'), - url(r'^prednasky/seznam_prednasek/(?P\d+)/export$', staff_member_required(views.SeznamExportView), name='seznam-export'), -# url(r'^korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), + url(r'^prednasky/$', views.newPrednaska), + url(r'^prednasky/hotovo$', views.Prednaska_hotovo), + url(r'^prednasky/metaseznam_prednasek$', staff_member_required(views.MetaSeznamListView.as_view()), name='metaseznam-list'), + url(r'^prednasky/seznam_prednasek/(?P\d+)/$', staff_member_required(views.SeznamListView.as_view()), name='seznam-list'), + url(r'^prednasky/seznam_prednasek/(?P\d+)/export$', staff_member_required(views.SeznamExportView), name='seznam-export'), +# url(r'^korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), ] diff --git a/prednasky/views.py b/prednasky/views.py index 05c63954..a5dbbd76 100644 --- a/prednasky/views.py +++ b/prednasky/views.py @@ -10,83 +10,83 @@ from seminar.models import Soustredeni from prednasky.forms import NewPrednaskyForm def newPrednaska(request): - # hlasovani se vztahuje k nejnovejsimu soustredeni - sous = Soustredeni.objects.first() - seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first() - print(seznam) - # obsluha formulare - if request.method == 'POST': - form = NewPrednaskyForm(request.POST, request.FILES) - if form.is_valid(): - jmeno = form.cleaned_data['ucastnik'] - for i in request.POST: - if i[0] == 'q': - hlasovani = Hlasovani() - print("q:"+i[1:]) - hlasovani.prednaska = Prednaska.objects.filter(pk = int(i[1:]))[0] - hlasovani.body = int(request.POST[i]) - hlasovani.ucastnik = jmeno - hlasovani.seznam = seznam - hlasovani.save() - - # presmerovani na prave vzniklou galerii - return HttpResponseRedirect('./hotovo') - - else: - form = NewPrednaskyForm() - - return render( - request, - 'prednasky/base.html', - {'form': form, 'prednasky': seznam} - ) + # hlasovani se vztahuje k nejnovejsimu soustredeni + sous = Soustredeni.objects.first() + seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first() + print(seznam) + # obsluha formulare + if request.method == 'POST': + form = NewPrednaskyForm(request.POST, request.FILES) + if form.is_valid(): + jmeno = form.cleaned_data['ucastnik'] + for i in request.POST: + if i[0] == 'q': + hlasovani = Hlasovani() + print("q:"+i[1:]) + hlasovani.prednaska = Prednaska.objects.filter(pk = int(i[1:]))[0] + hlasovani.body = int(request.POST[i]) + hlasovani.ucastnik = jmeno + hlasovani.seznam = seznam + hlasovani.save() + + # presmerovani na prave vzniklou galerii + return HttpResponseRedirect('./hotovo') + + else: + form = NewPrednaskyForm() + + return render( + request, + 'prednasky/base.html', + {'form': form, 'prednasky': seznam} + ) def Prednaska_hotovo(request): - return render(request, 'prednasky/hotovo.html') + return render(request, 'prednasky/hotovo.html') class MetaSeznamListView(generic.ListView): - model = Seznam - template_name = 'prednasky/metaseznam_prednasek.html' + model = Seznam + template_name = 'prednasky/metaseznam_prednasek.html' class SeznamListView(generic.ListView): - template_name = 'prednasky/seznam_prednasek.html' + template_name = 'prednasky/seznam_prednasek.html' - def get_queryset(self): - self.seznam = get_object_or_404(Seznam, id=self.kwargs["seznam"]) - prednasky = Prednaska.objects.filter(seznamy=self.seznam).order_by( - 'org__user__first_name', 'org__user__last_name' - ).annotate(body=Sum('hlasovani__body')) - return prednasky + def get_queryset(self): + self.seznam = get_object_or_404(Seznam, id=self.kwargs["seznam"]) + prednasky = Prednaska.objects.filter(seznamy=self.seznam).order_by( + 'org__user__first_name', 'org__user__last_name' + ).annotate(body=Sum('hlasovani__body')) + return prednasky def SeznamExportView(request, seznam): - u"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor""" - # TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro - # lidi? - hlasovani = Hlasovani.objects.filter(seznam=seznam) - prednasky = Prednaska.objects.filter(seznamy=seznam) - orgove = set(p.org for p in prednasky) - ucastnici = set(h.ucastnik for h in hlasovani) - - for p in prednasky: - p.body = [] - for u in ucastnici: - try: - p.body.append(hlasovani.get(ucastnik=u, prednaska=p).body) - except ObjectDoesNotExist: - # účastník nehlasoval - p.body.append("?") - - for h in hlasovani: - h.ucastnik = hash(h.ucastnik) - - return render( - request, - 'prednasky/seznam_prednasek_export.txt', - {"hlasovani": hlasovani, "prednasky": prednasky, "orgove": orgove}, - content_type="text/plain" - ) + u"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor""" + # TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro + # lidi? + hlasovani = Hlasovani.objects.filter(seznam=seznam) + prednasky = Prednaska.objects.filter(seznamy=seznam) + orgove = set(p.org for p in prednasky) + ucastnici = set(h.ucastnik for h in hlasovani) + + for p in prednasky: + p.body = [] + for u in ucastnici: + try: + p.body.append(hlasovani.get(ucastnik=u, prednaska=p).body) + except ObjectDoesNotExist: + # účastník nehlasoval + p.body.append("?") + + for h in hlasovani: + h.ucastnik = hash(h.ucastnik) + + return render( + request, + 'prednasky/seznam_prednasek_export.txt', + {"hlasovani": hlasovani, "prednasky": prednasky, "orgove": orgove}, + content_type="text/plain" + ) diff --git a/seminar/admin.py b/seminar/admin.py index 128c825e..55a59c07 100644 --- a/seminar/admin.py +++ b/seminar/admin.py @@ -18,34 +18,34 @@ from autocomplete_light import shortcuts as autocomplete_light class UserModelChoiceField(forms.ModelChoiceField): - u"""Vlastní ModelChoiceField pro uživatele. Zobrazí kromě loginu i jméno. - """ - def label_from_instance(self, obj): - return u"{} ({})".format(obj.get_full_name(), obj.username) + u"""Vlastní ModelChoiceField pro uživatele. Zobrazí kromě loginu i jméno. + """ + def label_from_instance(self, obj): + return u"{} ({})".format(obj.get_full_name(), obj.username) def get_form_predvypln_autora(self, request, obj=None, *args, **kwargs): - u"""get_form fce pro Adminy. Předvyplňí přihlášeného uživatele jako autora. - """ - form = super(self.__class__, self).get_form(request, *args, **kwargs) - form.base_fields['autor'].initial = request.user.id - return form + u"""get_form fce pro Adminy. Předvyplňí přihlášeného uživatele jako autora. + """ + form = super(self.__class__, self).get_form(request, *args, **kwargs) + form.base_fields['autor'].initial = request.user.id + return form def make_set_action(atribut, hodnota, nazev): - u""" - Pomocnik pro rychle vytvareni hromadnych admin akci ktere jen nastavuji - atribut (dany jako string) na danou hodnotu. - nazev je krátký popis akce pro admin rozhraní.""" - def action_f(modeladmin, request, queryset): - for obj in queryset: - assert atribut in obj.__dict__ - obj.__setattr__(atribut, hodnota) - obj.save() - action_f.short_description = nazev - # Trik: je potřeba, aby se funkce různě (ale libovolně) jmenovaly, - # jinak je Django v seznamu akcí splácne do jedné - action_f.__name__ = 'action_f_%d_%d_%d' % (id(atribut), id(hodnota), id(nazev), ) - return action_f + u""" + Pomocnik pro rychle vytvareni hromadnych admin akci ktere jen nastavuji + atribut (dany jako string) na danou hodnotu. + nazev je krátký popis akce pro admin rozhraní.""" + def action_f(modeladmin, request, queryset): + for obj in queryset: + assert atribut in obj.__dict__ + obj.__setattr__(atribut, hodnota) + obj.save() + action_f.short_description = nazev + # Trik: je potřeba, aby se funkce různě (ale libovolně) jmenovaly, + # jinak je Django v seznamu akcí splácne do jedné + action_f.__name__ = 'action_f_%d_%d_%d' % (id(atribut), id(hodnota), id(nazev), ) + return action_f ### Globální nastavení @@ -56,202 +56,202 @@ admin.site.register(Nastaveni, SingletonModelAdmin) ### UTILS (pro verbose_name a help_text) def field_labels(model, fieldname): - f = [i for i in model._meta.fields if i.name == fieldname][0] - return {'label': f.verbose_name.capitalize(), 'help_text': f.help_text, } + f = [i for i in model._meta.fields if i.name == fieldname][0] + return {'label': f.verbose_name.capitalize(), 'help_text': f.help_text, } def create_modeladmin(modeladmin, model, name = None, verbose_name = None, verbose_name_plural = None): - - class Meta: - proxy = True - app_label = model._meta.app_label - Meta.verbose_name = verbose_name - Meta.verbose_name_plural = verbose_name_plural - - attrs = {'__module__': '', 'Meta': Meta} - newmodel = type(name, (model,), attrs) - admin.site.register(newmodel, modeladmin) - return modeladmin + + class Meta: + proxy = True + app_label = model._meta.app_label + Meta.verbose_name = verbose_name + Meta.verbose_name_plural = verbose_name_plural + + attrs = {'__module__': '', 'Meta': Meta} + newmodel = type(name, (model,), attrs) + admin.site.register(newmodel, modeladmin) + return modeladmin ### INLINES class ResitelInline(admin.TabularInline): - model = Resitel - fields = ['osoba_jmeno', 'osoba_prijmeni', 'skola', 'osoba_mesto', 'rok_maturity', ] - readonly_fields = ['osoba_jmeno', 'osoba_prijmeni', 'skola', 'osoba_mesto', 'rok_maturity', ] - extra = 0 - view_on_site = False + model = Resitel + fields = ['osoba_jmeno', 'osoba_prijmeni', 'skola', 'osoba_mesto', 'rok_maturity', ] + readonly_fields = ['osoba_jmeno', 'osoba_prijmeni', 'skola', 'osoba_mesto', 'rok_maturity', ] + extra = 0 + view_on_site = False - def osoba_jmeno(self, obj): - return obj.osoba.jmeno + def osoba_jmeno(self, obj): + return obj.osoba.jmeno - def osoba_prijmeni(self, obj): - return obj.osoba.prijmeni + def osoba_prijmeni(self, obj): + return obj.osoba.prijmeni - def osoba_mesto(self, obj): - return obj.osoba.mesto + def osoba_mesto(self, obj): + return obj.osoba.mesto - def has_add_permission(self, req): return False + def has_add_permission(self, req): return False class CisloInline(admin.TabularInline): - model = Cislo - fields = ['cislo', - 'datum_vydani', 'datum_deadline', 'datum_deadline_soustredeni', - 'verejne_db', 'poznamka'] - readonly_fields = ['cislo'] - extra = 0 - formfield_overrides = { - models.TextField: {'widget': forms.TextInput}, - } - view_on_site = Cislo.verejne_url + model = Cislo + fields = ['cislo', + 'datum_vydani', 'datum_deadline', 'datum_deadline_soustredeni', + 'verejne_db', 'poznamka'] + readonly_fields = ['cislo'] + extra = 0 + formfield_overrides = { + models.TextField: {'widget': forms.TextInput}, + } + view_on_site = Cislo.verejne_url - def has_add_permission(self, req): return False + def has_add_permission(self, req): return False class PrilohaReseniInline(admin.StackedInline): - model = PrilohaReseni - fields = ['vytvoreno', 'soubor', 'poznamka'] - readonly_fields = ['vytvoreno'] - formfield_overrides = { - models.TextField: {'widget': forms.TextInput}, - } - view_on_site = False + model = PrilohaReseni + fields = ['vytvoreno', 'soubor', 'poznamka'] + readonly_fields = ['vytvoreno'] + formfield_overrides = { + models.TextField: {'widget': forms.TextInput}, + } + view_on_site = False - extra = 0 + extra = 0 class ProblemInline(admin.TabularInline): - model = Problem - fields = ['kod', 'nazev', 'autor', 'garant', 'opravovatele', 'stav'] - formfield_overrides = { - models.TextField: {'widget': forms.TextInput}, - } - view_on_site = Problem.verejne_url + model = Problem + fields = ['kod', 'nazev', 'autor', 'garant', 'opravovatele', 'stav'] + formfield_overrides = { + models.TextField: {'widget': forms.TextInput}, + } + view_on_site = Problem.verejne_url - extra = 0 + extra = 0 class ReseniKProblemuInline(admin.TabularInline): - form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['resitele'], fields=['resitele']) - model = Reseni - fields = ['resitele', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka'] - readonly_fields = ['timestamp'] - extra = 0 - formfield_overrides = { - models.TextField: {'widget': forms.TextInput}, - } - view_on_site = False - - def get_queryset(self, request): - qs = super(ReseniKProblemuInline, self).get_queryset(request) - return qs.select_related('problem', 'cislo_body', 'resitele') - - # Potenciální DB HOG (cislo_body se dotazovalo na cisla pri kazdem zobrazeni jejich selectu ...) - def formfield_for_dbfield(self, db_field, **kwargs): - formfield = super(ReseniKProblemuInline, self).formfield_for_dbfield(db_field, **kwargs) - if db_field.name == 'cislo_body': - # dirty trick so queryset is evaluated and cached in .choices - formfield.choices = formfield.choices - return formfield + form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['resitele'], fields=['resitele']) + model = Reseni + fields = ['resitele', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka'] + readonly_fields = ['timestamp'] + extra = 0 + formfield_overrides = { + models.TextField: {'widget': forms.TextInput}, + } + view_on_site = False + + def get_queryset(self, request): + qs = super(ReseniKProblemuInline, self).get_queryset(request) + return qs.select_related('problem', 'cislo_body', 'resitele') + + # Potenciální DB HOG (cislo_body se dotazovalo na cisla pri kazdem zobrazeni jejich selectu ...) + def formfield_for_dbfield(self, db_field, **kwargs): + formfield = super(ReseniKProblemuInline, self).formfield_for_dbfield(db_field, **kwargs) + if db_field.name == 'cislo_body': + # dirty trick so queryset is evaluated and cached in .choices + formfield.choices = formfield.choices + return formfield class ReseniKResiteliInline(admin.TabularInline): - model = Reseni - fields = ['problem', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka'] - readonly_fields = ['cas_doruceni', 'problem'] - extra = 0 - formfield_overrides = { - models.TextField: {'widget': forms.TextInput}, - } - view_on_site = False - - def has_add_permission(self, req): return False - - def get_queryset(self, request): - qs = super(ReseniKResiteliInline, self).get_queryset(request) - return qs.select_related('problem', 'cislo_body', 'resitel') - - # Potenciální DB HOG (cislo_body se dotazovalo na cisla pri kazdem zobrazeni jejich selectu ...) - def formfield_for_dbfield(self, db_field, **kwargs): - formfield = super(ReseniKResiteliInline, self).formfield_for_dbfield(db_field, **kwargs) - if db_field.name == 'cislo_body': - # dirty trick so queryset is evaluated and cached in .choices - formfield.choices = formfield.choices - return formfield + model = Reseni + fields = ['problem', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka'] + readonly_fields = ['cas_doruceni', 'problem'] + extra = 0 + formfield_overrides = { + models.TextField: {'widget': forms.TextInput}, + } + view_on_site = False + + def has_add_permission(self, req): return False + + def get_queryset(self, request): + qs = super(ReseniKResiteliInline, self).get_queryset(request) + return qs.select_related('problem', 'cislo_body', 'resitel') + + # Potenciální DB HOG (cislo_body se dotazovalo na cisla pri kazdem zobrazeni jejich selectu ...) + def formfield_for_dbfield(self, db_field, **kwargs): + formfield = super(ReseniKResiteliInline, self).formfield_for_dbfield(db_field, **kwargs) + if db_field.name == 'cislo_body': + # dirty trick so queryset is evaluated and cached in .choices + formfield.choices = formfield.choices + return formfield class Soustredeni_UcastniciInline(admin.TabularInline): - form = autocomplete_light.modelform_factory(Soustredeni_Ucastnici, autocomplete_fields=['resitel'], fields=['resitel']) - model = Soustredeni_Ucastnici - fields = ['resitel', 'poznamka', ] - extra = 0 - formfield_overrides = { - models.TextField: {'widget': forms.TextInput}, - } + form = autocomplete_light.modelform_factory(Soustredeni_Ucastnici, autocomplete_fields=['resitel'], fields=['resitel']) + model = Soustredeni_Ucastnici + fields = ['resitel', 'poznamka', ] + extra = 0 + formfield_overrides = { + models.TextField: {'widget': forms.TextInput}, + } - def get_queryset(self, request): - qs = super(Soustredeni_UcastniciInline, self).get_queryset(request) - return qs.select_related('resitel', 'soustredeni') + def get_queryset(self, request): + qs = super(Soustredeni_UcastniciInline, self).get_queryset(request) + return qs.select_related('resitel', 'soustredeni') class Soustredeni_OrganizatoriInline(admin.TabularInline): - form = autocomplete_light.modelform_factory(Soustredeni_Organizatori, autocomplete_fields=['organizator'], fields=['organizator'],) - model = Soustredeni_Organizatori - fields = ['organizator', 'poznamka', ] - extra = 0 - formfield_overrides = { - models.TextField: {'widget': forms.TextInput}, - } - - def get_queryset(self, request): - qs = super(Soustredeni_OrganizatoriInline, self).get_queryset(request) - return qs.select_related('organizator', 'soustredeni') + form = autocomplete_light.modelform_factory(Soustredeni_Organizatori, autocomplete_fields=['organizator'], fields=['organizator'],) + model = Soustredeni_Organizatori + fields = ['organizator', 'poznamka', ] + extra = 0 + formfield_overrides = { + models.TextField: {'widget': forms.TextInput}, + } + + def get_queryset(self, request): + qs = super(Soustredeni_OrganizatoriInline, self).get_queryset(request) + return qs.select_related('organizator', 'soustredeni') ### Resitel class ResitelAdmin(VersionAdmin): - form = autocomplete_light.modelform_factory(Resitel, autocomplete_fields=['skola'], fields=['skola']) - fk_name = 'osoba' - fieldsets = [ - (None, {'fields': ['jmeno', 'prijmeni', 'user']}), - (u'Škola', {'fields': ['skola', 'rok_maturity']}), - (u'Seminář', {'fields': ['datum_souhlasu_udaje', 'datum_souhlasu_zasilani', 'datum_prihlaseni', 'zasilat']}), - (u'Osobní údaje', {'fields': ['pohlavi_muz', 'datum_narozeni', 'email', 'telefon']}), - (u'Adresa', {'fields': ['ulice', 'mesto', 'psc', 'stat']}), - ] - list_display = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__user', 'osoba__pohlavi_muz', 'skola', 'rok_maturity', 'pocet_reseni'] - list_filter = ['osoba__pohlavi_muz', 'rok_maturity', 'zasilat'] - search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__ulice', 'osoba__mesto', 'osoba__email'] -# inlines = [ReseniKResiteliInline] # FIXME: - view_on_site = False - - def osoba__jmeno(self, obj): - return obj.osoba.jmeno - - def osoba__prijmeni(self, obj): - return obj.osoba.prijmeni - - def osoba__user(self, obj): - return obj.osoba.user - - def osoba__pohlavi_muz(self, obj): - return obj.osoba.pohlavi_muz - - def osoba__ulice(self, obj): - return obj.osoba.ulice - - def osoba__mesto(self, obj): - return obj.osoba.mesto - - def osoba__email(self, obj): - return obj.osoba.email - - def get_queryset(self, request): - qs = super(ResitelAdmin, self).get_queryset(request) - return qs.select_related('skola', 'user').annotate(pocet_reseni=Count('reseni')) - - def pocet_reseni(self, obj): - return obj.pocet_reseni + form = autocomplete_light.modelform_factory(Resitel, autocomplete_fields=['skola'], fields=['skola']) + fk_name = 'osoba' + fieldsets = [ + (None, {'fields': ['jmeno', 'prijmeni', 'user']}), + (u'Škola', {'fields': ['skola', 'rok_maturity']}), + (u'Seminář', {'fields': ['datum_souhlasu_udaje', 'datum_souhlasu_zasilani', 'datum_prihlaseni', 'zasilat']}), + (u'Osobní údaje', {'fields': ['pohlavi_muz', 'datum_narozeni', 'email', 'telefon']}), + (u'Adresa', {'fields': ['ulice', 'mesto', 'psc', 'stat']}), + ] + list_display = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__user', 'osoba__pohlavi_muz', 'skola', 'rok_maturity', 'pocet_reseni'] + list_filter = ['osoba__pohlavi_muz', 'rok_maturity', 'zasilat'] + search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__ulice', 'osoba__mesto', 'osoba__email'] +# inlines = [ReseniKResiteliInline] # FIXME: + view_on_site = False + + def osoba__jmeno(self, obj): + return obj.osoba.jmeno + + def osoba__prijmeni(self, obj): + return obj.osoba.prijmeni + + def osoba__user(self, obj): + return obj.osoba.user + + def osoba__pohlavi_muz(self, obj): + return obj.osoba.pohlavi_muz + + def osoba__ulice(self, obj): + return obj.osoba.ulice + + def osoba__mesto(self, obj): + return obj.osoba.mesto + + def osoba__email(self, obj): + return obj.osoba.email + + def get_queryset(self, request): + qs = super(ResitelAdmin, self).get_queryset(request) + return qs.select_related('skola', 'user').annotate(pocet_reseni=Count('reseni')) + + def pocet_reseni(self, obj): + return obj.pocet_reseni admin.site.register(Resitel, ResitelAdmin) @@ -260,17 +260,17 @@ admin.site.register(Resitel, ResitelAdmin) ### Skola class SkolaAdmin(VersionAdmin): - fieldsets = [ - (None, {'fields': ['nazev', 'kratky_nazev', 'je_zs', 'je_ss']}), - (u'Interní ID', {'fields': ['aesop_id', 'izo'], 'classes': ['collapse']}), - (u'Adresa', {'fields': ['ulice', 'mesto', 'psc', 'stat']}), - (None, {'fields': ['poznamka']}), - ] - list_display = ['nazev', 'aesop_id', 'mesto', 'ulice', 'stat', 'je_zs', 'je_ss'] - list_filter = ['stat', 'je_zs', 'je_ss'] - search_fields = ['nazev', 'mesto', 'ulice'] - inlines = [ResitelInline] - view_on_site = False + fieldsets = [ + (None, {'fields': ['nazev', 'kratky_nazev', 'je_zs', 'je_ss']}), + (u'Interní ID', {'fields': ['aesop_id', 'izo'], 'classes': ['collapse']}), + (u'Adresa', {'fields': ['ulice', 'mesto', 'psc', 'stat']}), + (None, {'fields': ['poznamka']}), + ] + list_display = ['nazev', 'aesop_id', 'mesto', 'ulice', 'stat', 'je_zs', 'je_ss'] + list_filter = ['stat', 'je_zs', 'je_ss'] + search_fields = ['nazev', 'mesto', 'ulice'] + inlines = [ResitelInline] + view_on_site = False admin.site.register(Skola, SkolaAdmin) @@ -278,59 +278,59 @@ admin.site.register(Skola, SkolaAdmin) ### Cislo class CisloAdmin(VersionAdmin): - fieldsets = [ - (None, { - 'fields': [ - 'cislo', - 'rocnik', - 'verejne_db', - 'verejna_vysledkovka', - 'faze', - 'poznamka', - 'pdf' - ] - }), - ('Data', {'fields': ['datum_vydani', 'datum_deadline', - 'datum_deadline_soustredeni']}), - ] - list_display = [ - 'kod', - 'rocnik', - 'cislo', - 'datum_vydani', - 'datum_deadline', - 'verejne', - 'verejna_vysledkovka' - ] - list_filter = ['rocnik'] - view_on_site = Cislo.verejne_url - actions = [ - make_set_action('verejne_db', True, 'Zveřejnit číslo'), - make_set_action('verejne_db', False, 'Skrýt (zneveřejnit) číslo'), - make_set_action('verejna_vysledkovka', True, 'Zveřejnit výsledkovku'), - make_set_action('verejna_vysledkovka', False, 'Skrýt (zneveřejnit) výsledkovku'), - ] - #inlines = [ProblemInline] - - def get_queryset(self, request): - qs = super(CisloAdmin, self).get_queryset(request) - return qs.select_related('rocnik') + fieldsets = [ + (None, { + 'fields': [ + 'cislo', + 'rocnik', + 'verejne_db', + 'verejna_vysledkovka', + 'faze', + 'poznamka', + 'pdf' + ] + }), + ('Data', {'fields': ['datum_vydani', 'datum_deadline', + 'datum_deadline_soustredeni']}), + ] + list_display = [ + 'kod', + 'rocnik', + 'cislo', + 'datum_vydani', + 'datum_deadline', + 'verejne', + 'verejna_vysledkovka' + ] + list_filter = ['rocnik'] + view_on_site = Cislo.verejne_url + actions = [ + make_set_action('verejne_db', True, 'Zveřejnit číslo'), + make_set_action('verejne_db', False, 'Skrýt (zneveřejnit) číslo'), + make_set_action('verejna_vysledkovka', True, 'Zveřejnit výsledkovku'), + make_set_action('verejna_vysledkovka', False, 'Skrýt (zneveřejnit) výsledkovku'), + ] + #inlines = [ProblemInline] + + def get_queryset(self, request): + qs = super(CisloAdmin, self).get_queryset(request) + return qs.select_related('rocnik') admin.site.register(Cislo, CisloAdmin) ### Rocnik class RocnikAdmin(VersionAdmin): - fieldsets = [ - (None, {'fields': ['rocnik', 'prvni_rok', 'exportovat']}), - ] - list_display = ['rocnik', 'prvni_rok', 'exportovat', 'verejne'] - inlines = [CisloInline] - view_on_site = Rocnik.verejne_url - actions = [ - make_set_action('exportovat', True, u'Nastavit pro AESOP export'), - make_set_action('exportovat', False, u'Skrýt pro AESOP export'), - ] + fieldsets = [ + (None, {'fields': ['rocnik', 'prvni_rok', 'exportovat']}), + ] + list_display = ['rocnik', 'prvni_rok', 'exportovat', 'verejne'] + inlines = [CisloInline] + view_on_site = Rocnik.verejne_url + actions = [ + make_set_action('exportovat', True, u'Nastavit pro AESOP export'), + make_set_action('exportovat', False, u'Skrýt pro AESOP export'), + ] admin.site.register(Rocnik, RocnikAdmin) @@ -338,14 +338,14 @@ admin.site.register(Rocnik, RocnikAdmin) ### PrilohaReseni # NOTE: Nemá pravděpodobně smysl používat # class PrilohaReseniAdmin(reversion.VersionAdmin): -# readonly_fields = ['timestamp', 'reseni'] -# fieldsets = [ -# (None, {'fields': ['reseni', 'soubor', 'timestamp']}), -# (u'Poznámky', {'fields': ['poznamka']}), -# ] -# list_display = ['reseni', 'soubor', 'timestamp'] -# list_filter = ['reseni', 'timestamp'] -# search_fields = [] +# readonly_fields = ['timestamp', 'reseni'] +# fieldsets = [ +# (None, {'fields': ['reseni', 'soubor', 'timestamp']}), +# (u'Poznámky', {'fields': ['poznamka']}), +# ] +# list_display = ['reseni', 'soubor', 'timestamp'] +# list_filter = ['reseni', 'timestamp'] +# search_fields = [] # # admin.site.register(PrilohaReseni, PrilohaReseniAdmin) @@ -353,21 +353,21 @@ admin.site.register(Rocnik, RocnikAdmin) ### Reseni class ReseniAdmin(VersionAdmin): - #form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['problem', 'resitele'], fields=['problem', 'resitele']) - fieldsets = [ - (None, {'fields': ['problem__set', 'resitele__set', 'forma', 'cas_doruceni']}), - (u'Poznámky', {'fields': ['poznamka']}), - ] - readonly_fields = ['cas_doruceni'] - list_display = [ResitelInline, 'forma', 'cas_doruceni'] - list_filter = ['cas_doruceni', 'forma'] - search_fields = [] - inlines = [PrilohaReseniInline] # FIXME: odmazáno ProblemInline,ResitelInline - view_on_site = False - - def get_queryset(self, request): - qs = super(ReseniAdmin, self).get_queryset(request) - return qs.select_related('resitele', 'problem', 'cislo_body') + #form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['problem', 'resitele'], fields=['problem', 'resitele']) + fieldsets = [ + (None, {'fields': ['problem__set', 'resitele__set', 'forma', 'cas_doruceni']}), + (u'Poznámky', {'fields': ['poznamka']}), + ] + readonly_fields = ['cas_doruceni'] + list_display = [ResitelInline, 'forma', 'cas_doruceni'] + list_filter = ['cas_doruceni', 'forma'] + search_fields = [] + inlines = [PrilohaReseniInline] # FIXME: odmazáno ProblemInline,ResitelInline + view_on_site = False + + def get_queryset(self, request): + qs = super(ReseniAdmin, self).get_queryset(request) + return qs.select_related('resitele', 'problem', 'cislo_body') admin.site.register(Reseni, ReseniAdmin) @@ -375,52 +375,52 @@ admin.site.register(Reseni, ReseniAdmin) ### Pohádka class PohadkaAdminForm(forms.ModelForm): - class Meta: - model = Pohadka - exclude = [] - autor = UserModelChoiceField(User.objects.filter(is_staff=True)) - uloha = forms.ModelChoiceField( - Uloha.objects.all() - ) + class Meta: + model = Pohadka + exclude = [] + autor = UserModelChoiceField(User.objects.filter(is_staff=True)) + uloha = forms.ModelChoiceField( + Uloha.objects.all() + ) - def __init__(self, *args, **kwargs): - super(PohadkaAdminForm, self).__init__(*args, **kwargs) - instance = getattr(self, 'instance', None) + def __init__(self, *args, **kwargs): + super(PohadkaAdminForm, self).__init__(*args, **kwargs) + instance = getattr(self, 'instance', None) - # viz ProblemAdminForm.__init__ - if instance and instance.pk: - if instance.uloha and instance.uloha.cislo_zadani: - if instance.uloha.cislo_zadani.faze != 'admin': - self.fields['text'].widget.attrs['readonly'] = True + # viz ProblemAdminForm.__init__ + if instance and instance.pk: + if instance.uloha and instance.uloha.cislo_zadani: + if instance.uloha.cislo_zadani.faze != 'admin': + self.fields['text'].widget.attrs['readonly'] = True class PohadkaAdmin(VersionAdmin): - form = PohadkaAdminForm - view_on_site = False + form = PohadkaAdminForm + view_on_site = False - def get_kod_ulohy(self, obj): - return obj.uloha.kod_v_rocniku() - get_kod_ulohy.short_description = u'Kód úlohy' + def get_kod_ulohy(self, obj): + return obj.uloha.kod_v_rocniku() + get_kod_ulohy.short_description = u'Kód úlohy' - def get_rocnik(self, obj): - return obj.uloha.cislo_zadani.rocnik.rocnik - get_rocnik.short_description = u'Ročník' + def get_rocnik(self, obj): + return obj.uloha.cislo_zadani.rocnik.rocnik + get_rocnik.short_description = u'Ročník' - list_display = [ - '__str__', - 'get_rocnik', - 'get_kod_ulohy', - 'uloha', - 'autor' - ] + list_display = [ + '__str__', + 'get_rocnik', + 'get_kod_ulohy', + 'uloha', + 'autor' + ] - get_form = get_form_predvypln_autora + get_form = get_form_predvypln_autora class PohadkaKProblemuInline(admin.TabularInline): - form = PohadkaAdminForm - model = Pohadka - exclude = [] - extra = 0 + form = PohadkaAdminForm + model = Pohadka + exclude = [] + extra = 0 admin.site.register(Pohadka, PohadkaAdmin) @@ -431,78 +431,78 @@ from autocomplete_light.contrib.taggit_field import TaggitField, TaggitWidget class ProblemAdminForm(forms.ModelForm): - #text_zadani = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_zadani')) - #text_reseni = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_reseni')) - #text_org = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_org')) - zamereni = TaggitField(widget=TaggitWidget('TagAutocomplete'), required=False) - autor = UserModelChoiceField(User.objects.filter(is_staff=True)) - opravovatel = UserModelChoiceField(User.objects.filter(is_staff=True), required=False) - class Meta: - model = Problem - exclude = ['nadproblem'] - - def __init__(self, *args, **kwargs): - super(ProblemAdminForm, self).__init__(*args, **kwargs) - instance = getattr(self, 'instance', None) - - # Nedovol měnit název a zadání resp. řešení, pokud je cislo_zadani - # resp. cislo_reseni mimo fázi admin. - # - # Nastavení readonly fields sice vypadá lépe (nevygeneruje input tag), - # ale při ukládání změny vypíše admin nespecifikovanou chybu, která je - # způsobena zřejmě tím, že se neodešle žádná hodnota pro povinné pole - # nazev. Navíc by se smazalo nepovinné pole zadání. - # - # Toto řešení je z http://stackoverflow.com/a/325038/4786205. - # - # TODO Django 1.9: použít field s atributem disabled? - if instance and instance.pk: - if instance.cislo_zadani and instance.cislo_zadani.faze != 'admin': - # CKEditor neumí readonly ... - self.fields['text_zadani'] = forms.CharField( - widget=forms.Textarea, - required=False - ) - for f in ['nazev', 'text_zadani', 'body']: - self.fields[f].widget.attrs['readonly'] = True - if instance.cislo_reseni and instance.cislo_reseni.faze != 'admin': - self.fields['text_reseni'] = forms.CharField( - widget=forms.Textarea, - required=False - ) - self.fields['text_reseni'].widget.attrs['readonly'] = True + #text_zadani = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_zadani')) + #text_reseni = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_reseni')) + #text_org = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_org')) + zamereni = TaggitField(widget=TaggitWidget('TagAutocomplete'), required=False) + autor = UserModelChoiceField(User.objects.filter(is_staff=True)) + opravovatel = UserModelChoiceField(User.objects.filter(is_staff=True), required=False) + class Meta: + model = Problem + exclude = ['nadproblem'] + + def __init__(self, *args, **kwargs): + super(ProblemAdminForm, self).__init__(*args, **kwargs) + instance = getattr(self, 'instance', None) + + # Nedovol měnit název a zadání resp. řešení, pokud je cislo_zadani + # resp. cislo_reseni mimo fázi admin. + # + # Nastavení readonly fields sice vypadá lépe (nevygeneruje input tag), + # ale při ukládání změny vypíše admin nespecifikovanou chybu, která je + # způsobena zřejmě tím, že se neodešle žádná hodnota pro povinné pole + # nazev. Navíc by se smazalo nepovinné pole zadání. + # + # Toto řešení je z http://stackoverflow.com/a/325038/4786205. + # + # TODO Django 1.9: použít field s atributem disabled? + if instance and instance.pk: + if instance.cislo_zadani and instance.cislo_zadani.faze != 'admin': + # CKEditor neumí readonly ... + self.fields['text_zadani'] = forms.CharField( + widget=forms.Textarea, + required=False + ) + for f in ['nazev', 'text_zadani', 'body']: + self.fields[f].widget.attrs['readonly'] = True + if instance.cislo_reseni and instance.cislo_reseni.faze != 'admin': + self.fields['text_reseni'] = forms.CharField( + widget=forms.Textarea, + required=False + ) + self.fields['text_reseni'].widget.attrs['readonly'] = True class ProblemAdmin(VersionAdmin): - form = ProblemAdminForm - fieldsets = [ - (None, {'fields': ['nazev', 'typ', 'stav', 'autor', 'zamereni', 'body', 'timestamp', 'import_dakos_id']}), - (u'Vydání', {'fields': ['kod', 'cislo_reseni', 'opravovatel',]}), - (None, {'fields': ['text_zadani', 'text_reseni', 'text_org',]}), - ] - list_select_related = True - search_fields = ['nazev', 'text_zadani', 'text_reseni', 'text_org'] - view_on_site = Problem.verejne_url - ordering = ['-timestamp'] - - readonly_fields = ['timestamp', 'import_dakos_id'] - - def get_queryset(self, request): - qs = super(ProblemAdmin, self).get_queryset(request) - return qs.select_related('autor', 'opravovatel', 'cislo_reseni') - - def pocet_reseni(self, obj): - return obj.pocet_reseni + form = ProblemAdminForm + fieldsets = [ + (None, {'fields': ['nazev', 'typ', 'stav', 'autor', 'zamereni', 'body', 'timestamp', 'import_dakos_id']}), + (u'Vydání', {'fields': ['kod', 'cislo_reseni', 'opravovatel',]}), + (None, {'fields': ['text_zadani', 'text_reseni', 'text_org',]}), + ] + list_select_related = True + search_fields = ['nazev', 'text_zadani', 'text_reseni', 'text_org'] + view_on_site = Problem.verejne_url + ordering = ['-timestamp'] + + readonly_fields = ['timestamp', 'import_dakos_id'] + + def get_queryset(self, request): + qs = super(ProblemAdmin, self).get_queryset(request) + return qs.select_related('autor', 'opravovatel', 'cislo_reseni') + + def pocet_reseni(self, obj): + return obj.pocet_reseni class ProblemNavrhAdmin(ProblemAdmin): - list_display = ['nazev', 'typ', 'stav', 'autor', 'timestamp'] - list_filter = ['typ', 'zamereni', 'timestamp', 'stav'] + list_display = ['nazev', 'typ', 'stav', 'autor', 'timestamp'] + list_filter = ['typ', 'zamereni', 'timestamp', 'stav'] - def get_queryset(self, request): - qs = super(ProblemNavrhAdmin, self).get_queryset(request) - return qs.filter(stav__in=[Problem.STAV_NAVRH, Problem.STAV_SMAZANY]) + def get_queryset(self, request): + qs = super(ProblemNavrhAdmin, self).get_queryset(request) + return qs.filter(stav__in=[Problem.STAV_NAVRH, Problem.STAV_SMAZANY]) - get_form = get_form_predvypln_autora + get_form = get_form_predvypln_autora #FIXME @@ -510,54 +510,54 @@ class ProblemNavrhAdmin(ProblemAdmin): class ProblemZadanyAdmin(ProblemAdmin): - list_display = [ - 'nazev', - 'typ', - 'cislo_zadani_link', - 'cislo_reseni_link', - 'autor', - 'opravovatel', - 'kod', - 'verejne' - ] - list_filter = [ - 'typ', 'zamereni', 'cislo_zadani__cislo', 'cislo_zadani__rocnik' - ] - - def cislo_zadani_link(self, obj): - if not obj.cislo_zadani: - return "" - return mark_safe('{}'.format( - reverse("admin:seminar_cislo_change", args=(obj.cislo_zadani.pk,)), - obj.cislo_zadani - )) - cislo_zadani_link.short_description = u'Číslo zadání' - - # TODO pokud se budou odkazy v adminu více používat, možná by se hodilo je - # nějak zjednodušit, např. tímto? - # https://github.com/gitaarik/django-admin-relation-links - def cislo_reseni_link(self, obj): - if not obj.cislo_reseni: - return "" - return mark_safe('{}'.format( - reverse("admin:seminar_cislo_change", args=(obj.cislo_reseni.pk,)), - obj.cislo_reseni - )) - cislo_reseni_link.short_description = u'Číslo řešení' - - def get_inline_instances(self, request, obj=None): - if obj and obj.typ == Problem.TYP_ULOHA: - inlines = [ReseniKProblemuInline, PohadkaKProblemuInline] - else: - inlines = [ReseniKProblemuInline] - - return [inline(self.model, self.admin_site) for inline in inlines] - - def get_queryset(self, request): - qs = super(ProblemZadanyAdmin, self).get_queryset(request) - return qs.filter(stav=Problem.STAV_ZADANY) - - get_form = get_form_predvypln_autora + list_display = [ + 'nazev', + 'typ', + 'cislo_zadani_link', + 'cislo_reseni_link', + 'autor', + 'opravovatel', + 'kod', + 'verejne' + ] + list_filter = [ + 'typ', 'zamereni', 'cislo_zadani__cislo', 'cislo_zadani__rocnik' + ] + + def cislo_zadani_link(self, obj): + if not obj.cislo_zadani: + return "" + return mark_safe('{}'.format( + reverse("admin:seminar_cislo_change", args=(obj.cislo_zadani.pk,)), + obj.cislo_zadani + )) + cislo_zadani_link.short_description = u'Číslo zadání' + + # TODO pokud se budou odkazy v adminu více používat, možná by se hodilo je + # nějak zjednodušit, např. tímto? + # https://github.com/gitaarik/django-admin-relation-links + def cislo_reseni_link(self, obj): + if not obj.cislo_reseni: + return "" + return mark_safe('{}'.format( + reverse("admin:seminar_cislo_change", args=(obj.cislo_reseni.pk,)), + obj.cislo_reseni + )) + cislo_reseni_link.short_description = u'Číslo řešení' + + def get_inline_instances(self, request, obj=None): + if obj and obj.typ == Problem.TYP_ULOHA: + inlines = [ReseniKProblemuInline, PohadkaKProblemuInline] + else: + inlines = [ReseniKProblemuInline] + + return [inline(self.model, self.admin_site) for inline in inlines] + + def get_queryset(self, request): + qs = super(ProblemZadanyAdmin, self).get_queryset(request) + return qs.filter(stav=Problem.STAV_ZADANY) + + get_form = get_form_predvypln_autora #FIXME #create_modeladmin(ProblemZadanyAdmin, Problem, 'ProblemZadany', verbose_name=u'Problém (zadaný)', verbose_name_plural=u'Problémy (zadané)') @@ -567,94 +567,94 @@ class ProblemZadanyAdmin(ProblemAdmin): ### Prispevek (k tematkum) #class PrispevekAdminForm(forms.ModelForm): -# text_org = forms.CharField(widget=CKEditorUploadingWidget(), required=False, -# **field_labels(Prispevek, 'text_org')) -# text_resitel = forms.CharField(widget=CKEditorUploadingWidget(), required=False, -# **field_labels(Prispevek, 'text_resitel')) +# text_org = forms.CharField(widget=CKEditorUploadingWidget(), required=False, +# **field_labels(Prispevek, 'text_org')) +# text_resitel = forms.CharField(widget=CKEditorUploadingWidget(), required=False, +# **field_labels(Prispevek, 'text_resitel')) # -# class Meta: -# model = Prispevek -# exclude = [] +# class Meta: +# model = Prispevek +# exclude = [] # #class PrispevekAdmin(VersionAdmin): -# form = PrispevekAdminForm -# list_display = ['nazev', 'problem', 'reseni', 'zverejnit'] +# form = PrispevekAdminForm +# list_display = ['nazev', 'problem', 'reseni', 'zverejnit'] # #admin.site.register(Prispevek, PrispevekAdmin) ### Soustredeni class SoustredeniAdminForm(forms.ModelForm): - text = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Soustredeni, 'text')) - class Meta: - model = Soustredeni - exclude = [] + text = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Soustredeni, 'text')) + class Meta: + model = Soustredeni + exclude = [] class SoustredeniAdmin(VersionAdmin): - form = SoustredeniAdminForm - fieldsets = [ - (None, {'fields': ['rocnik', 'misto', 'typ', 'verejne_db', 'exportovat', 'text']}), - ('Data', {'fields': ['datum_zacatku', 'datum_konce']}), - ] - list_display = ['rocnik', 'misto', 'datum_zacatku', 'typ', 'exportovat', 'verejne'] - inlines = [Soustredeni_UcastniciInline, Soustredeni_OrganizatoriInline] - list_filter = ['typ', 'rocnik'] - view_on_site = Soustredeni.verejne_url - actions = [ - make_set_action('verejne_db', True, u'Zveřejnit soustředění'), - make_set_action('verejne_db', False, u'Skrýt (zneveřejnit) soustředění'), - make_set_action('exportovat', True, u'Nastavit pro AESOP export'), - make_set_action('exportovat', False, u'Skrýt pro AESOP export'), - ] + form = SoustredeniAdminForm + fieldsets = [ + (None, {'fields': ['rocnik', 'misto', 'typ', 'verejne_db', 'exportovat', 'text']}), + ('Data', {'fields': ['datum_zacatku', 'datum_konce']}), + ] + list_display = ['rocnik', 'misto', 'datum_zacatku', 'typ', 'exportovat', 'verejne'] + inlines = [Soustredeni_UcastniciInline, Soustredeni_OrganizatoriInline] + list_filter = ['typ', 'rocnik'] + view_on_site = Soustredeni.verejne_url + actions = [ + make_set_action('verejne_db', True, u'Zveřejnit soustředění'), + make_set_action('verejne_db', False, u'Skrýt (zneveřejnit) soustředění'), + make_set_action('exportovat', True, u'Nastavit pro AESOP export'), + make_set_action('exportovat', False, u'Skrýt pro AESOP export'), + ] admin.site.register(Soustredeni, SoustredeniAdmin) ### Konfery class KonferaAdminForm(forms.ModelForm): - class Meta: - model=Konfera - exclude = [] + class Meta: + model=Konfera + exclude = [] class KonferaAdmin(VersionAdmin): - form = KonferaAdminForm - list_filter = ['soustredeni'] - list_display = ['nazev','soustredeni','organizator','typ_prezentace'] -# inlines = [Konfera_UcastniciInline] + form = KonferaAdminForm + list_filter = ['soustredeni'] + list_display = ['nazev','soustredeni','organizator','typ_prezentace'] +# inlines = [Konfera_UcastniciInline] admin.site.register(Konfera,KonferaAdmin) ### Novinky class NovinkyAdminForm(forms.ModelForm): - text = forms.CharField(widget=CKEditorUploadingWidget(), required=False, - **field_labels(Novinky, 'text')) - autor = UserModelChoiceField(User.objects.filter(is_staff=True)) + text = forms.CharField(widget=CKEditorUploadingWidget(), required=False, + **field_labels(Novinky, 'text')) + autor = UserModelChoiceField(User.objects.filter(is_staff=True)) - class Meta: - model = Novinky - exclude = [] + class Meta: + model = Novinky + exclude = [] def zverejnit_novinky(modeladmin, request, queryset): - ''' zverejni vybrane novinky ''' - for novinka in queryset: - novinka.zverejneno = True - novinka.save() - zverejnit_novinky.short_description = 'Zveřejnit vybané novinky' + ''' zverejni vybrane novinky ''' + for novinka in queryset: + novinka.zverejneno = True + novinka.save() + zverejnit_novinky.short_description = 'Zveřejnit vybané novinky' def zneverejnit_novinky(modeladmin, request, queryset): - ''' zneverejni vybrane novinky''' - for novinka in queryset: - novinka.zverejneno = False - novinka.save() - zneverejnit_novinky.short_description = 'Zneveřejnit vybrané novinky' + ''' zneverejni vybrane novinky''' + for novinka in queryset: + novinka.zverejneno = False + novinka.save() + zneverejnit_novinky.short_description = 'Zneveřejnit vybrané novinky' class NovinkyAdmin(VersionAdmin): - form = NovinkyAdminForm - list_display = ['datum', 'autor', 'text', 'zverejneno', 'obrazek'] - actions = [zverejnit_novinky, zneverejnit_novinky] + form = NovinkyAdminForm + list_display = ['datum', 'autor', 'text', 'zverejneno', 'obrazek'] + actions = [zverejnit_novinky, zneverejnit_novinky] - get_form = get_form_predvypln_autora + get_form = get_form_predvypln_autora admin.site.register(Novinky, NovinkyAdmin) @@ -662,40 +662,40 @@ admin.site.register(Novinky, NovinkyAdmin) ### Organizator def jmeno_organizatora(obj): - ''' vraci jmeno organizatora ''' - jmeno = obj.user.first_name - if obj.prezdivka: - jmeno = jmeno + ' "' + obj.prezdivka + '"' - jmeno = jmeno + ' ' + obj.user.last_name - if jmeno == ' ': # zobrazeni bezejmennych orgu - return 'org' - return jmeno + ''' vraci jmeno organizatora ''' + jmeno = obj.user.first_name + if obj.prezdivka: + jmeno = jmeno + ' "' + obj.prezdivka + '"' + jmeno = jmeno + ' ' + obj.user.last_name + if jmeno == ' ': # zobrazeni bezejmennych orgu + return 'org' + return jmeno jmeno_organizatora.short_description = 'Jméno organizátora' def je_organizator_aktivni(obj): - ''' zjisti, zda-li je organizator aktivni ''' - return obj.user.is_active + ''' zjisti, zda-li je organizator aktivni ''' + return obj.user.is_active je_organizator_aktivni.short_description = 'Aktivní' je_organizator_aktivni.boolean = True def zaktivovat_organizatory(modeladmin, request, queryset): - ''' vybrane organizatory oznaci jako aktivni ''' - for org in queryset: - org.user.is_active = True - org.user.save() + ''' vybrane organizatory oznaci jako aktivni ''' + for org in queryset: + org.user.is_active = True + org.user.save() zaktivovat_organizatory.short_description = 'Zaktivovat organizátory' def deaktivovat_organizatory(modeladmin, request, queryset): - ''' deaktivuje vybrane organizatory ''' - for org in queryset: - org.user.is_active = False - org.user.save() + ''' deaktivuje vybrane organizatory ''' + for org in queryset: + org.user.is_active = False + org.user.save() deaktivovat_organizatory.short_description = 'Deaktivovat organizátory' @admin.register(Organizator) class OrganizatorAdmin(VersionAdmin): - list_filter = ['organizuje_do'] - list_display = [jmeno_organizatora, je_organizator_aktivni,] - actions = [zaktivovat_organizatory, deaktivovat_organizatory,] + list_filter = ['organizuje_do'] + list_display = [jmeno_organizatora, je_organizator_aktivni,] + actions = [zaktivovat_organizatory, deaktivovat_organizatory,] diff --git a/seminar/forms.py b/seminar/forms.py index fe150c55..693e36df 100644 --- a/seminar/forms.py +++ b/seminar/forms.py @@ -1,6 +1,6 @@ from django import forms class NameForm(forms.Form): - your_name = forms.CharField(label='Your name', max_length=100) + your_name = forms.CharField(label='Your name', max_length=100) diff --git a/seminar/management/commands/testdata.py b/seminar/management/commands/testdata.py index dda7b097..0fa189a1 100644 --- a/seminar/management/commands/testdata.py +++ b/seminar/management/commands/testdata.py @@ -4,7 +4,7 @@ import datetime import os import random -from django.core.management.base import NoArgsCommand +from django.core.management.base import BaseCommand from django.core.management import call_command from django.conf import settings @@ -14,10 +14,10 @@ import django.contrib.auth User = django.contrib.auth.get_user_model() -class Command(NoArgsCommand): +class Command(BaseCommand): help = "Clear database and load testing data." - def handle_noargs(self, **options): + def handle(self, *args, **options): assert settings.DEBUG == True dbfile = settings.DATABASES['default']['NAME'] if os.path.exists(dbfile): @@ -26,9 +26,10 @@ class Command(NoArgsCommand): call_command('migrate', noinput=True) self.stdout.write('Vytvarim uzivatele "admin" (heslo "admin") a pseudo-nahodna data ...') create_test_data(size=8) - self.stdout.write('Vytvoreno %d uzivatelu, %d skol, %d resitelu, %d rocniku, %d cisel, %d problemu, %d reseni.' % - (User.objects.count(), Skola.objects.count(), Resitel.objects.count(), Rocnik.objects.count(), - Cislo.objects.count(), Problem.objects.count(), Reseni.objects.count())) + self.stdout.write('Vytvoreno %d uzivatelu, %d skol, %d resitelu, %d rocniku, %d cisel,' + ' %d problemu, %d reseni.'.format(User.objects.count(), Skola.objects.count(), + Resitel.objects.count(), Rocnik.objects.count(), Cislo.objects.count(), + Problem.objects.count(), Reseni.objects.count())) diff --git a/seminar/models.py b/seminar/models.py index e8c9900b..1ab29ee8 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -64,7 +64,8 @@ class Osoba(SeminarModelBase): prezdivka = models.CharField('přezdívka', max_length=256) # User, pokud má na webu účet - user = models.OneToOneField(settings.AUTH_USER_MODEL, blank=True, null=True, verbose_name='uživatel') + user = models.OneToOneField(settings.AUTH_USER_MODEL, blank=True, null=True, + verbose_name='uživatel') # Pohlaví. Že ho neznáme se snad nestane (a ušetří to práci při programování) pohlavi_muz = models.BooleanField('pohlaví (muž)', default=False) @@ -119,7 +120,8 @@ class Osoba(SeminarModelBase): return force_unicode('%s %s' % (self.jmeno, self.prijmeni)) def inicial_krestni(self): - return force_unicode('%s.' % (self.jmeno[0])) + jmena = self.jmeno.split() + return " ".join(['{}.'.format(jmeno[0]) for jmeno in jmena]) def __str__(self): return force_unicode("Osoba({})".format(self.plne_jmeno())) @@ -400,7 +402,7 @@ class Cislo(SeminarModelBase): 'zveřejněna výsledkovka', default=False, help_text='Je-li false u veřejného čísla,\ - není výsledkovka zatím veřejná.') + není výsledkovka zatím veřejná.') poznamka = models.TextField('neveřejná poznámka', blank=True, help_text='Neveřejná poznámka k číslu (plain text)') @@ -828,7 +830,7 @@ class Hodnoceni(SeminarModelBase): # Django neumí jednoduše serializovat partial nebo třídu s __call__ # (https://docs.djangoproject.com/en/1.8/topics/migrations/), -# neprojdou pak migrace. Takže rozlišení funkcí generujících názvy souboru +# neprojdou pak migrace. Takže rozlišení funkcí generujících názvy souboru # podle adresáře řešíme takto. ## @@ -1083,7 +1085,7 @@ class Obrazek(SeminarModelBase): null=True, blank=True) text = models.ForeignKey(Text, verbose_name='text', - help_text='text, ve kterém se obrázek vyskytuje', null=False, blank=False) + help_text='text, ve kterém se obrázek vyskytuje', null=False, blank=False) do_cisla_barevny = models.FileField('barevný obrázek do čísla', help_text = 'Barevná verze obrázku do čísla', diff --git a/seminar/tests.py b/seminar/tests.py index 80bbfaa3..a5e74f01 100644 --- a/seminar/tests.py +++ b/seminar/tests.py @@ -14,81 +14,81 @@ from seminar import ovvpfile from seminar import utils class SeminarBasicTests(TestCase): - def setUp(self): - create_test_data(size=2) - self.client = Client() - - def tearDown(self): - call_command('flush', noinput=True, verbosity=0, interactive=False) - self.cleint = None - - def test_rocniky(self): - r19 = Rocnik.objects.get(rocnik=21) - self.assertEqual(r19.roman(), 'XXI') - - def test_render_cislo_e2e(self): - cs = Cislo.objects.all() - for c in cs[:4]: - url = c.verejne_url() - r = self.client.get(url) - assert r.status_code == 200 - assert len(r.content) >= 100 - # TODO: Validate cntent as HTML - - def test_render_problem_e2e(self): - ps = Problem.objects.all() - for p in ps[:4]: - url = p.verejne_url() - r = self.client.get(url) - assert r.status_code == 200 - assert len(r.content) >= 100 - # TODO: Validate cntent as HTML - - def test_export_e2e(self): - i_url = '/aesop-export/index.csv' - i_r = self.client.get(i_url) - assert i_r.status_code == 200 - ls = i_r.content.strip().split('\n') - - for u in [ls[0], ls[-1]]: - ex_r = self.client.get('/aesop-export/' + u) - assert ex_r.status_code == 200 - assert len(ex_r.content) >= 100 - o = ovvpfile.parse(ex_r.content) - assert o.headers['version'] == '1' - - def test_admin_url(self): - for m in [Skola, Resitel, Rocnik, Cislo, Problem, Reseni, Nastaveni]: - o = m.objects.first() - url = o.admin_url() - assert url - view = resolve(url) - assert view - - def test_verejne_url(self): - for m in [Rocnik, Cislo, Problem]: - p = Problem.objects.first() - url = p.verejne_url() - assert url - view = resolve(url) - assert view - - def test_ovvpfile(self): - filetext = "H1\ta\nH2\tb\tc\n\nx\ty\tz\n0\t1\t2\n3\t4\t5\n" - o = ovvpfile.parse(filetext) - assert len(o.headers) == 2 - assert o.headers['H2'] == 'b\tc' - - assert o.columns == ['x','y','z'] - assert len(o.rows) == 2 - assert o.rows[0]['z'] == '2' - - t = o.to_string() - assert t == filetext - - def test_roman(self): - for i in [0, 1, 23, 2015, 1999, 42, 4, 400, 78, 4321, 8765, 999]: - r = utils.roman(i) - fr = utils.from_roman(r) - assert fr == i + def setUp(self): + create_test_data(size=2) + self.client = Client() + + def tearDown(self): + call_command('flush', noinput=True, verbosity=0, interactive=False) + self.cleint = None + + def test_rocniky(self): + r19 = Rocnik.objects.get(rocnik=21) + self.assertEqual(r19.roman(), 'XXI') + + def test_render_cislo_e2e(self): + cs = Cislo.objects.all() + for c in cs[:4]: + url = c.verejne_url() + r = self.client.get(url) + assert r.status_code == 200 + assert len(r.content) >= 100 + # TODO: Validate cntent as HTML + + def test_render_problem_e2e(self): + ps = Problem.objects.all() + for p in ps[:4]: + url = p.verejne_url() + r = self.client.get(url) + assert r.status_code == 200 + assert len(r.content) >= 100 + # TODO: Validate cntent as HTML + + def test_export_e2e(self): + i_url = '/aesop-export/index.csv' + i_r = self.client.get(i_url) + assert i_r.status_code == 200 + ls = i_r.content.strip().split('\n') + + for u in [ls[0], ls[-1]]: + ex_r = self.client.get('/aesop-export/' + u) + assert ex_r.status_code == 200 + assert len(ex_r.content) >= 100 + o = ovvpfile.parse(ex_r.content) + assert o.headers['version'] == '1' + + def test_admin_url(self): + for m in [Skola, Resitel, Rocnik, Cislo, Problem, Reseni, Nastaveni]: + o = m.objects.first() + url = o.admin_url() + assert url + view = resolve(url) + assert view + + def test_verejne_url(self): + for m in [Rocnik, Cislo, Problem]: + p = Problem.objects.first() + url = p.verejne_url() + assert url + view = resolve(url) + assert view + + def test_ovvpfile(self): + filetext = "H1\ta\nH2\tb\tc\n\nx\ty\tz\n0\t1\t2\n3\t4\t5\n" + o = ovvpfile.parse(filetext) + assert len(o.headers) == 2 + assert o.headers['H2'] == 'b\tc' + + assert o.columns == ['x','y','z'] + assert len(o.rows) == 2 + assert o.rows[0]['z'] == '2' + + t = o.to_string() + assert t == filetext + + def test_roman(self): + for i in [0, 1, 23, 2015, 1999, 42, 4, 400, 78, 4321, 8765, 999]: + r = utils.roman(i) + fr = utils.from_roman(r) + assert fr == i diff --git a/seminar/testutils.py b/seminar/testutils.py index d98b21b9..a991660e 100644 --- a/seminar/testutils.py +++ b/seminar/testutils.py @@ -4,8 +4,9 @@ import datetime import random import django.contrib.auth from django.db import transaction +import unidecode -from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici +from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Osoba, Organizator from django.contrib.flatpages.models import FlatPage from django.contrib.sites.models import Site @@ -14,89 +15,213 @@ User = django.contrib.auth.get_user_model() @transaction.atomic def create_test_data(size = 6, rnd = None): - assert size >= 1 - # pevna pseudo-nahodnost - rnd = rnd or random.Random(x=42) - - # static URL stranky - s = Site.objects.filter(name="example.com") - f = FlatPage.objects.create(url="/", title="Seminář M&M", content = "

Vítejte na stránce semináře MaM!

") - f.sites.add(s[0]) - f.save() - - # users - admin = User.objects.create_superuser(username='admin', email='', password='admin') - - usernames = ['anet', 'bara', 'cyril', 'david', 'eva', 'filip'] - orgs = [] - for org in usernames[:size]: - o = User.objects.create_user(username=org, password=org) - o.first_name = org.capitalize() - o.save() - orgs.append(o) - - # skoly - Skola.objects.create(mesto = u'Praha', stat='CZ', psc='101 00', ulice=u'Krátká 5', nazev=u'První ZŠ', je_zs=True, je_ss=False) - Skola.objects.create(mesto = u'Praha', stat='CZ', psc='101 00', ulice=u'Krátká 5', nazev=u'První SŠ', je_zs=False, je_ss=True) - Skola.objects.create(mesto = u'Praha', stat='CZ', psc='102 00', ulice=u'Dlouhá 5', nazev=u'Druhá SŠ', je_zs=False, je_ss=True) - Skola.objects.create(mesto = u'Praha', stat='CZ', psc='103 00', ulice=u'Široká 3', nazev=u'Třetí SŠ a ZŠ', je_zs=True, je_ss=True) - Skola.objects.create(mesto = u'Ostrava', stat='CZ', psc='700 00', ulice=u'Hluboká 42', nazev=u'Hutní gympl', je_zs=False, je_ss=True) - Skola.objects.create(mesto = u'Humenné', stat='SK', psc='012 34', ulice=u'Pltká 1', nazev=u'Sredná škuola', je_zs=False, je_ss=True) - - # resitele - jmena_m = ['Aleš', 'Tomáš', 'Martin', 'Jakub', 'Petr', 'Lukáš', 'Cyril'] - jmena_f = ['Eva', 'Karolína', 'Zuzana', 'Sylvie', 'Iva', 'Jana', 'Marie'] - prijmeni_m = ['Novotný', 'Svoboda', 'Pecha', 'Kořen', 'Holan', 'Uhlíř', 'Chytráček', 'Pokora', 'Koch', 'Szegedy', 'Rudý'] - prijmeni_f = ['Novotná', 'Svobodová', 'Machová', 'Zelená', 'Yu-Xin', 'Mlsná', 'Dubná', 'Mrkvová', 'Suchá', 'Lovelace', 'Holcová'] - for i in range(3*size): - skola = rnd.choice(Skola.objects.all()) - pohlavi = rnd.randint(0,1) - jmeno = rnd.choice([jmena_m, jmena_f][pohlavi]) - prijmeni = rnd.choice([prijmeni_m, prijmeni_f][pohlavi]) - Resitel.objects.create(skola = skola, datum_prihlaseni = datetime.date(rnd.randint(2002, 2014), rnd.randint(1,12), 1), - jmeno =jmeno, prijmeni = prijmeni, rok_maturity = rnd.randint(2015, 2019), - stat = skola.stat, zasilat = Resitel.ZASILAT_NIKAM, pohlavi_muz = pohlavi) - resitele = list(Resitel.objects.all()) - - # rocniky - last_rocnik = 21 - for ri in range(last_rocnik - size, last_rocnik + 1): - r = Rocnik.objects.create(prvni_rok = 1993 + ri, rocnik = ri) - - # cisla - cisel = rnd.randint(4, 6) - - cs = {} - for ci in range(1, cisel + 1): - vydano = datetime.date(r.prvni_rok, ci + 6, 1) - deadline = datetime.date(r.prvni_rok, ci + 8, 1) if ci + 2 < cisel else None - c = Cislo.objects.create(rocnik = r, cislo = str(ci), datum_vydani=vydano, datum_deadline=deadline, verejne_db=True) - cs[ci] = c - - # problemy resene v ci - seq='#ABCDEFGHIJKLMNOPQRSTUVWXYZ' - if ci >= 3: - for pi in range(1, ((size + 1) // 2) + 1): - p = Problem.objects.create(autor = rnd.choice(orgs), cislo_zadani=cs[ci-2], cislo_reseni=cs[ci], - opravovatel = rnd.choice(orgs), kod = str(pi), nazev = u'Dummy úloha %s-%s' % (seq[ci], seq[pi]), - stav = Problem.STAV_ZADANY, typ = Problem.TYP_ULOHA, body = rnd.randint(1, 5)) - p.text_problemu = (u"

Text problému %s.%s %s [id %d] za %d body.

" % - (p.cislo_zadani.kod(), p.kod, p.nazev, p.id, p.body)) - p.text_problemu_org = u"

Neveřejný text problému.

" - p.save() - - poc_reseni = rnd.randint(size // 2, size * 2) - res_sel = rnd.sample(resitele, min(poc_reseni, len(resitele) - 2)) - for resitel in res_sel: - res = Reseni.objects.create(problem = p, resitel = resitel, - body = rnd.randint(0, p.body), cislo_body = cs[ci]) - - sous = Soustredeni.objects.create(rocnik=Rocnik.objects.first(), verejne_db=True, misto=u'Někde', - datum_zacatku=datetime.date(2000, 11, 23), datum_konce=datetime.date(2000, 11, 27)) - for res in rnd.sample(resitele, 6): - Soustredeni_Ucastnici.objects.create(resitel=res, soustredeni=sous) - sous.save() - - nastaveni = Nastaveni.objects.create(aktualni_rocnik = Rocnik.objects.last(), - aktualni_cislo = Cislo.objects.all()[1]) + assert size >= 1 + # pevna pseudo-nahodnost + rnd = rnd or random.Random(x=42) + + # static URL stranky + # FIXME: nakopirovat sem vsechny z produkcni databaze + s = Site.objects.filter(name="example.com") + f = FlatPage.objects.create(url="/", title="Seminář M&M", + content = "

Vítejte na stránce semináře MaM!

") + f.sites.add(s[0]) + f.save() + + # users + admin = User.objects.create_superuser(username='admin', email='', password='admin') + + usernames = ['anet', 'bara', 'cyril', 'david', 'eva', 'filip'] + orgs = [] + for org in usernames[:size]: + o = User.objects.create_user(username=org, password=org) + o.first_name = org.capitalize() + o.save() + orgs.append(o) + + # skoly + skoly = [] +# prvnizs = Skola.objects.create(mesto='Praha', stat='CZ', psc='101 00', ulice='Krátká 5', nazev='První ZŠ', je_zs=True, je_ss=False) +# skoly.append(prvnizs) +# skoly.append(Skola.objects.create(mesto='Praha', stat='CZ', psc='101 00', +# ulice='Krátká 5', nazev='První SŠ', je_zs=False, je_ss=True)) +# skoly.append(Skola.objects.create(mesto='Praha', stat='CZ', psc='102 00', +# ulice='Dlouhá 5', nazev='Druhá SŠ', je_zs=False, je_ss=True)) +# skoly.append(Skola.objects.create(mesto='Praha', stat='CZ', psc='103 00', +# ulice='Široká 3', nazev='Třetí SŠ a ZŠ', je_zs=True, je_ss=True)) +# skoly.append(Skola.objects.create(mesto='Ostrava', stat='CZ', psc='700 00', +# ulice='Hluboká 42', nazev='Hutní gympl', je_zs=False, je_ss=True)) +# skoly.append(Skola.objects.create(mesto='Humenné', stat='SK', psc='012 34', +# ulice='Pltká 1', nazev='Sredná škuola', je_zs=False, je_ss=True)) +# #FIXME pridat kontaktni osobu alespon nekde +# skoly.append(zlinska = Skola.objects.create(mesto = 'Zlín', stat='CZ', psc='76001', +# ulice='náměstí T.G. Masaryka 2734-9', +# nazev='Gymnázium a Střední jazyková škola s právem SJZ', +# kratky_nazev="GaSJŠspSJZ", je_zs=True, je_ss=True)) + + # osoby + jmena_m = ['Aleš', 'Tomáš', 'Martin', 'Jakub', 'Petr', 'Lukáš', 'Cyril', 'Pavel Karel'] + jmena_f = ['Eva', 'Karolína', 'Zuzana', 'Sylvie', 'Iva', 'Jana', 'Marie', + 'Marta Iva', 'Shu Shan'] + prijmeni_m = ['Novotný', 'Svoboda', 'Pecha', 'Kořen', 'Holan', 'Uhlíř', 'Chytráček', + 'Pokora', 'Koch', 'Szegedy', 'Rudý', "von Neumann", "d'Este"] + prijmeni_f = ['Novotná', 'Svobodová', 'Machová', 'Zelená', 'Yu-Xin', 'Mlsná', 'Dubná', + 'Mrkvová', 'Suchá', 'Lovelace', 'Holcová', 'Rui'] + prezdivka = ['Kaki', 'Hurdur', 'Maracuja', 'Bobbo', "", "", "", "", "", + "", "", 'Riki', 'Sapa', "", '', '---', 'Koko'] + domain = ['example.com', 'dolujeme.eu', 'mff.cuni.cz', 'strcprstskrzkrk.cz', + 'british.co.uk', 'splachni.to', 'haha.org'] + seznam_ulic = ['Krátká', 'Vlhká', 'Jungmanova', '17. listopadu', '4. října', 'Roztocká', + 'Forstova', 'Generála Františka Janouška', 'Náměstí Války', + 'Svratecké náměstí', 'Zelená lhota', 'Z Plynu', 'K Jezeru', 'U Kocourkova', + 'Uštěpačná', 'Ostrorepská', 'Zubří'] + seznam_mest = ['Praha', 'Brno', 'Ostrava', 'Horní Jelení', 'Dolní Zábrdovice', 'Prdelkov', + 'Stará myslivna', 'Kocourkov', 'Šalingrad', 'Medvědí hora', 'Basilej', + 'Unterschiedlich', 'Old York', 'Lancastershire', 'Vóloďháza'] + + osoby = [] + for i in range(3 * size): + pohlavi = rnd.randint(0,1) + jmeno = rnd.choice([jmena_m, jmena_f][pohlavi]) + prijmeni = rnd.choice([prijmeni_m, prijmeni_f][pohlavi]) + prezdivka = rnd.choice([prezdivka]) + email = "@".join([unidecode.unidecode(jmeno), rnd.choice(domain)]) + telefon = [rnd.choice([k for k in range(10)]) for i in range(10)] + narozeni = datetime.date(rnd.randint(1980, 2020), rnd.randint(1, 12), + rnd.randint(1, 28)) + ulic = rnd.choice(seznam_ulic) + print(ulic) + cp = rnd.randint(1, 99) + ulice = " ".join([ulic, str(cp)]) + mesto = rnd.choice([seznam_mest]) + psc = [rnd.choice([k for k in range(10)]) for i in range(6)] + osoby.append(Osoba.objects.create(jmeno = jmeno, prijmeni = prijmeni, + prezdivka = prezdivka, pohlavi_muz = pohlavi, email = email, + telefon = telefon, datum_narozeni = narozeni, ulice = ulice, + mesto = mesto, psc = psc, + datum_registrace = datetime.date(rnd.randint(2019, 2029), + rnd.randint(1, 12), rnd.randint(1, 28)))) + #TODO pridat foto male a velke. Jak? + + # resitele a organizatori + last_rocnik = 25 + resitele = [] + organizatori = [] + for os in osoby: + rand = rnd.randint(0, 8) + if not (rand % 8 == 0): + resitele.append(Resitel.objects.create(osoba=os, skola=rnd.choice([skoly]), + rok_maturity=rnd.randint(2019, 2029), + zasilat=rnd.choice(Resitel.ZASILAT_CHOICES))) + else: + pusobnost = rnd.randint(1, last_rocnik) + od = 1993 + last_rocnik - pusobnost + do = od + rnd.randint(1, 6) + # aktualni organizatori jeste nemaji vyplnene organizuje_do + #if do > datetime.datetime.now().year: + # do = None + organizatori.append(Organizator.objects.create(osoba=os)) + #organizuje_od=od)) + #, organizuje_do=do)) + + # prijemci + prijemci = [] + for i in range(10): + randos = rnd.choice(osoby) + prijemci.add(Prijemce.objects.create(osoba=randos)) + + zlinska.kontaktni_osoba=rnd.choice(osoby) + zlinska.save() + + # rocniky + for ri in range(min(last_rocnik - size, 1), last_rocnik + 1): + r = Rocnik.objects.create(prvni_rok = 1993 + ri, rocnik = ri) + + # cisla + cisel = rnd.randint(4, 8) + + slovnik_cisel = {} + for ci in range(1, cisel + 1): + if ci >= 3: + vydano = datetime.date(r.prvni_rok, ci + 6, rnd.randint(1, 28)) + deadline = datetime.date(r.prvni_rok, ci + 8, rnd.randint(1, 28)) + else: + vydano = datetime.date(r.druhy_rok, ci - 3, rnd.randint(1, 28)) + # posledni 2 cisla v rocniku nemaji deadline + if (ci + 2 > cisel): + deadline = datetime.date(r.druhy_rok, ci - 1, + rnd.randint(1, 28)) + else: + deadline = None + cislo = Cislo.objects.create(rocnik = r, cislo = str(ci), + datum_vydani=vydano, datum_deadline=deadline, verejne_db=True) + slovnik_cisel[ci] = cislo + + # FIXME: misto typu ruzne typy objektu a vnoreni do sebe + # TODO: vytvorit temata s ruznymi vlakny + # TODO: nagenerovat starsim rocnikum pohadku + + # ulohy resene v ci + jaka = ["Šachová", "Černá", "Větrná", "Dlouhá", "Křehká", "Rychlá", + "Zákeřná", "Fyzikální"] + co = ["kostka", "smršť", "díra", "zrada", "toulka", "tyč", + "úloha", "blecha"] + sloveso = ["Najděte", "Spočítejte", "Zapište", "Změřte", "Odhadněte"] + koho = ["délku", "počet", "množství", "dílky"] + ceho = ["všech", "správných", "konstatních", "zelených"] + jmeno = ["řešení", "tahů", "čísel", "kalhot", "koulí", "hadů"] + kde = ["na zemi", "ve vesmíru", "ve vzduchu", "na šňůře", "v letadle"] + obor = ["M", "F", "I", "O", "B"] + reseni = ["to je přece jasné", "triviální", "omlouváme se," + "otevřený problém", "neřešitelné", "triviálně triviální", + "použitím věty z prvního semestru na matfyzu", + "jednoduše pomocí látky z druhého semestru na matfyzu", + "netriviální aplikace diferenciálních rovnic", "zadání je vnitřně" + "sporné", "nepopsatelně jednoduché", "pokud jste na to nepřišli," + "tak jste fakt hloupí"] + + if ci >= 3: + for pi in range(1, ((size + 1) // 2) + 1): + poc_op = rnd.randint(1, 4) + poc_oboru = rnd.randint(1, 2) + p = Uloha.objects.create( + nazev=" ".join([rnd.choice(jaka), rnd.choice(co)]), + stav=Problem.STAV_ZADANY, + zamereni=rnd.sample(zamereni, poc_oboru), + autor=rnd.choice(organizatori), + garant=rnd.choice(organizatori), + opravovatele=rnd.sample(organizatori, poc_op), + kod=str(pi), + cislo_zadani=cs[ci-2], + cislo_reseni=cs[ci], + cislo_deadline=cs[ci], + max_body = rnd.randint(1, 8)) + p.zadani = " ".join([rnd.choice(sloveso), rnd.choice(koho), + rnd.choice(ceho), rnd.choice(jmeno), rnd.choice(kde)]) + p.vzorak = " - ".join([p.zadani, rnd.choice(reseni)]) + p.save() + + # reseni ulohy + poc_reseni = rnd.randint(size // 2, size * 2) + poc_resitel = rnd.randint(1, 3) + res_sel = rnd.sample(resitele, min(poc_reseni, len(resitele) - 2)) + for resitel in res_sel: + res = Reseni.objects.create(problem = p, + resitele=[resitel], + forma=rnd.choice(Reseni.FORMA_CHOICES)) + hod = Hodnoceni.objects.create(body=rnd.randint(0, p.max_body), + cislo_body=cs[ci], reseni=res, problem=p) + + # TODO: nahodne nagenerovat problemum reseni a prilohy reseni, hodnoceni + + + # TODO: vice soustredeni a k nim nahodne podmnoziny organizatoru a ucastniku + sous = Soustredeni.objects.create(rocnik=Rocnik.objects.first(), verejne_db=True, misto=u'Někde', + datum_zacatku=datetime.date(2000, 11, 23), datum_konce=datetime.date(2000, 11, 27)) + for res in rnd.sample(resitele, 6): + Soustredeni_Ucastnici.objects.create(resitel=res, soustredeni=sous) + sous.save() + + nastaveni = Nastaveni.objects.create(aktualni_rocnik = Rocnik.objects.last(), + aktualni_cislo = Cislo.objects.all()[1]) + diff --git a/seminar/tools.py b/seminar/tools.py index eb83332f..2f8f8666 100644 --- a/seminar/tools.py +++ b/seminar/tools.py @@ -5,78 +5,78 @@ from .models import Resitel from reversion import revisions as reversion def merge_props(r1, r2, prop, pretend=True, smaller=False, equal=True): - """Merge r2.`prop` into r1.`prop`. + """Merge r2.`prop` into r1.`prop`. - If r1.`prop` unset, use r1.`prop`=r2.`prop`. - If both set and equal=True, warn if not equal. - If both set and smaller=True, use the smaller one. - With pretend=True does not modify r1. - """ - a1 = r1.__getattribute__(prop) - a2 = r2.__getattribute__(prop) - if not a1: - if not pretend: - r1.__setattr__(prop, a2) - elif a2: - if equal and a1 != a2: - log.warn(u"merge: Ruzna %s: %s VS %s", prop, a1, a2) - if smaller: - if not pretend: - r1.__setattr__(prop, min(a1, a2)) + If r1.`prop` unset, use r1.`prop`=r2.`prop`. + If both set and equal=True, warn if not equal. + If both set and smaller=True, use the smaller one. + With pretend=True does not modify r1. + """ + a1 = r1.__getattribute__(prop) + a2 = r2.__getattribute__(prop) + if not a1: + if not pretend: + r1.__setattr__(prop, a2) + elif a2: + if equal and a1 != a2: + log.warn(u"merge: Ruzna %s: %s VS %s", prop, a1, a2) + if smaller: + if not pretend: + r1.__setattr__(prop, min(a1, a2)) def merge_Resitel(rbase, rmerge, pretend=True): - """Zahrne data a vztahy Resitele rmerge do Resitele rbase, pak smaze rmerge. + """Zahrne data a vztahy Resitele rmerge do Resitele rbase, pak smaze rmerge. - Selze pro uzivatele s user!=NULL. S pretend=True nezmeni databazi. - """ - # Ma relace: skola - # Je v relaci: user, reseni, soustredeni_ucastnici, vysledky_base(VIEW) + Selze pro uzivatele s user!=NULL. S pretend=True nezmeni databazi. + """ + # Ma relace: skola + # Je v relaci: user, reseni, soustredeni_ucastnici, vysledky_base(VIEW) - log.info(u"merge: %s <- %s", unicode(rbase), unicode(rmerge)) + log.info(u"merge: %s <- %s", unicode(rbase), unicode(rmerge)) - assert not rbase.user - assert not rmerge.user - assert rbase != rmerge + assert not rbase.user + assert not rmerge.user + assert rbase != rmerge - if (rbase.jmeno != rmerge.jmeno) or (rbase.prijmeni != rmerge.prijmeni): - log.error(u"merge: Ruzna jmena: %s VS %s", rbase, rmerge) - if rbase.rok_maturity != rmerge.rok_maturity: - log.error(u"merge: Ruzne roky maturity: %s VS %s", rbase.rok_maturity, rmerge.rok_maturity) + if (rbase.jmeno != rmerge.jmeno) or (rbase.prijmeni != rmerge.prijmeni): + log.error(u"merge: Ruzna jmena: %s VS %s", rbase, rmerge) + if rbase.rok_maturity != rmerge.rok_maturity: + log.error(u"merge: Ruzne roky maturity: %s VS %s", rbase.rok_maturity, rmerge.rok_maturity) - with reversion.create_revision(): - reversion.set_comment('Merge duplicitnich Resitelu: %r <- %r' % (rbase.pk, rmerge.pk)) + with reversion.create_revision(): + reversion.set_comment('Merge duplicitnich Resitelu: %r <- %r' % (rbase.pk, rmerge.pk)) - merge_props(rbase, rmerge, 'skola', pretend=pretend) - merge_props(rbase, rmerge, 'datum_narozeni', pretend=pretend) - merge_props(rbase, rmerge, 'datum_prihlaseni', pretend=pretend) - merge_props(rbase, rmerge, 'datum_souhlasu_zasilani', pretend=pretend, smaller=True, equal=False) - merge_props(rbase, rmerge, 'datum_souhlasu_udaje', pretend=pretend, smaller=True, equal=False) - merge_props(rbase, rmerge, 'email', pretend=pretend) - if rmerge.import_mamoper_id and not pretend: - rbase.import_mamoper_id += ' ' + rmerge.import_mamoper_id - if rmerge.poznamka and not pretend: - rbase.poznamka += ' ' + rmerge.poznamka - merge_props(rbase, rmerge, 'mesto', pretend=pretend) - merge_props(rbase, rmerge, 'pohlavi_muz', pretend=pretend) - merge_props(rbase, rmerge, 'psc', pretend=pretend) - merge_props(rbase, rmerge, 'stat', pretend=pretend) - merge_props(rbase, rmerge, 'telefon', pretend=pretend) - merge_props(rbase, rmerge, 'ulice', pretend=pretend) - merge_props(rbase, rmerge, 'zasilat', pretend=pretend) + merge_props(rbase, rmerge, 'skola', pretend=pretend) + merge_props(rbase, rmerge, 'datum_narozeni', pretend=pretend) + merge_props(rbase, rmerge, 'datum_prihlaseni', pretend=pretend) + merge_props(rbase, rmerge, 'datum_souhlasu_zasilani', pretend=pretend, smaller=True, equal=False) + merge_props(rbase, rmerge, 'datum_souhlasu_udaje', pretend=pretend, smaller=True, equal=False) + merge_props(rbase, rmerge, 'email', pretend=pretend) + if rmerge.import_mamoper_id and not pretend: + rbase.import_mamoper_id += ' ' + rmerge.import_mamoper_id + if rmerge.poznamka and not pretend: + rbase.poznamka += ' ' + rmerge.poznamka + merge_props(rbase, rmerge, 'mesto', pretend=pretend) + merge_props(rbase, rmerge, 'pohlavi_muz', pretend=pretend) + merge_props(rbase, rmerge, 'psc', pretend=pretend) + merge_props(rbase, rmerge, 'stat', pretend=pretend) + merge_props(rbase, rmerge, 'telefon', pretend=pretend) + merge_props(rbase, rmerge, 'ulice', pretend=pretend) + merge_props(rbase, rmerge, 'zasilat', pretend=pretend) - for res in rmerge.reseni.all(): - if not pretend: - res.resitel = rbase - res.save() + for res in rmerge.reseni.all(): + if not pretend: + res.resitel = rbase + res.save() - for uc in rmerge.soustredeni_ucastnici_set.all(): - if not pretend: - uc.resitel = rbase - uc.save() + for uc in rmerge.soustredeni_ucastnici_set.all(): + if not pretend: + uc.resitel = rbase + uc.save() - if not pretend: - rmerge.delete() - rbase.save() - + if not pretend: + rmerge.delete() + rbase.save() + diff --git a/seminar/urls.py b/seminar/urls.py index a224fa0c..aa41c386 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -8,108 +8,108 @@ from django.views.generic.base import RedirectView staff_member_required = user_passes_test(lambda u: u.is_staff) urlpatterns = [ - # REDIRECTy - url(r'^jak-resit/$', RedirectView.as_view(url='/co-je-MaM/jak-resit/')), + # REDIRECTy + url(r'^jak-resit/$', RedirectView.as_view(url='/co-je-MaM/jak-resit/')), - # Organizatori - url(r'^co-je-MaM/organizatori/$', views.CojemamOrganizatoriView.as_view(), name='organizatori'), - url(r'^co-je-MaM/organizatori/organizovali/$', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'), + # Organizatori + url(r'^co-je-MaM/organizatori/$', views.CojemamOrganizatoriView.as_view(), name='organizatori'), + url(r'^co-je-MaM/organizatori/organizovali/$', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'), - # Archiv - url(r'^archiv/cisla/$', views.ArchivView.as_view()), - url(r'^archiv/temata/$', views.ArchivTemataView.as_view()), + # Archiv + url(r'^archiv/cisla/$', views.ArchivView.as_view()), + url(r'^archiv/temata/$', views.ArchivTemataView.as_view()), - url(r'^rocnik/(?P\d+)/$', views.RocnikView.as_view(), name='seminar_rocnik'), - #url(r'^cislo/(?P\d+)\.(?P[0-9-]+)/$', views.CisloView.as_view(), name='seminar_cislo'), - url(r'^problem/(?P\d+)/$', views.ProblemView.as_view(), name='seminar_problem'), - #url(r'^problem/(?P\d+)/(?P\d+)/$', views.PrispevekView.as_view(), name='seminar_problem_prispevek'), + url(r'^rocnik/(?P\d+)/$', views.RocnikView.as_view(), name='seminar_rocnik'), + #url(r'^cislo/(?P\d+)\.(?P[0-9-]+)/$', views.CisloView.as_view(), name='seminar_cislo'), + url(r'^problem/(?P\d+)/$', views.ProblemView.as_view(), name='seminar_problem'), + #url(r'^problem/(?P\d+)/(?P\d+)/$', views.PrispevekView.as_view(), name='seminar_problem_prispevek'), - # Soustredeni - url( - r'^soustredeni/probehlo/$', - views.SoustredeniListView.as_view(), - name='seminar_seznam_soustredeni' - ), - url( - r'^soustredeni/probehlo/(?P\d+)/$', - views.SoustredeniView.as_view(), - name='seminar_soustredeni' - ), - url( - r'^soustredeni/(?P\d+)/seznam_ucastniku$', - staff_member_required(views.SoustredeniUcastniciView.as_view()), - name='soustredeni_ucastnici' - ), - url( - r'^soustredeni/(?P\d+)/maily_ucastniku$', - staff_member_required(views.SoustredeniMailyUcastnikuView.as_view()), - name='maily_ucastniku' - ), - url( - r'^soustredeni/(?P\d+)/stvrzenky/(?P\d+)$', - staff_member_required(views.soustredeniStvrzenkyExportView), - name='soustredeni_stvrzenky' - ), - url( - r'^soustredeni/(?P\d+)/export_ucastniku$', - staff_member_required(views.soustredeniUcastniciExportView), - name='soustredeni_ucastnici_export' - ), - url( - r'^soustredeni/(?P\d+)/fotogalerie/', - include('galerie.urls') - ), + # Soustredeni + url( + r'^soustredeni/probehlo/$', + views.SoustredeniListView.as_view(), + name='seminar_seznam_soustredeni' + ), + url( + r'^soustredeni/probehlo/(?P\d+)/$', + views.SoustredeniView.as_view(), + name='seminar_soustredeni' + ), + url( + r'^soustredeni/(?P\d+)/seznam_ucastniku$', + staff_member_required(views.SoustredeniUcastniciView.as_view()), + name='soustredeni_ucastnici' + ), + url( + r'^soustredeni/(?P\d+)/maily_ucastniku$', + staff_member_required(views.SoustredeniMailyUcastnikuView.as_view()), + name='maily_ucastniku' + ), + url( + r'^soustredeni/(?P\d+)/stvrzenky/(?P\d+)$', + staff_member_required(views.soustredeniStvrzenkyExportView), + name='soustredeni_stvrzenky' + ), + url( + r'^soustredeni/(?P\d+)/export_ucastniku$', + staff_member_required(views.soustredeniUcastniciExportView), + name='soustredeni_ucastnici_export' + ), + url( + r'^soustredeni/(?P\d+)/fotogalerie/', + include('galerie.urls') + ), - # Zadani - url(r'^zadani/aktualni/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'), - url(r'^zadani/temata/$', views.ZadaniTemataView, name='seminar_temata'), - #url(r'^zadani/vysledkova-listina/$', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'), - url(r'^$', views.TitulniStranaView.as_view(), name='titulni_strana'), - url(r'^stare-novinky/$', views.StareNovinkyView.as_view(), name='stare_novinky'), + # Zadani + url(r'^zadani/aktualni/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'), + url(r'^zadani/temata/$', views.ZadaniTemataView, name='seminar_temata'), + #url(r'^zadani/vysledkova-listina/$', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'), + url(r'^$', views.TitulniStranaView.as_view(), name='titulni_strana'), + url(r'^stare-novinky/$', views.StareNovinkyView.as_view(), name='stare_novinky'), - # Clanky - url(r'^clanky/resitel/$', views.ClankyResitelView.as_view(), name='clanky_resitel'), - #url(r'^clanky/org/$', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'), + # Clanky + url(r'^clanky/resitel/$', views.ClankyResitelView.as_view(), name='clanky_resitel'), + #url(r'^clanky/org/$', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'), - # Aesop - url(r'^aesop-export/mam-rocnik-(?P\d+)\.csv$', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'), - url(r'^aesop-export/mam-sous-(?P[\d-]+)\.csv$', export.ExportSousView.as_view(), name='seminar_export_sous'), - url(r'^aesop-export/index.csv$', export.ExportIndexView.as_view(), name='seminar_export_index'), + # Aesop + url(r'^aesop-export/mam-rocnik-(?P\d+)\.csv$', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'), + url(r'^aesop-export/mam-sous-(?P[\d-]+)\.csv$', export.ExportSousView.as_view(), name='seminar_export_sous'), + url(r'^aesop-export/index.csv$', export.ExportIndexView.as_view(), name='seminar_export_index'), - # Stranky viditelne pouze pro orgy: - #url( - # r'^rocnik/(?P\d+)/vysledkovka.tex$', - # staff_member_required(views.RocnikVysledkovkaView.as_view()), - # name='seminar_cislo_vysledkovka' - #), - #url(r'^cislo/(?P\d+).(?P[0-9-]+)/vysledkovka.tex$', - # staff_member_required(views.CisloVysledkovkaView.as_view()), name='seminar_cislo_vysledkovka'), - url(r'^cislo/(?P\d+).(?P[0-9-]+)/obalky.pdf$', - staff_member_required(views.cisloObalkyView), name='seminar_cislo_obalky'), + # Stranky viditelne pouze pro orgy: + #url( + # r'^rocnik/(?P\d+)/vysledkovka.tex$', + # staff_member_required(views.RocnikVysledkovkaView.as_view()), + # name='seminar_cislo_vysledkovka' + #), + #url(r'^cislo/(?P\d+).(?P[0-9-]+)/vysledkovka.tex$', + # staff_member_required(views.CisloVysledkovkaView.as_view()), name='seminar_cislo_vysledkovka'), + url(r'^cislo/(?P\d+).(?P[0-9-]+)/obalky.pdf$', + staff_member_required(views.cisloObalkyView), name='seminar_cislo_obalky'), - #url(r'^cislo/(?P\d+).(?P[0-9-]+)/tituly.tex$', - # staff_member_required(views.TitulyView), name='seminar_cislo_titul'), - url(r'^stav$', - staff_member_required(views.StavDatabazeView), name='stav_databaze'), - url(r'^cislo/(?P\d+).(?P[0-9-]+)/obalkovani$', - staff_member_required(views.obalkovaniView), name='seminar_cislo_resitel_obalkovani'), - url(r'^cislo/(?P\d+).(?P[0-9-]+)/tex-download.json$', - staff_member_required(views.texDownloadView), name='seminar_tex_download'), - url(r'^soustredeni/(?P\d+)/obalky.pdf', - staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), + #url(r'^cislo/(?P\d+).(?P[0-9-]+)/tituly.tex$', + # staff_member_required(views.TitulyView), name='seminar_cislo_titul'), + url(r'^stav$', + staff_member_required(views.StavDatabazeView), name='stav_databaze'), + url(r'^cislo/(?P\d+).(?P[0-9-]+)/obalkovani$', + staff_member_required(views.obalkovaniView), name='seminar_cislo_resitel_obalkovani'), + url(r'^cislo/(?P\d+).(?P[0-9-]+)/tex-download.json$', + staff_member_required(views.texDownloadView), name='seminar_tex_download'), + url(r'^soustredeni/(?P\d+)/obalky.pdf', + staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), - url(r'^tex-upload/login/$', views.LoginView, name='seminar_login'), - url( - r'^tex-upload/$', - staff_member_required(views.texUploadView), - name='seminar_tex_upload' - ), - url(r'^prihlaska/$',views.get_name), + url(r'^tex-upload/login/$', views.LoginView, name='seminar_login'), + url( + r'^tex-upload/$', + staff_member_required(views.texUploadView), + name='seminar_tex_upload' + ), + url(r'^prihlaska/$',views.get_name), - # Ceka na autocomplete v3 - # url(r'^autocomplete/organizatori/$', - # staff_member_required(views.OrganizatorAutocomplete.as_view()), - # name='seminar_autocomplete_organizator') + # Ceka na autocomplete v3 + # url(r'^autocomplete/organizatori/$', + # staff_member_required(views.OrganizatorAutocomplete.as_view()), + # name='seminar_autocomplete_organizator') ] diff --git a/seminar/utils.py b/seminar/utils.py index f08e1f51..75092384 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -6,77 +6,77 @@ from django.contrib.auth.decorators import user_passes_test staff_member_required = user_passes_test(lambda u: u.is_staff) def histogram(seznam): - d = {} - for i in seznam: - if i not in d: - d[i] = 0 - d[i] += 1 - return d + d = {} + for i in seznam: + if i not in d: + d[i] = 0 + d[i] += 1 + return d roman_numerals = zip((1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1), - ('M', 'CM', 'D', 'CD','C', 'XC','L','XL','X','IX','V','IV','I')) + ('M', 'CM', 'D', 'CD','C', 'XC','L','XL','X','IX','V','IV','I')) def roman(num): - res = "" - for i, n in roman_numerals: - res += n * (num // i) - num %= i - return res + res = "" + for i, n in roman_numerals: + res += n * (num // i) + num %= i + return res def from_roman(rom): - if not rom: - return 0 - for i, n in roman_numerals: - if rom.upper().startswith(n): - return i + from_roman(rom[len(n):]) - raise Exception('Invalid roman numeral: "%s"', rom) + if not rom: + return 0 + for i, n in roman_numerals: + if rom.upper().startswith(n): + return i + from_roman(rom[len(n):]) + raise Exception('Invalid roman numeral: "%s"', rom) def seznam_problemu(): - from .models import Problem, Resitel, Rocnik, Reseni, Cislo - problemy = [] - - # Pomocna fce k formatovani problemovych hlasek - def prb(cls, msg, objs=None): - s = u'%s: %s' % (cls.__name__, msg) - if objs: - s += u' [' - for o in objs: - try: - url = o.admin_url() - except: - url = None - if url: - s += u'%s, ' % (url, o.pk, ) - else: - s += u'%s, ' % (o.pk, ) - s = s[:-2] + u']' - problemy.append(s) - - # Duplicita jmen - jmena = {} - for r in Resitel.objects.all(): - j = r.plne_jmeno() - if j not in jmena: - jmena[j] = [] - jmena[j].append(r) - for j in jmena: - if len(jmena[j]) > 1: - prb(Resitel, u'Duplicitní jméno "%s"' % (j, ), jmena[j]) - - # Data maturity a narození - for r in Resitel.objects.all(): - if not r.rok_maturity: - prb(Resitel, u'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, u'Podezřelé datum maturity', [r]) - if r.datum_narozeni and (r.datum_narozeni.year < 1970 or r.datum_narozeni.year > datetime.date.today().year - 12): - prb(Resitel, u'Podezřelé datum narození', [r]) + from .models import Problem, Resitel, Rocnik, Reseni, Cislo + problemy = [] + + # Pomocna fce k formatovani problemovych hlasek + def prb(cls, msg, objs=None): + s = u'%s: %s' % (cls.__name__, msg) + if objs: + s += u' [' + for o in objs: + try: + url = o.admin_url() + except: + url = None + if url: + s += u'%s, ' % (url, o.pk, ) + else: + s += u'%s, ' % (o.pk, ) + s = s[:-2] + u']' + problemy.append(s) + + # Duplicita jmen + jmena = {} + for r in Resitel.objects.all(): + j = r.plne_jmeno() + if j not in jmena: + jmena[j] = [] + jmena[j].append(r) + for j in jmena: + if len(jmena[j]) > 1: + prb(Resitel, u'Duplicitní jméno "%s"' % (j, ), jmena[j]) + + # Data maturity a narození + for r in Resitel.objects.all(): + if not r.rok_maturity: + prb(Resitel, u'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, u'Podezřelé datum maturity', [r]) + if r.datum_narozeni and (r.datum_narozeni.year < 1970 or r.datum_narozeni.year > datetime.date.today().year - 12): + prb(Resitel, u'Podezřelé datum narození', [r]) # if not r.email: # prb(Resitel, u'Neznámý email', [r]) - return problemy + return problemy diff --git a/seminar/views.py b/seminar/views.py index d208e673..3f01376f 100644 --- a/seminar/views.py +++ b/seminar/views.py @@ -33,929 +33,929 @@ import csv def verejna_temata(rocnik): - """Vrací queryset zveřejněných témat v daném ročníku. - """ - return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod') + """Vrací queryset zveřejněných témat v daném ročníku. + """ + return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod') def AktualniZadaniView(request): - nastaveni = get_object_or_404(Nastaveni) - verejne = nastaveni.aktualni_cislo.verejne() - problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany') - ulohy = problemy.filter(typ = 'uloha').order_by('kod') - serialy = problemy.filter(typ = 'serial').order_by('kod') - jednorazove_problemy = [ulohy, serialy] - return render(request, 'seminar/zadani/AktualniZadani.html', - {'nastaveni': nastaveni, - 'jednorazove_problemy': jednorazove_problemy, - 'temata': verejna_temata(nastaveni.aktualni_rocnik), - 'verejne': verejne, - }, - ) + nastaveni = get_object_or_404(Nastaveni) + verejne = nastaveni.aktualni_cislo.verejne() + problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany') + ulohy = problemy.filter(typ = 'uloha').order_by('kod') + serialy = problemy.filter(typ = 'serial').order_by('kod') + jednorazove_problemy = [ulohy, serialy] + return render(request, 'seminar/zadani/AktualniZadani.html', + {'nastaveni': nastaveni, + 'jednorazove_problemy': jednorazove_problemy, + 'temata': verejna_temata(nastaveni.aktualni_rocnik), + 'verejne': verejne, + }, + ) def ZadaniTemataView(request): - nastaveni = get_object_or_404(Nastaveni) - temata = verejna_temata(nastaveni.aktualni_rocnik) - for t in temata: - if request.user.is_staff: - t.prispevky = t.prispevek_set.filter(problem=t) - else: - t.prispevky = t.prispevek_set.filter(problem=t, zverejnit=True) - return render(request, 'seminar/zadani/Temata.html', - { - 'temata': temata, - } - ) + nastaveni = get_object_or_404(Nastaveni) + temata = verejna_temata(nastaveni.aktualni_rocnik) + for t in temata: + if request.user.is_staff: + t.prispevky = t.prispevek_set.filter(problem=t) + else: + t.prispevky = t.prispevek_set.filter(problem=t, zverejnit=True) + return render(request, 'seminar/zadani/Temata.html', + { + 'temata': temata, + } + ) #def ZadaniAktualniVysledkovkaView(request): -# nastaveni = get_object_or_404(Nastaveni) -# # Aktualni verejna vysledkovka -# vysledkovka = vysledkovka_rocniku(nastaveni.aktualni_rocnik) -# # kdyz neni verejna vysledkovka, tak zobraz starou -# if not vysledkovka: -# try: -# minuly_rocnik = Rocnik.objects.get( -# prvni_rok=(nastaveni.aktualni_rocnik.prvni_rok-1)) -# vysledkovka = vysledkovka_rocniku(minuly_rocnik) -# except ObjectDoesNotExist: -# pass -# # vysledkovka s neverejnyma vysledkama -# vysledkovka_s_neverejnymi = vysledkovka_rocniku(nastaveni.aktualni_rocnik, jen_verejne=False) -# return render( -# request, -# 'seminar/zadani/AktualniVysledkovka.html', -# { -# 'nastaveni': nastaveni, -# 'vysledkovka': vysledkovka, -# 'vysledkovka_s_neverejnymi': vysledkovka_s_neverejnymi, -# } -# ) +# nastaveni = get_object_or_404(Nastaveni) +# # Aktualni verejna vysledkovka +# vysledkovka = vysledkovka_rocniku(nastaveni.aktualni_rocnik) +# # kdyz neni verejna vysledkovka, tak zobraz starou +# if not vysledkovka: +# try: +# minuly_rocnik = Rocnik.objects.get( +# prvni_rok=(nastaveni.aktualni_rocnik.prvni_rok-1)) +# vysledkovka = vysledkovka_rocniku(minuly_rocnik) +# except ObjectDoesNotExist: +# pass +# # vysledkovka s neverejnyma vysledkama +# vysledkovka_s_neverejnymi = vysledkovka_rocniku(nastaveni.aktualni_rocnik, jen_verejne=False) +# return render( +# request, +# 'seminar/zadani/AktualniVysledkovka.html', +# { +# 'nastaveni': nastaveni, +# 'vysledkovka': vysledkovka, +# 'vysledkovka_s_neverejnymi': vysledkovka_s_neverejnymi, +# } +# ) ### Titulni strana class TitulniStranaView(generic.ListView): - model = Novinky - template_name='seminar/titulnistrana.html' - queryset = Novinky.objects.order_by('-datum')[:5] - - def get_context_data(self, **kwargs): - context = super(TitulniStranaView, self).get_context_data(**kwargs) - nastaveni = get_object_or_404(Nastaveni) - - # zjisteni spravneho terminu - if nastaveni.aktualni_cislo.datum_deadline_soustredeni: - cas_deadline_soustredeni = nastaveni.aktualni_cislo.\ - datum_deadline_soustredeni - if (datetime.now().date() <= cas_deadline_soustredeni): - cas_deadline = cas_deadline_soustredeni - deadline_soustredeni = True - else: - cas_deadline = nastaveni.aktualni_cislo.datum_deadline - deadline_soustredeni = False - else: - cas_deadline = nastaveni.aktualni_cislo.datum_deadline - deadline_soustredeni = False - - # Pokud neni zverejnene cislo nezverejnuj odpocet - if nastaveni.aktualni_cislo.verejne(): - # pokus se zjistit termin odeslani a pokud neni zadany, - # nezverejnuj odpocet - context['deadline_soustredeni'] = deadline_soustredeni - try: - context['dead'] = datetime.combine(cas_deadline, - datetime.max.time()) - context['ted'] = datetime.now() - except: - context['dead'] = None - else: - context['dead'] = None - context['deadline_soustredeni'] = deadline_soustredeni - return context + model = Novinky + template_name='seminar/titulnistrana.html' + queryset = Novinky.objects.order_by('-datum')[:5] + + def get_context_data(self, **kwargs): + context = super(TitulniStranaView, self).get_context_data(**kwargs) + nastaveni = get_object_or_404(Nastaveni) + + # zjisteni spravneho terminu + if nastaveni.aktualni_cislo.datum_deadline_soustredeni: + cas_deadline_soustredeni = nastaveni.aktualni_cislo.\ + datum_deadline_soustredeni + if (datetime.now().date() <= cas_deadline_soustredeni): + cas_deadline = cas_deadline_soustredeni + deadline_soustredeni = True + else: + cas_deadline = nastaveni.aktualni_cislo.datum_deadline + deadline_soustredeni = False + else: + cas_deadline = nastaveni.aktualni_cislo.datum_deadline + deadline_soustredeni = False + + # Pokud neni zverejnene cislo nezverejnuj odpocet + if nastaveni.aktualni_cislo.verejne(): + # pokus se zjistit termin odeslani a pokud neni zadany, + # nezverejnuj odpocet + context['deadline_soustredeni'] = deadline_soustredeni + try: + context['dead'] = datetime.combine(cas_deadline, + datetime.max.time()) + context['ted'] = datetime.now() + except: + context['dead'] = None + else: + context['dead'] = None + context['deadline_soustredeni'] = deadline_soustredeni + return context class StareNovinkyView(generic.ListView): - model = Novinky - template_name = 'seminar/stare_novinky.html' - queryset = Novinky.objects.filter(zverejneno=True).order_by('-datum') + model = Novinky + template_name = 'seminar/stare_novinky.html' + queryset = Novinky.objects.filter(zverejneno=True).order_by('-datum') ### Co je M&M # Organizatori def aktivniOrganizatori(datum=date.today()): - return Organizator.objects.exclude( - organizuje_do__isnull=False, - organizuje_do__lt=datum - ).order_by('user__first_name') + return Organizator.objects.exclude( + organizuje_do__isnull=False, + organizuje_do__lt=datum + ).order_by('user__first_name') class CojemamOrganizatoriView(generic.ListView): - model = Organizator - template_name = 'seminar/cojemam/organizatori.html' - queryset = aktivniOrganizatori() + model = Organizator + template_name = 'seminar/cojemam/organizatori.html' + queryset = aktivniOrganizatori() - def get_context_data(self, **kwargs): - context = super(CojemamOrganizatoriView, self).get_context_data(**kwargs) - context['aktivni'] = True - return context + def get_context_data(self, **kwargs): + context = super(CojemamOrganizatoriView, self).get_context_data(**kwargs) + context['aktivni'] = True + return context class CojemamOrganizatoriStariView(generic.ListView): - model = Organizator - template_name = 'seminar/cojemam/organizatori.html' - queryset = Organizator.objects.exclude( - id__in=aktivniOrganizatori()).order_by('-organizuje_do') + model = Organizator + template_name = 'seminar/cojemam/organizatori.html' + queryset = Organizator.objects.exclude( + id__in=aktivniOrganizatori()).order_by('-organizuje_do') ### Archiv class ArchivView(generic.ListView): - model = Rocnik - template_name='seminar/archiv/cisla.html' - - def get_context_data(self, **kwargs): - context = super(ArchivView, self).get_context_data(**kwargs) - - vyska = 297 # px - sirka = 210 # px - - cisla = Cislo.objects.filter(verejne_db=True)[:10] - - png_dir = op.join(settings.MEDIA_ROOT, "cislo", "png") - - # seznam [(url obrázku, číslo)] - urls = [] - - for i, c in enumerate(cisla): - if not c.pdf: - continue - filename = os.path.split(c.pdf.file.name)[1].split(".")[0] - png_filename = "{}-{}px.png".format(filename, vyska) - - # Pokud obrázek neexistuje nebo není aktuální, vytvoř jej - png_path = op.join(png_dir, png_filename) - if not op.exists(png_path) or \ - op.getmtime(png_path) < op.getmtime(c.pdf.path): - - subprocess.call([ - "convert", - "-density", "180x180", - "-geometry", "{}x{}".format(vyska, vyska), - "-background", "white", - "-flatten", - "-rotate", str(90 * i), - "{}[0]".format(c.pdf.path), # titulní strana - png_path - ]) - - urls.append( - (op.join(settings.MEDIA_URL, "cislo", "png", png_filename), c) - ) - vyska, sirka = sirka, vyska / 2 - - tags = [] - - def spirala(urls, tags, idx): - """Rekurzivně prochází urls a generuje strom elementů do tags""" - if idx >= len(urls): - return - - img_url, cislo = urls[idx] - tags.append( - "
" - .format( - 50 if idx % 4 == 2 else 0, - 50 if idx % 4 == 1 else 0, - 50 if idx % 2 == 1 else 100, - 50 if idx > 0 and idx % 2 == 0 else 100 - ) - ) - tags.append("".format( - cislo.verejne_url(), cislo.kod() - )) - tags.append( - "" - .format( - img_url, - 50 if idx % 4 == 3 else 0, - 50 if idx % 4 == 2 else 0, - 50 if idx % 2 == 0 else 100, - 50 if idx % 2 == 1 else 100 - ) - ) - tags.append("") - spirala(urls, tags, idx + 1) - tags.append("
") - spirala(urls, tags, 0) - - context["nahledy"] = "\n".join(tags) - return context + model = Rocnik + template_name='seminar/archiv/cisla.html' + + def get_context_data(self, **kwargs): + context = super(ArchivView, self).get_context_data(**kwargs) + + vyska = 297 # px + sirka = 210 # px + + cisla = Cislo.objects.filter(verejne_db=True)[:10] + + png_dir = op.join(settings.MEDIA_ROOT, "cislo", "png") + + # seznam [(url obrázku, číslo)] + urls = [] + + for i, c in enumerate(cisla): + if not c.pdf: + continue + filename = os.path.split(c.pdf.file.name)[1].split(".")[0] + png_filename = "{}-{}px.png".format(filename, vyska) + + # Pokud obrázek neexistuje nebo není aktuální, vytvoř jej + png_path = op.join(png_dir, png_filename) + if not op.exists(png_path) or \ + op.getmtime(png_path) < op.getmtime(c.pdf.path): + + subprocess.call([ + "convert", + "-density", "180x180", + "-geometry", "{}x{}".format(vyska, vyska), + "-background", "white", + "-flatten", + "-rotate", str(90 * i), + "{}[0]".format(c.pdf.path), # titulní strana + png_path + ]) + + urls.append( + (op.join(settings.MEDIA_URL, "cislo", "png", png_filename), c) + ) + vyska, sirka = sirka, vyska / 2 + + tags = [] + + def spirala(urls, tags, idx): + """Rekurzivně prochází urls a generuje strom elementů do tags""" + if idx >= len(urls): + return + + img_url, cislo = urls[idx] + tags.append( + "
" + .format( + 50 if idx % 4 == 2 else 0, + 50 if idx % 4 == 1 else 0, + 50 if idx % 2 == 1 else 100, + 50 if idx > 0 and idx % 2 == 0 else 100 + ) + ) + tags.append("".format( + cislo.verejne_url(), cislo.kod() + )) + tags.append( + "" + .format( + img_url, + 50 if idx % 4 == 3 else 0, + 50 if idx % 4 == 2 else 0, + 50 if idx % 2 == 0 else 100, + 50 if idx % 2 == 1 else 100 + ) + ) + tags.append("") + spirala(urls, tags, idx + 1) + tags.append("
") + spirala(urls, tags, 0) + + context["nahledy"] = "\n".join(tags) + return context def sloupec_s_poradim(vysledky): - # počet řešitelů ve výsledkovce nad aktuálním - lepsich_resitelu = 0 - - poradi_l = [] - # projdeme skupiny řešitelů se stejným počtem bodů - for skupina in (list(x) for _, x in groupby(vysledky, lambda x: x.body)): - - # připravíme si obsahy buněk ve sloupci pořadí pro skupinu - if len(skupina) == 1: - poradi_l += ["{}.".format(lepsich_resitelu + 1)] - # je-li účastníků se stejným počtem bodů víc, pořadí (rozsah X.-Y.) je jen u prvního - else: - poradi_l += [u"{}.–{}.".format(lepsich_resitelu + 1, lepsich_resitelu + len(skupina))] + [""] * (len(skupina)-1) - lepsich_resitelu += len(skupina) + # počet řešitelů ve výsledkovce nad aktuálním + lepsich_resitelu = 0 + + poradi_l = [] + # projdeme skupiny řešitelů se stejným počtem bodů + for skupina in (list(x) for _, x in groupby(vysledky, lambda x: x.body)): + + # připravíme si obsahy buněk ve sloupci pořadí pro skupinu + if len(skupina) == 1: + poradi_l += ["{}.".format(lepsich_resitelu + 1)] + # je-li účastníků se stejným počtem bodů víc, pořadí (rozsah X.-Y.) je jen u prvního + else: + poradi_l += [u"{}.–{}.".format(lepsich_resitelu + 1, lepsich_resitelu + len(skupina))] + [""] * (len(skupina)-1) + lepsich_resitelu += len(skupina) #pomlcka je opravdu pomlcka v unicode!!dulezite pro vysledkovku v TeXu - return poradi_l + return poradi_l #def vysledkovka_rocniku(rocnik, jen_verejne=True): -# """Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve -# formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" -# """ -# -# #vyberu vsechny vysledky z rocniku -# cisla_v_rocniku = VysledkyKCisluZaRocnik.objects.filter(cislo__rocnik=rocnik).order_by('cislo') -# if jen_verejne: -# cisla_v_rocniku = cisla_v_rocniku.filter(cislo__verejna_vysledkovka=True) -# -# #pokud žádné nejsou, výsledkovka se nezobrazí -# if not cisla_v_rocniku: -# return None -# -# #vybere vsechny vysledky z posledniho (verejneho) cisla a setridi sestupne dle bodu -# vysledky = list(cisla_v_rocniku.filter(cislo = cisla_v_rocniku[0].cislo).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno').select_related('resitel')) -# -# class Vysledkovka: -# def __init__(self): -# self.rocnik = rocnik.rocnik -# self.radky = [] -# self.cisla = [] -# -# vysledkovka = Vysledkovka() -# vysledkovka.cisla = (rocnik.verejne_vysledkovky_cisla() if jen_verejne else rocnik.cisla.all().order_by('cislo')) -# -# # doplníme některé údaje do řádků výsledkovky pro řešitele ve skupině -# for poradi, v in zip(sloupec_s_poradim(vysledky), vysledky): -# v.poradi = poradi -# v.resitel.rocnik = v.resitel.rocnik(rocnik) -# -# verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__rocnik=rocnik, cislo=cisla_v_rocniku[0].cislo) -# if jen_verejne: -# verejne_vysl_odjakziva = verejne_vysl_odjakziva.filter(cislo__verejna_vysledkovka=True) -# -# v.body_odjakziva = verejne_vysl_odjakziva.filter(resitel = v.resitel)[0].body -# v.titul = v.resitel.get_titul(v.body_odjakziva) -# v.body_rocnik = v.body -# v.body_cisla = [] -# -# #pokud pro dany rok a cislo nema resitel vysledky, ma defaultne 0 -# for cis in vysledkovka.cisla: -# if not jen_verejne or cis.verejna_vysledkovka: -# #seznam vysledku se spravnym rocnikem a cislem pro resitele -# #zobrazim jen je-li vysledkovka verejna -# body_za_cislo = VysledkyZaCislo.objects.filter(cislo__rocnik=rocnik).filter(cislo = cis).filter(resitel = v.resitel) -# if body_za_cislo: -# #neprazdne vysledky by mely obsahovat prave jeden vysledek -# v.body_cisla.append(body_za_cislo[0].body) -# else: -# #resitel nema za cislo body -# v.body_cisla.append(0) -# -# vysledkovka.radky.append(v) -# -# return vysledkovka +# """Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve +# formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" +# """ +# +# #vyberu vsechny vysledky z rocniku +# cisla_v_rocniku = VysledkyKCisluZaRocnik.objects.filter(cislo__rocnik=rocnik).order_by('cislo') +# if jen_verejne: +# cisla_v_rocniku = cisla_v_rocniku.filter(cislo__verejna_vysledkovka=True) +# +# #pokud žádné nejsou, výsledkovka se nezobrazí +# if not cisla_v_rocniku: +# return None +# +# #vybere vsechny vysledky z posledniho (verejneho) cisla a setridi sestupne dle bodu +# vysledky = list(cisla_v_rocniku.filter(cislo = cisla_v_rocniku[0].cislo).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno').select_related('resitel')) +# +# class Vysledkovka: +# def __init__(self): +# self.rocnik = rocnik.rocnik +# self.radky = [] +# self.cisla = [] +# +# vysledkovka = Vysledkovka() +# vysledkovka.cisla = (rocnik.verejne_vysledkovky_cisla() if jen_verejne else rocnik.cisla.all().order_by('cislo')) +# +# # doplníme některé údaje do řádků výsledkovky pro řešitele ve skupině +# for poradi, v in zip(sloupec_s_poradim(vysledky), vysledky): +# v.poradi = poradi +# v.resitel.rocnik = v.resitel.rocnik(rocnik) +# +# verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__rocnik=rocnik, cislo=cisla_v_rocniku[0].cislo) +# if jen_verejne: +# verejne_vysl_odjakziva = verejne_vysl_odjakziva.filter(cislo__verejna_vysledkovka=True) +# +# v.body_odjakziva = verejne_vysl_odjakziva.filter(resitel = v.resitel)[0].body +# v.titul = v.resitel.get_titul(v.body_odjakziva) +# v.body_rocnik = v.body +# v.body_cisla = [] +# +# #pokud pro dany rok a cislo nema resitel vysledky, ma defaultne 0 +# for cis in vysledkovka.cisla: +# if not jen_verejne or cis.verejna_vysledkovka: +# #seznam vysledku se spravnym rocnikem a cislem pro resitele +# #zobrazim jen je-li vysledkovka verejna +# body_za_cislo = VysledkyZaCislo.objects.filter(cislo__rocnik=rocnik).filter(cislo = cis).filter(resitel = v.resitel) +# if body_za_cislo: +# #neprazdne vysledky by mely obsahovat prave jeden vysledek +# v.body_cisla.append(body_za_cislo[0].body) +# else: +# #resitel nema za cislo body +# v.body_cisla.append(0) +# +# vysledkovka.radky.append(v) +# +# return vysledkovka class RocnikView(generic.DetailView): - model = Rocnik - template_name = 'seminar/archiv/rocnik.html' + model = Rocnik + template_name = 'seminar/archiv/rocnik.html' - # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik) - def get_object(self, queryset=None): - if queryset is None: - queryset = self.get_queryset() - rocnik_arg = self.kwargs.get('rocnik') - queryset = queryset.filter(rocnik=rocnik_arg) + # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik) + def get_object(self, queryset=None): + if queryset is None: + queryset = self.get_queryset() + rocnik_arg = self.kwargs.get('rocnik') + queryset = queryset.filter(rocnik=rocnik_arg) - try: - obj = queryset.get() - except queryset.model.DoesNotExist: - raise Http404(_("No %(verbose_name)s found matching the query") % - {'verbose_name': queryset.model._meta.verbose_name}) - return obj + try: + obj = queryset.get() + except queryset.model.DoesNotExist: + raise Http404(_("No %(verbose_name)s found matching the query") % + {'verbose_name': queryset.model._meta.verbose_name}) + return obj - def get_context_data(self, **kwargs): - context = super(RocnikView, self).get_context_data(**kwargs) + def get_context_data(self, **kwargs): + context = super(RocnikView, self).get_context_data(**kwargs) - #context['vysledkovka'] = vysledkovka_rocniku(context["rocnik"]) - #context['vysledkovka_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False) - context['temata_v_rocniku'] = verejna_temata(context["rocnik"]) + #context['vysledkovka'] = vysledkovka_rocniku(context["rocnik"]) + #context['vysledkovka_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False) + context['temata_v_rocniku'] = verejna_temata(context["rocnik"]) - return context + return context class ProblemView(generic.DetailView): - model = Problem + model = Problem - def _je_clanek(self, problem): - return problem.typ in [Problem.TYP_ORG_CLANEK, Problem.TYP_RES_CLANEK] + def _je_clanek(self, problem): + return problem.typ in [Problem.TYP_ORG_CLANEK, Problem.TYP_RES_CLANEK] - def get_template_names(self, **kwargs): - context = super(ProblemView, self).get_context_data(**kwargs) - return ['seminar/archiv/problem_' + ('clanek.html' if self._je_clanek(context['problem']) else 'uloha_tema.html')] + def get_template_names(self, **kwargs): + context = super(ProblemView, self).get_context_data(**kwargs) + return ['seminar/archiv/problem_' + ('clanek.html' if self._je_clanek(context['problem']) else 'uloha_tema.html')] - def get_context_data(self, **kwargs): - context = super(ProblemView, self).get_context_data(**kwargs) - if not context['problem'].verejne() and not self.request.user.is_staff: - raise PermissionDenied() - if context['problem'].typ == Problem.TYP_RES_CLANEK: - context['reseni'] = Reseni.objects.filter(problem=context['problem']).select_related('resitel').order_by('resitel__prijmeni') - return context + def get_context_data(self, **kwargs): + context = super(ProblemView, self).get_context_data(**kwargs) + if not context['problem'].verejne() and not self.request.user.is_staff: + raise PermissionDenied() + if context['problem'].typ == Problem.TYP_RES_CLANEK: + context['reseni'] = Reseni.objects.filter(problem=context['problem']).select_related('resitel').order_by('resitel__prijmeni') + return context ## Prispevek byl zrusen, mozna ale bude podobny nahled na neco jineho. #class PrispevekView(generic.DetailView): -# model = Prispevek -# template_name = 'seminar/archiv/prispevek.html' -# -# # Vlastni ziskavani objektu z databaze podle prispevku -# # pokud je prispevek neverejny zobrazi se jenom orgum -# def get_object(self, queryset=None): -# if queryset is None: -# queryset = self.get_queryset() -# problem_arg = self.kwargs.get('pk') -# prispevek_arg = self.kwargs.get('prispevek') -# queryset = queryset.filter(pk=prispevek_arg) -# -# try: -# obj = queryset.get() -# except queryset.model.DoesNotExist: -# raise Http404(_("No %(verbose_name)s found matching the query") % -# {'verbose_name': queryset.model._meta.verbose_name}) -# -# if self.request.user.is_staff or obj.zverejnit: -# return obj -# else: -# raise Http404() -# -# def get_context_data(self, **kwargs): -# context = super(PrispevekView, self).get_context_data(**kwargs) -# # snaho o ziskani titulu -# titul = '' -# try: -# resitel = context['prispevek'].reseni.resitel -# cislo = context['prispevek'].reseni.cislo_body -# body = VysledkyKCisluOdjakziva.objects.get(resitel=resitel, -# cislo=cislo).body -# titul = resitel.get_titul(body) -# except: -# pass -# context['titul'] = titul -# return context +# model = Prispevek +# template_name = 'seminar/archiv/prispevek.html' +# +# # Vlastni ziskavani objektu z databaze podle prispevku +# # pokud je prispevek neverejny zobrazi se jenom orgum +# def get_object(self, queryset=None): +# if queryset is None: +# queryset = self.get_queryset() +# problem_arg = self.kwargs.get('pk') +# prispevek_arg = self.kwargs.get('prispevek') +# queryset = queryset.filter(pk=prispevek_arg) +# +# try: +# obj = queryset.get() +# except queryset.model.DoesNotExist: +# raise Http404(_("No %(verbose_name)s found matching the query") % +# {'verbose_name': queryset.model._meta.verbose_name}) +# +# if self.request.user.is_staff or obj.zverejnit: +# return obj +# else: +# raise Http404() +# +# def get_context_data(self, **kwargs): +# context = super(PrispevekView, self).get_context_data(**kwargs) +# # snaho o ziskani titulu +# titul = '' +# try: +# resitel = context['prispevek'].reseni.resitel +# cislo = context['prispevek'].reseni.cislo_body +# body = VysledkyKCisluOdjakziva.objects.get(resitel=resitel, +# cislo=cislo).body +# titul = resitel.get_titul(body) +# except: +# pass +# context['titul'] = titul +# return context class RadekVysledkovky(object): - pass + pass #class CisloView(generic.DetailView): -# model = Cislo -# template_name = 'seminar/archiv/cislo.html' -# -# # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik) -# def get_object(self, queryset=None): -# if queryset is None: -# queryset = self.get_queryset() -# rocnik_arg = self.kwargs.get('rocnik') -# cislo_arg = self.kwargs.get('cislo') -# queryset = queryset.filter(rocnik__rocnik=rocnik_arg, cislo=cislo_arg) -# -# try: -# obj = queryset.get() -# except queryset.model.DoesNotExist: -# raise Http404(_("No %(verbose_name)s found matching the query") % -# {'verbose_name': queryset.model._meta.verbose_name}) -# return obj -# -# -# def get_context_data(self, **kwargs): -# context = super(CisloView, self).get_context_data(**kwargs) -# -# vysledky = VysledkyKCisluZaRocnik.objects.filter(cislo = context['cislo']).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno') -# reseni = Reseni.objects.filter(cislo_body = context['cislo']).select_related("resitel") -# -# # typy úloh, které se mají zobrazovat u čísla, tj. těch, které byly v čísle skutečně zadány -# typy_skutecne_zadanych = [Problem.TYP_ULOHA, Problem.TYP_SERIAL, Problem.TYP_ORG_CLANEK] -# v_cisle_zadane = Problem.objects.filter(cislo_zadani=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('kod') -# -# resene_problemy = Problem.objects.filter(cislo_reseni=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('cislo_zadani__cislo', 'kod') -# -# poradi_typu = { -# Problem.TYP_ULOHA: 1, -# Problem.TYP_SERIAL: 2, -# Problem.TYP_ORG_CLANEK: 3, -# Problem.TYP_TEMA: 4, -# Problem.TYP_RES_CLANEK: 5 -# } -# problemy = sorted(set(r.problem for r in reseni), key=lambda x:(poradi_typu[x.typ], x.kod_v_rocniku())) -# #setridi problemy podle typu a poradi zadani -# problem_index = {} -# for i in range(len(problemy)): -# problem_index[problemy[i].id] = i -# #umoznuje zjistit index podle id problemu -# -# vysledky_resitele = {} -# vysledkovka = [] -# -# # doplníme některé údaje do řádků výsledkovky pro řešitele ve skupině -# for poradi, v in zip(sloupec_s_poradim(vysledky), vysledky): -# v.poradi = poradi -# v.body_celkem_rocnik = v.body -# v.body_celkem_odjakziva = VysledkyKCisluOdjakziva.objects.get(resitel=v.resitel, cislo=context['cislo']).body -# v.resitel.rocnik = v.resitel.rocnik(v.cislo.rocnik) -# -# # je tady '', aby se nezobrazovala 0, pokud se řešitel o řešení úlohy ani nepokusil -# v.body_ulohy = [''] * len(problemy) -# -# v.titul = v.resitel.get_titul(v.body_celkem_odjakziva) -# -# body_cislo_q = VysledkyZaCislo.objects.filter(resitel=v.resitel, cislo=context['cislo']) -# v.body_cislo = body_cislo_q[0].body if body_cislo_q else 0 -# -# vysledkovka.append(v) -# -# # připravíme si odkaz na řádek, abychom do něj mohli doplnit body za jednotlivé úlohy -# vysledky_resitele[v.resitel.id] = v -# -# # za každé řešení doplníme k příslušnému řešiteli a úloze body -# for r in reseni: -# vysledky_resitele[r.resitel.id].body_ulohy[problem_index[r.problem.id]] = r.body -# -# context['vysledkovka'] = vysledkovka -# context['problemy'] = problemy -# context['v_cisle_zadane'] = v_cisle_zadane -# context['resene_problemy'] = resene_problemy -# return context +# model = Cislo +# template_name = 'seminar/archiv/cislo.html' +# +# # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik) +# def get_object(self, queryset=None): +# if queryset is None: +# queryset = self.get_queryset() +# rocnik_arg = self.kwargs.get('rocnik') +# cislo_arg = self.kwargs.get('cislo') +# queryset = queryset.filter(rocnik__rocnik=rocnik_arg, cislo=cislo_arg) +# +# try: +# obj = queryset.get() +# except queryset.model.DoesNotExist: +# raise Http404(_("No %(verbose_name)s found matching the query") % +# {'verbose_name': queryset.model._meta.verbose_name}) +# return obj +# +# +# def get_context_data(self, **kwargs): +# context = super(CisloView, self).get_context_data(**kwargs) +# +# vysledky = VysledkyKCisluZaRocnik.objects.filter(cislo = context['cislo']).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno') +# reseni = Reseni.objects.filter(cislo_body = context['cislo']).select_related("resitel") +# +# # typy úloh, které se mají zobrazovat u čísla, tj. těch, které byly v čísle skutečně zadány +# typy_skutecne_zadanych = [Problem.TYP_ULOHA, Problem.TYP_SERIAL, Problem.TYP_ORG_CLANEK] +# v_cisle_zadane = Problem.objects.filter(cislo_zadani=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('kod') +# +# resene_problemy = Problem.objects.filter(cislo_reseni=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('cislo_zadani__cislo', 'kod') +# +# poradi_typu = { +# Problem.TYP_ULOHA: 1, +# Problem.TYP_SERIAL: 2, +# Problem.TYP_ORG_CLANEK: 3, +# Problem.TYP_TEMA: 4, +# Problem.TYP_RES_CLANEK: 5 +# } +# problemy = sorted(set(r.problem for r in reseni), key=lambda x:(poradi_typu[x.typ], x.kod_v_rocniku())) +# #setridi problemy podle typu a poradi zadani +# problem_index = {} +# for i in range(len(problemy)): +# problem_index[problemy[i].id] = i +# #umoznuje zjistit index podle id problemu +# +# vysledky_resitele = {} +# vysledkovka = [] +# +# # doplníme některé údaje do řádků výsledkovky pro řešitele ve skupině +# for poradi, v in zip(sloupec_s_poradim(vysledky), vysledky): +# v.poradi = poradi +# v.body_celkem_rocnik = v.body +# v.body_celkem_odjakziva = VysledkyKCisluOdjakziva.objects.get(resitel=v.resitel, cislo=context['cislo']).body +# v.resitel.rocnik = v.resitel.rocnik(v.cislo.rocnik) +# +# # je tady '', aby se nezobrazovala 0, pokud se řešitel o řešení úlohy ani nepokusil +# v.body_ulohy = [''] * len(problemy) +# +# v.titul = v.resitel.get_titul(v.body_celkem_odjakziva) +# +# body_cislo_q = VysledkyZaCislo.objects.filter(resitel=v.resitel, cislo=context['cislo']) +# v.body_cislo = body_cislo_q[0].body if body_cislo_q else 0 +# +# vysledkovka.append(v) +# +# # připravíme si odkaz na řádek, abychom do něj mohli doplnit body za jednotlivé úlohy +# vysledky_resitele[v.resitel.id] = v +# +# # za každé řešení doplníme k příslušnému řešiteli a úloze body +# for r in reseni: +# vysledky_resitele[r.resitel.id].body_ulohy[problem_index[r.problem.id]] = r.body +# +# context['vysledkovka'] = vysledkovka +# context['problemy'] = problemy +# context['v_cisle_zadane'] = v_cisle_zadane +# context['resene_problemy'] = resene_problemy +# return context class ArchivTemataView(generic.ListView): - model = Problem - template_name = 'seminar/archiv/temata.html' - queryset = Tema.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod') + model = Problem + template_name = 'seminar/archiv/temata.html' + queryset = Tema.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod') ### Generovani vysledkovky #class CisloVysledkovkaView(CisloView): -# model = Cislo -# template_name = 'seminar/archiv/cislo_vysledkovka.tex' -# #content_type = 'application/x-tex; charset=UTF8' -# #umozni rovnou stahnout TeXovsky dokument -# content_type = 'text/plain; charset=UTF8' -# #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani +# model = Cislo +# template_name = 'seminar/archiv/cislo_vysledkovka.tex' +# #content_type = 'application/x-tex; charset=UTF8' +# #umozni rovnou stahnout TeXovsky dokument +# content_type = 'text/plain; charset=UTF8' +# #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani # #class RocnikVysledkovkaView(RocnikView): -# model = Rocnik -# template_name = 'seminar/archiv/rocnik_vysledkovka.tex' -# #content_type = 'application/x-tex; charset=UTF8' -# #umozni rovnou stahnout TeXovsky dokument -# content_type = 'text/plain; charset=UTF8' -# #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani +# model = Rocnik +# template_name = 'seminar/archiv/rocnik_vysledkovka.tex' +# #content_type = 'application/x-tex; charset=UTF8' +# #umozni rovnou stahnout TeXovsky dokument +# content_type = 'text/plain; charset=UTF8' +# #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani ### Generovani obalek class CisloObalkyStruct: - rocnik = None - cisla = None + rocnik = None + cisla = None # Vraci QuerySet aktualnich resitelu = nekdy neco poslali, ale jeste neodmaturovali def aktualniResitele(rocnik): - letos = Rocnik.objects.get(rocnik = rocnik) - return Resitel.objects.filter(rok_maturity__gt = letos.prvni_rok) -# # ALERT: pokud nekdo nema vypleny rok maturity, tak neni aktualni, protoze Karel Tesar a jini -# return Resitel.objects.filter(Q(rok_maturity__gt = letos.prvni_rok)|Q(rok_maturity = None)) + letos = Rocnik.objects.get(rocnik = rocnik) + return Resitel.objects.filter(rok_maturity__gt = letos.prvni_rok) +# # ALERT: pokud nekdo nema vypleny rok maturity, tak neni aktualni, protoze Karel Tesar a jini +# return Resitel.objects.filter(Q(rok_maturity__gt = letos.prvni_rok)|Q(rok_maturity = None)) # Vraci QuerySet aktivnich resitelu = # jeste neodmaturovali && # (pokud je aktualni cislo mensi nez 3, pak (letos || loni) neco poslali # jinak letos neco poslali) def aktivniResitele(rocnik,cislo): - letos = CisloObalkyStruct() - loni = CisloObalkyStruct() + letos = CisloObalkyStruct() + loni = CisloObalkyStruct() - aktualni_resitele = aktualniResitele(rocnik) + aktualni_resitele = aktualniResitele(rocnik) - letos.rocnik = Rocnik.objects.get(rocnik = rocnik) - loni.rocnik = Rocnik.objects.get(rocnik = int(rocnik)-1) - letos.cisla = Cislo.objects.filter(rocnik=letos.rocnik,cislo__lte = cislo) - loni.cisla = Cislo.objects.filter(rocnik=loni.rocnik) - if int(cislo) > 3: - problemy = Problem.objects.filter(cislo_zadani__in = letos.cisla) - else: - problemy = Problem.objects.filter(Q(cislo_zadani__in = letos.cisla)|Q(cislo_zadani__in = loni.cisla)) - resitele = aktualni_resitele.filter(reseni__in = Reseni.objects.filter(problem__in=problemy)).distinct() - return resitele + letos.rocnik = Rocnik.objects.get(rocnik = rocnik) + loni.rocnik = Rocnik.objects.get(rocnik = int(rocnik)-1) + letos.cisla = Cislo.objects.filter(rocnik=letos.rocnik,cislo__lte = cislo) + loni.cisla = Cislo.objects.filter(rocnik=loni.rocnik) + if int(cislo) > 3: + problemy = Problem.objects.filter(cislo_zadani__in = letos.cisla) + else: + problemy = Problem.objects.filter(Q(cislo_zadani__in = letos.cisla)|Q(cislo_zadani__in = loni.cisla)) + resitele = aktualni_resitele.filter(reseni__in = Reseni.objects.filter(problem__in=problemy)).distinct() + return resitele def cisloObalkyView(request,rocnik,cislo): - return obalkyView(request,aktivniResitele(rocnik,cislo)) + return obalkyView(request,aktivniResitele(rocnik,cislo)) def obalkyView(request,resitele): - tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content + tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content - tempdir = tempfile.mkdtemp() - with open(tempdir+"/obalky.tex","w") as texfile: - texfile.write(tex) - shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.eps'),tempdir) - subprocess.call(["pdflatex","obalky.tex"],cwd = tempdir) + tempdir = tempfile.mkdtemp() + with open(tempdir+"/obalky.tex","w") as texfile: + texfile.write(tex) + shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.eps'),tempdir) + subprocess.call(["pdflatex","obalky.tex"],cwd = tempdir) - with open(tempdir+"/obalky.pdf","rb") as pdffile: - response = HttpResponse(pdffile.read(),content_type='application/pdf') - shutil.rmtree(tempdir) - return response + with open(tempdir+"/obalky.pdf","rb") as pdffile: + response = HttpResponse(pdffile.read(),content_type='application/pdf') + shutil.rmtree(tempdir) + return response def obalkovaniView(request, rocnik, cislo): - rocnik = Rocnik.objects.get(rocnik=rocnik) - cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo) - - reseni = ( - Reseni.objects.filter(cislo_body=cislo) - .order_by( - 'resitel__prijmeni', - 'resitel__jmeno', - 'problem__typ', - 'problem__kod' - ) - ) - - problemy = sorted(set(r.problem for r in reseni), key=lambda p: (p.typ, p.kod)) - return render( - request, - 'seminar/archiv/cislo_obalkovani.html', - {'cislo': cislo, 'problemy': problemy, 'reseni': reseni} - ) + rocnik = Rocnik.objects.get(rocnik=rocnik) + cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo) + + reseni = ( + Reseni.objects.filter(cislo_body=cislo) + .order_by( + 'resitel__prijmeni', + 'resitel__jmeno', + 'problem__typ', + 'problem__kod' + ) + ) + + problemy = sorted(set(r.problem for r in reseni), key=lambda p: (p.typ, p.kod)) + return render( + request, + 'seminar/archiv/cislo_obalkovani.html', + {'cislo': cislo, 'problemy': problemy, 'reseni': reseni} + ) ### Tituly # TODO udelat neco jako get_objects_or_404 # FIXME: prepsat, aby nepouzivalo VysledkyK... #def TitulyView(request, rocnik, cislo): -# rocnik_obj = Rocnik.objects.get(rocnik = rocnik) -# resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok) -# cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, cislo = cislo) +# rocnik_obj = Rocnik.objects.get(rocnik = rocnik) +# resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok) +# cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, cislo = cislo) # -# asciijmena = [] -# broken = False +# asciijmena = [] +# broken = False # -# for resitel in resitele: -# try: -# vys = VysledkyKCisluOdjakziva.objects.get(resitel = resitel, cislo = cislo_obj) -# body = vys.body -# except ObjectDoesNotExist: -# body = 0 -# resitel.titul = resitel.get_titul(body) -# resitel.ascii = unicodedata.normalize('NFKD',resitel.jmeno+resitel.prijmeni).encode("ascii","ignore").replace(" ","") -# if resitel.ascii not in asciijmena: -# asciijmena.append(resitel.ascii) -# else: -# broken = True +# for resitel in resitele: +# try: +# vys = VysledkyKCisluOdjakziva.objects.get(resitel = resitel, cislo = cislo_obj) +# body = vys.body +# except ObjectDoesNotExist: +# body = 0 +# resitel.titul = resitel.get_titul(body) +# resitel.ascii = unicodedata.normalize('NFKD',resitel.jmeno+resitel.prijmeni).encode("ascii","ignore").replace(" ","") +# if resitel.ascii not in asciijmena: +# asciijmena.append(resitel.ascii) +# else: +# broken = True # -# return render(request, 'seminar/archiv/tituly.tex',{'resitele': resitele,'broken':broken},content_type="text/plain") +# return render(request, 'seminar/archiv/tituly.tex',{'resitele': resitele,'broken':broken},content_type="text/plain") ### Soustredeni class SoustredeniListView(generic.ListView): - model = Soustredeni - template_name = 'seminar/soustredeni/seznam_soustredeni.html' + model = Soustredeni + template_name = 'seminar/soustredeni/seznam_soustredeni.html' class SoustredeniView(generic.DetailView): - model = Soustredeni - template_name = 'seminar/archiv/soustredeni.html' + model = Soustredeni + template_name = 'seminar/archiv/soustredeni.html' def soustredeniObalkyView(request,soustredeni): - soustredeni = get_object_or_404(Soustredeni,id = soustredeni) - return obalkyView(request,soustredeni.ucastnici.all()) + soustredeni = get_object_or_404(Soustredeni,id = soustredeni) + return obalkyView(request,soustredeni.ucastnici.all()) class SoustredeniUcastniciBaseView(generic.ListView): - model = Soustredeni_Ucastnici + model = Soustredeni_Ucastnici - def get_queryset(self): - soustredeni = get_object_or_404( - Soustredeni, - pk=self.kwargs["soustredeni"] - ) - return Soustredeni_Ucastnici.objects.filter( - soustredeni=soustredeni).select_related('resitel') + def get_queryset(self): + soustredeni = get_object_or_404( + Soustredeni, + pk=self.kwargs["soustredeni"] + ) + return Soustredeni_Ucastnici.objects.filter( + soustredeni=soustredeni).select_related('resitel') class SoustredeniMailyUcastnikuView(SoustredeniUcastniciBaseView): - """Seznam e-mailů řešitelů oddělených čárkami""" - model = Soustredeni_Ucastnici - template_name = 'seminar/soustredeni/maily_ucastniku.txt' + """Seznam e-mailů řešitelů oddělených čárkami""" + model = Soustredeni_Ucastnici + template_name = 'seminar/soustredeni/maily_ucastniku.txt' class SoustredeniUcastniciView(SoustredeniUcastniciBaseView): - """HTML tabulka účastníků pro tisk""" - model = Soustredeni_Ucastnici - template_name = 'seminar/soustredeni/seznam_ucastniku.html' + """HTML tabulka účastníků pro tisk""" + model = Soustredeni_Ucastnici + template_name = 'seminar/soustredeni/seznam_ucastniku.html' def soustredeniStvrzenkyExportView(request,soustredeni,first_num): - first_num = int(first_num) - soustredeni = get_object_or_404(Soustredeni,id = soustredeni) - ucastnici = Resitel.objects.filter(soustredeni=soustredeni) - for (idx,u) in enumerate(ucastnici): - u.cislo_stvrzenky = first_num+idx; - tex = render(request,'seminar/soustredeni/ucastnici.tex', {'ucastnici': ucastnici, 'datum':soustredeni.datum_zacatku }).content - - tempdir = tempfile.mkdtemp() - with open(tempdir+"/ucastnici.tex","w") as texfile: - # Pokud TeX chce ISO Latin, tak se da encode nastavit - texfile.write(tex.decode("utf-8").encode("utf-8")) - shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/stvrzenka.sty'),tempdir) - shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/stvrzenky.tex'),tempdir) - subprocess.call(["cslatex","stvrzenky.tex"],cwd = tempdir) - subprocess.call(["dvipdf","stvrzenky.dvi"],cwd = tempdir) - - with open(tempdir+"/stvrzenky.pdf","rb") as pdffile: - response = HttpResponse(pdffile.read(),content_type='application/pdf') - shutil.rmtree(tempdir) - return response + first_num = int(first_num) + soustredeni = get_object_or_404(Soustredeni,id = soustredeni) + ucastnici = Resitel.objects.filter(soustredeni=soustredeni) + for (idx,u) in enumerate(ucastnici): + u.cislo_stvrzenky = first_num+idx; + tex = render(request,'seminar/soustredeni/ucastnici.tex', {'ucastnici': ucastnici, 'datum':soustredeni.datum_zacatku }).content + + tempdir = tempfile.mkdtemp() + with open(tempdir+"/ucastnici.tex","w") as texfile: + # Pokud TeX chce ISO Latin, tak se da encode nastavit + texfile.write(tex.decode("utf-8").encode("utf-8")) + shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/stvrzenka.sty'),tempdir) + shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/stvrzenky.tex'),tempdir) + subprocess.call(["cslatex","stvrzenky.tex"],cwd = tempdir) + subprocess.call(["dvipdf","stvrzenky.dvi"],cwd = tempdir) + + with open(tempdir+"/stvrzenky.pdf","rb") as pdffile: + response = HttpResponse(pdffile.read(),content_type='application/pdf') + shutil.rmtree(tempdir) + return response def soustredeniUcastniciExportView(request,soustredeni): - soustredeni = get_object_or_404(Soustredeni,id = soustredeni) - ucastnici = Resitel.objects.filter(soustredeni=soustredeni) - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="ucastnici.csv"' + soustredeni = get_object_or_404(Soustredeni,id = soustredeni) + ucastnici = Resitel.objects.filter(soustredeni=soustredeni) + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="ucastnici.csv"' - writer = UnicodeWriter(response) - writer.writerow(["jmeno", "prijmeni", "rok_maturity", "telefon", "email", "ulice", "mesto", "psc","stat"]) - for u in ucastnici: - writer.writerow([u.jmeno, u.prijmeni, str(u.rok_maturity), u.telefon, u.email, u.ulice, u.mesto, u.psc, u.stat.name]) - return response + writer = UnicodeWriter(response) + writer.writerow(["jmeno", "prijmeni", "rok_maturity", "telefon", "email", "ulice", "mesto", "psc","stat"]) + for u in ucastnici: + writer.writerow([u.jmeno, u.prijmeni, str(u.rok_maturity), u.telefon, u.email, u.ulice, u.mesto, u.psc, u.stat.name]) + return response ### Články # FIXME: clanky jsou vsechny, pokud budou i neresitelske, tak se take zobrazi class ClankyResitelView(generic.ListView): - model = Problem - template_name = 'seminar/clanky/resitelske_clanky.html' - queryset = Clanek.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod') + model = Problem + template_name = 'seminar/clanky/resitelske_clanky.html' + queryset = Clanek.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod') # FIXME: pokud chceme orgoclanky, tak nejak zavest do modelu a podle toho odkomentovat a upravit #class ClankyOrganizatorView(generic.ListView): -# model = Problem -# template_name = 'seminar/clanky/organizatorske_clanky.html' -# queryset = Problem.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod') +# model = Problem +# template_name = 'seminar/clanky/organizatorske_clanky.html' +# 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(pohlavi_muz=True) - zeny = Resitel.objects.filter(pohlavi_muz=False) - return render(request, 'seminar/stav_databaze.html', - { -# 'nastaveni': nastaveni, - 'problemy': problemy, +# nastaveni = Nastaveni.objects.get() + problemy = utils.seznam_problemu() + muzi = Resitel.objects.filter(pohlavi_muz=True) + zeny = Resitel.objects.filter(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.jmeno for r in muzi]), - 'jmena_zen': utils.histogram([r.jmeno for r in zeny]), - }) + 'resitele': Resitel.objects.all(), + 'muzi': muzi, + 'zeny': zeny, + 'jmena_muzu': utils.histogram([r.jmeno for r in muzi]), + 'jmena_zen': utils.histogram([r.jmeno for r in zeny]), + }) @ensure_csrf_cookie def LoginView(request): - """Pro přihlášení při nahrávání z texu""" - q = request.POST - # nastavení cookie csrftoken - if not q: - return JsonResponse({"ok": 1}) - - if "username" in q: - username = q["username"] - password = q["password"] - user = authenticate(username=username, password=password) - if user is not None and user.is_staff: - login(request, user) - return JsonResponse({"ok": 1}) - else: - return JsonResponse({"error": "Neplatné uživatelské jméno nebo heslo"}) + """Pro přihlášení při nahrávání z texu""" + q = request.POST + # nastavení cookie csrftoken + if not q: + return JsonResponse({"ok": 1}) + + if "username" in q: + username = q["username"] + password = q["password"] + user = authenticate(username=username, password=password) + if user is not None and user.is_staff: + login(request, user) + return JsonResponse({"ok": 1}) + else: + return JsonResponse({"error": "Neplatné uživatelské jméno nebo heslo"}) @ensure_csrf_cookie def texUploadView(request): - def uloz_soubory(files, rocnik, cislo): - for filename, f in files: - path = os.path.join( - settings.MEDIA_ROOT, - settings.CISLO_IMG_DIR, - rocnik, - cislo, - filename - ) - - adresar = os.path.dirname(path) - if not os.path.exists(adresar): - os.makedirs(adresar) - - with open(path, "wb+") as fout: - for chunk in f.chunks(): - fout.write(chunk) - - q = request.POST - # nastavení cookie csrftoken - if not q: - return JsonResponse({"ok": 1}) - - # Odchytíme všechny výjimky a traceback pošleme v odpovědi - try: - meta = json.loads(q["meta"]) - html = q["html"] - - if meta["typ"] in ["uloha", "serial", "reseni", "tema"]: - - # Uložíme soubory - if meta["typ"] != "reseni": - c = meta["cislo"] - else: - # Řešení má nastavené číslo svojí úlohy, ale obrázky jsou - # ukládány do čísla, kde řešení vyšlo - c = meta["cislo_reseni"] - - # Zjistíme typ ukládaného problému - typy = { - "uloha": Problem.TYP_ULOHA, - "serial": Problem.TYP_SERIAL, - "reseni": Problem.TYP_ULOHA, - "tema": Problem.TYP_TEMA, - } - problem_typ = typy[meta["typ"]] - - # Pokud už problém existuje, vytáhneme jej z db a upravíme - # Pokud neexistuje, vytvoříme jej jedině pokud je to vynucené - - # Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku -> - # číslo/ročník se musí založit ručně v adminu - rocnik = Rocnik.objects.get(rocnik=meta["rocnik"]) - cislo = Cislo.objects.get(rocnik=rocnik, cislo=meta["cislo"]) - - existujici = Problem.objects.filter( - typ=problem_typ, - stav=Problem.STAV_ZADANY, - cislo_zadani=cislo, - kod=meta["kod"] - ) - - problem = None - if existujici: - problem = existujici[0] - elif "vytvor" in q: - # vytvoříme nový - problem = Problem( - typ=problem_typ, - stav=Problem.STAV_ZADANY, - kod=meta["kod"], - cislo_zadani=cislo - ) - else: - return JsonResponse({ - "error": "Problém neexistuje: {} {}.{} kód {}".format( - meta["typ"], meta["rocnik"], meta["cislo"], meta["kod"] - ) - }) - - uloz_soubory(request.FILES.items(), meta["rocnik"], c) - - if meta["typ"] == "reseni": - problem.text_reseni = html - - # Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku -> - # číslo/ročník se musí založit ručně v adminu - problem.cislo_reseni = Cislo.objects.get( - rocnik=rocnik, - cislo=meta["cislo_reseni"] - ) - # při nahrávání řešení už původní zadání atd. neměníme - else: - problem.text_zadani = html - problem.nazev = meta["nazev"] - if meta["typ"] != "tema": - problem.body = meta["body"] - - problem.save() - cislo.faze = cislo.FAZE_NAHRANO - cislo.save() - - # Vrátíme id dané úlohy, aby se k ní dala případně připojit pohádka - return JsonResponse({"db_id": problem.id}) - - elif meta["typ"] == "pohadka": - uloha = Problem.objects.get(typ=Problem.TYP_ULOHA, pk=meta["uloha"]) - - # Pokud už příslušná pohádka existuje, jen ji upravíme - existujici = Pohadka.objects.filter(uloha=uloha, pred=meta["pred"]) - pohadka = None - if existujici: - pohadka = existujici[0] - else: - pohadka = Pohadka(uloha=uloha, pred=meta["pred"]) - pohadka.text = q["html"] - pohadka.save() - - return JsonResponse({"db_id": pohadka.id}) - - except Exception as e: - # Pošleme zpátky traceback, ať uživatel ví, v čem je problém - tb = "".join(traceback.format_exception(type(e), e, sys.exc_info()[2])) - return JsonResponse({"error": tb}) + def uloz_soubory(files, rocnik, cislo): + for filename, f in files: + path = os.path.join( + settings.MEDIA_ROOT, + settings.CISLO_IMG_DIR, + rocnik, + cislo, + filename + ) + + adresar = os.path.dirname(path) + if not os.path.exists(adresar): + os.makedirs(adresar) + + with open(path, "wb+") as fout: + for chunk in f.chunks(): + fout.write(chunk) + + q = request.POST + # nastavení cookie csrftoken + if not q: + return JsonResponse({"ok": 1}) + + # Odchytíme všechny výjimky a traceback pošleme v odpovědi + try: + meta = json.loads(q["meta"]) + html = q["html"] + + if meta["typ"] in ["uloha", "serial", "reseni", "tema"]: + + # Uložíme soubory + if meta["typ"] != "reseni": + c = meta["cislo"] + else: + # Řešení má nastavené číslo svojí úlohy, ale obrázky jsou + # ukládány do čísla, kde řešení vyšlo + c = meta["cislo_reseni"] + + # Zjistíme typ ukládaného problému + typy = { + "uloha": Problem.TYP_ULOHA, + "serial": Problem.TYP_SERIAL, + "reseni": Problem.TYP_ULOHA, + "tema": Problem.TYP_TEMA, + } + problem_typ = typy[meta["typ"]] + + # Pokud už problém existuje, vytáhneme jej z db a upravíme + # Pokud neexistuje, vytvoříme jej jedině pokud je to vynucené + + # Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku -> + # číslo/ročník se musí založit ručně v adminu + rocnik = Rocnik.objects.get(rocnik=meta["rocnik"]) + cislo = Cislo.objects.get(rocnik=rocnik, cislo=meta["cislo"]) + + existujici = Problem.objects.filter( + typ=problem_typ, + stav=Problem.STAV_ZADANY, + cislo_zadani=cislo, + kod=meta["kod"] + ) + + problem = None + if existujici: + problem = existujici[0] + elif "vytvor" in q: + # vytvoříme nový + problem = Problem( + typ=problem_typ, + stav=Problem.STAV_ZADANY, + kod=meta["kod"], + cislo_zadani=cislo + ) + else: + return JsonResponse({ + "error": "Problém neexistuje: {} {}.{} kód {}".format( + meta["typ"], meta["rocnik"], meta["cislo"], meta["kod"] + ) + }) + + uloz_soubory(request.FILES.items(), meta["rocnik"], c) + + if meta["typ"] == "reseni": + problem.text_reseni = html + + # Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku -> + # číslo/ročník se musí založit ručně v adminu + problem.cislo_reseni = Cislo.objects.get( + rocnik=rocnik, + cislo=meta["cislo_reseni"] + ) + # při nahrávání řešení už původní zadání atd. neměníme + else: + problem.text_zadani = html + problem.nazev = meta["nazev"] + if meta["typ"] != "tema": + problem.body = meta["body"] + + problem.save() + cislo.faze = cislo.FAZE_NAHRANO + cislo.save() + + # Vrátíme id dané úlohy, aby se k ní dala případně připojit pohádka + return JsonResponse({"db_id": problem.id}) + + elif meta["typ"] == "pohadka": + uloha = Problem.objects.get(typ=Problem.TYP_ULOHA, pk=meta["uloha"]) + + # Pokud už příslušná pohádka existuje, jen ji upravíme + existujici = Pohadka.objects.filter(uloha=uloha, pred=meta["pred"]) + pohadka = None + if existujici: + pohadka = existujici[0] + else: + pohadka = Pohadka(uloha=uloha, pred=meta["pred"]) + pohadka.text = q["html"] + pohadka.save() + + return JsonResponse({"db_id": pohadka.id}) + + except Exception as e: + # Pošleme zpátky traceback, ať uživatel ví, v čem je problém + tb = "".join(traceback.format_exception(type(e), e, sys.exc_info()[2])) + return JsonResponse({"error": tb}) def texDownloadView(request, rocnik, cislo): - """View posílající JSON se zadanými a řešenými problémy pro založení čísla - """ - cislo = Cislo.objects.get(rocnik__rocnik=rocnik, cislo=cislo) - if cislo.faze == cislo.FAZE_NAHRANO: - # obsah byl nahrán z TeXu na web, už je příliš složitý - return JsonResponse( - {"error": "Obsah čísla už byl nahrán z TeXu na web."} - ) - - zadane = Problem.objects.filter( - cislo_zadani=cislo, - stav=Problem.STAV_ZADANY - ) - resene = Problem.objects.filter( - cislo_reseni=cislo, - stav=Problem.STAV_ZADANY, - typ=Problem.TYP_ULOHA - ) - pred_pohadky = Pohadka.objects.filter(uloha__cislo_zadani=cislo, pred=True) - po_pohadky = Pohadka.objects.filter(uloha__cislo_zadani=cislo, pred=False) - - response = { - "zadane": [ - { - "nazev": p.nazev, - "typ": p.typ, - "kod": p.kod, - "body": p.body, - "zadani": p.text_zadani, - "pred_pohadky": [x.text for x in pred_pohadky.filter(uloha=p)], - "po_pohadky": [x.text for x in po_pohadky.filter(uloha=p)], - } for p in zadane - ], - "resene": [ - { - "nazev": p.nazev, - "typ": p.typ, - "kod": p.kod, - "body": p.body, - "zadani": p.text_zadani, - "reseni": p.text_reseni, - "cislo_zadani": p.cislo_zadani.cislo, - } for p in resene - ], - } - - cislo.faze = Cislo.FAZE_TEX - cislo.save() - return JsonResponse(response) + """View posílající JSON se zadanými a řešenými problémy pro založení čísla + """ + cislo = Cislo.objects.get(rocnik__rocnik=rocnik, cislo=cislo) + if cislo.faze == cislo.FAZE_NAHRANO: + # obsah byl nahrán z TeXu na web, už je příliš složitý + return JsonResponse( + {"error": "Obsah čísla už byl nahrán z TeXu na web."} + ) + + zadane = Problem.objects.filter( + cislo_zadani=cislo, + stav=Problem.STAV_ZADANY + ) + resene = Problem.objects.filter( + cislo_reseni=cislo, + stav=Problem.STAV_ZADANY, + typ=Problem.TYP_ULOHA + ) + pred_pohadky = Pohadka.objects.filter(uloha__cislo_zadani=cislo, pred=True) + po_pohadky = Pohadka.objects.filter(uloha__cislo_zadani=cislo, pred=False) + + response = { + "zadane": [ + { + "nazev": p.nazev, + "typ": p.typ, + "kod": p.kod, + "body": p.body, + "zadani": p.text_zadani, + "pred_pohadky": [x.text for x in pred_pohadky.filter(uloha=p)], + "po_pohadky": [x.text for x in po_pohadky.filter(uloha=p)], + } for p in zadane + ], + "resene": [ + { + "nazev": p.nazev, + "typ": p.typ, + "kod": p.kod, + "body": p.body, + "zadani": p.text_zadani, + "reseni": p.text_reseni, + "cislo_zadani": p.cislo_zadani.cislo, + } for p in resene + ], + } + + cislo.faze = Cislo.FAZE_TEX + cislo.save() + return JsonResponse(response) ## Formulare def get_name(request): - # if this is a POST request we need to process the form data - if request.method == 'POST': - # create a form instance and populate it with data from the request: - form = NameForm(request.POST) - # check whether it's valid: - if form.is_valid(): - # process the data in form.cleaned_data as required - # ... - # redirect to a new URL: - return HttpResponseRedirect('/thanks/') - - # if a GET (or any other method) we'll create a blank form - else: - form = NameForm() - - return render(request, 'seminar/prihlaska.html', {'form': form}) + # if this is a POST request we need to process the form data + if request.method == 'POST': + # create a form instance and populate it with data from the request: + form = NameForm(request.POST) + # check whether it's valid: + if form.is_valid(): + # process the data in form.cleaned_data as required + # ... + # redirect to a new URL: + return HttpResponseRedirect('/thanks/') + + # if a GET (or any other method) we'll create a blank form + else: + form = NameForm() + + return render(request, 'seminar/prihlaska.html', {'form': form}) # Ceka na autocomplete v3 # class OrganizatorAutocomplete(autocomplete.Select2QuerySetView):