diff --git a/galerie/admin.py b/galerie/admin.py index 4f95c951..1441ce09 100644 --- a/galerie/admin.py +++ b/galerie/admin.py @@ -3,6 +3,9 @@ from galerie.models import Obrazek, Galerie from django.contrib import admin from django.http import HttpResponseRedirect +from django import forms +from django.db import models +import autocomplete_light # akction @@ -27,17 +30,25 @@ def prepnout_fotogalerii_do_org_rezimu(modeladmin, request, queryset): 'Přepnout do režimu úprav (zneveřejní galerii)' class GalerieInline(admin.TabularInline): - model = Obrazek + 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') + list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag') -class GalerieAdmin(admin.ModelAdmin): - model = Galerie - fields = ('zobrazit', 'nazev', 'titulni_obrazek', 'popis', 'galerie_up', 'soustredeni', 'poradi') - list_display = ('nazev', 'pk', 'datum_zmeny', 'zobrazit', 'soustredeni') - inlines = [GalerieInline] - actions = [zverejnit_fotogalerii, prepnout_fotogalerii_do_org_rezimu] +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', 'pk', 'poradi', 'datum_zmeny', 'zobrazit', 'soustredeni') + 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/autocomplete_light_registry.py b/galerie/autocomplete_light_registry.py new file mode 100644 index 00000000..7b624d20 --- /dev/null +++ b/galerie/autocomplete_light_registry.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals + +import autocomplete_light + +from models import Obrazek, Galerie +from views import cesta_od_korene + + +class ObrazekAutocomplete(autocomplete_light.AutocompleteModelBase): + + model = Obrazek + search_fields = ['nazev', 'popis'] + split_words = True + limit_choices = 15 + attrs = { + # This will set the input placeholder attribute: + 'placeholder': u'Obrázek', + # This will set the yourlabs.Autocomplete.minimumCharacters + # options, the naming conversion is handled by jQuery + 'data-autocomplete-minimum-characters': 1, + } + + choice_html_format = ''' + + + {} + {} + + + ''' + + def choice_label(self, obrazek): + cesta = "/".join(g.nazev for g in cesta_od_korene(obrazek.galerie)) + popis = "{}
".format(obrazek.popis) if obrazek.popis else "" + return '{}
{}{}'.format(obrazek.nazev, popis, cesta) + + def choice_html(self, obrazek): + """Vrátí kus html i s obrázkem, které se pak ukazuje v nabídce""" + return self.choice_html_format.format(self.choice_value(obrazek), + obrazek.obrazek_maly_tag(), self.choice_label(obrazek)) + + widget_attrs={ + 'data-widget-maximum-values': 15, + 'class': 'modern-style', + } + +autocomplete_light.register(ObrazekAutocomplete) diff --git a/galerie/migrations/0006_django_imagekit.py b/galerie/migrations/0006_django_imagekit.py new file mode 100644 index 00000000..6b90b791 --- /dev/null +++ b/galerie/migrations/0006_django_imagekit.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('galerie', '0005_obrazek_ordering_datum'), + ] + + operations = [ + migrations.RemoveField( + model_name='obrazek', + name='obrazek_maly', + ), + migrations.RemoveField( + model_name='obrazek', + name='obrazek_stredni', + ), + ] diff --git a/galerie/migrations/0007_obrazek_odstranen_datum.py b/galerie/migrations/0007_obrazek_odstranen_datum.py new file mode 100644 index 00000000..94c3596b --- /dev/null +++ b/galerie/migrations/0007_obrazek_odstranen_datum.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('galerie', '0006_django_imagekit'), + ] + + operations = [ + migrations.AlterModelOptions( + name='obrazek', + options={'ordering': ['nazev'], 'verbose_name': 'Obr\xe1zek', 'verbose_name_plural': 'Obr\xe1zky'}, + ), + migrations.RemoveField( + model_name='obrazek', + name='datum', + ), + ] diff --git a/galerie/models.py b/galerie/models.py index 22457ba1..4c08c4f2 100644 --- a/galerie/models.py +++ b/galerie/models.py @@ -1,17 +1,12 @@ # coding: utf-8 from django.db import models -import seminar.models -from django.db.models import Q -from django.utils import timezone +#from django.db.models import Q from django.utils.encoding import force_unicode +from imagekit.models import ImageSpecField +from imagekit.processors import ResizeToFit, Transpose -from PIL import Image -from PIL.ExifTags import TAGS import os -from cStringIO import StringIO -from django.core.files.base import ContentFile -from datetime import datetime from seminar.models import Soustredeni @@ -24,120 +19,49 @@ VIDITELNOST = ( (NIKDY, 'Nikdy'), ) -def get_exif(fn): - ret = {} - info = fn._getexif() - for tag, value in info.items(): - decoded = TAGS.get(tag, tag) - ret[decoded] = value - return ret - -def flip_horizontal(im): return im.transpose(Image.FLIP_LEFT_RIGHT) -def flip_vertical(im): return im.transpose(Image.FLIP_TOP_BOTTOM) -def rotate_180(im): return im.transpose(Image.ROTATE_180) -def rotate_90(im): return im.transpose(Image.ROTATE_90) -def rotate_270(im): return im.transpose(Image.ROTATE_270) -def transpose(im): return rotate_90(flip_horizontal(im)) -def transverse(im): return rotate_90(flip_vertical(im)) -orientation_funcs = [None, - lambda x: x, - flip_horizontal, - rotate_180, - flip_vertical, - transpose, - rotate_270, - transverse, - rotate_90 - ] - +# 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 +def obrazek_filename_stredni(): + pass +def obrazek_filename_velky(): + pass def obrazek_filename(self, filename): - return obrazek_filename_obecny(self, filename, "velky") - -def obrazek_filename_stredni(self, filename): - return obrazek_filename_obecny(self, filename, "stredni") - -def obrazek_filename_maly(self, filename): - return obrazek_filename_obecny(self, filename, "maly") - -def obrazek_filename_obecny(self, filename, typ): gal = self.galerie cislo_gal = force_unicode(gal.pk) cesta = "" while(not gal.soustredeni): gal = gal.galerie_up - return os.path.join('Galerie', "soustredeni_" + force_unicode(gal.soustredeni.pk), "galerie_" + cislo_gal, typ, force_unicode(self.nazev)) + return os.path.join('Galerie', "soustredeni_" + force_unicode(gal.soustredeni.pk), "galerie_" + cislo_gal, "velky", force_unicode(self.nazev)) 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 = models.ImageField(upload_to=obrazek_filename_stredni, null = True, editable = False) - obrazek_maly = models.ImageField(upload_to=obrazek_filename_maly, null = True, editable = False) + 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) - datum = models.DateTimeField('Datum pořízení fotografie', blank = True, null = True) galerie = models.ForeignKey('Galerie', blank=True, null=True) poradi = models.IntegerField('Pořadí', blank = True, null = True) def __unicode__(self): - return self.nazev + " -- " + unicode(self.obrazek_velky.name) + " (" + str(self.datum) + ")" + return self.nazev + " -- " + unicode(self.obrazek_velky.name) class Meta: verbose_name = 'Obrázek' verbose_name_plural = 'Obrázky' - ordering = ['datum'] - def save(self): - original = Image.open(self.obrazek_velky) - # vycteni EXIFu - exif = get_exif(original) - # otoceni podle EXIFu - if exif['Orientation']: - f = orientation_funcs[exif['Orientation']] - original_otoceny = f(original) - original_otoceny.format = original.format - original = original_otoceny - # datum podle EXIfu - if exif['DateTimeOriginal']: - datum_string = ":".join(exif['DateTimeOriginal'].split(' ')).split(":") - datum_int = [] - for retezec in datum_string: - datum_int.append(int(retezec)) - self.datum = datetime(datum_int[0], datum_int[1], datum_int[2], - datum_int[3], datum_int[4], datum_int[5]) - jmeno = os.path.basename(self.obrazek_velky.file.name) - if not self.obrazek_stredni: - Obrazek._vyrobMiniaturu(original, jmeno, 1024, self.obrazek_stredni) - if not self.obrazek_maly: - Obrazek._vyrobMiniaturu(original, jmeno, 200, self.obrazek_maly) - super(Obrazek, self).save() + ordering = ['nazev'] - @staticmethod - def _vyrobMiniaturu(original, jmeno, maximum, field): - zmensenina = Obrazek._zmensiObrazek(original, maximum) - f = StringIO() - try: - zmensenina.save(f, format=original.format) - data = ContentFile(f.getvalue()) - finally: - f.close() - field.save(jmeno, data, save = False) - - @staticmethod - def _zmensiObrazek(original, maximum): - """Preskaluje obrazek tak, aby byl zachovan pomer stran a zadny rozmer - nepresahoval maxRozmer. Pokud zadny rozmer nepresahuje maxRozmer, tak - vrati puvodni obrazek (tj. nedojde ke zvetseni obrazku).""" - novaVelikost = Obrazek._zmensiVelikost(original.size, maximum) - return original.resize(novaVelikost, Image.ANTIALIAS) + 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 - @staticmethod - def _zmensiVelikost(velikost, maximum): - maximum = float(maximum) - w, h = velikost - soucasneMaximum = max(w, h) - if soucasneMaximum <= maximum: - return velikost - pomer = maximum/soucasneMaximum - return (int(w * pomer), int(h * pomer)) class Galerie(models.Model): diff --git a/galerie/templates/galerie/GalerieNahled.html b/galerie/templates/galerie/GalerieNahled.html index 1a4656b4..bb475b50 100644 --- a/galerie/templates/galerie/GalerieNahled.html +++ b/galerie/templates/galerie/GalerieNahled.html @@ -6,6 +6,10 @@ Galerie {{galerie.nazev}} {% block content %} + {% if galerie.zobrazit > 0 %} +
+ {% endif %} +

{% for g in cesta %} {% if not forloop.last %} @@ -19,7 +23,7 @@ Galerie {{galerie.nazev}} {% if not obrazky %}
{% if galerie.titulni_obrazek %} - + {% endif %}
{% endif %} @@ -45,8 +49,8 @@ Galerie {{galerie.nazev}} {% if galerie.titulni_obrazek %} {% with galerie.titulni_obrazek.obrazek_maly as obrazek %} + width="{% widthratio obrazek.width 167 obrazek.width %}" + height="{% widthratio obrazek.width 167 obrazek.height %}" /> {% endwith %} {% endif %}
@@ -76,8 +80,8 @@ Galerie {{galerie.nazev}} {% for obrazek in obrazky %} + width="{{ obrazek.obrazek_maly.width }}" + height="{{ obrazek.obrazek_maly.height }}" /> {% endfor %}
@@ -103,4 +107,9 @@ Galerie {{galerie.nazev}}
{% endif %} {% endif %} + + {% if galerie.zobrazit > 0 %} +

{# mam-org-only #} + {% endif %} + {% endblock content %} diff --git a/galerie/views.py b/galerie/views.py index 9e23133f..46860810 100644 --- a/galerie/views.py +++ b/galerie/views.py @@ -38,7 +38,7 @@ def nahled(request, pk, soustredeni): if not request.user.is_staff: podgalerie = podgalerie.filter(zobrazit__lt=1) - obrazky = Obrazek.objects.filter(galerie = galerie).order_by('datum') + obrazky = Obrazek.objects.filter(galerie = galerie) preview = zobrazit(galerie, request) sourozenci = [] @@ -82,7 +82,7 @@ def detail(request, pk, fotka, soustredeni): 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().order_by('datum') + obrazky = galerie.obrazek_set.all() # vytvoreni a obslouzeni formulare if request.method == 'POST': diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index 5b3fe86b..67072e59 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -111,6 +111,8 @@ INSTALLED_APPS = ( 'django.contrib.flatpages', 'django.contrib.humanize', + 'imagekit', + # MaMweb 'mamweb', 'seminar', @@ -155,6 +157,7 @@ CKEDITOR_IMAGE_BACKEND = 'pillow' #CKEDITOR_JQUERY_URL = '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js' CKEDITOR_CONFIGS = { 'default': { + 'entities': False, 'toolbar': [ ['Source', 'ShowBlocks', '-', 'Maximize'], ['Bold', 'Italic', 'Subscript', 'Superscript', '-', 'RemoveFormat'], @@ -233,12 +236,3 @@ LOGGING = { # MaM specific SEMINAR_RESENI_DIR = os.path.join(BASE_DIR, 'media', 'reseni') - - -CKEDITOR_CONFIGS = { - 'default': { - 'entities': False - } -} - - diff --git a/mamweb/settings_prod.py b/mamweb/settings_prod.py index ee8233e3..b56a9380 100644 --- a/mamweb/settings_prod.py +++ b/mamweb/settings_prod.py @@ -50,6 +50,7 @@ ADMINS = [ ('Petr Pecha', 'nejlepsitextovyeditorjevim@gmail.com'), ('Tomas Gavenciak', 'gavento@gmail.com'), ('Matěj Kocián', 'matej.kocian@gmail.com'), + ('M&M ERRORs', 'mam-errors@atrey.karlin.mff.cuni.cz'), ] diff --git a/mamweb/settings_test.py b/mamweb/settings_test.py index abe315ad..3d1b0010 100644 --- a/mamweb/settings_test.py +++ b/mamweb/settings_test.py @@ -50,6 +50,7 @@ import os SERVER_EMAIL = 'mamweb-test-errors@mam.mff.cuni.cz' ADMINS = [ ('Petr Pecha', 'nejlepsitextovyeditorjevim@gmail.com'), + ('M&M ERRORs', 'mam-errors@atrey.karlin.mff.cuni.cz'), ] diff --git a/mamweb/static/css/mamweb.css b/mamweb/static/css/mamweb.css index bfdb87b0..8b1ef07d 100644 --- a/mamweb/static/css/mamweb.css +++ b/mamweb/static/css/mamweb.css @@ -18,6 +18,15 @@ body { border: orange 2px dashed; } +.mam-org-only .mam-org-only { + border: 0px; +} + +li.mam-org-only { + padding: 3px 0px; + margin: -2px 0px; +} + table .border-r { border-right: solid 1px; } @@ -437,7 +446,7 @@ div.zadani_azad_termin { float: none; width: 70%; margin-left: auto; - margin-right: auto + margin-right: auto; } } @@ -446,7 +455,8 @@ div.zadani_azad_termin { /* galerie */ /* velká fotka */ -.galerie .obrazek { +/* zmenšování spolu s oknem prohlížeče */ +.galerie .obrazek, .titulni_obrazek { max-width: 100%; height: auto; width: auto\9; /* ie8 */ @@ -482,7 +492,6 @@ div.zadani_azad_termin { .galerie { position: relative; text-align: center; - /*width: 100%;*/ margin: 20px auto 0 auto; } @@ -503,6 +512,11 @@ div.zadani_azad_termin { text-align: center; } +/* titulní obrázek hlavní galerie soustředění */ +.titulni_obrazek { + border: 1px solid black; +} + .galerie_nahledy{ /*margin: 1em 0;*/ margin: 0 auto 30px auto; @@ -649,3 +663,11 @@ div.zadani_azad_termin { float: right; max-width: 42%; } + +.novinka_obrazek img { + margin-bottom: 15px; +} + +div.novinka_obrazek { + width: 100%; +} diff --git a/requirements.txt b/requirements.txt index ea1261ee..cff14d30 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,6 +23,7 @@ django-flat-theme==0.9.3 django-taggit==0.17 django-autocomplete-light==2.2.6 django-crispy-forms==1.4.0 +django-imagekit==3.2.7 # Comments akismet==0.2.0 @@ -32,7 +33,7 @@ django-contrib-comments==1.6.1 # debug tools/extensions -django-debug-toolbar==1.3.2 +django-debug-toolbar==1.4 django-extensions==1.5.6 sqlparse==0.1.16 Werkzeug==0.10.4 diff --git a/seminar/admin.py b/seminar/admin.py index 3a680fc4..b86d933a 100644 --- a/seminar/admin.py +++ b/seminar/admin.py @@ -334,7 +334,7 @@ create_modeladmin(ProblemNavrhAdmin, Problem, 'ProblemNavrh', verbose_name=u'Pro class ProblemZadanyAdmin(ProblemAdmin): list_display = ['nazev', 'typ', 'autor', 'opravovatel', 'kod', 'cislo_zadani', 'pocet_reseni', 'verejne'] - list_filter = ['typ', 'cislo_zadani__cislo', 'cislo_zadani__rocnik'] + list_filter = ['typ', 'zamereni', 'cislo_zadani__cislo', 'cislo_zadani__rocnik'] inlines = [ReseniKProblemuInline] def get_queryset(self, request): diff --git a/seminar/migrations/0035_django_imagekit.py b/seminar/migrations/0035_django_imagekit.py new file mode 100644 index 00000000..dd443018 --- /dev/null +++ b/seminar/migrations/0035_django_imagekit.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import imagekit.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('seminar', '0034_reseni_forma_default_email'), + ] + + operations = [ + migrations.RemoveField( + model_name='organizator', + name='foto_male', + ), + migrations.AlterField( + model_name='organizator', + name='foto', + field=imagekit.models.fields.ProcessedImageField(help_text=b'Vlo\xc5\xbe fotografii organiz\xc3\xa1tora o libovoln\xc3\xa9 velikosti', upload_to=b'image_organizatori/velke/%Y/', null=True, verbose_name=b'Fotografie organiz\xc3\xa1tora', blank=True), + preserve_default=True, + ), + ] diff --git a/seminar/models.py b/seminar/models.py index 0f65c272..fbb2a9d5 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -11,6 +11,8 @@ from django.utils.encoding import force_unicode from django.utils.text import slugify from django.core.urlresolvers import reverse from django.core.cache import cache +from imagekit.models import ImageSpecField, ProcessedImageField +from imagekit.processors import ResizeToFit, Transpose from PIL import Image import os @@ -183,6 +185,9 @@ class Resitel(SeminarModelBase): def plne_jmeno(self): return force_unicode(u'%s %s' % (self.jmeno, self.prijmeni)) + def inicial_krestni(self): + return force_unicode(u'%s.' % (self.jmeno[0])) + def __str__(self): return force_unicode(self.plne_jmeno()) @@ -755,6 +760,12 @@ class Novinky(models.Model): text = models.TextField('Text novinky', blank=True, null=True) obrazek = models.ImageField('Obrázek', upload_to='image_novinky/%Y/%m/%d/', null=True, blank=True) + obrazek_maly = ImageSpecField(source='obrazek', + processors=[ + ResizeToFit(350, 200, upscale=False) + ], + options={'quality': 95}) + autor = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='Autor novinky') zverejneno = models.BooleanField('Zveřejněno', default="False") @@ -785,11 +796,19 @@ class Organizator(models.Model): "'Přednáší na MFF'") strucny_popis_organizatora = models.TextField('Stručný popis organizátora', null = True, blank = True) - foto = models.ImageField('Fotografie organizátora', + foto = ProcessedImageField(verbose_name='Fotografie organizátora', upload_to='image_organizatori/velke/%Y/', null = True, blank = True, - help_text = 'Vlož fotografii organizátora o libovolné velikosti') - foto_male = models.ImageField(upload_to='image_organizatori/male/%Y/', - null = True, blank = True, editable = False) + help_text = 'Vlož fotografii organizátora o libovolné velikosti', + processors=[ + Transpose(Transpose.AUTO), + ResizeToFit(500, 500, upscale=False) + ], + options={'quality': 95}) + foto_male = ImageSpecField(source='foto', + processors=[ + ResizeToFit(200, 200, upscale=False) + ], + options={'quality': 95}) def __str__(self): return str(self.user) @@ -797,52 +816,3 @@ class Organizator(models.Model): class Meta: verbose_name = 'Organizátor' verbose_name_plural = 'Organizátoři' - - def save(self): - # v databázi uložený záznam o organizátorovi - puvodni = None - - # pokud už organizátor v databázi existuje, nastav puvodni - if self.id is not None: - puvodni = Organizator.objects.get(id=self.id) - # pokud nahráváme fotku - if self.foto: - # a je jiná než ta stará - if not puvodni or puvodni.foto != self.foto: - # uložíme ji - original = Image.open(self.foto) - jmeno = os.path.basename(self.foto.file.name) - Organizator._vyrobMiniaturu(original, jmeno, 500, self.foto) - Organizator._vyrobMiniaturu(original, jmeno, 200, self.foto_male) - super(Organizator, self).save() - - @staticmethod - def _vyrobMiniaturu(original, jmeno, maximum, field): - zmensenina = Organizator._zmensiObrazek(original, maximum) - f = StringIO() - try: - zmensenina.save(f, format=original.format) - data = ContentFile(f.getvalue()) - finally: - f.close() - field.save(jmeno, data, save = False) - - @staticmethod - def _zmensiObrazek(original, maximum): - """Preskaluje obrazek tak, aby byl zachovan pomer stran - a zadny rozmer nepresahoval maxRozmer. Pokud zadny rozmer - nepresahuje maxRozmer, tak vrati puvodni obrazek - (tj. nedojde ke zvetseni obrazku).""" - novaVelikost = Organizator._zmensiVelikost(original.size, maximum) - return original.resize(novaVelikost, Image.ANTIALIAS) - - @staticmethod - def _zmensiVelikost(velikost, maximum): - maximum = float(maximum) - w, h = velikost - soucasneMaximum = max(w, h) - if soucasneMaximum <= maximum: - return velikost - pomer = maximum/soucasneMaximum - return (int(w * pomer), int(h * pomer)) - diff --git a/seminar/templates/seminar/archiv/cislo.html b/seminar/templates/seminar/archiv/cislo.html index 2978cc84..a398a6cb 100644 --- a/seminar/templates/seminar/archiv/cislo.html +++ b/seminar/templates/seminar/archiv/cislo.html @@ -27,6 +27,16 @@ {% endfor %} + {% if user.is_staff %} +
+

Orgovské odkazy

+ +
+ {% endif %} + {% if cislo.verejna_vysledkovka %}

Výsledkovka

{% else %} diff --git a/seminar/templates/seminar/archiv/cislo_vysledkovka.tex b/seminar/templates/seminar/archiv/cislo_vysledkovka.tex index e988484c..619b30e1 100644 --- a/seminar/templates/seminar/archiv/cislo_vysledkovka.tex +++ b/seminar/templates/seminar/archiv/cislo_vysledkovka.tex @@ -1,33 +1,9 @@ -\begin{longtable}{r|l|c|l|c - {% for p in problemy %} - @\hskip.5em}c {% endfor %} - |c|r|r} -\hline -& & & & \multicolumn{ {{ problemy|length }} }{c|}{\textbf{Úlohy}} & & \\ -\textbf{Poř.} & \textbf{Jméno} & \textbf{R.} & \raisebox{0.7mm}{$\sum_{-1}$} & -{% for p in problemy %} - {% if p.TYP_ULOHA %} - \textbf{ r{{ p.kod }} } & - {% else %} - \textbf{ t{{ p.kod }} } & - {% endif %} -{% endfor %} -\raisebox{0.7mm}{$\sum_0$} & -\raisebox{0.7mm}{$\sum_1$} \\ -\hline +\setlength{\tabcolsep}{3pt} +\begin{longtable}{|r|l|c|r|{% for p in problemy %}c@{\hskip.5em}{% endfor %}|r|r|}\hline +& & & & \multicolumn{ {{ problemy|length}} }{c|}{\textbf{Úlohy}} & & \\\textbf{Poř.}& \textbf{Jméno}& \textbf{R.}& \raisebox{0.7mm}{$\sum_{-1}$}& {% for p in problemy %}{% if p.typ == "uloha" %}\textbf{r{{p.kod}}}&{% elif p.typ = "tema" %}\textbf{t{{p.kod}}}&{% else %}\textbf{ {{p.kod}} }&{% endif %}{% endfor %}\raisebox{0.7mm}{$\sum_0$}&\raisebox{0.7mm}{$\sum_1$}\\\hline \endhead \hline -\endfoot - -{% for rv in vysledkovka %} - {{ rv.poradi }} & -{% if rv.resitel.titul %} - \titul{ {{ rv.titul }} } -{% endif %} - {{ rv.resitel.plne_jmeno }} & {{ rv.resitel.rocnik |default:"" }} & {{ rv.body_minule }} - {% for b in rv.body %} - {{ b }} & - {% endfor %} - {{ rv.body_celkem_rocnik |default:0 }} & {{ rv.body_celkem_minule }} \\ +\endfoot +{% for rv in vysledkovka %}{{rv.poradi}}&{% if rv.titul %}\titul{ {{ rv.titul}}}{% endif %}{{rv.resitel.inicial_krestni}}{{rv.resitel.prijmeni}}&{{rv.resitel.rocnik|default:""}}&{{rv.body_celkem_odjakziva}}&{% for b in rv.body_ulohy %}{{b}}&{% endfor %}{{rv.body_cislo}}&{{rv.body_celkem_rocnik|default:0}}\\ {% endfor %} \end{longtable} diff --git a/seminar/templates/seminar/novinky.html b/seminar/templates/seminar/novinky.html index c13407f5..0ac99356 100644 --- a/seminar/templates/seminar/novinky.html +++ b/seminar/templates/seminar/novinky.html @@ -1,21 +1,24 @@ {% for novinka in object_list %} {# pripravene div-y na stylovani#}
+ {% if not novinka.zverejneno and user.is_staff %} +
+ {% endif %} + {% if novinka.zverejneno or user.is_staff %} {# datum #}
{{novinka.datum}}
{# text #} {{ novinka.text | safe }} {# obrazek #} {% if novinka.obrazek %} -
- + {% if novinka.obrazek.height > novinka.obrazek_maly.height %} + + + {% else %} - {{novinka.obrazek.height}} + {% endif%} - '>
{% endif %} {# autor #} @@ -26,6 +29,10 @@ {{novinka.autor.last_name}}

+ {% endif %} + {% if not novinka.zverejneno and user.is_staff %} +
+ {% endif %} {% endfor%} diff --git a/seminar/templates/seminar/soustredeni/seznam_soustredeni.html b/seminar/templates/seminar/soustredeni/seznam_soustredeni.html index be7a3644..f7bc73a8 100644 --- a/seminar/templates/seminar/soustredeni/seznam_soustredeni.html +++ b/seminar/templates/seminar/soustredeni/seznam_soustredeni.html @@ -21,46 +21,44 @@ {# Projdi vsechna soustredeni #} {% for soustredeni in object_list %} {# Kdyz je verejne -> zobraz #} - {% if soustredeni.verejne_db or user.is_authenticated %} - {% if not soustredeni.verejne_db and user.is_authenticated %} - Groups of user: {{user.groups.all}}
- - Toto soustředění není veřejné, vidíte ho jen proto, - že jste přihlášení.
+ {% if soustredeni.verejne_db or user.is_staff %} + {% if not soustredeni.verejne_db and user.is_staff %} +
+ {% endif %} {# misto soustredeni TODO upravit#} -

- {{soustredeni.get_typ_display}} - {{soustredeni.misto}} -

- - {% if user.is_staff %} -
- Vytvořit novou fotogalerii -
- {% endif %} - {# popis soustredeni #} - {% if soustredeni.text %} - {% autoescape off %}{{soustredeni.text}}{% endautoescape %} - {% endif %} + {# popis soustredeni #} + {% if soustredeni.text %} + {% autoescape off %}{{soustredeni.text}}{% endautoescape %} + {% endif %} {% if user.is_authenticated %} {# Účastníci #}

Soustředění se zúčastnili tito účastníci:

@@ -72,9 +70,12 @@ {% endfor %} {% endif %} + {% if not soustredeni.verejne_db and user.is_staff %} +
{# class="mam-org-only" #} + {% endif %} {% endif %} - {% empty %} - Žádná soustředění zatím neproběhla! + {% empty %} + Žádná soustředění zatím neproběhla! {% endfor %} {% endblock %} diff --git a/seminar/templates/seminar/titulnistrana.html b/seminar/templates/seminar/titulnistrana.html index a28ffa15..ae949d7e 100644 --- a/seminar/templates/seminar/titulnistrana.html +++ b/seminar/templates/seminar/titulnistrana.html @@ -20,25 +20,11 @@ M&M je korespondeční seminář. Několikrát do roka zdarma vydáváme ča
{% if dead %}
-

Do konce odeslání řešení zbývá:
+

Do konce odeslání řešení zbývá:
{{ted|timesince:dead}}

- - - -
{% endif %} + {# Novinky #}

Novinky

{% include 'seminar/novinky.html' %} diff --git a/seminar/templates/seminar/zadani/AktualniVysledkovka.html b/seminar/templates/seminar/zadani/AktualniVysledkovka.html index 9996b567..8e0898ca 100644 --- a/seminar/templates/seminar/zadani/AktualniVysledkovka.html +++ b/seminar/templates/seminar/zadani/AktualniVysledkovka.html @@ -19,7 +19,7 @@ {% if vysledkovka %} {% include "seminar/vysledkovka_rocnik.html" %} {% else %} - V tomto ročníku zatím žádné výsledky nejsou + V tomto ročníku zatím žádné výsledky nejsou. {% endif %} {% if user.is_staff and vysledkovka_s_neverejnymi %} diff --git a/seminar/templates/seminar/zadani/AktualniZadani.html b/seminar/templates/seminar/zadani/AktualniZadani.html index ff6c3cd3..a9f84a64 100644 --- a/seminar/templates/seminar/zadani/AktualniZadani.html +++ b/seminar/templates/seminar/zadani/AktualniZadani.html @@ -13,7 +13,11 @@ {% block content %}
- {% with nastaveni.aktualni_cislo as ac %} +{% with nastaveni.aktualni_cislo as ac %} + +{# Zobrazovani neverejnych zadani jen organizatorum #} +{% if user.is_staff or verejne %} +{% if user.is_staff and not verejne %}
{% endif %} {% if ac.zadane_problemy.all %}
@@ -45,6 +49,12 @@ Aktuálně nejsou zadané žádné úlohy k řešení. {% endfor %} +{% if user.is_staff and not verejne%}
{% endif %} +{% else %} +

Aktuálně nejsou zveřejněny žádné úlohy

+{% endif %} + +

Témata

    {% for problem in temata %} @@ -56,7 +66,8 @@ Aktuálně nejsou zadána žádná témata k řešení. {% endfor %}
- {% endwith %} + +{% endwith %}
{% endblock content %} diff --git a/seminar/views.py b/seminar/views.py index 36002799..4bef203a 100644 --- a/seminar/views.py +++ b/seminar/views.py @@ -7,6 +7,7 @@ from django.core.urlresolvers import reverse from django.views import generic from django.utils.translation import ugettext as _ from django.http import Http404 +from django.db.models import Q from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva @@ -29,6 +30,7 @@ def verejna_temata(rocnik): 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') @@ -37,6 +39,7 @@ def AktualniZadaniView(request): {'nastaveni': nastaveni, 'jednorazove_problemy': jednorazove_problemy, 'temata': verejna_temata(nastaveni.aktualni_rocnik), + 'verejne': verejne, }, ) @@ -66,22 +69,22 @@ def ZadaniAktualniVysledkovkaView(request): class TitulniStranaView(generic.ListView): model = Novinky template_name='seminar/titulnistrana.html' - queryset = Novinky.objects.filter(zverejneno=True).order_by('-datum')[:5] + 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) cas_deadline = nastaveni.aktualni_cislo.datum_deadline - try: - rozdil_casu = datetime.combine(cas_deadline, datetime.max.time()) \ - - datetime.now() - context['cas_do_konce_dni'] = rozdil_casu.days - context['cas_do_konce_hodin'] = rozdil_casu.seconds / 3600 - context['cas_do_konce_minut'] = (rozdil_casu.seconds / 60) % 60 - context['cas_do_konce_sekund'] = rozdil_casu.seconds % 60 - context['dead'] = datetime.combine(cas_deadline, datetime.max.time()) - context['ted'] = datetime.now() - except: + # Pokud neni zverejnene cislo nezverejnuj odpocet + if nastaveni.aktualni_cislo.verejne(): + # pokus se zjistit termin odeslani a pokud neni zadany, + # nezverejnuj odpocet + try: + context['dead'] = datetime.combine(cas_deadline, datetime.max.time()) + context['ted'] = datetime.now() + except: + context['dead'] = None + else: context['dead'] = None return context @@ -128,8 +131,9 @@ def sloupec_s_poradim(vysledky): 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 += ["{}.–{}.".format(lepsich_resitelu + 1, lepsich_resitelu + len(skupina))] + [""] * (len(skupina)-1) + 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 @@ -293,6 +297,7 @@ class CisloView(generic.DetailView): 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) @@ -342,28 +347,42 @@ class RocnikVysledkovkaView(RocnikView): ### Generovani obalek class CisloObalkyStruct: - resitele = None rocnik = None - problemy = None - -def cisloObalkyView(request,rocnik,cislo): + cisla = None + + +# Vraci QuerySet aktualnich resitelu = nekdy neco poslali, ale jeste neodmaturovali +def aktualniResitele(rocnik): + letos = Rocnik.objects.filter(rocnik = rocnik).first() + 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.rocnik = Rocnik.objects.filter(rocnik = rocnik)[0] - loni.rocnik = Rocnik.objects.filter(rocnik = int(rocnik)-1)[0] - letos.problemy = Problem.objects.filter(cislo_zadani = Cislo.objects.filter(rocnik=letos.rocnik,cislo__lte = cislo)) - loni.problemy = Problem.objects.filter(cislo_zadani = Cislo.objects.filter(rocnik=loni.rocnik)) - letos.resitele = Resitel.objects.filter(reseni = Reseni.objects.filter(problem=letos.problemy)).distinct() - loni.resitele = Resitel.objects.filter(reseni = Reseni.objects.filter(problem=loni.problemy)).distinct() - - loni.resitele = loni.resitele.filter(rok_maturity__gt = letos.rocnik.prvni_rok) - + aktualni_resitele = aktualniResitele(rocnik) + + letos.rocnik = Rocnik.objects.filter(rocnik = rocnik).first() + loni.rocnik = Rocnik.objects.filter(rocnik = int(rocnik)-1).first() + letos.cisla = Cislo.objects.filter(rocnik=letos.rocnik,cislo__lte = cislo) + loni.cisla = Cislo.objects.filter(rocnik=loni.rocnik) if int(cislo) > 3: - resitele = letos.resitele + problemy = Problem.objects.filter(cislo_zadani = letos.cisla) else: - resitele = list(letos.resitele) + list(loni.resitele) - return obalkyView(request,resitele) + problemy = Problem.objects.filter(Q(cislo_zadani = letos.cisla)|Q(cislo_zadani=loni.cisla)) + resitele = aktualni_resitele.filter(reseni = Reseni.objects.filter(problem=problemy)).distinct() + + return resitele + + +def cisloObalkyView(request,rocnik,cislo): + return obalkyView(request,aktivniResitele(rocnik,cislo)) def obalkyView(request,resitele):