Merge branch 'opraf' of atrey.karlin.mff.cuni.cz:/akce/MaM/MaMweb/mamweb into opraf
This commit is contained in:
		
						commit
						80a38c26be
					
				
					 24 changed files with 505 additions and 252 deletions
				
			
		|  | @ -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 | ||||
| 
 | ||||
|  | @ -28,16 +31,24 @@ def prepnout_fotogalerii_do_org_rezimu(modeladmin, request, queryset): | |||
| 
 | ||||
| class GalerieInline(admin.TabularInline): | ||||
|     model = Obrazek | ||||
|     fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag'] | ||||
|     readonly_fields = ['nazev', 'obrazek_maly_tag'] | ||||
|     formfield_overrides = { | ||||
|         models.TextField: {'widget': forms.TextInput}, | ||||
|     } | ||||
| 
 | ||||
| class ObrazekAdmin(admin.ModelAdmin): | ||||
|   list_display = ('obrazek_velky', 'nazev', 'popis') | ||||
|     list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag') | ||||
|    | ||||
| class GalerieAdmin(admin.ModelAdmin): | ||||
|     form = autocomplete_light.modelform_factory(Galerie, autocomplete_fields=['titulni_obrazek'], fields=['titulni_obrazek']) | ||||
|     model = Galerie | ||||
|     fields = ('zobrazit', 'nazev', 'titulni_obrazek', 'popis', 'galerie_up', 'soustredeni', 'poradi') | ||||
|   list_display = ('nazev', 'pk', 'datum_zmeny', 'zobrazit', 'soustredeni') | ||||
|     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) | ||||
|  |  | |||
							
								
								
									
										49
									
								
								galerie/autocomplete_light_registry.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								galerie/autocomplete_light_registry.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								galerie/migrations/0007_obrazek_odstranen_datum.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -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', | ||||
|         ), | ||||
|     ] | ||||
|  | @ -1,19 +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 | ||||
| 
 | ||||
|  | @ -26,14 +19,6 @@ 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 | ||||
| 
 | ||||
| # 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(): | ||||
|  | @ -46,10 +31,19 @@ def obrazek_filename_velky(): | |||
| def obrazek_filename(self, filename): | ||||
|     gal = self.galerie | ||||
|     cislo_gal = force_unicode(gal.pk) | ||||
|     cesta = "" | ||||
|     while(not gal.soustredeni): | ||||
| 
 | ||||
|     # najdi kořenovou galerii | ||||
|     while (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): | ||||
|     obrazek_velky = models.ImageField(upload_to=obrazek_filename, | ||||
|  | @ -60,26 +54,32 @@ class Obrazek(models.Model): | |||
|     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) | ||||
|     nazev = models.CharField('Název', max_length=50, blank=True, null=True) | ||||
|     popis = models.TextField('Popis', blank=True, null=True) | ||||
|     datum_vlozeni = models.DateTimeField('Datum vložení', auto_now_add=True) | ||||
|     galerie = models.ForeignKey('Galerie', blank=True, null=True) | ||||
|   poradi = models.IntegerField('Pořadí', blank = True, null = True) | ||||
|     poradi = models.IntegerField('Pořadí', blank=True, null=True) | ||||
| 
 | ||||
|     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' | ||||
|       verbose_name_plural = 'Obrázky' | ||||
|     ordering = ['datum'] | ||||
|   def save(self): | ||||
|     original = Image.open(self.obrazek_velky) | ||||
|     # vycteni EXIFu | ||||
|     exif = get_exif(original) | ||||
|     if exif['DateTimeOriginal']: | ||||
|         datum_ints = map(int, ":".join(exif['DateTimeOriginal'].split(' ')).split(":")) | ||||
|         self.datum = datetime(*datum_ints) | ||||
|     super(Obrazek, self).save() | ||||
|       ordering = ['nazev'] | ||||
| 
 | ||||
|     def obrazek_maly_tag(self): | ||||
|       return u'<img src="{}">'.format(self.obrazek_maly.url) | ||||
|     obrazek_maly_tag.short_description = "Náhled" | ||||
|     obrazek_maly_tag.allow_tags = True | ||||
| 
 | ||||
|     def save(self, *args, **kwargs): | ||||
|         # obrázek potřebuje název, protože se z něj generuje cesta pro jeho uložení | ||||
|         # (a pak se podle něj taky řadí) | ||||
|         if self.nazev is None: | ||||
|             self.nazev = os.path.basename(self.obrazek_velky.name) | ||||
|         super(Obrazek, self).save(*args, **kwargs) | ||||
| 
 | ||||
|    | ||||
| 
 | ||||
| class Galerie(models.Model): | ||||
|  |  | |||
|  | @ -6,6 +6,10 @@ Galerie {{galerie.nazev}} | |||
| 
 | ||||
| {% block content %} | ||||
| 
 | ||||
|   {% if galerie.zobrazit > 0 %} | ||||
|     <div class="mam-org-only"> | ||||
|   {% endif %} | ||||
| 
 | ||||
|   <h2> | ||||
|     {% for g in cesta %} | ||||
|       {% if not forloop.last %} | ||||
|  | @ -19,7 +23,7 @@ Galerie {{galerie.nazev}} | |||
|   {% if not obrazky %} | ||||
|    <div class="galerie_hlavicka"> | ||||
|     {% 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 %} | ||||
|    </div> | ||||
|   {% endif %} | ||||
|  | @ -39,18 +43,22 @@ Galerie {{galerie.nazev}} | |||
|     {% endif %} | ||||
| 
 | ||||
|     {% if podgalerie %} | ||||
|       {% with 22 as max_delka_nazvu %} | ||||
|       <div class="galerie_nahledy"> | ||||
|       {% 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 %} | ||||
|               {% with galerie.titulni_obrazek.obrazek_maly as obrazek %} | ||||
|                 <img src="{{ obrazek.url }}" | ||||
|                 width="{{ obrazek.width }}" | ||||
|                 height="{{ obrazek.height }}" /> | ||||
|                 /> | ||||
|               {% endwith %} | ||||
|             {% endif %} | ||||
|             <div> | ||||
|             {{ galerie }} | ||||
|             <div class="nazev_galerie"> | ||||
|             {{ galerie|truncatechars:max_delka_nazvu }} | ||||
|             </div> | ||||
|         </a> | ||||
|         {% if user.is_staff and galerie.zobrazit > 0 %} | ||||
|  | @ -62,6 +70,7 @@ Galerie {{galerie.nazev}} | |||
|         {% endif %} | ||||
|       {% endfor %} | ||||
|       </div> | ||||
|       {% endwith %} | ||||
|     {% endif %} | ||||
|   {% endif %} | ||||
|   {% if user.is_staff and galerie.zobrazit > 0 %} | ||||
|  | @ -74,8 +83,15 @@ Galerie {{galerie.nazev}} | |||
|   {% if obrazky %} | ||||
|   <div class="galerie_nahledy"> | ||||
|     {% 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}}" | ||||
|             {% if obrazek.popis %} | ||||
|               title="{{ obrazek.popis }}" | ||||
|             {% endif %} | ||||
|             width="{{ obrazek.obrazek_maly.width }}" | ||||
|             height="{{ obrazek.obrazek_maly.height }}" /> | ||||
|         </a> | ||||
|  | @ -103,4 +119,9 @@ Galerie {{galerie.nazev}} | |||
|       </div> | ||||
|     {% endif %} | ||||
|   {% endif %} | ||||
| 
 | ||||
|   {% if galerie.zobrazit > 0 %} | ||||
|     </div> {# mam-org-only #} | ||||
|   {% endif %} | ||||
| 
 | ||||
| {% endblock content %} | ||||
|  |  | |||
|  | @ -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': | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| {% block title %} Nápověda ke korigovátku {% endblock title %} | ||||
| 
 | ||||
| {% block content %} | ||||
|  <link rel="stylesheet" type="text/css" media="screen, projection" href="{% static "korektury/opraf.css"%}" /> | ||||
| <h1> Nápověda ke korigovátku</h1> | ||||
| <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 | ||||
|  | @ -32,17 +31,17 @@ původní korekturou. | |||
| <h2> Stavy </h2> | ||||
| <h3> Korektura </h3> | ||||
| <ul> | ||||
| 	<li> <span class="box"> K opravě </span>- zadaná, čeká na zanesení / zahození | ||||
| 	<li> <span class="box-done">Zanesená</span> - zanesená v TeXu | ||||
| 	<li> <span class="box-wontfix">Irelevantní</span> - není to chyba, nebude zanesena | ||||
| 	<li> K opravě - zadaná, čeká na zanesení / zahození | ||||
| 	<li> Zanesená - zanesená v TeXu | ||||
| 	<li> Irelevantní - není to chyba, nebude zanesena | ||||
| 	<li> K reakci - vyžaduje reakci od autora <i>(zatím není | ||||
| 	implementováno)</i> | ||||
| </ul> | ||||
| <h3> PDF </h3> | ||||
| <ul> | ||||
| 	<li><span class="adding"> Přidávání </span> - šedé pozadí - probíhá přidávání korektur | ||||
| 	<li><span class="comitting"> Zanášení </span>- probíhá zanášení korektur do TeXu | ||||
| 	<li><span class="deprecated"> Zastaralé </span> - PDF je zastaralé, nepřidávat nové korektury | ||||
| 	<li> Přidávání - probíhá přidávání korektur | ||||
| 	<li> Zanášení - probíhá zanášení korektur do TeXu | ||||
| 	<li> Zastaralé - PDF je zastaralé, nepřidávat nové korektury | ||||
| </ul> | ||||
| 
 | ||||
| {% endblock content %} | ||||
|  |  | |||
|  | @ -161,6 +161,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'], | ||||
|  | @ -241,12 +242,3 @@ LOGGING = { | |||
| SEMINAR_RESENI_DIR = os.path.join(BASE_DIR, 'media', 'reseni') | ||||
| KOREKTURY_PDF_DIR = os.path.join(BASE_DIR, 'media', 'korektury','pdf') | ||||
| KOREKTURY_IMG_DIR = os.path.join(BASE_DIR, 'media', 'korektury','img') | ||||
| 
 | ||||
| 
 | ||||
| CKEDITOR_CONFIGS = { | ||||
|     'default': { | ||||
|         'entities': False | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
|  | @ -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; | ||||
|  | @ -599,6 +613,14 @@ div.zadani_azad_termin { | |||
| .podgalerie_nahled img { | ||||
|     margin-top: 20px; | ||||
|     margin-bottom: 15px; | ||||
|     max-height: 125px; | ||||
|     max-width: 167px; | ||||
| } | ||||
| 
 | ||||
| .podgalerie_nahled .nazev_galerie { | ||||
|     position: absolute; | ||||
|     width: 100%; | ||||
|     top: 160px; | ||||
| } | ||||
| 
 | ||||
| /* plus a minus tlacitka */ | ||||
|  |  | |||
|  | @ -22,6 +22,10 @@ | |||
|       {% with "jak-resit" as selected %} | ||||
|       {% include "seminar/cojemam/submenu.html" %} | ||||
|       {% endwith %} | ||||
|     {% elif "odmeny" in flatpage.url %} | ||||
|       {% with "odmeny" as selected %} | ||||
|       {% include "seminar/cojemam/submenu.html" %} | ||||
|       {% endwith %} | ||||
|     {% elif "FAQ" in flatpage.url %} | ||||
|       {% with "FAQ" as selected %} | ||||
|       {% include "seminar/cojemam/submenu.html" %} | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ from django.db import models | |||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -163,6 +163,19 @@ class Soustredeni_UcastniciInline(admin.TabularInline): | |||
|         qs = super(Soustredeni_UcastniciInline, self).get_queryset(request) | ||||
|         return qs.select_related('resitel', 'soustredeni') | ||||
| 
 | ||||
| class Soustredeni_OrganizatoriInline(admin.TabularInline): | ||||
|     form = autocomplete_light.modelform_factory(Soustredeni_Organizatori, autocomplete_fields=['organizator'], fields=['organizator'],) | ||||
|     model = Soustredeni_Organizatori | ||||
|     fields = ['organizator', 'poznamka', ] | ||||
|     extra = 0 | ||||
|     formfield_overrides = { | ||||
|         models.TextField: {'widget': forms.TextInput}, | ||||
|     } | ||||
| 
 | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(Soustredeni_OrganizatoriInline, self).get_queryset(request) | ||||
|         return qs.select_related('organizator', 'soustredeni') | ||||
| 
 | ||||
| ### Resitel | ||||
| 
 | ||||
| class ResitelAdmin(VersionAdmin): | ||||
|  | @ -334,7 +347,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): | ||||
|  | @ -362,7 +375,7 @@ class SoustredeniAdmin(VersionAdmin): | |||
|         (u'Data',           {'fields': ['datum_zacatku', 'datum_konce']}), | ||||
|         ] | ||||
|     list_display = ['rocnik', 'misto', 'datum_zacatku', 'typ', 'exportovat', 'verejne'] | ||||
|     inlines = [Soustredeni_UcastniciInline] | ||||
|     inlines = [Soustredeni_UcastniciInline, Soustredeni_OrganizatoriInline] | ||||
|     list_filter = ['typ', 'rocnik'] | ||||
|     view_on_site = Soustredeni.verejne_url | ||||
|     actions = [ | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| import autocomplete_light | ||||
| 
 | ||||
| from models import Skola, Resitel, Problem | ||||
| from models import Skola, Resitel, Problem, Organizator | ||||
| from taggit.models import Tag | ||||
| 
 | ||||
| 
 | ||||
|  | @ -64,6 +64,38 @@ class ResitelAutocomplete(autocomplete_light.AutocompleteModelBase): | |||
| 
 | ||||
| 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): | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										36
									
								
								seminar/migrations/0036_add_org_to_soustredeni.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								seminar/migrations/0036_add_org_to_soustredeni.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -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, | ||||
|         ), | ||||
|     ] | ||||
|  | @ -185,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()) | ||||
| 
 | ||||
|  | @ -576,6 +579,51 @@ class PrilohaReseni(SeminarModelBase): | |||
|         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) | ||||
| @python_2_unicode_compatible | ||||
| class Soustredeni(SeminarModelBase): | ||||
|  | @ -605,6 +653,11 @@ class Soustredeni(SeminarModelBase): | |||
|     ucastnici = models.ManyToManyField(Resitel, verbose_name=u'účastníci soustředění', | ||||
|         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='') | ||||
| 
 | ||||
|     TYP_JARNI = 'jarni' | ||||
|  | @ -656,6 +709,30 @@ class Soustredeni_Ucastnici(models.Model): | |||
|         return force_unicode(u'%s na %s' % (self.resitel, self.soustredeni, )) | ||||
|         # 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 | ||||
| class VysledkyBase(SeminarModelBase): | ||||
|  | @ -775,41 +852,3 @@ class Novinky(models.Model): | |||
|         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' | ||||
|  |  | |||
|  | @ -27,6 +27,16 @@ | |||
|   {% endfor %} | ||||
|   </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 %} | ||||
|   <h3>Výsledkovka</h3> | ||||
|   {% else %} | ||||
|  |  | |||
|  | @ -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 }} \\ | ||||
| {% 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} | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| {% load comments %} | ||||
| 
 | ||||
| {% block content %} | ||||
| <div> | ||||
| <div {% if not problem.verejne and user.is_staff %}class="mam-org-only"{% endif %}> | ||||
|   {% block problem %} | ||||
|   {% endblock %} | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,14 +8,10 @@ | |||
|     </h2> | ||||
|   {% if problem.cislo_zadani %} | ||||
|     <p>Zadáno v čísle <a href='{{ problem.cislo_zadani.verejne_url }}'>{{ problem.cislo_zadani.kod }}</a>. | ||||
|   {% endif %} | ||||
|   {% 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 %} | ||||
| 
 | ||||
| 
 | ||||
|   <h3>Zadání</h3> | ||||
|   {{ problem.text_zadani |safe }} | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| <ul> | ||||
|   <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 == "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 == "FAQ" %}selected{% endif %}"><a href="{{cesta}}/FAQ/">Často kladené dotazy</a> | ||||
| </ul> | ||||
|  |  | |||
|  | @ -21,13 +21,10 @@ | |||
|   {# 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}} <br> | ||||
|         <!-- TODO pri prihlasovani ucastniku dodelat prava | ||||
|         jen na group org ve view --> | ||||
|         Toto soustředění není veřejné, vidíte ho jen proto, | ||||
|         že jste přihlášení. <br> | ||||
|     {% if soustredeni.verejne_db or user.is_staff %} | ||||
|       {% if not soustredeni.verejne_db and user.is_staff %} | ||||
|         <div class="mam-org-only"> | ||||
|         <!--Groups of user: {{user.groups.all}} <br>--> | ||||
|       {% endif %} | ||||
|       {# misto soustredeni TODO upravit#} | ||||
|       <h2> | ||||
|  | @ -42,7 +39,7 @@ | |||
|         {% if soustredeni.galerie_set.all %} | ||||
|           {% for galerie in soustredeni.galerie_set.all %} | ||||
|             {% if galerie.zobrazit == 0 or user.is_staff %} | ||||
|         <li> | ||||
|               <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> | ||||
|  | @ -63,15 +60,29 @@ | |||
|         {% autoescape off %}{{soustredeni.text}}{% endautoescape %} | ||||
|       {% endif %} | ||||
|       {% if user.is_authenticated %} | ||||
|       <div class="mam-org-only"> | ||||
|         {# Účastníci #} | ||||
|         <h3>Soustředění se zúčastnili tito účastníci:</h3> | ||||
|         <ul> | ||||
|         <p> | ||||
|         {% for i in soustredeni.soustredeni_ucastnici_set.all %} | ||||
|           <li>{{i.resitel}} | ||||
|           {{i.resitel}}{% if forloop.last %}.{% else %},{% endif %} | ||||
|         {% empty %} | ||||
|           <li>Nic! | ||||
|           Nic! | ||||
|         {% 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 %} | ||||
|     {% empty %} | ||||
|  |  | |||
|  | @ -22,23 +22,9 @@ M&M je korespondeční seminář. Několikrát do roka zdarma vydáváme ča | |||
|   <div class="odpocet"> | ||||
|     <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> | ||||
| 
 | ||||
|       | ||||
|     <!--  | ||||
|     {{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> | ||||
|   {% endif %} | ||||
| 
 | ||||
|   {# Novinky #} | ||||
|   <h2>Novinky</h2> | ||||
|   {% include 'seminar/novinky.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 %} | ||||
|  |  | |||
|  | @ -13,7 +13,11 @@ | |||
| {% block content %} | ||||
| <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 %} | ||||
| 	<div class="zadani_azad_termin"> | ||||
|  | @ -45,6 +49,12 @@ | |||
|       Aktuálně nejsou zadané žádné úlohy k řešení. | ||||
|     {% 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> | ||||
|       <ul> | ||||
|       {% for problem in temata %} | ||||
|  | @ -56,7 +66,8 @@ | |||
|         Aktuálně nejsou zadána žádná témata k řešení. | ||||
|       {% endfor %} | ||||
|       </ul> | ||||
|   {% endwith %} | ||||
| 
 | ||||
| {% endwith %} | ||||
| 
 | ||||
| </div> | ||||
| {% endblock content %} | ||||
|  |  | |||
|  | @ -1,12 +1,13 @@ | |||
| # coding:utf-8 | ||||
| 
 | ||||
| from django.shortcuts import get_object_or_404, render | ||||
| from django.http import HttpResponseRedirect | ||||
| from django.http import HttpResponse | ||||
| from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden | ||||
| from django.core.urlresolvers import reverse | ||||
| from django.core.exceptions import PermissionDenied | ||||
| 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, | ||||
|                 }, | ||||
|             ) | ||||
| 
 | ||||
|  | @ -72,17 +75,17 @@ class TitulniStranaView(generic.ListView): | |||
|         context = super(TitulniStranaView, self).get_context_data(**kwargs) | ||||
|         nastaveni = get_object_or_404(Nastaveni) | ||||
|         cas_deadline = nastaveni.aktualni_cislo.datum_deadline | ||||
|         # Pokud neni zverejnene cislo nezverejnuj odpocet | ||||
|         if nastaveni.aktualni_cislo.verejne(): | ||||
|           # pokus se zjistit termin odeslani a pokud neni zadany, | ||||
|           # nezverejnuj odpocet | ||||
|           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: | ||||
|               context['dead'] = None | ||||
|         else: | ||||
|             context['dead'] = None | ||||
|         return context | ||||
| 
 | ||||
| class StareNovinkyView(generic.ListView): | ||||
|  | @ -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 | ||||
| 
 | ||||
|  | @ -231,11 +235,14 @@ class ProblemView(generic.DetailView): | |||
| 
 | ||||
|     def get_context_data(self, **kwargs): | ||||
|         context = super(ProblemView, self).get_context_data(**kwargs) | ||||
|         if not context['problem'].verejne() and not self.request.user.is_staff: | ||||
|             raise PermissionDenied() | ||||
|         if context['problem'].typ == Problem.TYP_RES_CLANEK: | ||||
|             context['reseni'] = Reseni.objects.filter(problem=context['problem']).select_related('resitel').order_by('resitel__prijmeni') | ||||
|         return context | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| class RadekVysledkovky(object): | ||||
|     pass | ||||
| 
 | ||||
|  | @ -293,6 +300,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 +350,42 @@ class RocnikVysledkovkaView(RocnikView): | |||
| 
 | ||||
| ### Generovani obalek | ||||
| class CisloObalkyStruct: | ||||
|     resitele = 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() | ||||
|     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): | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue