Browse Source

Merge branch 'opraf' of atrey.karlin.mff.cuni.cz:/akce/MaM/MaMweb/mamweb into opraf

remotes/origin/opraf
parent
commit
80a38c26be
  1. 27
      galerie/admin.py
  2. 49
      galerie/autocomplete_light_registry.py
  3. 22
      galerie/migrations/0007_obrazek_odstranen_datum.py
  4. 94
      galerie/models.py
  5. 41
      galerie/templates/galerie/GalerieNahled.html
  6. 4
      galerie/views.py
  7. 13
      korektury/templates/korektury/help.html
  8. 10
      mamweb/settings_common.py
  9. 26
      mamweb/static/css/mamweb.css
  10. 4
      mamweb/templates/flatpages/default.html
  11. 19
      seminar/admin.py
  12. 34
      seminar/autocomplete_light_registry.py
  13. 36
      seminar/migrations/0036_add_org_to_soustredeni.py
  14. 115
      seminar/models.py
  15. 10
      seminar/templates/seminar/archiv/cislo.html
  16. 34
      seminar/templates/seminar/archiv/cislo_vysledkovka.tex
  17. 2
      seminar/templates/seminar/archiv/problem.html
  18. 10
      seminar/templates/seminar/archiv/problem_uloha_tema.html
  19. 1
      seminar/templates/seminar/cojemam/submenu.html
  20. 91
      seminar/templates/seminar/soustredeni/seznam_soustredeni.html
  21. 16
      seminar/templates/seminar/titulnistrana.html
  22. 2
      seminar/templates/seminar/zadani/AktualniVysledkovka.html
  23. 15
      seminar/templates/seminar/zadani/AktualniZadani.html
  24. 80
      seminar/views.py

27
galerie/admin.py

@ -3,6 +3,9 @@
from galerie.models import Obrazek, Galerie from galerie.models import Obrazek, Galerie
from django.contrib import admin from django.contrib import admin
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django import forms
from django.db import models
import autocomplete_light
# akction # akction
@ -27,17 +30,25 @@ def prepnout_fotogalerii_do_org_rezimu(modeladmin, request, queryset):
'Přepnout do režimu úprav (zneveřejní galerii)' 'Přepnout do režimu úprav (zneveřejní galerii)'
class GalerieInline(admin.TabularInline): 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): class ObrazekAdmin(admin.ModelAdmin):
list_display = ('obrazek_velky', 'nazev', 'popis') list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag')
class GalerieAdmin(admin.ModelAdmin): class GalerieAdmin(admin.ModelAdmin):
model = Galerie form = autocomplete_light.modelform_factory(Galerie, autocomplete_fields=['titulni_obrazek'], fields=['titulni_obrazek'])
fields = ('zobrazit', 'nazev', 'titulni_obrazek', 'popis', 'galerie_up', 'soustredeni', 'poradi') model = Galerie
list_display = ('nazev', 'pk', 'datum_zmeny', 'zobrazit', 'soustredeni') fields = ('zobrazit', 'nazev', 'titulni_obrazek', 'popis', 'galerie_up', 'soustredeni', 'poradi')
inlines = [GalerieInline] list_display = ('nazev', 'pk', 'poradi', 'datum_zmeny', 'zobrazit', 'soustredeni')
actions = [zverejnit_fotogalerii, prepnout_fotogalerii_do_org_rezimu] 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(Obrazek, ObrazekAdmin)
admin.site.register(Galerie, GalerieAdmin) admin.site.register(Galerie, GalerieAdmin)

49
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 = '''
<span class="block" data-value="{}">
<span class="block">
{}
<span class="block">{}</span>
</span>
</span>
'''
def choice_label(self, obrazek):
cesta = "/".join(g.nazev for g in cesta_od_korene(obrazek.galerie))
popis = "{}<br>".format(obrazek.popis) if obrazek.popis else ""
return '{}<br>{}{}'.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)

22
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',
),
]

94
galerie/models.py

@ -1,19 +1,12 @@
# coding: utf-8 # coding: utf-8
from django.db import models from django.db import models
import seminar.models #from django.db.models import Q
from django.db.models import Q
from django.utils import timezone
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode
from imagekit.models import ImageSpecField from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFit, Transpose from imagekit.processors import ResizeToFit, Transpose
from PIL import Image
from PIL.ExifTags import TAGS
import os import os
from cStringIO import StringIO
from django.core.files.base import ContentFile
from datetime import datetime
from seminar.models import Soustredeni from seminar.models import Soustredeni
@ -26,14 +19,6 @@ VIDITELNOST = (
(NIKDY, 'Nikdy'), (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
# tyhle funkce jsou tady jen kvůli starým migracím, které se na ně odkazují # 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 # až se ty migrace někdy squashnou, tak by mělo být možné funkce smazat
def obrazek_filename_maly(): def obrazek_filename_maly():
@ -46,40 +31,55 @@ def obrazek_filename_velky():
def obrazek_filename(self, filename): def obrazek_filename(self, filename):
gal = self.galerie gal = self.galerie
cislo_gal = force_unicode(gal.pk) cislo_gal = force_unicode(gal.pk)
cesta = ""
while(not gal.soustredeni): # najdi kořenovou galerii
while (gal.galerie_up):
gal = gal.galerie_up gal = gal.galerie_up
return os.path.join('Galerie', "soustredeni_" + force_unicode(gal.soustredeni.pk), "galerie_" + cislo_gal, "velky", 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)
class Obrazek(models.Model): class Obrazek(models.Model):
obrazek_velky = models.ImageField(upload_to=obrazek_filename, 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.") 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', obrazek_stredni = ImageSpecField(source='obrazek_velky',
processors=[Transpose(Transpose.AUTO), ResizeToFit(900, 675, upscale=False)], processors=[Transpose(Transpose.AUTO), ResizeToFit(900, 675, upscale=False)],
options={'quality': 95}) options={'quality': 95})
obrazek_maly = ImageSpecField(source='obrazek_velky', obrazek_maly = ImageSpecField(source='obrazek_velky',
processors=[Transpose(Transpose.AUTO), ResizeToFit(167, 167, upscale=False)], processors=[Transpose(Transpose.AUTO), ResizeToFit(167, 167, upscale=False)],
options={'quality': 95}) options={'quality': 95})
nazev = models.CharField('Název', max_length=50, blank = True, null = True) nazev = models.CharField('Název', max_length=50, blank=True, null=True)
popis = models.TextField('Popis', blank = True, null = True) popis = models.TextField('Popis', blank=True, null=True)
datum_vlozeni = models.DateTimeField('Datum vložení', auto_now_add = 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)
galerie = models.ForeignKey('Galerie', blank=True, null=True) poradi = models.IntegerField('Pořadí', blank=True, null=True)
poradi = models.IntegerField('Pořadí', blank = True, null = True)
def __unicode__(self): def __unicode__(self):
return self.nazev + " -- " + unicode(self.obrazek_velky.name) + " (" + str(self.datum) + ")" return unicode(self.obrazek_velky.name)
class Meta:
verbose_name = 'Obrázek' class Meta:
verbose_name_plural = 'Obrázky' verbose_name = 'Obrázek'
ordering = ['datum'] verbose_name_plural = 'Obrázky'
def save(self): ordering = ['nazev']
original = Image.open(self.obrazek_velky)
# vycteni EXIFu def obrazek_maly_tag(self):
exif = get_exif(original) return u'<img src="{}">'.format(self.obrazek_maly.url)
if exif['DateTimeOriginal']: obrazek_maly_tag.short_description = "Náhled"
datum_ints = map(int, ":".join(exif['DateTimeOriginal'].split(' ')).split(":")) obrazek_maly_tag.allow_tags = True
self.datum = datetime(*datum_ints)
super(Obrazek, self).save() 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): class Galerie(models.Model):

41
galerie/templates/galerie/GalerieNahled.html

@ -6,6 +6,10 @@ Galerie {{galerie.nazev}}
{% block content %} {% block content %}
{% if galerie.zobrazit > 0 %}
<div class="mam-org-only">
{% endif %}
<h2> <h2>
{% for g in cesta %} {% for g in cesta %}
{% if not forloop.last %} {% if not forloop.last %}
@ -19,7 +23,7 @@ Galerie {{galerie.nazev}}
{% if not obrazky %} {% if not obrazky %}
<div class="galerie_hlavicka"> <div class="galerie_hlavicka">
{% if galerie.titulni_obrazek %} {% if galerie.titulni_obrazek %}
<img src="{{ galerie.titulni_obrazek.obrazek_stredni.url }}" style="border: 1px solid black;"> <img src="{{ galerie.titulni_obrazek.obrazek_stredni.url }}" class="titulni_obrazek">
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
@ -39,18 +43,22 @@ Galerie {{galerie.nazev}}
{% endif %} {% endif %}
{% if podgalerie %} {% if podgalerie %}
{% with 22 as max_delka_nazvu %}
<div class="galerie_nahledy"> <div class="galerie_nahledy">
{% for galerie in podgalerie %} {% for galerie in podgalerie %}
<a href="../{{galerie.pk}}" class="podgalerie_nahled"> <a href="../{{galerie.pk}}"
{% if galerie.nazev|length > max_delka_nazvu %}
title="{{ galerie.nazev }}"
{% endif %}
class="podgalerie_nahled">
{% if galerie.titulni_obrazek %} {% if galerie.titulni_obrazek %}
{% with galerie.titulni_obrazek.obrazek_maly as obrazek %} {% with galerie.titulni_obrazek.obrazek_maly as obrazek %}
<img src="{{ obrazek.url }}" <img src="{{ obrazek.url }}"
width="{{ obrazek.width }}" />
height="{{ obrazek.height }}" /> {% endwith %}
{% endwith %}
{% endif %} {% endif %}
<div> <div class="nazev_galerie">
{{ galerie }} {{ galerie|truncatechars:max_delka_nazvu }}
</div> </div>
</a> </a>
{% if user.is_staff and galerie.zobrazit > 0 %} {% if user.is_staff and galerie.zobrazit > 0 %}
@ -62,6 +70,7 @@ Galerie {{galerie.nazev}}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% endwith %}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if user.is_staff and galerie.zobrazit > 0 %} {% if user.is_staff and galerie.zobrazit > 0 %}
@ -74,8 +83,15 @@ Galerie {{galerie.nazev}}
{% if obrazky %} {% if obrazky %}
<div class="galerie_nahledy"> <div class="galerie_nahledy">
{% for obrazek in obrazky %} {% for obrazek in obrazky %}
<a title="Zobrazit tuto fotografii" href="./{{obrazek.pk}}#nahoru" class="galerie_nahled"><span class="vystredeno"></span><img <a
{% if obrazek.popis %}
title="{{ obrazek.popis }}"
{% endif %}
href="./{{obrazek.pk}}#nahoru" class="galerie_nahled"><span class="vystredeno"></span><img
src="{{obrazek.obrazek_maly.url}}" src="{{obrazek.obrazek_maly.url}}"
{% if obrazek.popis %}
title="{{ obrazek.popis }}"
{% endif %}
width="{{ obrazek.obrazek_maly.width }}" width="{{ obrazek.obrazek_maly.width }}"
height="{{ obrazek.obrazek_maly.height }}" /> height="{{ obrazek.obrazek_maly.height }}" />
</a> </a>
@ -103,4 +119,9 @@ Galerie {{galerie.nazev}}
</div> </div>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if galerie.zobrazit > 0 %}
</div> {# mam-org-only #}
{% endif %}
{% endblock content %} {% endblock content %}

4
galerie/views.py

@ -38,7 +38,7 @@ def nahled(request, pk, soustredeni):
if not request.user.is_staff: if not request.user.is_staff:
podgalerie = podgalerie.filter(zobrazit__lt=1) 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) preview = zobrazit(galerie, request)
sourozenci = [] sourozenci = []
@ -82,7 +82,7 @@ def detail(request, pk, fotka, soustredeni):
galerie = get_object_or_404(Galerie, pk=pk) galerie = get_object_or_404(Galerie, pk=pk)
preview = zobrazit(galerie, request) preview = zobrazit(galerie, request)
obrazek = get_object_or_404(Obrazek, pk=fotka) 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 # vytvoreni a obslouzeni formulare
if request.method == 'POST': if request.method == 'POST':

13
korektury/templates/korektury/help.html

@ -4,7 +4,6 @@
{% block title %} Nápověda ke korigovátku {% endblock title %} {% block title %} Nápověda ke korigovátku {% endblock title %}
{% block content %} {% block content %}
<link rel="stylesheet" type="text/css" media="screen, projection" href="{% static "korektury/opraf.css"%}" />
<h1> Nápověda ke korigovátku</h1> <h1> Nápověda ke korigovátku</h1>
<p> Korigovátko slouží ke korigování PDF souborů. Umožňuje přidávat a komentovat <p> Korigovátko slouží ke korigování PDF souborů. Umožňuje přidávat a komentovat
korektury a označovat je jako zanesené / irelevantní. Rovněž umožňuje o PDF korektury a označovat je jako zanesené / irelevantní. Rovněž umožňuje o PDF
@ -32,17 +31,17 @@ původní korekturou.
<h2> Stavy </h2> <h2> Stavy </h2>
<h3> Korektura </h3> <h3> Korektura </h3>
<ul> <ul>
<li> <span class="box"> K opravě </span>- zadaná, čeká na zanesení / zahození <li> K opravě - zadaná, čeká na zanesení / zahození
<li> <span class="box-done">Zanesená</span> - zanesená v TeXu <li> Zanesená - zanesená v TeXu
<li> <span class="box-wontfix">Irelevantní</span> - není to chyba, nebude zanesena <li> Irelevantní - není to chyba, nebude zanesena
<li> K reakci - vyžaduje reakci od autora <i>(zatím není <li> K reakci - vyžaduje reakci od autora <i>(zatím není
implementováno)</i> implementováno)</i>
</ul> </ul>
<h3> PDF </h3> <h3> PDF </h3>
<ul> <ul>
<li><span class="adding"> Přidávání </span> - šedé pozadí - probíhá přidávání korektur <li> Přidávání - probíhá přidávání korektur
<li><span class="comitting"> Zanášení </span>- probíhá zanášení korektur do TeXu <li> Zanášení - probíhá zanášení korektur do TeXu
<li><span class="deprecated"> Zastaralé </span> - PDF je zastaralé, nepřidávat nové korektury <li> Zastaralé - PDF je zastaralé, nepřidávat nové korektury
</ul> </ul>
{% endblock content %} {% endblock content %}

10
mamweb/settings_common.py

@ -161,6 +161,7 @@ CKEDITOR_IMAGE_BACKEND = 'pillow'
#CKEDITOR_JQUERY_URL = '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js' #CKEDITOR_JQUERY_URL = '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'
CKEDITOR_CONFIGS = { CKEDITOR_CONFIGS = {
'default': { 'default': {
'entities': False,
'toolbar': [ 'toolbar': [
['Source', 'ShowBlocks', '-', 'Maximize'], ['Source', 'ShowBlocks', '-', 'Maximize'],
['Bold', 'Italic', 'Subscript', 'Superscript', '-', 'RemoveFormat'], ['Bold', 'Italic', 'Subscript', 'Superscript', '-', 'RemoveFormat'],
@ -241,12 +242,3 @@ LOGGING = {
SEMINAR_RESENI_DIR = os.path.join(BASE_DIR, 'media', 'reseni') SEMINAR_RESENI_DIR = os.path.join(BASE_DIR, 'media', 'reseni')
KOREKTURY_PDF_DIR = os.path.join(BASE_DIR, 'media', 'korektury','pdf') KOREKTURY_PDF_DIR = os.path.join(BASE_DIR, 'media', 'korektury','pdf')
KOREKTURY_IMG_DIR = os.path.join(BASE_DIR, 'media', 'korektury','img') KOREKTURY_IMG_DIR = os.path.join(BASE_DIR, 'media', 'korektury','img')
CKEDITOR_CONFIGS = {
'default': {
'entities': False
}
}

26
mamweb/static/css/mamweb.css

@ -18,6 +18,15 @@ body {
border: orange 2px dashed; 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 { table .border-r {
border-right: solid 1px; border-right: solid 1px;
} }
@ -446,7 +455,8 @@ div.zadani_azad_termin {
/* galerie */ /* galerie */
/* velká fotka */ /* velká fotka */
.galerie .obrazek { /* zmenšování spolu s oknem prohlížeče */
.galerie .obrazek, .titulni_obrazek {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
width: auto\9; /* ie8 */ width: auto\9; /* ie8 */
@ -482,7 +492,6 @@ div.zadani_azad_termin {
.galerie { .galerie {
position: relative; position: relative;
text-align: center; text-align: center;
/*width: 100%;*/
margin: 20px auto 0 auto; margin: 20px auto 0 auto;
} }
@ -503,6 +512,11 @@ div.zadani_azad_termin {
text-align: center; text-align: center;
} }
/* titulní obrázek hlavní galerie soustředění */
.titulni_obrazek {
border: 1px solid black;
}
.galerie_nahledy{ .galerie_nahledy{
/*margin: 1em 0;*/ /*margin: 1em 0;*/
margin: 0 auto 30px auto; margin: 0 auto 30px auto;
@ -599,6 +613,14 @@ div.zadani_azad_termin {
.podgalerie_nahled img { .podgalerie_nahled img {
margin-top: 20px; margin-top: 20px;
margin-bottom: 15px; margin-bottom: 15px;
max-height: 125px;
max-width: 167px;
}
.podgalerie_nahled .nazev_galerie {
position: absolute;
width: 100%;
top: 160px;
} }
/* plus a minus tlacitka */ /* plus a minus tlacitka */

4
mamweb/templates/flatpages/default.html

@ -22,6 +22,10 @@
{% with "jak-resit" as selected %} {% with "jak-resit" as selected %}
{% include "seminar/cojemam/submenu.html" %} {% include "seminar/cojemam/submenu.html" %}
{% endwith %} {% endwith %}
{% elif "odmeny" in flatpage.url %}
{% with "odmeny" as selected %}
{% include "seminar/cojemam/submenu.html" %}
{% endwith %}
{% elif "FAQ" in flatpage.url %} {% elif "FAQ" in flatpage.url %}
{% with "FAQ" as selected %} {% with "FAQ" as selected %}
{% include "seminar/cojemam/submenu.html" %} {% include "seminar/cojemam/submenu.html" %}

19
seminar/admin.py

@ -11,7 +11,7 @@ from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Novinky, Organizator from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Novinky, Organizator
import autocomplete_light import autocomplete_light
@ -163,6 +163,19 @@ class Soustredeni_UcastniciInline(admin.TabularInline):
qs = super(Soustredeni_UcastniciInline, self).get_queryset(request) qs = super(Soustredeni_UcastniciInline, self).get_queryset(request)
return qs.select_related('resitel', 'soustredeni') 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')
### Resitel ### Resitel
class ResitelAdmin(VersionAdmin): class ResitelAdmin(VersionAdmin):
@ -334,7 +347,7 @@ create_modeladmin(ProblemNavrhAdmin, Problem, 'ProblemNavrh', verbose_name=u'Pro
class ProblemZadanyAdmin(ProblemAdmin): class ProblemZadanyAdmin(ProblemAdmin):
list_display = ['nazev', 'typ', 'autor', 'opravovatel', 'kod', 'cislo_zadani', 'pocet_reseni', 'verejne'] 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] inlines = [ReseniKProblemuInline]
def get_queryset(self, request): def get_queryset(self, request):
@ -362,7 +375,7 @@ class SoustredeniAdmin(VersionAdmin):
(u'Data', {'fields': ['datum_zacatku', 'datum_konce']}), (u'Data', {'fields': ['datum_zacatku', 'datum_konce']}),
] ]
list_display = ['rocnik', 'misto', 'datum_zacatku', 'typ', 'exportovat', 'verejne'] list_display = ['rocnik', 'misto', 'datum_zacatku', 'typ', 'exportovat', 'verejne']
inlines = [Soustredeni_UcastniciInline] inlines = [Soustredeni_UcastniciInline, Soustredeni_OrganizatoriInline]
list_filter = ['typ', 'rocnik'] list_filter = ['typ', 'rocnik']
view_on_site = Soustredeni.verejne_url view_on_site = Soustredeni.verejne_url
actions = [ actions = [

34
seminar/autocomplete_light_registry.py

@ -2,7 +2,7 @@
import autocomplete_light import autocomplete_light
from models import Skola, Resitel, Problem from models import Skola, Resitel, Problem, Organizator
from taggit.models import Tag from taggit.models import Tag
@ -64,6 +64,38 @@ class ResitelAutocomplete(autocomplete_light.AutocompleteModelBase):
autocomplete_light.register(ResitelAutocomplete) autocomplete_light.register(ResitelAutocomplete)
class OrganizatorAutocomplete(autocomplete_light.AutocompleteModelBase):
model = Organizator
search_fields=['user__first_name', 'user__last_name', 'prezdivka']
split_words = False
limit_choices = 15
def choice_label(self, organizator):
return u"%s '%s' %s" % (organizator.user.first_name,
organizator.prezdivka,
organizator.user.last_name)
attrs={
# This will set the input placeholder attribute:
'placeholder': u'Organizátor',
# This will set the yourlabs.Autocomplete.minimumCharacters
# options, the naming conversion is handled by jQuery
'data-autocomplete-minimum-characters': 1,
}
widget_attrs={
'data-widget-maximum-values': 15,
# Enable modern-style widget !
'class': 'modern-style',
}
autocomplete_light.register(OrganizatorAutocomplete)
class ProblemAutocomplete(autocomplete_light.AutocompleteModelBase): class ProblemAutocomplete(autocomplete_light.AutocompleteModelBase):

36
seminar/migrations/0036_add_org_to_soustredeni.py

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0035_django_imagekit'),
]
operations = [
migrations.CreateModel(
name='Soustredeni_Organizatori',
fields=[
('id', models.AutoField(serialize=False, primary_key=True)),
('poznamka', models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka k \xfa\u010dasti organiz\xe1tora (plain text)', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True)),
('organizator', models.ForeignKey(verbose_name='organiz\xe1tor', to='seminar.Organizator')),
('soustredeni', models.ForeignKey(verbose_name='soust\u0159ed\u011bn\xed', to='seminar.Soustredeni')),
],
options={
'ordering': ['soustredeni', 'organizator'],
'db_table': 'seminar_soustredeni_organizatori',
'verbose_name': '\xda\u010dast organiz\xe1tor\u016f na soust\u0159ed\u011bn\xed',
'verbose_name_plural': '\xda\u010dasti organiz\xe1tor\u016f na soust\u0159ed\u011bn\xed',
},
bases=(models.Model,),
),
migrations.AddField(
model_name='soustredeni',
name='organizatori',
field=models.ManyToManyField(help_text='Seznam organiz\xe1tor\u016f soust\u0159ed\u011bn\xed', to='seminar.Organizator', verbose_name='Organiz\xe1to\u0159i soust\u0159ed\u011bn\xed', through='seminar.Soustredeni_Organizatori'),
preserve_default=True,
),
]

115
seminar/models.py

@ -185,6 +185,9 @@ class Resitel(SeminarModelBase):
def plne_jmeno(self): def plne_jmeno(self):
return force_unicode(u'%s %s' % (self.jmeno, self.prijmeni)) 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): def __str__(self):
return force_unicode(self.plne_jmeno()) return force_unicode(self.plne_jmeno())
@ -576,6 +579,51 @@ class PrilohaReseni(SeminarModelBase):
return force_unicode(self.soubor) return force_unicode(self.soubor)
@reversion.register(ignore_duplicate_revisions=True)
@python_2_unicode_compatible
class Organizator(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name='Osoba',
help_text = 'Vyber účet spřažený s organizátorem.')
prezdivka = models.CharField('Přezdívka', max_length = 32,
null = True, blank = True)
organizuje_od_roku = models.IntegerField('Organizuje od roku',
null = True, blank = True)
organizuje_do_roku = models.IntegerField('Organizuje do roku',
null = True, blank = True)
studuje = models.CharField('Studium aj.', max_length = 256,
null = True, blank = True,
help_text="Např. 'Studuje Obecnou fyziku (Bc.), 3. ročník', "
"'Vystudovala Diskrétní modely a algoritmy (Mgr.)' nebo "
"'Přednáší na MFF'")
strucny_popis_organizatora = models.TextField('Stručný popis organizátora',
null = True, blank = True)
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',
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):
if self.prezdivka:
return u"%s '%s' %s" % (self.user.first_name,
self.prezdivka,
self.user.last_name)
else:
return u"%s %s" % (self.user.first_name, self.user.last_name)
class Meta:
verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři'
@reversion.register(ignore_duplicate_revisions=True) @reversion.register(ignore_duplicate_revisions=True)
@python_2_unicode_compatible @python_2_unicode_compatible
class Soustredeni(SeminarModelBase): class Soustredeni(SeminarModelBase):
@ -605,6 +653,11 @@ class Soustredeni(SeminarModelBase):
ucastnici = models.ManyToManyField(Resitel, verbose_name=u'účastníci soustředění', ucastnici = models.ManyToManyField(Resitel, verbose_name=u'účastníci soustředění',
help_text=u'Seznam účastníků soustředění', through='Soustredeni_Ucastnici') help_text=u'Seznam účastníků soustředění', through='Soustredeni_Ucastnici')
organizatori = models.ManyToManyField(Organizator,
verbose_name=u'Organizátoři soustředění',
help_text=u'Seznam organizátorů soustředění',
through='Soustredeni_Organizatori')
text = models.TextField(u'text k soustředění (HTML)', blank=True, default='') text = models.TextField(u'text k soustředění (HTML)', blank=True, default='')
TYP_JARNI = 'jarni' TYP_JARNI = 'jarni'
@ -656,6 +709,30 @@ class Soustredeni_Ucastnici(models.Model):
return force_unicode(u'%s na %s' % (self.resitel, self.soustredeni, )) return force_unicode(u'%s na %s' % (self.resitel, self.soustredeni, ))
# NOTE: Poteciální DB HOG bez select_related # NOTE: Poteciální DB HOG bez select_related
@reversion.register(ignore_duplicate_revisions=True)
@python_2_unicode_compatible
class Soustredeni_Organizatori(models.Model):
class Meta:
db_table = 'seminar_soustredeni_organizatori'
verbose_name = u'Účast organizátorů na soustředění'
verbose_name_plural = u'Účasti organizátorů na soustředění'
ordering = ['soustredeni', 'organizator']
# Interní ID
id = models.AutoField(primary_key = True)
organizator = models.ForeignKey(Organizator, verbose_name=u'organizátor')
soustredeni = models.ForeignKey(Soustredeni, verbose_name=u'soustředění')
poznamka = models.TextField(u'neveřejná poznámka', blank=True,
help_text=u'Neveřejná poznámka k účasti organizátora (plain text)')
def __str__(self):
return force_unicode(u'%s na %s' % (self.organizator, self.soustredeni, ))
# NOTE: Poteciální DB HOG bez select_related
@python_2_unicode_compatible @python_2_unicode_compatible
class VysledkyBase(SeminarModelBase): class VysledkyBase(SeminarModelBase):
@ -775,41 +852,3 @@ class Novinky(models.Model):
verbose_name_plural = 'Novinky' verbose_name_plural = 'Novinky'
@reversion.register(ignore_duplicate_revisions=True)
@python_2_unicode_compatible
class Organizator(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name='Osoba',
help_text = 'Vyber účet spřažený s organizátorem.')
prezdivka = models.CharField('Přezdívka', max_length = 32,
null = True, blank = True)
organizuje_od_roku = models.IntegerField('Organizuje od roku',
null = True, blank = True)
organizuje_do_roku = models.IntegerField('Organizuje do roku',
null = True, blank = True)
studuje = models.CharField('Studium aj.', max_length = 256,
null = True, blank = True,
help_text="Např. 'Studuje Obecnou fyziku (Bc.), 3. ročník', "
"'Vystudovala Diskrétní modely a algoritmy (Mgr.)' nebo "
"'Přednáší na MFF'")
strucny_popis_organizatora = models.TextField('Stručný popis organizátora',
null = True, blank = True)
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',
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)
class Meta:
verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři'

10
seminar/templates/seminar/archiv/cislo.html

@ -27,6 +27,16 @@
{% endfor %} {% endfor %}
</ul> </ul>
{% if user.is_staff %}
<div class="mam-org-only">
<h3> Orgovské odkazy </h3>
<ul>
<li><a href="obalky.pdf">Obálky (PDF)</a></li>
<li><a href="tituly.tex">Tituly (TeX)</a></li>
</ul>
</div>
{% endif %}
{% if cislo.verejna_vysledkovka %} {% if cislo.verejna_vysledkovka %}
<h3>Výsledkovka</h3> <h3>Výsledkovka</h3>
{% else %} {% else %}

34
seminar/templates/seminar/archiv/cislo_vysledkovka.tex

@ -1,33 +1,9 @@
\begin{longtable}{r|l|c|l|c \setlength{\tabcolsep}{3pt}
{% for p in problemy %} \begin{longtable}{|r|l|c|r|{% for p in problemy %}c@{\hskip.5em}{% endfor %}|r|r|}\hline
@\hskip.5em}c {% endfor %} & & & & \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
|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
\endhead \endhead
\hline \hline
\endfoot \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}}\\
{% 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 }} \\
{% endfor %} {% endfor %}
\end{longtable} \end{longtable}

2
seminar/templates/seminar/archiv/problem.html

@ -3,7 +3,7 @@
{% load comments %} {% load comments %}
{% block content %} {% block content %}
<div> <div {% if not problem.verejne and user.is_staff %}class="mam-org-only"{% endif %}>
{% block problem %} {% block problem %}
{% endblock %} {% endblock %}

10
seminar/templates/seminar/archiv/problem_uloha_tema.html

@ -8,14 +8,10 @@
</h2> </h2>
{% if problem.cislo_zadani %} {% if problem.cislo_zadani %}
<p>Zadáno v čísle <a href='{{ problem.cislo_zadani.verejne_url }}'>{{ problem.cislo_zadani.kod }}</a>. <p>Zadáno v čísle <a href='{{ problem.cislo_zadani.verejne_url }}'>{{ problem.cislo_zadani.kod }}</a>.
{% if problem.cislo_reseni %}
<p>Řešeno v čísle <a href='{{ problem.cislo_reseni.verejne_url }}'>{{ problem.cislo_reseni.kod }}</a>.
{% endif %}
{% else %}
{# TODO ? #}
<h2>Problém {{ problem.nazev }}</h2>
{% endif %} {% endif %}
{% if problem.cislo_reseni %}
<p>Řešeno v čísle <a href='{{ problem.cislo_reseni.verejne_url }}'>{{ problem.cislo_reseni.kod }}</a>.
{% endif %}
<h3>Zadání</h3> <h3>Zadání</h3>
{{ problem.text_zadani |safe }} {{ problem.text_zadani |safe }}

1
seminar/templates/seminar/cojemam/submenu.html

@ -4,6 +4,7 @@
<ul> <ul>
<li class="{% if selected == "uvod" %}selected{% endif %}"><a href="{{cesta}}/uvod/">Úvod</a> <li class="{% if selected == "uvod" %}selected{% endif %}"><a href="{{cesta}}/uvod/">Úvod</a>
<li class="{% if selected == "jak-resit" %}selected{% endif %}"><a href="{{cesta}}/jak-resit/">Jak řešit</a> <li class="{% if selected == "jak-resit" %}selected{% endif %}"><a href="{{cesta}}/jak-resit/">Jak řešit</a>
<li class="{% if selected == "odmeny" %}selected{% endif %}"><a href="{{cesta}}/odmeny/">Odměny</a>
<li class="{% if selected == "org" %}selected{% endif %}"><a href="{{cesta}}/organizatori/">Organizátoři</a> <li class="{% if selected == "org" %}selected{% endif %}"><a href="{{cesta}}/organizatori/">Organizátoři</a>
<li class="{% if selected == "FAQ" %}selected{% endif %}"><a href="{{cesta}}/FAQ/">Často kladené dotazy</a> <li class="{% if selected == "FAQ" %}selected{% endif %}"><a href="{{cesta}}/FAQ/">Často kladené dotazy</a>
</ul> </ul>

91
seminar/templates/seminar/soustredeni/seznam_soustredeni.html

@ -21,61 +21,72 @@
{# Projdi vsechna soustredeni #} {# Projdi vsechna soustredeni #}
{% for soustredeni in object_list %} {% for soustredeni in object_list %}
{# Kdyz je verejne -> zobraz #} {# Kdyz je verejne -> zobraz #}
{% if soustredeni.verejne_db or user.is_authenticated %} {% if soustredeni.verejne_db or user.is_staff %}
{% if not soustredeni.verejne_db and user.is_authenticated %} {% if not soustredeni.verejne_db and user.is_staff %}
Groups of user: {{user.groups.all}} <br> <div class="mam-org-only">
<!-- TODO pri prihlasovani ucastniku dodelat prava <!--Groups of user: {{user.groups.all}} <br>-->
jen na group org ve view -->
Toto soustředění není veřejné, vidíte ho jen proto,
že jste přihlášení. <br>
{% endif %} {% endif %}
{# misto soustredeni TODO upravit#} {# misto soustredeni TODO upravit#}
<h2> <h2>
{{soustredeni.get_typ_display}} {{soustredeni.get_typ_display}}
{{soustredeni.misto}} {{soustredeni.misto}}
</h2> </h2>
<ul> <ul>
<li>
{{soustredeni.datum_zacatku}}&thinsp;&ndash;&thinsp;{{soustredeni.datum_konce}}
</li>
{# Zobrazeni odkazu na galerie #}
{% if soustredeni.galerie_set.all %}
{% for galerie in soustredeni.galerie_set.all %}
{% if galerie.zobrazit == 0 or user.is_staff %}
<li> <li>
<a href="../{{soustredeni.pk}}/fotogalerie/{{galerie.pk}}">Fotogalerie</a> {{soustredeni.datum_zacatku}}&thinsp;&ndash;&thinsp;{{soustredeni.datum_konce}}
{# TODO kdyz je titulni obrazek, tak asi i titulni obrazek #}
</li> </li>
{# Zobrazeni odkazu na galerie #}
{% if soustredeni.galerie_set.all %}
{% for galerie in soustredeni.galerie_set.all %}
{% if galerie.zobrazit == 0 or user.is_staff %}
<li {% if galerie.zobrazit > 0 and user.is_staff %}class="mam-org-only"{% endif %}>
<a href="../{{soustredeni.pk}}/fotogalerie/{{galerie.pk}}">Fotogalerie</a>
{# TODO kdyz je titulni obrazek, tak asi i titulni obrazek #}
</li>
{% endif %}
{% endfor %}
{% endif %}
</ul>
{% if user.is_staff %}
<div class="mam-org-only">
<a href="../{{soustredeni.pk}}/fotogalerie/0/new/">Vytvořit novou fotogalerii</a><br>
<a href="../{{soustredeni.pk}}/obalky.pdf">Vygenerovat obálky pro účastníky</a>
</div>
{% endif %} {% endif %}
{% endfor %}
{% endif %}
</ul>
{% if user.is_staff %}
<div class="mam-org-only">
<a href="../{{soustredeni.pk}}/fotogalerie/0/new/">Vytvořit novou fotogalerii</a><br>
<a href="../{{soustredeni.pk}}/obalky.pdf">Vygenerovat obálky pro účastníky</a>
</div>
{% endif %}
{# popis soustredeni #} {# popis soustredeni #}
{% if soustredeni.text %} {% if soustredeni.text %}
{% autoescape off %}{{soustredeni.text}}{% endautoescape %} {% autoescape off %}{{soustredeni.text}}{% endautoescape %}
{% endif %} {% endif %}
{% if user.is_authenticated %} {% if user.is_authenticated %}
<div class="mam-org-only">
{# Účastníci #} {# Účastníci #}
<h3>Soustředění se zúčastnili tito účastníci:</h3> <h3>Soustředění se zúčastnili tito účastníci:</h3>
<ul> <p>
{% for i in soustredeni.soustredeni_ucastnici_set.all %} {% for i in soustredeni.soustredeni_ucastnici_set.all %}
<li>{{i.resitel}} {{i.resitel}}{% if forloop.last %}.{% else %},{% endif %}
{% empty %} {% empty %}
<li>Nic! Nic!
{% endfor %} {% endfor %}
</ul> </p>
<h3>Soustředění se účastnili tito organizátoři:</h3>
<p>
{% for i in soustredeni.soustredeni_organizatori_set.all %}
{{i.organizator}}{% if forloop.last %}.{% else %},{% endif %}
{% empty %}
Nic!
{% endfor %}
</p>
{% endif %}
</div>
{% if not soustredeni.verejne_db and user.is_staff %}
</div> {# class="mam-org-only" #}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% empty %} {% empty %}
Žádná soustředění zatím neproběhla! Žádná soustředění zatím neproběhla!
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}

16
seminar/templates/seminar/titulnistrana.html

@ -22,23 +22,9 @@ M&amp;M je korespondeční seminář. Několikrát do roka zdarma vydáváme ča
<div class="odpocet"> <div class="odpocet">
<p><b>Do konce <a href="https://mam.mff.cuni.cz/zadani/aktualni/">odeslání řešení</a> zbývá:<br> <p><b>Do konce <a href="https://mam.mff.cuni.cz/zadani/aktualni/">odeslání řešení</a> zbývá:<br>
<big>{{ted|timesince:dead}}</big></b></p> <big>{{ted|timesince:dead}}</big></b></p>
<!--
{{cas_do_konce_dni}} dní
{% if cas_do_konce_dni < 5 %}
{{cas_do_konce_hodin}} hodin
{% if cas_do_konce_hodin < 5 %}
{{cas_do_konce_minut}} minut
{% if cas_do_konce_minut < 5 %}
{{cas_do_konce_sekund}}
{% endif %}
{% endif %}
{% endif %}
-->
</div> </div>
{% endif %} {% endif %}
{# Novinky #} {# Novinky #}
<h2>Novinky</h2> <h2>Novinky</h2>
{% include 'seminar/novinky.html' %} {% include 'seminar/novinky.html' %}

2
seminar/templates/seminar/zadani/AktualniVysledkovka.html

@ -19,7 +19,7 @@
{% if vysledkovka %} {% if vysledkovka %}
{% include "seminar/vysledkovka_rocnik.html" %} {% include "seminar/vysledkovka_rocnik.html" %}
{% else %} {% else %}
V tomto ročníku zatím žádné výsledky nejsou V tomto ročníku zatím žádné výsledky nejsou.
{% endif %} {% endif %}
{% if user.is_staff and vysledkovka_s_neverejnymi %} {% if user.is_staff and vysledkovka_s_neverejnymi %}

15
seminar/templates/seminar/zadani/AktualniZadani.html

@ -13,7 +13,11 @@
{% block content %} {% block content %}
<div> <div>
{% 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 %}<div class="mam-org-only">{% endif %}
{% if ac.zadane_problemy.all %} {% if ac.zadane_problemy.all %}
<div class="zadani_azad_termin"> <div class="zadani_azad_termin">
@ -45,6 +49,12 @@
Aktuálně nejsou zadané žádné úlohy k řešení. Aktuálně nejsou zadané žádné úlohy k řešení.
{% endfor %} {% endfor %}
{% if user.is_staff and not verejne%}</div>{% endif %}
{% else %}
<h3>Aktuálně nejsou zveřejněny žádné úlohy</h3>
{% endif %}
<h3>Témata</h3> <h3>Témata</h3>
<ul> <ul>
{% for problem in temata %} {% for problem in temata %}
@ -56,7 +66,8 @@
Aktuálně nejsou zadána žádná témata k řešení. Aktuálně nejsou zadána žádná témata k řešení.
{% endfor %} {% endfor %}
</ul> </ul>
{% endwith %}
{% endwith %}
</div> </div>
{% endblock content %} {% endblock content %}

80
seminar/views.py

@ -1,12 +1,13 @@
# coding:utf-8 # coding:utf-8
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.http import HttpResponse
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
from django.views import generic from django.views import generic
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.http import Http404 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 Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici
from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
@ -29,6 +30,7 @@ def verejna_temata(rocnik):
def AktualniZadaniView(request): def AktualniZadaniView(request):
nastaveni = get_object_or_404(Nastaveni) nastaveni = get_object_or_404(Nastaveni)
verejne = nastaveni.aktualni_cislo.verejne()
problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany') problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany')
ulohy = problemy.filter(typ = 'uloha').order_by('kod') ulohy = problemy.filter(typ = 'uloha').order_by('kod')
serialy = problemy.filter(typ = 'serial').order_by('kod') serialy = problemy.filter(typ = 'serial').order_by('kod')
@ -37,6 +39,7 @@ def AktualniZadaniView(request):
{'nastaveni': nastaveni, {'nastaveni': nastaveni,
'jednorazove_problemy': jednorazove_problemy, 'jednorazove_problemy': jednorazove_problemy,
'temata': verejna_temata(nastaveni.aktualni_rocnik), 'temata': verejna_temata(nastaveni.aktualni_rocnik),
'verejne': verejne,
}, },
) )
@ -72,16 +75,16 @@ class TitulniStranaView(generic.ListView):
context = super(TitulniStranaView, self).get_context_data(**kwargs) context = super(TitulniStranaView, self).get_context_data(**kwargs)
nastaveni = get_object_or_404(Nastaveni) nastaveni = get_object_or_404(Nastaveni)
cas_deadline = nastaveni.aktualni_cislo.datum_deadline cas_deadline = nastaveni.aktualni_cislo.datum_deadline
try: # Pokud neni zverejnene cislo nezverejnuj odpocet
rozdil_casu = datetime.combine(cas_deadline, datetime.max.time()) \ if nastaveni.aktualni_cislo.verejne():
- datetime.now() # pokus se zjistit termin odeslani a pokud neni zadany,
context['cas_do_konce_dni'] = rozdil_casu.days # nezverejnuj odpocet
context['cas_do_konce_hodin'] = rozdil_casu.seconds / 3600 try:
context['cas_do_konce_minut'] = (rozdil_casu.seconds / 60) % 60 context['dead'] = datetime.combine(cas_deadline, datetime.max.time())
context['cas_do_konce_sekund'] = rozdil_casu.seconds % 60 context['ted'] = datetime.now()
context['dead'] = datetime.combine(cas_deadline, datetime.max.time()) except:
context['ted'] = datetime.now() context['dead'] = None
except: else:
context['dead'] = None context['dead'] = None
return context return context
@ -128,8 +131,9 @@ def sloupec_s_poradim(vysledky):
poradi_l += ["{}.".format(lepsich_resitelu + 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 # je-li účastníků se stejným počtem bodů víc, pořadí (rozsah X.-Y.) je jen u prvního
else: else:
poradi_l += ["{}.&ndash;{}.".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) lepsich_resitelu += len(skupina)
#pomlcka je opravdu pomlcka v unicode!!dulezite pro vysledkovku v TeXu
return poradi_l return poradi_l
@ -231,11 +235,14 @@ class ProblemView(generic.DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(ProblemView, self).get_context_data(**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: if context['problem'].typ == Problem.TYP_RES_CLANEK:
context['reseni'] = Reseni.objects.filter(problem=context['problem']).select_related('resitel').order_by('resitel__prijmeni') context['reseni'] = Reseni.objects.filter(problem=context['problem']).select_related('resitel').order_by('resitel__prijmeni')
return context return context
class RadekVysledkovky(object): class RadekVysledkovky(object):
pass pass
@ -293,6 +300,7 @@ class CisloView(generic.DetailView):
v.poradi = poradi v.poradi = poradi
v.body_celkem_rocnik = v.body v.body_celkem_rocnik = v.body
v.body_celkem_odjakziva = VysledkyKCisluOdjakziva.objects.get(resitel=v.resitel, cislo=context['cislo']).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 # je tady '', aby se nezobrazovala 0, pokud se řešitel o řešení úlohy ani nepokusil
v.body_ulohy = [''] * len(problemy) v.body_ulohy = [''] * len(problemy)
@ -342,28 +350,42 @@ class RocnikVysledkovkaView(RocnikView):
### Generovani obalek ### Generovani obalek
class CisloObalkyStruct: class CisloObalkyStruct:
resitele = None
rocnik = None rocnik = None
problemy = None cisla = None
def cisloObalkyView(request,rocnik,cislo):
# 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() letos = CisloObalkyStruct()
loni = CisloObalkyStruct() loni = CisloObalkyStruct()
letos.rocnik = Rocnik.objects.filter(rocnik = rocnik)[0] aktualni_resitele = aktualniResitele(rocnik)
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)) letos.rocnik = Rocnik.objects.filter(rocnik = rocnik).first()
loni.problemy = Problem.objects.filter(cislo_zadani = Cislo.objects.filter(rocnik=loni.rocnik)) loni.rocnik = Rocnik.objects.filter(rocnik = int(rocnik)-1).first()
letos.resitele = Resitel.objects.filter(reseni = Reseni.objects.filter(problem=letos.problemy)).distinct() letos.cisla = Cislo.objects.filter(rocnik=letos.rocnik,cislo__lte = cislo)
loni.resitele = Resitel.objects.filter(reseni = Reseni.objects.filter(problem=loni.problemy)).distinct() loni.cisla = Cislo.objects.filter(rocnik=loni.rocnik)
loni.resitele = loni.resitele.filter(rok_maturity__gt = letos.rocnik.prvni_rok)
if int(cislo) > 3: if int(cislo) > 3:
resitele = letos.resitele problemy = Problem.objects.filter(cislo_zadani = letos.cisla)
else: else:
resitele = list(letos.resitele) + list(loni.resitele) problemy = Problem.objects.filter(Q(cislo_zadani = letos.cisla)|Q(cislo_zadani=loni.cisla))
return obalkyView(request,resitele) 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): def obalkyView(request,resitele):

Loading…
Cancel
Save