diff --git a/galerie/admin.py b/galerie/admin.py index 1441ce09..8e9c1897 100644 --- a/galerie/admin.py +++ b/galerie/admin.py @@ -5,7 +5,7 @@ from django.contrib import admin from django.http import HttpResponseRedirect from django import forms from django.db import models -import autocomplete_light +from autocomplete_light import shortcuts as autocomplete_light # akction diff --git a/galerie/autocomplete_light_registry.py b/galerie/autocomplete_light_registry.py index 7b624d20..69dc6a5b 100644 --- a/galerie/autocomplete_light_registry.py +++ b/galerie/autocomplete_light_registry.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals -import autocomplete_light +from autocomplete_light import shortcuts as autocomplete_light from models import Obrazek, Galerie from views import cesta_od_korene diff --git a/galerie/urls.py b/galerie/urls.py index b2980b52..396ff962 100644 --- a/galerie/urls.py +++ b/galerie/urls.py @@ -1,12 +1,13 @@ # coding: utf-8 from django.conf.urls import patterns, include, url +from . import views -urlpatterns = patterns('', - (r'^(?P\d+)/$', 'galerie.views.nahled'), - (r'^(?P\d+)/(?P\d+)/$', 'galerie.views.detail'), - (r'^(?P\d+)/new/$', 'galerie.views.new_galerie'), - (r'^(?P\d+)/plus/(?P\d+)/$', 'galerie.views.plus_galerie'), - (r'^(?P\d+)/minus/(?P\d+)/$', 'galerie.views.minus_galerie'), -) +urlpatterns = [ + url(r'^(?P\d+)/$', views.nahled), + url(r'^(?P\d+)/(?P\d+)/$', views.detail), + url(r'^(?P\d+)/new/$', views.new_galerie), + url(r'^(?P\d+)/plus/(?P\d+)/$', views.plus_galerie), + url(r'^(?P\d+)/minus/(?P\d+)/$', views.minus_galerie), +] diff --git a/korektury/models.py b/korektury/models.py index f69196f6..6b598fd1 100644 --- a/korektury/models.py +++ b/korektury/models.py @@ -8,7 +8,7 @@ from django.utils.encoding import force_unicode from django.core.exceptions import ObjectDoesNotExist import subprocess -import reversion +from reversion import revisions as reversion # PrilohaReseni method def generate_filename(self, filename): diff --git a/korektury/urls.py b/korektury/urls.py index ab6024a4..dc9ac569 100644 --- a/korektury/urls.py +++ b/korektury/urls.py @@ -5,8 +5,8 @@ from . import views staff_member_required = user_passes_test(lambda u: u.is_staff) -urlpatterns = patterns('', +urlpatterns = [ url(r'^korektury/$', staff_member_required(views.KorekturyListView.as_view()), name='korektury-list'), url(r'^korektury/(?P\d+)/$', staff_member_required(views.KorekturyView.as_view()), name='korektury'), url(r'^korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), -) +] diff --git a/korektury/views.py b/korektury/views.py index 7302758e..e50f7458 100644 --- a/korektury/views.py +++ b/korektury/views.py @@ -31,7 +31,6 @@ class KorekturyView(generic.TemplateView): scroll = q.get('scroll') autor = q.get('au') - print "autor:" + unicode(autor) if not autor: autor = 'anonym' if not scroll: diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index d3eaabb5..81850341 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -240,5 +240,6 @@ LOGGING = { # MaM specific SEMINAR_RESENI_DIR = os.path.join(BASE_DIR, 'media', 'reseni') +SEMINAR_KONFERY_DIR = os.path.join(BASE_DIR, 'media', 'konfery') KOREKTURY_PDF_DIR = os.path.join(BASE_DIR, 'media', 'korektury','pdf') KOREKTURY_IMG_DIR = os.path.join(BASE_DIR, 'media', 'korektury','img') diff --git a/mamweb/urls.py b/mamweb/urls.py index 223bdae8..5b72ee5b 100644 --- a/mamweb/urls.py +++ b/mamweb/urls.py @@ -4,12 +4,13 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.contrib import admin from django.conf import settings from django.views.generic.base import TemplateView +from django import views -urlpatterns = patterns('', +urlpatterns = [ # Admin a nastroje url(r'^admin/', include(admin.site.urls)), # NOQA - url(r'^ckeditor/', include('ckeditor.urls')), + url(r'^ckeditor/', include('ckeditor_uploader.urls')), url(r'^autocomplete/', include('autocomplete_light.urls')), # Seminarova aplikace (ma vlastni podadresare) @@ -22,11 +23,11 @@ urlpatterns = patterns('', url(r'^comments_dj/', include('django_comments.urls')), url(r'^comments_fl/', include('fluent_comments.urls')), -) +] # This is only needed when using runserver. if settings.DEBUG: - urlpatterns = patterns('', + urlpatterns = [ url(r'^media/(?P.*)$', 'django.views.static.serve', # NOQA {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}), - ) + staticfiles_urlpatterns() + urlpatterns # NOQA + ] + staticfiles_urlpatterns() + urlpatterns # NOQA diff --git a/requirements.txt b/requirements.txt index cff14d30..c6401ada 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,47 +2,47 @@ psycopg2==2.6.1 html5lib==0.9999999 -ipython==4.0.0 -Pillow==2.9.0 -pytz==2014.10 -six==1.9.0 -pexpect==3.3 +ipython==4.0.1 +Pillow==3.1.0 +pytz==2015.7 +six==1.10.0 +pexpect==4.0.1 traitlets==4.0.0 # Django and modules -Django==1.7.10 # Updatable to 1.9 (possibly incompatible) -django-bootstrap-sass==0.0.6a0 -django-mptt==0.7.3 -django-reversion==1.9.3 -django-sekizai==0.8.1 -django-countries==3.2 -django-solo==1.1.0 -django-ckeditor==4.4.7 # Updatable to 5.0 (some incompatible changes) -django-flat-theme==0.9.3 -django-taggit==0.17 -django-autocomplete-light==2.2.6 -django-crispy-forms==1.4.0 -django-imagekit==3.2.7 +Django==1.8.8 +#django-bootstrap-sass +django-mptt==0.8.0 +django-reversion==1.10.0 +django-sekizai==0.9.0 +django-countries==3.4.1 +django-solo==1.1.1 +django-ckeditor==5.0.2 +django-flat-theme==1.1.3 +django-taggit==0.17.6 +django-autocomplete-light==2.2.10 +django-crispy-forms==1.6.0 +django-imagekit==3.3 # Comments akismet==0.2.0 -django-fluent-comments==1.0.2 -django-threadedcomments==1.0b1 -django-contrib-comments==1.6.1 +django-fluent-comments==1.1 +django-threadedcomments==1.0.1 +django-contrib-comments==1.6.2 # debug tools/extensions django-debug-toolbar==1.4 -django-extensions==1.5.6 -sqlparse==0.1.16 -Werkzeug==0.10.4 +django-extensions==1.6.1 +sqlparse==0.1.18 +Werkzeug==0.11.3 # G+, FB authorisation -# django-allauth==0.19.1 -# oauthlib==0.7.2 -# python-openid==2.2.5 -# requests==2.5.3 -# requests-oauthlib==0.4.2 +# django-allauth +# oauthlib +# python-openid +# requests +# requests-oauthlib diff --git a/seminar/admin.py b/seminar/admin.py index 8fd5aa61..e2ec58cd 100644 --- a/seminar/admin.py +++ b/seminar/admin.py @@ -12,7 +12,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, Soustredeni_Organizatori, Novinky, Organizator -import autocomplete_light +from autocomplete_light import shortcuts as autocomplete_light class UserModelChoiceField(forms.ModelChoiceField): diff --git a/seminar/autocomplete_light_registry.py b/seminar/autocomplete_light_registry.py index 76b9f6ba..13318877 100644 --- a/seminar/autocomplete_light_registry.py +++ b/seminar/autocomplete_light_registry.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -import autocomplete_light +from autocomplete_light import shortcuts as autocomplete_light from models import Skola, Resitel, Problem, Organizator from taggit.models import Tag diff --git a/seminar/models.py b/seminar/models.py index d54a5868..c5df19e9 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -16,6 +16,7 @@ from imagekit.processors import ResizeToFit, Transpose from PIL import Image import os +from functools import partial from cStringIO import StringIO from django.core.files.base import ContentFile @@ -23,7 +24,7 @@ from django_countries.fields import CountryField from solo.models import SingletonModel from taggit.managers import TaggableManager -import reversion +from reversion import revisions as reversion from seminar.utils import roman @@ -544,13 +545,13 @@ class Reseni(SeminarModelBase): # PrilohaReseni method -def generate_filename(self, filename): +def generate_filename(self, filename, directory): clean = filename.replace('/','-').replace('\0', '') datedir = timezone.now().strftime('%Y-%m') fname = "%s_%s" % ( timezone.now().strftime('%Y-%m-%d-%H:%M'), clean) - return os.path.join(settings.SEMINAR_RESENI_DIR, datedir, fname) + return os.path.join(directory, datedir, fname) @reversion.register(ignore_duplicate_revisions=True) @@ -570,7 +571,7 @@ class PrilohaReseni(SeminarModelBase): timestamp = models.DateTimeField(u'vytvořeno', default=timezone.now, blank=True, editable=False) - soubor = models.FileField(u'soubor', upload_to = generate_filename) + soubor = models.FileField(u'soubor', upload_to = partial(generate_filename,directory=settings.SEMINAR_RESENI_DIR)) poznamka = models.TextField(u'neveřejná poznámka', blank=True, help_text=u'Neveřejná poznámka k příloze řešení (plain text), např. o původu') @@ -734,6 +735,72 @@ class Soustredeni_Organizatori(models.Model): # NOTE: Poteciální DB HOG bez select_related + +@reversion.register(ignore_duplicate_revisions=True) +@python_2_unicode_compatible +class Konfera(models.Model): + class Meta: + db_table = 'seminar_konfera' + verbose_name = u'Konfera' + verbose_name_plural = u'Konfery' + # Interní ID + id = models.AutoField(primary_key = True) + nazev = models.CharField(u'název konfery', max_length=40, help_text = u'Název konfery') + popis = models.TextField(u'popis konfery', blank=True, + help_text=u'Popis konfery k zobrazení na webu') + abstrakt = models.TextField(u'abstrakt', blank=True, + help_text=u'Abstrakt konfery tak, jak byl uveden ve sborníku') + organizator = models.ForeignKey(Organizator, verbose_name=u'organizátor', related_name='konfery', + on_delete = models.SET_NULL, null=True) + ucastnici = models.ManyToManyField(Resitel, verbose_name=u'účastníci konfery', + help_text=u'Seznam účastníků konfery', through='Konfery_Ucastnici') + soustredeni = models.ForeignKey(Soustredeni, verbose_name=u'soustředění', related_name='konfery', + on_delete = models.SET_NULL, null=True) + org_poznamka = models.TextField(u'neveřejná poznámka', blank=True, + help_text=u'Neveřejná poznámka ke konfeře(plain text)') + #prispevek #TODO + TYP_VELETRH = 'veletrh' + TYP_PREZENTACE = 'prezentace' + TYP_CHOICES = [ + (TYP_VELETRH, u'Veletrh (postery)'), + (TYP_PREZENTACE, u'Prezentace (přednáška)'), + ] + typ_prezentace = models.CharField(u'typ prezentace', max_length=16, choices=TYP_CHOICES, blank=False, default=TYP_VELETRH) + prezentace = models.FileField(u'prezentace',help_text = u'Prezentace nebo fotka posteru', + upload_to = partial(generate_filename,directory=settings.SEMINAR_KONFERY_DIR)) + materialy = models.FileField(u'materialy',help_text = u'Další materiály ke konfeře zabalené do jednoho souboru', + upload_to = partial(generate_filename,directory=settings.SEMINAR_KONFERY_DIR)) + + def __str__(self): + return force_unicode(u"%s: (%s)" % (self.nazev, self.soustredeni)) + + + +@reversion.register(ignore_duplicate_revisions=True) +@python_2_unicode_compatible +class Konfery_Ucastnici(models.Model): + + class Meta: + db_table = 'seminar_konfery_ucastnici' + verbose_name = u'Účast na konfeře' + verbose_name_plural = u'Účasti na konfeře' + ordering = ['konfera', 'resitel'] + + # Interní ID + id = models.AutoField(primary_key = True) + + resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel') + + konfera = models.ForeignKey(Konfera, verbose_name=u'konfera') + + poznamka = models.TextField(u'neveřejná poznámka', blank=True, + help_text=u'Neveřejná poznámka k účasti (plain text)') + + def __str__(self): + return force_unicode(u'%s na %s' % (self.resitel, self.konfera, )) + # NOTE: Poteciální DB HOG bez select_related + + @python_2_unicode_compatible class VysledkyBase(SeminarModelBase): diff --git a/seminar/templates/seminar/archiv/cislo.html b/seminar/templates/seminar/archiv/cislo.html index a398a6cb..56d75675 100644 --- a/seminar/templates/seminar/archiv/cislo.html +++ b/seminar/templates/seminar/archiv/cislo.html @@ -33,6 +33,7 @@ {% endif %} diff --git a/seminar/templates/seminar/archiv/resitel_uloha.html b/seminar/templates/seminar/archiv/resitel_uloha.html new file mode 100644 index 00000000..f61ee704 --- /dev/null +++ b/seminar/templates/seminar/archiv/resitel_uloha.html @@ -0,0 +1,22 @@ + +{% extends "seminar/archiv/base.html" %} + +{% block content %} +

K obálkování

+ + +{% for u in ulohy %} + + {% for cell in row%} + + {% endfor %} + +{% endfor %} +
+ Jméno{{u.nazev}} +{% endfor %} + +{% for row in kdoco %} +
{{cell}}
+{% endblock content %} + diff --git a/seminar/templates/seminar/archiv/tituly.tex b/seminar/templates/seminar/archiv/tituly.tex index 323cf3b5..0720e736 100644 --- a/seminar/templates/seminar/archiv/tituly.tex +++ b/seminar/templates/seminar/archiv/tituly.tex @@ -1,3 +1,8 @@ +{% if broken %} +%% POZOR! %% Dva resitele maji stejne makro!!! +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +{% endif %} + {% autoescape off %} {% load tex %} diff --git a/seminar/tools.py b/seminar/tools.py index 686ccb02..eb83332f 100644 --- a/seminar/tools.py +++ b/seminar/tools.py @@ -2,7 +2,7 @@ import logging as log from .models import Resitel -import reversion +from reversion import revisions as reversion def merge_props(r1, r2, prop, pretend=True, smaller=False, equal=True): """Merge r2.`prop` into r1.`prop`. diff --git a/seminar/urls.py b/seminar/urls.py index bf5f113e..59de212b 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -1,9 +1,12 @@ from django.conf.urls import * # NOQA from django.conf.urls import patterns, url +from django.contrib.auth.decorators import user_passes_test from . import views, export +from utils import staff_member_required -urlpatterns = patterns('', +staff_member_required = user_passes_test(lambda u: u.is_staff) +urlpatterns = [ url(r'^co-je-MaM/organizatori/$', views.CojemamOrganizatoriView.as_view(), name='organizatori'), url(r'^co-je-MaM/organizatori/organizovali/$', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'), @@ -18,7 +21,6 @@ urlpatterns = patterns('', name = 'seminar_seznam_soustredeni'), url(r'^soustredeni/probehlo/(?P\d+)/$', views.SoustredeniView.as_view(), name='seminar_soustredeni'), url(r'^soustredeni/(?P\d+)/fotogalerie/', include('galerie.urls')), - url(r'^soustredeni/(?P\d+)/obalky.pdf', views.soustredeniObalkyView,name='seminar_soustredeni_obalky'), url(r'^zadani/aktualni/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'), url(r'^zadani/temata/$', views.ZadaniTemataView, name='seminar_temata'), @@ -29,15 +31,22 @@ urlpatterns = patterns('', url(r'^clanky/resitel/$', views.ClankyResitelView.as_view(), name='clanky_resitel'), url(r'^clanky/org/$', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'), - - url(r'^stav$', views.StavDatabazeView, name='stav_databaze'), - url(r'^aesop-export/mam-rocnik-(?P\d+)\.csv$', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'), url(r'^aesop-export/mam-sous-(?P[\d-]+)\.csv$', export.ExportSousView.as_view(), name='seminar_export_sous'), url(r'^aesop-export/index.csv$', export.ExportIndexView.as_view(), name='seminar_export_index'), - url(r'^cislo/(?P\d+).(?P\d+)/vysledkovka.tex$', views.CisloVysledkovkaView.as_view(), name='seminar_cislo_vysledkovka'), - url(r'^cislo/(?P\d+).(?P\d+)/obalky.pdf$',views.cisloObalkyView, name='seminar_cislo_obalky'), - url(r'^cislo/(?P\d+).(?P\d+)/tituly.tex$', views.TitulyView, - name='seminar_cislo_titul'), -) + #### Stranky viditelne pouze pro orgy: + url(r'^cislo/(?P\d+).(?P\d+)/vysledkovka.tex$', + staff_member_required(views.CisloVysledkovkaView.as_view()), name='seminar_cislo_vysledkovka'), + url(r'^cislo/(?P\d+).(?P\d+)/obalky.pdf$', + staff_member_required(views.cisloObalkyView), name='seminar_cislo_obalky'), + + url(r'^cislo/(?P\d+).(?P\d+)/tituly.tex$', + staff_member_required(views.TitulyView), name='seminar_cislo_titul'), + url(r'^stav$', + staff_member_required(views.StavDatabazeView), name='stav_databaze'), + url(r'^cislo/(?P\d+).(?P\d+)/resitel_uloha.html$', + staff_member_required(views.resitelUlohaView),name='seminar_cislo_resitel_uloha'), + url(r'^soustredeni/(?P\d+)/obalky.pdf', + staff_member_required(views.soustredeniObalkyView),name='seminar_soustredeni_obalky'), +] diff --git a/seminar/utils.py b/seminar/utils.py index 9c9636d5..f08e1f51 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- import datetime +from django.contrib.auth.decorators import user_passes_test +staff_member_required = user_passes_test(lambda u: u.is_staff) def histogram(seznam): d = {} @@ -76,3 +78,5 @@ def seznam_problemu(): return problemy + + diff --git a/seminar/views.py b/seminar/views.py index 93945778..cdc5217a 100644 --- a/seminar/views.py +++ b/seminar/views.py @@ -3,7 +3,7 @@ from django.shortcuts import get_object_or_404, render from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden from django.core.urlresolvers import reverse -from django.core.exceptions import PermissionDenied +from django.core.exceptions import PermissionDenied, ObjectDoesNotExist from django.views import generic from django.utils.translation import ugettext as _ from django.http import Http404 @@ -356,7 +356,7 @@ class CisloObalkyStruct: # Vraci QuerySet aktualnich resitelu = nekdy neco poslali, ale jeste neodmaturovali def aktualniResitele(rocnik): - letos = Rocnik.objects.filter(rocnik = rocnik).first() + letos = Rocnik.objects.get(rocnik = rocnik) return Resitel.objects.filter(rok_maturity__gt = letos.prvni_rok) # # ALERT: pokud nekdo nema vypleny rok maturity, tak neni aktualni, protoze Karel Tesar a jini # return Resitel.objects.filter(Q(rok_maturity__gt = letos.prvni_rok)|Q(rok_maturity = None)) @@ -371,8 +371,8 @@ def aktivniResitele(rocnik,cislo): aktualni_resitele = aktualniResitele(rocnik) - letos.rocnik = Rocnik.objects.filter(rocnik = rocnik).first() - loni.rocnik = Rocnik.objects.filter(rocnik = int(rocnik)-1).first() + letos.rocnik = Rocnik.objects.get(rocnik = rocnik) + loni.rocnik = Rocnik.objects.get(rocnik = int(rocnik)-1) letos.cisla = Cislo.objects.filter(rocnik=letos.rocnik,cislo__lte = cislo) loni.cisla = Cislo.objects.filter(rocnik=loni.rocnik) if int(cislo) > 3: @@ -404,24 +404,53 @@ def obalkyView(request,resitele): shutil.rmtree(tempdir) return response +def resitelUlohaView(request,rocnik,cislo): + rocnik = Rocnik.objects.get(rocnik=rocnik) + cislo = Cislo.objects.get(rocnik=rocnik,cislo=cislo) + reseni = Reseni.objects.filter(cislo_body=cislo).order_by('resitel') + # TODO: Nasledujici 4 radky jsou fuj. Znate neco lepsiho? + resitele = list(set([r.resitel for r in reseni])) + resitele.sort(key=lambda r: (r.prijmeni,r.jmeno)) + ulohy = list(set([r.problem for r in reseni])) + ulohy.sort(key=lambda u: (u.typ,u.kod)) + + kdoco = [] + for r in resitele: + res_ulohy = [r.jmeno+" "+r.prijmeni] + for u in ulohy: + try: + rsni = reseni.get(resitel=r,problem=u) + res_ulohy.append(rsni.body) + except ObjectDoesNotExist: + res_ulohy.append("") + kdoco.append(res_ulohy) + return render(request, 'seminar/archiv/resitel_uloha.html',{'ulohy':ulohy,'kdoco':kdoco}) + ### Tituly # TODO udelat neco jako get_objects_or_404 def TitulyView(request, rocnik, cislo): - rocnik_obj = Rocnik.objects.filter(rocnik = rocnik).first() + rocnik_obj = Rocnik.objects.get(rocnik = rocnik) resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok) - cislo_obj = Cislo.objects.filter(rocnik = rocnik_obj, cislo = cislo).first() + cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, cislo = cislo) + + asciijmena = [] + broken = False for resitel in resitele: - vys = VysledkyKCisluOdjakziva.objects.filter(resitel = resitel, cislo = cislo_obj).first() - if vys == None: - body = 0 - else: + try: + vys = VysledkyKCisluOdjakziva.objects.get(resitel = resitel, cislo = cislo_obj) body = vys.body + except ObjectDoesNotExist: + body = 0 resitel.titul = resitel.get_titul(body) resitel.ascii = unicodedata.normalize('NFKD',resitel.jmeno+resitel.prijmeni).encode("ascii","ignore").replace(" ","") + if resitel.ascii not in asciijmena: + asciijmena.append(resitel.ascii) + else: + broken = True - return render(request, 'seminar/archiv/tituly.tex',{'resitele': resitele}) + return render(request, 'seminar/archiv/tituly.tex',{'resitele': resitele,'broken':broken}) ### Soustredeni