diff --git a/galerie/TODO b/galerie/TODO new file mode 100644 index 00000000..c8afd3c4 --- /dev/null +++ b/galerie/TODO @@ -0,0 +1,25 @@ +======== +| TODO | +|======| + +Aktualni +* co s titulni fotkou +* do CSS + * nahledy + * nastylovat tabulku s nahledy + * komentare uz na nahledy? + * detail + * nahledy pred a po + * opravit prechodove sipky + * vyrobit prechodove sipky ve M&M-stylu + +Dlouhodobe +* sipky na prechazeni mezi fotkami +* hromadne PRIDANI fotek do jiz existujici galerie + +Fylozoficke +* zvolit velikosti velke a male fotky +* je potreba i jine razeni nez automaticky podle casu nebo staci podgalerie? + * napr. dve hry na dvou ruznych mistech ve stejny cas + * fotky od ucastniku ze hry (skupinky se pohybuji ve stejny cas, ale maji sled fotek) -- nestaci to pripadne vrazit do podgalerii? + diff --git a/galerie/__init__.py b/galerie/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/galerie/admin.py b/galerie/admin.py new file mode 100644 index 00000000..60af9e3d --- /dev/null +++ b/galerie/admin.py @@ -0,0 +1,43 @@ +#coding: utf-8 + +from galerie.models import Obrazek, Galerie +from django.contrib import admin +from django.http import HttpResponseRedirect + +# 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' + + +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)' + +class GalerieInline(admin.TabularInline): + model = Obrazek + +class ObrazekAdmin(admin.ModelAdmin): + list_display = ('obrazek_velky', 'nazev', 'popis') + +class GalerieAdmin(admin.ModelAdmin): + model = Galerie + fields = ('zobrazit', 'nazev', 'titulni_obrazek', 'popis', 'galerie_up', 'soustredeni') + list_display = ('nazev', 'pk', 'datum_zmeny', 'zobrazit', 'soustredeni') + inlines = [GalerieInline] + actions = [zverejnit_fotogalerii, prepnout_fotogalerii_do_org_rezimu] + +admin.site.register(Obrazek, ObrazekAdmin) +admin.site.register(Galerie, GalerieAdmin) diff --git a/galerie/forms.py b/galerie/forms.py new file mode 100644 index 00000000..3e09fe15 --- /dev/null +++ b/galerie/forms.py @@ -0,0 +1,11 @@ +#coding: utf-8 + +from django import forms +from seminar.models import Soustredeni + +class KomentarForm(forms.Form): + 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) diff --git a/galerie/migrations/0001_initial.py b/galerie/migrations/0001_initial.py new file mode 100644 index 00000000..b7406da6 --- /dev/null +++ b/galerie/migrations/0001_initial.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('seminar', '0033_organizator_studuje_popisek'), + ] + + operations = [ + migrations.CreateModel( + name='Galerie', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('nazev', models.CharField(max_length=100, verbose_name=b'N\xc3\xa1zev')), + ('datum_vytvoreni', models.DateTimeField(auto_now_add=True, verbose_name=b'Datum vytvo\xc5\x99en\xc3\xad')), + ('datum_zmeny', models.DateTimeField(auto_now=True, verbose_name=b'Datum posledn\xc3\xad zm\xc4\x9bny')), + ('popis', models.TextField(null=True, verbose_name=b'Popis', blank=True)), + ('zobrazit', models.IntegerField(default=1, verbose_name=b'Zobrazit?', choices=[(0, b'V\xc5\xbedy'), (1, b'Organiz\xc3\xa1tor\xc5\xafm'), (2, b'Nikdy')])), + ('galerie_up', models.ForeignKey(blank=True, to='galerie.Galerie', null=True)), + ('soustredeni', models.ForeignKey(blank=True, to='seminar.Soustredeni', null=True)), + ], + options={ + 'verbose_name': 'Galerie', + 'verbose_name_plural': 'Galerie', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Obrazek', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('obrazek_velky', models.ImageField(help_text=b'Lze vlo\xc5\xbeit libovoln\xc4\x9b velk\xc3\xbd obr\xc3\xa1zek. Ide\xc3\xa1ln\xc3\xad je, aby alespo\xc5\x88 jeden rozm\xc4\x9br m\xc4\x9bl alespo\xc5\x88 500px.', upload_to=b'Galerie/%Y/%m/%d')), + ('obrazek_stredni', models.ImageField(upload_to=b'Galerie/%Y/%m/%d/stredni', null=True, editable=False)), + ('obrazek_maly', models.ImageField(upload_to=b'Galerie/%Y/%m/%d/male', null=True, editable=False)), + ('nazev', models.CharField(max_length=50, null=True, verbose_name=b'N\xc3\xa1zev', blank=True)), + ('popis', models.TextField(null=True, verbose_name=b'Popis', blank=True)), + ('datum_vlozeni', models.DateTimeField(auto_now_add=True, verbose_name=b'Datum vlo\xc5\xbeen\xc3\xad')), + ('datum', models.DateTimeField(verbose_name=b'Datum po\xc5\x99\xc3\xadzen\xc3\xad fotografie')), + ('poradi', models.IntegerField(null=True, verbose_name=b'Po\xc5\x99ad\xc3\xad', blank=True)), + ('galerie', models.ForeignKey(to='galerie.Galerie')), + ], + options={ + 'verbose_name': 'Obr\xe1zek', + 'verbose_name_plural': 'Obr\xe1zky', + }, + bases=(models.Model,), + ), + migrations.AddField( + model_name='galerie', + name='titulni_obrazek', + field=models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, to='galerie.Obrazek', null=True), + preserve_default=True, + ), + ] diff --git a/galerie/migrations/0002_auto_20151013_1145.py b/galerie/migrations/0002_auto_20151013_1145.py new file mode 100644 index 00000000..ea241267 --- /dev/null +++ b/galerie/migrations/0002_auto_20151013_1145.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('galerie', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='galerie', + name='titulni_obrazek', + field=models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='galerie.Obrazek', null=True), + preserve_default=True, + ), + migrations.AlterField( + model_name='obrazek', + name='datum', + field=models.DateTimeField(null=True, verbose_name=b'Datum po\xc5\x99\xc3\xadzen\xc3\xad fotografie', blank=True), + preserve_default=True, + ), + ] diff --git a/galerie/migrations/0003_add_galerie_poradi.py b/galerie/migrations/0003_add_galerie_poradi.py new file mode 100644 index 00000000..d9b32f48 --- /dev/null +++ b/galerie/migrations/0003_add_galerie_poradi.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import galerie.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('galerie', '0002_auto_20151013_1145'), + ] + + operations = [ + migrations.AddField( + model_name='galerie', + name='poradi', + field=models.IntegerField(null=True, verbose_name=b'Po\xc5\x99ad\xc3\xad', blank=True), + preserve_default=True, + ), + migrations.AlterField( + model_name='obrazek', + name='obrazek_maly', + field=models.ImageField(upload_to=galerie.models.obrazek_filename_maly, null=True, editable=False), + preserve_default=True, + ), + migrations.AlterField( + model_name='obrazek', + name='obrazek_stredni', + field=models.ImageField(upload_to=galerie.models.obrazek_filename_stredni, null=True, editable=False), + preserve_default=True, + ), + migrations.AlterField( + model_name='obrazek', + name='obrazek_velky', + field=models.ImageField(help_text=b'Lze vlo\xc5\xbeit libovoln\xc4\x9b velk\xc3\xbd obr\xc3\xa1zek. Ide\xc3\xa1ln\xc3\xad je, aby alespo\xc5\x88 jeden rozm\xc4\x9br m\xc4\x9bl alespo\xc5\x88 500px.', upload_to=galerie.models.obrazek_filename), + preserve_default=True, + ), + ] diff --git a/galerie/migrations/__init__.py b/galerie/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/galerie/models.py b/galerie/models.py new file mode 100644 index 00000000..e2da333b --- /dev/null +++ b/galerie/models.py @@ -0,0 +1,179 @@ +# coding: utf-8 + +from django.db import models +import seminar.models +from django.db.models import Q +from django.utils import timezone +from django.utils.encoding import force_unicode + +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 + +VZDY=0 +ORG=1 +NIKDY=2 +VIDITELNOST = ( + (VZDY, 'Vždy'), + (ORG, 'Organizátorům'), + (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 + ] + + +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)) + +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) + 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') + poradi = models.IntegerField('Pořadí', blank = True, null = True) + def __unicode__(self): + return self.nazev + " -- " + unicode(self.obrazek_velky.name) + " (" + str(self.datum) + ")" + class Meta: + verbose_name = 'Obrázek' + verbose_name_plural = 'Obrázky' + 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, 500, self.obrazek_stredni) + if not self.obrazek_maly: + Obrazek._vyrobMiniaturu(original, jmeno, 200, self.obrazek_maly) + super(Obrazek, self).save() + + @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) + + @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): + 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 +# + #@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/static/galerie/.gitignore b/galerie/static/galerie/.gitignore new file mode 100644 index 00000000..386e17f3 --- /dev/null +++ b/galerie/static/galerie/.gitignore @@ -0,0 +1,2 @@ +images +lightbox diff --git a/galerie/static/galerie/prvky/dalsi.png b/galerie/static/galerie/prvky/dalsi.png new file mode 100644 index 00000000..37064569 Binary files /dev/null and b/galerie/static/galerie/prvky/dalsi.png differ diff --git a/galerie/static/galerie/prvky/predchozi.png b/galerie/static/galerie/prvky/predchozi.png new file mode 100644 index 00000000..7a091bd6 Binary files /dev/null and b/galerie/static/galerie/prvky/predchozi.png differ diff --git a/galerie/templates/galerie/Base.html b/galerie/templates/galerie/Base.html new file mode 100644 index 00000000..61f96eb4 --- /dev/null +++ b/galerie/templates/galerie/Base.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} + +{# TODO predelat pres context processor #} +{% block header %}soustredeni{% endblock %} +{% block menu_soustredeni %}selected{% endblock %} +{% block submenu %}{% include 'seminar/soustredeni/submenu.html' %}{% endblock %} diff --git a/galerie/templates/galerie/Galerie.html b/galerie/templates/galerie/Galerie.html new file mode 100644 index 00000000..c37f5a62 --- /dev/null +++ b/galerie/templates/galerie/Galerie.html @@ -0,0 +1,65 @@ +{% extends "galerie/Base.html" %} + +{% block title %}{% block nadpis1a %} +{{galerie.nazev}} | Galerie +{% endblock %}{% endblock %} + +{% block content %} +

{{galerie.nazev}}

+ + + {# TODO šipky na přecházeni dodelat ve stylech #} +
+ {% if obrazky_predchozi %} + {% with obrazky_predchozi|last as predchozi_obrazek %} +
+ +
+ {% endwith %} + {% endif%} + {{obrazek.popis}} + {% if obrazky_dalsi %} + {% with obrazky_dalsi|first as dalsi_obrazek %} +
+ +
+ {% endwith %} + {% endif%} +
+ + {# Popisek fotky #} +
+ {% if preview %} +
+ {% csrf_token %} + + + {{form.as_table}} + +
{{obrazek.popis}}
+
+ {% else %} + {% if obrazek.popis %} + {{obrazek.popis}} + {% endif %} + {% endif %} +
+ +
+ {% for obrazek in obrazky_predchozi %} + + {% endfor %} + {{obrazek.popis}} + {% for obrazek in obrazky_dalsi %} + + {% endfor %} +
+{% endblock %} diff --git a/galerie/templates/galerie/GalerieNahled.html b/galerie/templates/galerie/GalerieNahled.html new file mode 100644 index 00000000..a2dce6fc --- /dev/null +++ b/galerie/templates/galerie/GalerieNahled.html @@ -0,0 +1,77 @@ +{% extends "galerie/Base.html" %} + +{% block title %}{% block nadpis1a %} +{{galerie.nazev}} | Galerie TODO title +{% endblock %}{% endblock %} + +{% block content %} +

{{galerie.nazev}}

+ + {# podgalerie #} + {% if podgalerie or galerie.galerie_up %} +

PODGALERIE

+ + {% endif %} + {% if user.is_staff and galerie.zobrazit > 0 %} + + {% endif %} + + {# obrazky v galerii #} + {% if obrazky %} + + {% for obrazek in obrazky %} + {% if forloop.counter|add:-1|divisibleby:3 %} + + {% endif %} + + {% if forloop.last %} + {% if not forloop.counter|divisibleby:3 %} + + {% endif %} + {% if not forloop.counter|divisibleby:2 %} + + {% endif %} + {% endif %} + {% if forloop.counter|divisibleby:3 or forloop.last %} + + {% endif %} + {% endfor %} +
+ + + + +
+ {% else %} +
+ V galerii nejsou žádné fotky. +
+ {% endif %} +{% endblock content %} diff --git a/galerie/templates/galerie/GalerieNew.html b/galerie/templates/galerie/GalerieNew.html new file mode 100644 index 00000000..38237d86 --- /dev/null +++ b/galerie/templates/galerie/GalerieNew.html @@ -0,0 +1,22 @@ +{% extends "galerie/Base.html" %} + +{% block title %}{% block nadpis1a %} +Vytvářím novou galerii +{% endblock %}{% endblock %} + +{% block content %} + +

Vytváření nové galerie

+ +

Vytvářím galerii k soustředění {{soustredeni}} jako {{galerie_text}}

+ +
+ {% csrf_token %} + {{form.as_table}} + + + +
 
+
+ +{% endblock %} diff --git a/galerie/urls.py b/galerie/urls.py new file mode 100644 index 00000000..b2980b52 --- /dev/null +++ b/galerie/urls.py @@ -0,0 +1,12 @@ +# coding: utf-8 + +from django.conf.urls import patterns, include, url + +urlpatterns = patterns('', + (r'^(?P\d+)/$', 'galerie.views.nahled'), + (r'^(?P\d+)/(?P\d+)/$', 'galerie.views.detail'), + (r'^(?P\d+)/new/$', 'galerie.views.new_galerie'), + (r'^(?P\d+)/plus/(?P\d+)/$', 'galerie.views.plus_galerie'), + (r'^(?P\d+)/minus/(?P\d+)/$', 'galerie.views.minus_galerie'), +) + diff --git a/galerie/views.py b/galerie/views.py new file mode 100644 index 00000000..f33c2ff6 --- /dev/null +++ b/galerie/views.py @@ -0,0 +1,169 @@ +# coding: utf-8 + +import random + +from django.http import HttpResponse, Http404 +from django.shortcuts import render, HttpResponseRedirect, get_object_or_404 +from django.template import RequestContext +from datetime import datetime + +from galerie.models import Obrazek, Galerie +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 + +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') + obrazky = Obrazek.objects.filter(galerie = galerie).order_by('datum') + preview = zobrazit(galerie, request) + return render(request, 'galerie/GalerieNahled.html', + {'galerie' : galerie, + 'podgalerie' : podgalerie, + 'obrazky' : obrazky, + 'preview' : preview, + }) + +def detail(request, pk, fotka, soustredeni): + """Zobrazeni nahledu fotky s id 'fotka'.""" + MAX_VYSKA = 600 + MAX_SIRKA = 600 + 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().order_by('datum') + + # 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. + obrazky_dalsi = obrazky[znacka+1:znacka+NAHLEDU+1] + if znacka > NAHLEDU: + obrazky_predchozi = obrazky[znacka-NAHLEDU:znacka] + else: + obrazky_predchozi = obrazky[0:znacka] + + # 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, + 'obrazek' : obrazek, + 'vyska' : vyska, + 'sirka' : sirka, + 'obrazky_predchozi' : obrazky_predchozi, + 'obrazky_dalsi' : obrazky_dalsi, + 'preview' : preview, + 'form' : form, + }) + + +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'] + 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('../../') + +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('../../') + diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index 71f16b9f..5833d80b 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -113,6 +113,7 @@ INSTALLED_APPS = ( # MaMweb 'mamweb', 'seminar', + 'galerie', # Admin upravy: diff --git a/mamweb/static/css/mamweb.css b/mamweb/static/css/mamweb.css index 2d0a283f..b7431e15 100644 --- a/mamweb/static/css/mamweb.css +++ b/mamweb/static/css/mamweb.css @@ -299,6 +299,21 @@ div.zadani_azad_termin { padding: 20px 0px 20px 0px; float: none; } + + div.novinky{ + max-width: 100%; + margin-left: auto; + margin-right: auto; + float: none; + } + + div.graf{ + float: none; + margin-left: auto; + margin-right: auto; + width: 70%; + } + } @media (max-width: 767px) { @@ -407,4 +422,83 @@ div.zadani_azad_termin { padding: 30px 0px 20px 0px; float: none; } + + div.novinky{ + max-width: 100%; + float: none; + } + + div.graf{ + float: none; + width: 70%; + margin-left: auto; + margin-right: auto + + } +} + + +/* galerie */ + +.predchozi_obrazek{ + position: absolute; + z-index: 1; + width: 33%; + height: 100%; + left: 0; + top: 0; +} +.predchozi_obrazek:hover{ + background-image: url("/static/galerie/prvky/predchozi.png"); + background-position: left center; + background-repeat: no-repeat; +} +.dalsi_obrazek{ + position: absolute; + z-index: 1; + width: 33%; + height: 100%; + left: 67%; + top: 0; +} +.dalsi_obrazek:hover{ + background-image: url("/static/galerie/prvky/dalsi.png"); + background-position: right center; + background-repeat: no-repeat; +} + +.galerie{ + position: relative; +} + +.galerie_nahledy{ + margin: 1em 0; + text-align: center; +} +.galerie_index{ + width: 100%; +} +.galerie_index td{ + width: 50%; +} +.galerie_nahled{ + width: 100%; +} +.galerie_nahled td{ + width: 33%; +} + +/* titulni stranka */ + +.zjistit_vic{ + text-align: center; +} + +.graf{ + float: left; +} + +.novinky{ + float: right; + max-width: 42%; } diff --git a/requirements.txt b/requirements.txt index b75f4810..ea1261ee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ traitlets==4.0.0 # Django and modules -Django==1.7.10 # Updatable to 1.8 (possibly incompatible) +Django==1.7.10 # Updatable to 1.9 (possibly incompatible) django-bootstrap-sass==0.0.6a0 django-mptt==0.7.3 django-reversion==1.9.3 diff --git a/seminar/admin.py b/seminar/admin.py index 28698611..299e6c75 100644 --- a/seminar/admin.py +++ b/seminar/admin.py @@ -319,7 +319,7 @@ class ProblemAdmin(reversion.VersionAdmin): return obj.pocet_reseni class ProblemNavrhAdmin(ProblemAdmin): - list_display = ['nazev', 'typ', 'zamereni', 'stav', 'autor', 'timestamp'] + list_display = ['nazev', 'typ', 'stav', 'autor', 'timestamp'] list_filter = ['typ', 'zamereni', 'timestamp', 'stav'] def get_queryset(self, request): diff --git a/seminar/models.py b/seminar/models.py index cc06cf36..ae59659d 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -795,10 +795,17 @@ class Organizator(models.Model): 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) diff --git a/seminar/templates/seminar/soustredeni/seznam_soustredeni.html b/seminar/templates/seminar/soustredeni/seznam_soustredeni.html index bd10f8fe..74bbee3b 100644 --- a/seminar/templates/seminar/soustredeni/seznam_soustredeni.html +++ b/seminar/templates/seminar/soustredeni/seznam_soustredeni.html @@ -17,8 +17,6 @@ Na galeriích ze soustředění a dalších informacích ještě pracujeme.

-{#% if user.is_authenticated %#}{# PRACUJE SE STRANKA #} - {# Projdi vsechna soustredeni #} {% for soustredeni in object_list %} @@ -40,12 +38,30 @@
  • {{soustredeni.datum_zacatku}} – {{soustredeni.datum_konce}}
  • + {# Zobrazeni odkazu na galerie #} + {% if soustredeni.galerie_set.all %} + {% for galerie in soustredeni.galerie_set.all %} + {% if galerie.zobrazit == 0 or user.is_staff %} +
  • + FOTOGALERIE: {{galerie}} + {# TODO kdyz je titulni obrazek, tak asi i titulni obrazek #} +
  • + {% endif %} + {% endfor %} + {% endif %} + {% if user.is_staff %} +
  • + VYTVOŘIT NOVOU FOTOGALERII +
  • + {% endif %} + - {% if user.is_authenticated %} + {# 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:

      @@ -61,7 +77,5 @@ Žádná soustředění zatím neproběhla! {% endfor %} -{#% else %}{% include 'seminar/pracuje_se.html' %}{% endif %#} - {% endblock %} diff --git a/seminar/templates/seminar/titulnistrana.html b/seminar/templates/seminar/titulnistrana.html index 66a29393..a28ffa15 100644 --- a/seminar/templates/seminar/titulnistrana.html +++ b/seminar/templates/seminar/titulnistrana.html @@ -17,42 +17,7 @@ M&M je korespondeční seminář. Několikrát do roka zdarma vydáváme ča M&M je taky soutěž. Můžeš vyhrát knížky, deskovky nebo dokonce dort. Můžeš se dostat na matfyz bez přijímaček. A především s námi můžeš jet na skvělé soustředění.

      - - - - - -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - -
      - -
      -

      Zjistit víc!

      -

      -
      +
      {% if dead %}

      Do konce odeslání řešení zbývá:
      @@ -79,10 +44,38 @@ M&M je korespondeční seminář. Několikrát do roka zdarma vydáváme ča {% include 'seminar/novinky.html' %} Archiv novinek -

      + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Zjistit víc!

      +
      +
      diff --git a/seminar/urls.py b/seminar/urls.py index be4947c6..6beec024 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -1,3 +1,4 @@ +from django.conf.urls import * # NOQA from django.conf.urls import patterns, url from . import views, export @@ -15,7 +16,8 @@ urlpatterns = patterns('', url(r'^soustredeni/probehlo/$', views.SoustredeniListView.as_view(), name = 'seminar_seznam_soustredeni'), - url(r'^soustredeni/(?P\d+)/$', views.SoustredeniView.as_view(), name='seminar_soustredeni'), + url(r'^soustredeni/probehlo/(?P\d+)/$', views.SoustredeniView.as_view(), name='seminar_soustredeni'), + url(r'^soustredeni/(?P\d+)/fotogalerie/', include('galerie.urls')), url(r'^zadani/aktualni/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'), url(r'^zadani/temata/$', views.ZadaniTemataView, name='seminar_temata'),