Browse Source

Merge remote-tracking branch 'origin/master' into stable

remotes/origin/temata v1.1
Bc. Petr Pecha 9 years ago
parent
commit
42993f688e
  1. 23
      Makefile
  2. 12
      mamweb/context_processors.py
  3. 84
      mamweb/middleware.py
  4. 2
      mamweb/settings_common.py
  5. 8
      mamweb/settings_prod.py
  6. 18
      mamweb/settings_test.py
  7. 20
      mamweb/static/css/mamweb.css
  8. BIN
      mamweb/static/images/header-bg-archiv-NOC.jpg
  9. BIN
      mamweb/static/images/header-bg-archiv.jpg
  10. BIN
      mamweb/static/images/header-bg-archiv.png
  11. BIN
      mamweb/static/images/header-bg-clanek-NOC.jpg
  12. BIN
      mamweb/static/images/header-bg-clanek.jpg
  13. BIN
      mamweb/static/images/header-bg-clanek.png
  14. BIN
      mamweb/static/images/header-bg-odevzdat-NOC.jpg
  15. BIN
      mamweb/static/images/header-bg-soustredeni-NOC.jpg
  16. BIN
      mamweb/static/images/header-bg-soustredeni.jpg
  17. BIN
      mamweb/static/images/header-bg-soustredeni.png
  18. BIN
      mamweb/static/images/header-bg-uvod-NOC.jpg
  19. BIN
      mamweb/static/images/header-bg-uvod.jpg
  20. BIN
      mamweb/static/images/header-bg-uvod.png
  21. BIN
      mamweb/static/images/header-bg-zadani-NOC.jpg
  22. BIN
      mamweb/static/images/header-bg-zadani.jpg
  23. BIN
      mamweb/static/images/header-bg-zadani.png
  24. BIN
      mamweb/static/images/header-bg.jpg
  25. BIN
      mamweb/static/images/header-bg.png
  26. 19
      mamweb/templates/400.html
  27. 19
      mamweb/templates/403.html
  28. 2
      mamweb/templates/base.html
  29. 1
      mamweb/templates/flatpages/default.html
  30. 2
      mamweb/urls.py
  31. 21
      mamweb/wsgi.py
  32. 26
      requirements.txt
  33. 38
      seminar/admin.py
  34. 8
      seminar/autocomplete_light_registry.py
  35. 20
      seminar/management/commands/auth.py
  36. 44
      seminar/migrations/0032_cislo_pdf_blank_typos.py
  37. 20
      seminar/migrations/0033_organizator_studuje_popisek.py
  38. 37
      seminar/models.py
  39. 41
      seminar/templates/seminar/archiv/rocnik.html
  40. 2
      seminar/templates/seminar/cojemam/organizatori.html
  41. 29
      seminar/templates/seminar/vysledkovka_rocnik.html
  42. 35
      seminar/templates/seminar/zadani/AktualniVysledkovka.html
  43. 2
      seminar/templates/seminar/zadani/AktualniZadani.html
  44. 1
      seminar/urls.py
  45. 126
      seminar/views.py

23
Makefile

@ -1,6 +1,6 @@
.PHONY: clean_env init_env clean_virtualenv install_packages clean install run all schema_seminar.pdf schema_all.pdf .PHONY: clean_env init_env clean_virtualenv install_packages clean install run all schema_seminar.pdf schema_all.pdf
PYTHON=python2.7 PYTHON=python2.7
VE_VER=12.0.7 VE_VER=13.1.2
LOCAL_PYTHON=bin/python LOCAL_PYTHON=bin/python
all: install all: install
@ -17,7 +17,7 @@ make_env: ${LOCAL_PYTHON}
# phony, but fast repeated execution # phony, but fast repeated execution
install_packages: make_env install_packages: make_env
bin/pip install -r requirements.txt bin/pip install -r requirements.txt --upgrade
# phony # phony
clean_env: clean_env:
@ -35,12 +35,13 @@ ${LOCAL_PYTHON}: virtualenv
virtualenv: virtualenv:
curl -O https://pypi.python.org/packages/source/v/virtualenv/virtualenv-${VE_VER}.tar.gz curl -O https://pypi.python.org/packages/source/v/virtualenv/virtualenv-${VE_VER}.tar.gz
tar xvfz virtualenv-${VE_VER}.tar.gz tar xvfz virtualenv-${VE_VER}.tar.gz
mv virtualenv-${VE_VER} virtualenv mv -T virtualenv-${VE_VER} virtualenv
rm virtualenv-${VE_VER}.tar.gz rm virtualenv-${VE_VER}.tar.gz
# phony # phony
clean_virtualenv: clean_virtualenv:
rm -rf virtualenv/ rm -rf virtualenv/
rm -rf virtualenv-*.tar.gz
run: run:
./manage.py runserver_plus ./manage.py runserver_plus
@ -60,21 +61,24 @@ schema_all.pdf:
# Deploy to current *mamweb-test* directory # Deploy to current *mamweb-test* directory
deploy_test: deploy_test:
@if [[ `pwd` != "/akce/MaM/WWW/mamweb-test" ]]; then echo "Only possible in /akce/MaM/WWW/mamweb-test"; exit 1; fi @if [ ${USER} != "www-mam" ]; then echo "Only possible by user www-mam"; exit 1; fi
@if [ `pwd` != "/akce/MaM/WWW/mamweb-test" ]; then echo "Only possible in /akce/MaM/WWW/mamweb-test"; exit 1; fi
@echo "Installing version from origin/master ..." @echo "Installing version from origin/master ..."
git pull origin master git pull origin master
git clean -f git clean -f
make install make install
./manage.py migrate ./manage.py migrate
./manage.py collectstatic --noinput ./manage.py collectstatic --noinput
(chown -Rf :mam . || true ) (chown -R :mam . || true )
(chmod -Rf g+w . || true ) (chmod -R g+rX,go-w . || true )
@echo Notifying apache about the change ...
touch mamweb/wsgi.py touch mamweb/wsgi.py
@echo Done. @echo Done.
# Deploy to current *mamweb-prod* directory # Deploy to current *mamweb-prod* directory
deploy_prod: deploy_prod:
@if [[ `pwd` != "/akce/MaM/WWW/mamweb-prod" ]]; then echo "Only possible in /akce/MaM/WWW/mamweb-prod"; exit 1; fi @if [ ${USER} != "www-mam" ]; then echo "Only possible by user www-mam"; exit 1; fi
@if [ `pwd` != "/akce/MaM/WWW/mamweb-prod" ]; then echo "Only possible in /akce/MaM/WWW/mamweb-prod"; exit 1; fi
@echo "Backing up production DB ..." @echo "Backing up production DB ..."
( cd .. && ./backup_prod_db.sh ) ( cd .. && ./backup_prod_db.sh )
@echo "Installing version from origin/stable ..." @echo "Installing version from origin/stable ..."
@ -83,8 +87,9 @@ deploy_prod:
make install make install
./manage.py migrate ./manage.py migrate
./manage.py collectstatic --noinput ./manage.py collectstatic --noinput
(chown -Rf :mam . || true ) (chown -R :mam . || true )
(chmod -Rf g+w . || true ) (chmod -R g+rX,go-w . || true )
@echo Notifying apache about the change ...
touch mamweb/wsgi.py touch mamweb/wsgi.py
@echo Done. @echo Done.

12
mamweb/context_processors.py

@ -0,0 +1,12 @@
from datetime import datetime, date
def vzhled(request):
''' Podle casu prida do templatu, zdali je nebo neni noc '''
hodin = datetime.now().hour
if (hodin <= 6) or (hodin >= 20):
noc = True
else:
noc = False
return {'noc' : noc}

84
mamweb/middleware.py

@ -0,0 +1,84 @@
from datetime import datetime, date
from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect
class LoggedInHintCookieMiddleware(object):
"""Middleware to securely help with 'logged-in' detection for dual HTTP/HTTPS sites.
On insecure requests: Checks for a (non-secure) cookie settings.LOGGED_IN_HINT_COOKIE_NAME
and if present, redirects to HTTPS (same adress).
Note this usually breaks non-GET (POST) requests.
On secure requests: Updates cookie settings.LOGGED_IN_HINT_COOKIE_NAME to reflect
whether an user is logged in in the current session (cookie set to 'True' or cleared).
The cookie is set to expire at the same time as the sessionid cookie.
By default, LOGGED_IN_HINT_COOKIE_NAME = 'logged_in_hint'.
"""
def __init__(self):
if hasattr(settings, 'LOGGED_IN_HINT_COOKIE_NAME'):
self.cookie_name = settings.LOGGED_IN_HINT_COOKIE_NAME
else: self.cookie_name = 'logged_in_hint'
self.cookie_value = 'True'
def cookie_correct(self, request):
return self.cookie_name in request.COOKIES and request.COOKIES[self.cookie_name] == self.cookie_value
def process_request(self, request):
if not request.is_secure():
if self.cookie_correct(request):
# redirect insecure (assuming http) requests with hint cookie to https
url = HttpRequest.build_absolute_uri()
assert url[:5] == 'http:'
return HttpResponseRedirect('https:' + url[5:])
return None
def process_response(self, request, response):
if request.is_secure():
# assuming full session info (as the conn. is secure)
if request.user.is_authenticated():
if not self.cookie_correct(request):
expiry = None if request.session.get_expire_at_browser_close() else request.session.get_expiry_date()
response.set_cookie(self.cookie_name, value=self.cookie_value, expires=expiry, secure=False)
else:
if self.cookie_name in request.COOKIES:
response.delete_cookie(self.cookie_name)
return response
class vzhled:
def process_request(self, request):
return None
def process_view(self, request, view_func, view_args, view_kwargs):
#print "====== process_request ======"
#print view_func
#print view_args
#print view_kwargs
#print "============================="
return None
def process_template_response(self, request, response):
hodin = datetime.now().hour
if (hodin <= 6) or (hodin >= 14): # TODO 20
response.context_data['noc'] = True
else:
response.context_data['noc'] = False
return response
def process_response(self, request, response):
#hodin = datetime.now().hour
#if (hodin <= 6) or (hodin >= 14): # TODO 20
#response.context_data['noc'] = True
#else:
#response.context_data['noc'] = False
return response
##def process_exception(request, exception):
#pass

2
mamweb/settings_common.py

@ -60,6 +60,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'mamweb.middleware.LoggedInHintCookieMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
@ -78,6 +79,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.tz', 'django.core.context_processors.tz',
'sekizai.context_processors.sekizai', 'sekizai.context_processors.sekizai',
'django.core.context_processors.static', 'django.core.context_processors.static',
'mamweb.context_processors.vzhled',
) )
INSTALLED_APPS = ( INSTALLED_APPS = (

8
mamweb/settings_prod.py

@ -47,12 +47,18 @@ import os
SERVER_EMAIL = 'mamweb-prod-errors@mam.mff.cuni.cz' SERVER_EMAIL = 'mamweb-prod-errors@mam.mff.cuni.cz'
ADMINS = [ ADMINS = [
('Tomas Gavenciak', 'gavento@ucw.cz'),
('Petr Pecha', 'nejlepsitextovyeditorjevim@gmail.com'), ('Petr Pecha', 'nejlepsitextovyeditorjevim@gmail.com'),
('Matěj Kocián', 'matej.kocian@gmail.com'), ('Matěj Kocián', 'matej.kocian@gmail.com'),
] ]
# SECURITY: only send sensitive cookies via HTTPS
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# LOGGING = { # LOGGING = {
# 'version': 1, # 'version': 1,
# 'disable_existing_loggers': True, # 'disable_existing_loggers': True,

18
mamweb/settings_test.py

@ -25,11 +25,11 @@ INSTALLED_APPS += (
SECRET_KEY = ')^u=i65*zmr_k53a*@f4q_+ji^o@!pgpef*5&8c7zzv9l+zo)n' SECRET_KEY = ')^u=i65*zmr_k53a*@f4q_+ji^o@!pgpef*5&8c7zzv9l+zo)n'
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = False
TEMPLATE_DEBUG = True TEMPLATE_DEBUG = False
ALLOWED_HOSTS = ['*.mam.mff.cuni.cz'] ALLOWED_HOSTS = ['*.mam.mff.cuni.cz', 'atrey.karlin.mff.cuni.cz', 'mam.mff.cuni.cz']
# Database # Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases # https://docs.djangoproject.com/en/1.7/ref/settings/#databases
@ -45,6 +45,18 @@ DATABASES = {
}, },
} }
import os
SERVER_EMAIL = 'mamweb-test-errors@mam.mff.cuni.cz'
ADMINS = [
('Petr Pecha', 'nejlepsitextovyeditorjevim@gmail.com'),
]
# SECURITY: only send sensitive cookies via HTTPS
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

20
mamweb/static/css/mamweb.css

@ -58,16 +58,24 @@ h2 {
#header { #header {
position: relative; position: relative;
font-size: 250%; font-size: 250%;
background: url("../images/header-bg-uvod.png") no-repeat center top; background: url("../images/header-bg-uvod.jpg") no-repeat center top;
height: 255px; height: 255px;
top: -1px; top: -1px;
} }
#header.cojemam { background-image: url("../images/header-bg-uvod.png"); }
#header.soustredeni { background-image: url("../images/header-bg-soustredeni.png"); } #header.cojemam { background-image: url("../images/header-bg-uvod.jpg"); }
#header.zadani { background-image: url("../images/header-bg-zadani.png"); } #header.soustredeni { background-image: url("../images/header-bg-soustredeni.jpg"); }
#header.clanky { background-image: url("../images/header-bg-clanek.png"); } #header.zadani { background-image: url("../images/header-bg-zadani.jpg"); }
#header.archiv { background-image: url("../images/header-bg-archiv.png"); } #header.clanky { background-image: url("../images/header-bg-clanek.jpg"); }
#header.archiv { background-image: url("../images/header-bg-archiv.jpg"); }
#header.NOC {background-image: url("../images/header-bg-uvod-NOC.jpg"); }
#header.NOCcojemam { background-image: url("../images/header-bg-uvod-NOC.jpg"); }
#header.NOCsoustredeni { background-image: url("../images/header-bg-soustredeni-NOC.jpg"); }
#header.NOCzadani { background-image: url("../images/header-bg-zadani-NOC.jpg"); }
#header.NOCclanky { background-image: url("../images/header-bg-clanek-NOC.jpg"); }
#header.NOCarchiv { background-image: url("../images/header-bg-archiv-NOC.jpg"); }
#header img.logo { #header img.logo {
position: absolute; position: absolute;

BIN
mamweb/static/images/header-bg-archiv-NOC.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
mamweb/static/images/header-bg-archiv.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
mamweb/static/images/header-bg-archiv.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 KiB

BIN
mamweb/static/images/header-bg-clanek-NOC.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
mamweb/static/images/header-bg-clanek.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
mamweb/static/images/header-bg-clanek.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 KiB

BIN
mamweb/static/images/header-bg-odevzdat-NOC.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
mamweb/static/images/header-bg-soustredeni-NOC.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
mamweb/static/images/header-bg-soustredeni.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
mamweb/static/images/header-bg-soustredeni.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 KiB

BIN
mamweb/static/images/header-bg-uvod-NOC.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
mamweb/static/images/header-bg-uvod.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
mamweb/static/images/header-bg-uvod.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 KiB

BIN
mamweb/static/images/header-bg-zadani-NOC.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
mamweb/static/images/header-bg-zadani.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
mamweb/static/images/header-bg-zadani.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

BIN
mamweb/static/images/header-bg.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
mamweb/static/images/header-bg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 KiB

19
mamweb/templates/400.html

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block content %}
<h2>
{% block nadpis1a %}{% block nadpis1b %}
O-jo-jo-jo-joj
{% endblock %}{% endblock %}
</h2>
<p>
Chybička se vloudila.
Zkuste přejít na <a href="/">titulní stránku</a>
nebo se podívat na <a href="/zadani/aktualni/">aktuální zadání</a>.
</p>
<img src="{% static '500.png' %}">
{% endblock %}

19
mamweb/templates/403.html

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block content %}
<h2>
{% block nadpis1a %}{% block nadpis1b %}
Vrrrrrrrrr
{% endblock %}{% endblock %}
</h2>
<p>
Tady pravděpodobně nemáte co dělat.
Zkuste přejít na <a href="/">titulní stránku</a>
nebo se podívat na <a href="/zadani/aktualni/">aktuální zadání</a>.
</p>
<img src="{% static '500.png' %}">
{% endblock %}

2
mamweb/templates/base.html

@ -48,7 +48,7 @@
<div class='row'> <div class='row'>
<div class='col-md-12'> <div class='col-md-12'>
<a href='/'> <a href='/'>
<div id="header" class="{% block header %}{% endblock %}"> <div id="header" class="{% if noc %}NOC{% endif %}{% block header %}{% endblock %}">
<img class="logo" src="{% static 'images/logo.png' %}" /> <img class="logo" src="{% static 'images/logo.png' %}" />
<!--<h1>{% block nadpis1b %}Nadpis 1. úrovně{% endblock %}</h1>--> <!--<h1>{% block nadpis1b %}Nadpis 1. úrovně{% endblock %}</h1>-->
</div> </div>

1
mamweb/templates/flatpages/default.html

@ -5,7 +5,6 @@
{% endblock %}{% endblock %} {% endblock %}{% endblock %}
{% block content %} {% block content %}
<div> <div>
{{ flatpage.content }} {{ flatpage.content }}
</div> </div>

2
mamweb/urls.py

@ -19,8 +19,6 @@ urlpatterns = patterns('',
url(r'^comments_dj/', include('django_comments.urls')), url(r'^comments_dj/', include('django_comments.urls')),
url(r'^comments_fl/', include('fluent_comments.urls')), url(r'^comments_fl/', include('fluent_comments.urls')),
# Obsah - flatpages
url(r'^', include('django.contrib.flatpages.urls')), # Pozor: musi byt posledni
) )
# This is only needed when using runserver. # This is only needed when using runserver.

21
mamweb/wsgi.py

@ -7,11 +7,22 @@ For more information on this file, see
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
""" """
import sys, os, os.path import sys, os, os.path, traceback, time, signal
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mamweb.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mamweb.settings")
sys.path.append(os.path.join(os.path.dirname(__file__), '..')) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'lib', 'python2.7', 'site-packages')) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'lib', 'python2.7', 'site-packages')))
try:
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
except Exception:
print 'handling WSGI exception'
# Error loading applications
if 'mod_wsgi' in sys.modules:
traceback.print_exc()
os.kill(os.getpid(), signal.SIGINT)
time.sleep(2)
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

26
requirements.txt

@ -1,25 +1,27 @@
# basic libs # basic libs
psycopg2==2.6 psycopg2==2.6.1
html5lib==0.999 html5lib==0.9999999
ipython==3.0.0 ipython==4.0.0
Pillow==2.7.0 Pillow==2.9.0
pytz==2014.10 pytz==2014.10
six==1.9.0 six==1.9.0
pexpect==3.3
traitlets==4.0.0
# Django and modules # Django and modules
Django==1.7.8 Django==1.7.10 # Updatable to 1.8 (possibly incompatible)
django-bootstrap-sass==0.0.6a0 django-bootstrap-sass==0.0.6a0
django-mptt==0.7.3 django-mptt==0.7.3
django-reversion==1.8.6 django-reversion==1.9.3
django-sekizai==0.8.1 django-sekizai==0.8.1
django-countries==3.2 django-countries==3.2
django-solo==1.1.0 django-solo==1.1.0
django-ckeditor==4.4.7 django-ckeditor==4.4.7 # Updatable to 5.0 (some incompatible changes)
django-flat-theme==0.9.3 django-flat-theme==0.9.3
django-taggit==0.14.0 django-taggit==0.17
django-autocomplete-light==2.1.1 django-autocomplete-light==2.2.6
django-crispy-forms==1.4.0 django-crispy-forms==1.4.0
# Comments # Comments
@ -30,9 +32,9 @@ django-contrib-comments==1.6.1
# debug tools/extensions # debug tools/extensions
django-debug-toolbar==1.3.0 django-debug-toolbar==1.3.2
django-extensions==1.5.3 django-extensions==1.5.6
sqlparse==0.1.15 sqlparse==0.1.16
Werkzeug==0.10.4 Werkzeug==0.10.4
# G+, FB authorisation # G+, FB authorisation

38
seminar/admin.py

@ -9,10 +9,26 @@ from ckeditor.widgets import CKEditorWidget
from django.db.models import Count from django.db.models import Count
from django.db import models 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, Novinky, Organizator
import autocomplete_light import autocomplete_light
class UserModelChoiceField(forms.ModelChoiceField):
u"""Vlastní ModelChoiceField pro uživatele. Zobrazí kromě loginu i jméno.
"""
def label_from_instance(self, obj):
return u"{} ({})".format(obj.get_full_name(), obj.username)
def get_form_predvypln_autora(self, request, obj=None, *args, **kwargs):
u"""get_form fce pro Adminy. Předvyplňí přihlášeného uživatele jako autora.
"""
form = super(self.__class__, self).get_form(request, *args, **kwargs)
form.base_fields['autor'].initial = request.user.id
return form
def make_set_action(atribut, hodnota, nazev): def make_set_action(atribut, hodnota, nazev):
u""" u"""
Pomocnik pro rychle vytvareni hromadnych admin akci ktere jen nastavuji Pomocnik pro rychle vytvareni hromadnych admin akci ktere jen nastavuji
@ -271,13 +287,14 @@ admin.site.register(Reseni, ReseniAdmin)
from autocomplete_light.contrib.taggit_field import TaggitField, TaggitWidget from autocomplete_light.contrib.taggit_field import TaggitField, TaggitWidget
#TODO: Autocomplete autor/opravovatel
class ProblemAdminForm(forms.ModelForm): class ProblemAdminForm(forms.ModelForm):
text_zadani = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Problem, 'text_zadani')) text_zadani = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Problem, 'text_zadani'))
text_reseni = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Problem, 'text_reseni')) text_reseni = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Problem, 'text_reseni'))
text_org = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Problem, 'text_org')) text_org = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Problem, 'text_org'))
zamereni = TaggitField(widget=TaggitWidget('TagAutocomplete'), required=False) zamereni = TaggitField(widget=TaggitWidget('TagAutocomplete'), required=False)
autor = UserModelChoiceField(User.objects.filter(is_staff=True))
opravovatel = UserModelChoiceField(User.objects.filter(is_staff=True), required=False)
class Meta: class Meta:
model = Problem model = Problem
exclude = [] exclude = []
@ -302,13 +319,16 @@ class ProblemAdmin(reversion.VersionAdmin):
return obj.pocet_reseni return obj.pocet_reseni
class ProblemNavrhAdmin(ProblemAdmin): class ProblemNavrhAdmin(ProblemAdmin):
list_display = ['nazev', 'typ', 'stav', 'autor', 'timestamp'] list_display = ['nazev', 'typ', 'zamereni', 'stav', 'autor', 'timestamp']
list_filter = ['typ', 'stav', 'timestamp'] list_filter = ['typ', 'zamereni', 'timestamp', 'stav']
def get_queryset(self, request): def get_queryset(self, request):
qs = super(ProblemNavrhAdmin, self).get_queryset(request) qs = super(ProblemNavrhAdmin, self).get_queryset(request)
return qs.filter(stav__in=[Problem.STAV_NAVRH, Problem.STAV_SMAZANY]) return qs.filter(stav__in=[Problem.STAV_NAVRH, Problem.STAV_SMAZANY])
get_form = get_form_predvypln_autora
create_modeladmin(ProblemNavrhAdmin, Problem, 'ProblemNavrh', verbose_name=u'Problém (návrh)', verbose_name_plural=u'Problémy (návrhy)') create_modeladmin(ProblemNavrhAdmin, Problem, 'ProblemNavrh', verbose_name=u'Problém (návrh)', verbose_name_plural=u'Problémy (návrhy)')
class ProblemZadanyAdmin(ProblemAdmin): class ProblemZadanyAdmin(ProblemAdmin):
@ -320,6 +340,8 @@ class ProblemZadanyAdmin(ProblemAdmin):
qs = super(ProblemZadanyAdmin, self).get_queryset(request) qs = super(ProblemZadanyAdmin, self).get_queryset(request)
return qs.filter(stav=Problem.STAV_ZADANY).annotate(pocet_reseni=Count('reseni')) return qs.filter(stav=Problem.STAV_ZADANY).annotate(pocet_reseni=Count('reseni'))
get_form = get_form_predvypln_autora
create_modeladmin(ProblemZadanyAdmin, Problem, 'ProblemZadany', verbose_name=u'Problém (zadaný)', verbose_name_plural=u'Problémy (zadané)') create_modeladmin(ProblemZadanyAdmin, Problem, 'ProblemZadany', verbose_name=u'Problém (zadaný)', verbose_name_plural=u'Problémy (zadané)')
#admin.site.register(Problem, ProblemAdmin) #admin.site.register(Problem, ProblemAdmin)
@ -356,6 +378,8 @@ admin.site.register(Soustredeni, SoustredeniAdmin)
class NovinkyAdminForm(forms.ModelForm): class NovinkyAdminForm(forms.ModelForm):
text = forms.CharField(widget=CKEditorWidget(), required=False, text = forms.CharField(widget=CKEditorWidget(), required=False,
**field_labels(Novinky, 'text')) **field_labels(Novinky, 'text'))
autor = UserModelChoiceField(User.objects.filter(is_staff=True))
class Meta: class Meta:
model = Novinky model = Novinky
exclude = [] exclude = []
@ -380,13 +404,7 @@ class NovinkyAdmin(admin.ModelAdmin):
list_display = ['datum', 'autor', 'text', 'zverejneno', 'obrazek'] list_display = ['datum', 'autor', 'text', 'zverejneno', 'obrazek']
actions = [zverejnit_novinky, zneverejnit_novinky] actions = [zverejnit_novinky, zneverejnit_novinky]
# předvyplnění přihlášeného uživatele jako autora novinky get_form = get_form_predvypln_autora
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'autor':
kwargs['initial'] = request.user.id
return super(NovinkyAdmin, self).formfield_for_foreignkey(
db_field, request, **kwargs
)
admin.site.register(Novinky, NovinkyAdmin) admin.site.register(Novinky, NovinkyAdmin)

8
seminar/autocomplete_light_registry.py

@ -77,7 +77,13 @@ class ProblemAutocomplete(autocomplete_light.AutocompleteModelBase):
def choice_label(self, p): def choice_label(self, p):
if p.stav == Problem.STAV_ZADANY: if p.stav == Problem.STAV_ZADANY:
return u"%s (%s, %s.%s)" % (p.nazev, p.typ, p.cislo_zadani.rocnik.rocnik, p.kod_v_rocniku()) popisek = ""
try:
popisek = u"%s (%s, %s.%s)" % (p.nazev, p.typ, p.cislo_zadani.rocnik.rocnik, p.kod_v_rocniku())
except:
#popisek = u"%s (%s, %s.%s)" % (p.nazev, p.typ, p.stav)
popisek = "CHYBA"
return popisek
else: else:
return u"%s (%s, %s)" % (p.nazev, p.typ, p.stav) return u"%s (%s, %s)" % (p.nazev, p.typ, p.stav)

20
seminar/management/commands/auth.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from django.core.management.base import NoArgsCommand
from django.contrib.sessions.models import Session
from django.contrib.auth.models import User
class Command(NoArgsCommand):
u"""Vypiš username přihlášeného orga s daným session_key.
Příkaz pro manage.py, který ze vstupu přečte session_key (tak, jak je
uložen v cookie sessionid) a pokud session existuje a příslušný přihlášený
uživatel právo přihlásit se do admina, vypíše jeho username.
"""
def handle_noargs(self, **options):
session_key = raw_input()
s = Session.objects.get(pk=session_key).get_decoded()
user_id = s['_auth_user_id']
user = User.objects.get(pk=user_id)
if user.is_staff:
print(user.username)

44
seminar/migrations/0032_cislo_pdf_blank_typos.py

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django_countries.fields
import seminar.models
class Migration(migrations.Migration):
dependencies = [
('seminar', '0031_cislo_pdf'),
]
operations = [
migrations.AlterModelOptions(
name='soustredeni',
options={'ordering': ['-rocnik__rocnik', '-datum_zacatku'], 'verbose_name': 'Soust\u0159ed\u011bn\xed', 'verbose_name_plural': 'Soust\u0159ed\u011bn\xed'},
),
migrations.AlterField(
model_name='cislo',
name='cislo',
field=models.CharField(help_text='V\u011bt\u0161inou jen "1", vyj\xedme\u010dn\u011b "7-8", lexikograficky ur\u010duje po\u0159ad\xed v ro\u010dn\xedku!', max_length=32, verbose_name='n\xe1zev \u010d\xedsla', db_index=True),
preserve_default=True,
),
migrations.AlterField(
model_name='cislo',
name='pdf',
field=models.FileField(help_text='Pdf \u010d\xedsla, kter\xe9 si mohou \u0159e\u0161itel\xe9 st\xe1hnout', upload_to=seminar.models.cislo_pdf_filename, null=True, verbose_name='pdf', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='problem',
name='typ',
field=models.CharField(default=b'uloha', max_length=32, verbose_name='typ probl\xe9mu', choices=[(b'uloha', '\xdaloha'), (b'tema', 'T\xe9ma'), (b'serial', 'Seri\xe1l'), (b'org-clanek', 'Organiz\xe1torsk\xfd \u010dl\xe1nek'), (b'res-clanek', '\u0158e\u0161itelsk\xfd \u010dl\xe1nek')]),
preserve_default=True,
),
migrations.AlterField(
model_name='skola',
name='stat',
field=django_countries.fields.CountryField(default=b'CZ', help_text='ISO 3166-1 k\xf3d zem\u011b velk\xfdmi p\xedsmeny (CZ, SK, ...)', max_length=2, verbose_name='st\xe1t'),
preserve_default=True,
),
]

20
seminar/migrations/0033_organizator_studuje_popisek.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0032_cislo_pdf_blank_typos'),
]
operations = [
migrations.AlterField(
model_name='organizator',
name='studuje',
field=models.CharField(help_text=b"Nap\xc5\x99. 'Studuje Obecnou fyziku (Bc.), 3. ro\xc4\x8dn\xc3\xadk', 'Vystudovala Diskr\xc3\xa9tn\xc3\xad modely a algoritmy (Mgr.)' nebo 'P\xc5\x99edn\xc3\xa1\xc5\xa1\xc3\xad na MFF'", max_length=256, null=True, verbose_name=b'Studium aj.', blank=True),
preserve_default=True,
),
]

37
seminar/models.py

@ -93,7 +93,7 @@ class Skola(SeminarModelBase):
# ISO 3166-1 dvojznakovy kod zeme velkym pismem (CZ, SK) # ISO 3166-1 dvojznakovy kod zeme velkym pismem (CZ, SK)
# Ekvivalentní s CharField(max_length=2, default='CZ', ...) # Ekvivalentní s CharField(max_length=2, default='CZ', ...)
stat = CountryField(u'stát', default='CZ', stat = CountryField(u'stát', default='CZ',
help_text=u'ISO 3166-1 kód zeme velkými písmeny (CZ, SK, ...)') help_text=u'ISO 3166-1 kód země velkými písmeny (CZ, SK, ...)')
# Jaké vzdělání škpla poskytuje? # Jaké vzdělání škpla poskytuje?
je_zs = models.BooleanField(u'základní stupeň', default=True) je_zs = models.BooleanField(u'základní stupeň', default=True)
@ -325,7 +325,7 @@ class Cislo(SeminarModelBase):
rocnik = models.ForeignKey(Rocnik, verbose_name=u'ročník', related_name='cisla', db_index=True) rocnik = models.ForeignKey(Rocnik, verbose_name=u'ročník', related_name='cisla', db_index=True)
cislo = models.CharField(u'název čísla', max_length=32, db_index=True, cislo = models.CharField(u'název čísla', max_length=32, db_index=True,
help_text=u'Většinou jen "1", vyjímečně "7-8", lexikograficky určije pořadí v ročníku!') help_text=u'Většinou jen "1", vyjímečně "7-8", lexikograficky určuje pořadí v ročníku!')
datum_vydani = models.DateField(u'datum vydání', blank=True, null=True, datum_vydani = models.DateField(u'datum vydání', blank=True, null=True,
help_text=u'Datum vydání finální verze') help_text=u'Datum vydání finální verze')
@ -349,7 +349,7 @@ class Cislo(SeminarModelBase):
kod.short_description = u'Kód čísla' kod.short_description = u'Kód čísla'
def __str__(self): def __str__(self):
# Potenciální DB HOG, pokud by se ročník neckešoval # Potenciální DB HOG, pokud by se ročník necachoval
r = Rocnik.cached_rocnik(self.rocnik_id) r = Rocnik.cached_rocnik(self.rocnik_id)
return force_unicode(u'%s.%s' % (r.rocnik, self.cislo, )) return force_unicode(u'%s.%s' % (r.rocnik, self.cislo, ))
@ -403,7 +403,7 @@ class Problem(SeminarModelBase):
(TYP_TEMA, u'Téma'), (TYP_TEMA, u'Téma'),
(TYP_SERIAL, u'Seriál'), (TYP_SERIAL, u'Seriál'),
(TYP_ORG_CLANEK, u'Organizátorský článek'), (TYP_ORG_CLANEK, u'Organizátorský článek'),
(TYP_RES_CLANEK, u'Řesitelský článek'), (TYP_RES_CLANEK, u'Řešitelský článek'),
] ]
typ = models.CharField(u'typ problému', max_length=32, choices=TYP_CHOICES, blank=False, default=TYP_ULOHA) typ = models.CharField(u'typ problému', max_length=32, choices=TYP_CHOICES, blank=False, default=TYP_ULOHA)
@ -454,11 +454,12 @@ class Problem(SeminarModelBase):
return force_unicode(u'%s' % (self.nazev, )) return force_unicode(u'%s' % (self.nazev, ))
def kod_v_rocniku(self): def kod_v_rocniku(self):
if self.typ == self.TYP_ULOHA: if self.stav == 'zadany':
return force_unicode(u"%s.u%s" % (self.cislo_zadani.cislo, self.kod,)) if self.typ == self.TYP_ULOHA:
if self.typ == self.TYP_TEMA: return force_unicode(u"%s.u%s" % (self.cislo_zadani.cislo, self.kod,))
return force_unicode(u"t%s" % (self.kod,)) if self.typ == self.TYP_TEMA:
return '' return force_unicode(u"t%s" % (self.kod,))
return ' Není zadaný '
def nazev_typu(self): def nazev_typu(self):
return dict(self.TYP_CHOICES)[self.typ] return dict(self.TYP_CHOICES)[self.typ]
@ -771,8 +772,11 @@ class Organizator(models.Model):
null = True, blank = True) null = True, blank = True)
organizuje_do_roku = models.IntegerField('Organizuje do roku', organizuje_do_roku = models.IntegerField('Organizuje do roku',
null = True, blank = True) null = True, blank = True)
studuje = models.CharField('Studuje', max_length = 256, studuje = models.CharField('Studium aj.', max_length = 256,
null = True, blank = True) 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', strucny_popis_organizatora = models.TextField('Stručný popis organizátora',
null = True, blank = True) null = True, blank = True)
foto = models.ImageField('Fotografie organizátora', foto = models.ImageField('Fotografie organizátora',
@ -789,11 +793,14 @@ class Organizator(models.Model):
verbose_name_plural = 'Organizátoři' verbose_name_plural = 'Organizátoři'
def save(self): def save(self):
if self.id is not None:
puvodni = Organizator.objects.get(id=self.id)
if self.foto: if self.foto:
original = Image.open(self.foto) if not puvodni or puvodni.foto != self.foto:
jmeno = os.path.basename(self.foto.file.name) original = Image.open(self.foto)
Organizator._vyrobMiniaturu(original, jmeno, 500, self.foto) jmeno = os.path.basename(self.foto.file.name)
Organizator._vyrobMiniaturu(original, jmeno, 200, self.foto_male) Organizator._vyrobMiniaturu(original, jmeno, 500, self.foto)
Organizator._vyrobMiniaturu(original, jmeno, 200, self.foto_male)
super(Organizator, self).save() super(Organizator, self).save()
@staticmethod @staticmethod

41
seminar/templates/seminar/archiv/rocnik.html

@ -29,38 +29,17 @@
{% endif %} {% endif %}
{% if vysledkovka %} {% if vysledkovka %}
<h3>Výsledkovka</h3> <h3>Výsledková listina</h3>
<table class='vysledkovka'> {% include "seminar/vysledkovka_rocnik.html" %}
<tr class='border-b'> {% endif %}
<th class='border-r'>#
<th class='border-r'>Jméno
<th class='border-r'>R.
<th class='border-r'>Odjakživa
{% for c in rocnik.verejna_cisla %}
{% if c.verejna_vysledkovka %}
<th class='border-r'><a href="{{ c.verejne_url }}">
{{c.rocnik.rocnik}}.{{ c.cislo }}</a>
{% endif %}
{% endfor %}
<th class='border-r'>Celkem
{% for rv in vysledkovka %} {% if user.is_staff and vysledkovka_s_neverejnymi %}
<tr> <div class='mam-org-only'>
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %} <h3>Výsledková listina včetně neveřejných bodů</h3>
<th class='border-r'> {% with vysledkovka_s_neverejnymi as vysledkovka %}
{% if rv.titul %} {% include "seminar/vysledkovka_rocnik.html" %}
{{ rv.titul }}<sup>MM</sup> {% endwith %}
{% endif %} </div>
{{ rv.resitel.plne_jmeno }}
<td class='border-r'>{{ rv.resitel.rocnik }}
<td class='border-r'>{{ rv.body_odjakziva }}
{% for b in rv.body_cisla %}
<td class='border-r'>{{ b }}
{% endfor %}
<td class='border-r'><b>{{ rv.body_rocnik }}</b>
</tr>
{% endfor %}
</table>
{% endif %} {% endif %}
</div> </div>

2
seminar/templates/seminar/cojemam/organizatori.html

@ -53,7 +53,7 @@
Aktivní v letech {{org.organizuje_od_roku | default:"?" }}&ndash;{{org.organizuje_do_roku | default:"?" }} Aktivní v letech {{org.organizuje_od_roku | default:"?" }}&ndash;{{org.organizuje_do_roku | default:"?" }}
{% endif %} {% endif %}
{% if org.studuje %} {% if org.studuje %}
<li>Studuje: {{org.studuje}} <li>{{org.studuje}}
{% endif %} {% endif %}
{% if org.user.email %} {% if org.user.email %}
<li>Pošta: <li>Pošta:

29
seminar/templates/seminar/vysledkovka_rocnik.html

@ -0,0 +1,29 @@
<table class='vysledkovka'>
<tr class='border-b'>
<th class='border-r'>#
<th class='border-r'>Jméno
<th class='border-r'>R.
<th class='border-r'>Odjakživa
{% for c in vysledkovka.cisla %}
<th class='border-r'><a href="{{ c.verejne_url }}">
{{c.rocnik.rocnik}}.{{ c.cislo }}</a>
{% endfor %}
<th class='border-r'>Celkem
{% for rv in vysledkovka.radky %}
<tr>
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}
<th class='border-r'>
{% if rv.titul %}
{{ rv.titul }}<sup>MM</sup>
{% endif %}
{{ rv.resitel.plne_jmeno }}
<td class='border-r'>{{ rv.resitel.rocnik }}
<td class='border-r'>{{ rv.body_odjakziva }}
{% for b in rv.body_cisla %}
<td class='border-r'>{{ b }}
{% endfor %}
<td class='border-r'><b>{{ rv.body_rocnik }}</b>
</tr>
{% endfor %}
</table>

35
seminar/templates/seminar/zadani/AktualniVysledkovka.html

@ -0,0 +1,35 @@
{% extends "seminar/zadani/base.html" %}
{% block submenu %}
{% with "vysledkova-listina" as selected %}
{% include 'seminar/zadani/submenu.html' %}
{% endwith %}
{% endblock submenu %}
{% block content %}
{% with nastaveni.aktualni_rocnik as rocnik %}
<h2>
{% block nadpis1a %}{% block nadpis1b %}
Výsledky
{% endblock %}{% endblock %}
</h2>
{% if vysledkovka %}
{% include "seminar/vysledkovka_rocnik.html" %}
{% else %}
V tomto ročníku zatím žádné výsledky nejsou
{% endif %}
{% if user.is_staff and vysledkovka_s_neverejnymi %}
<div class='mam-org-only'>
<h2>Výsledky včetně neveřejných</h2>
{% with vysledkovka_s_neverejnymi as vysledkovka %}
{% include "seminar/vysledkovka_rocnik.html" %}
{% endwith %}
</div>
{% endif %}
{% endwith %}
{% endblock content %}

2
seminar/templates/seminar/zadani/AktualniZadani.html

@ -18,8 +18,6 @@
{% if ac.zadane_problemy.all %} {% if ac.zadane_problemy.all %}
<div class="zadani_azad_termin"> <div class="zadani_azad_termin">
Termín odeslání {{ac.cislo}}. série: {{ac.datum_deadline}} Termín odeslání {{ac.cislo}}. série: {{ac.datum_deadline}}
<br>
Termín odeslání 1. série pro účast na soustředění: 21. září 2015
</div> </div>
{% endif %} {% endif %}
{#TODO a co speciální deadline pro účast na soustředění? #} {#TODO a co speciální deadline pro účast na soustředění? #}

1
seminar/urls.py

@ -19,6 +19,7 @@ urlpatterns = patterns('',
url(r'^zadani/aktualni/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'), url(r'^zadani/aktualni/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'),
url(r'^zadani/temata/$', views.ZadaniTemataView, name='seminar_temata'), url(r'^zadani/temata/$', views.ZadaniTemataView, name='seminar_temata'),
url(r'^zadani/vysledkova-listina/$', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'),
url(r'^$', views.TitulniStranaView.as_view(), name='titulni_strana'), url(r'^$', views.TitulniStranaView.as_view(), name='titulni_strana'),
url(r'^stare-novinky/$', views.StareNovinkyView.as_view(), name='stare_novinky'), url(r'^stare-novinky/$', views.StareNovinkyView.as_view(), name='stare_novinky'),

126
seminar/views.py

@ -15,17 +15,22 @@ from datetime import timedelta, date, datetime
from itertools import groupby from itertools import groupby
def verejna_temata(rocnik):
"""Vrací queryset zveřejněných témat v daném ročníku.
"""
return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod')
def AktualniZadaniView(request): def AktualniZadaniView(request):
nastaveni = get_object_or_404(Nastaveni) nastaveni = get_object_or_404(Nastaveni)
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')
temata = problemy.filter(typ = 'tema').order_by('kod')
jednorazove_problemy = [ulohy, serialy] jednorazove_problemy = [ulohy, serialy]
return render(request, 'seminar/zadani/AktualniZadani.html', return render(request, 'seminar/zadani/AktualniZadani.html',
{'nastaveni': nastaveni, {'nastaveni': nastaveni,
'jednorazove_problemy': jednorazove_problemy, 'jednorazove_problemy': jednorazove_problemy,
'temata': temata, 'temata': verejna_temata(nastaveni.aktualni_rocnik),
}, },
) )
@ -33,10 +38,23 @@ def ZadaniTemataView(request):
nastaveni = get_object_or_404(Nastaveni) nastaveni = get_object_or_404(Nastaveni)
return render(request, 'seminar/zadani/Temata.html', return render(request, 'seminar/zadani/Temata.html',
{ {
'temata': Problem.objects.filter(typ=Problem.TYP_TEMA, stav=Problem.STAV_ZADANY, cislo_zadani__rocnik=nastaveni.aktualni_rocnik).order_by('kod'), 'temata': verejna_temata(nastaveni.aktualni_rocnik)
}
)
def ZadaniAktualniVysledkovkaView(request):
nastaveni = get_object_or_404(Nastaveni)
vysledkovka = vysledkovka_rocniku(nastaveni.aktualni_rocnik)
vysledkovka_s_neverejnymi = vysledkovka_rocniku(nastaveni.aktualni_rocnik, jen_verejne=False)
return render(request, 'seminar/zadani/AktualniVysledkovka.html',
{
'nastaveni': nastaveni,
'vysledkovka': vysledkovka,
'vysledkovka_s_neverejnymi': vysledkovka_s_neverejnymi,
} }
) )
### Titulni strana ### Titulni strana
class TitulniStranaView(generic.ListView): class TitulniStranaView(generic.ListView):
@ -110,6 +128,63 @@ def sloupec_s_poradim(vysledky):
return poradi_l return poradi_l
def vysledkovka_rocniku(rocnik, jen_verejne=True):
"""Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve
formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html"
"""
#vyberu vsechny vysledky z rocniku
cisla_v_rocniku = VysledkyKCisluZaRocnik.objects.filter(cislo__rocnik=rocnik).order_by('cislo')
if jen_verejne:
cisla_v_rocniku = cisla_v_rocniku.filter(cislo__verejna_vysledkovka=True)
#pokud žádné nejsou, výsledkovka se nezobrazí
if not cisla_v_rocniku:
return None
#vybere vsechny vysledky z posledniho (verejneho) cisla a setridi sestupne dle bodu
vysledky = list(cisla_v_rocniku.filter(cislo = cisla_v_rocniku[0].cislo).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno').select_related('resitel'))
class Vysledkovka:
def __init__(self):
self.radky = []
self.cisla = []
vysledkovka = Vysledkovka()
vysledkovka.cisla = (rocnik.verejne_vysledkovky_cisla() if jen_verejne else rocnik.cisla.all().order_by('cislo'))
# doplníme některé údaje do řádků výsledkovky pro řešitele ve skupině
for poradi, v in zip(sloupec_s_poradim(vysledky), vysledky):
v.poradi = poradi
v.resitel.rocnik = v.resitel.rocnik(rocnik)
verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__rocnik=rocnik, cislo=cisla_v_rocniku[0].cislo)
if jen_verejne:
verejne_vysl_odjakziva = verejne_vysl_odjakziva.filter(cislo__verejna_vysledkovka=True)
v.body_odjakziva = verejne_vysl_odjakziva.filter(resitel = v.resitel)[0].body
v.titul = v.resitel.get_titul(v.body_odjakziva)
v.body_rocnik = v.body
v.body_cisla = []
#pokud pro dany rok a cislo nema resitel vysledky, ma defaultne 0
for cis in vysledkovka.cisla:
if not jen_verejne or cis.verejna_vysledkovka:
#seznam vysledku se spravnym rocnikem a cislem pro resitele
#zobrazim jen je-li vysledkovka verejna
body_za_cislo = VysledkyZaCislo.objects.filter(cislo__rocnik=rocnik).filter(cislo = cis).filter(resitel = v.resitel)
if body_za_cislo:
#neprazdne vysledky by mely obsahovat prave jeden vysledek
v.body_cisla.append(body_za_cislo[0].body)
else:
#resitel nema za cislo body
v.body_cisla.append(0)
vysledkovka.radky.append(v)
return vysledkovka
class RocnikView(generic.DetailView): class RocnikView(generic.DetailView):
model = Rocnik model = Rocnik
template_name = 'seminar/archiv/rocnik.html' template_name = 'seminar/archiv/rocnik.html'
@ -131,46 +206,9 @@ class RocnikView(generic.DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RocnikView, self).get_context_data(**kwargs) context = super(RocnikView, self).get_context_data(**kwargs)
cisla_v_rocniku = VysledkyKCisluZaRocnik.objects.filter(cislo__verejna_vysledkovka = True).filter(cislo__rocnik = context['rocnik']).order_by('cislo') context['vysledkovka'] = vysledkovka_rocniku(context["rocnik"])
#vyberu vsechny verejne vysledky z rocniku context['vysledkovka_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False)
#pokud žádné nejsou, výsledkovka se nezobrazí context['temata_v_rocniku'] = verejna_temata(context["rocnik"])
if cisla_v_rocniku:
vysledky = list(cisla_v_rocniku.filter(cislo = cisla_v_rocniku[0].cislo).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno').select_related('resitel'))
#vybere vsechny vysledky z posledniho verejneho cisla a setridi sestupne dle bodu
vysledkovka = []
# doplníme některé údaje do řádků výsledkovky pro řešitele ve skupině
for poradi, v in zip(sloupec_s_poradim(vysledky), vysledky):
v.poradi = poradi
v.resitel.rocnik = v.resitel.rocnik(context['rocnik'])
verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__verejna_vysledkovka = True).filter(cislo__rocnik = context['rocnik']).filter(cislo = cisla_v_rocniku[0].cislo)
v.body_odjakziva = verejne_vysl_odjakziva.filter(resitel = v.resitel)[0].body
v.titul = v.resitel.get_titul(v.body_odjakziva)
v.body_rocnik = v.body
v.body_cisla = []
#pokud pro dany rok a cislo nema resitel vysledky, ma defaultne 0
for cis in context['rocnik'].verejna_cisla():
if cis.verejna_vysledkovka:
body_za_cislo = VysledkyZaCislo.objects.filter(cislo__rocnik = context['rocnik']).filter(cislo = cis).filter(resitel = v.resitel)
#seznam vysledku se spravnym rocnikem a cislem pro resitele
#zobrazim jen je-li vysledkovka verejna
if body_za_cislo:
v.body_cisla.append(body_za_cislo[0].body)
#neprazdne vysledky by mely obsahovat prave jeden vysledek
else:
v.body_cisla.append(0)
#resitel nema za cislo body
vysledkovka.append(v)
context['vysledkovka'] = vysledkovka
temata_v_rocniku = Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=context['rocnik']).order_by('kod')
context['temata_v_rocniku'] = temata_v_rocniku
return context return context
@ -227,7 +265,7 @@ class CisloView(generic.DetailView):
resene_problemy = Problem.objects.filter(cislo_reseni=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('cislo_zadani__cislo', 'kod') resene_problemy = Problem.objects.filter(cislo_reseni=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('cislo_zadani__cislo', 'kod')
problemy = sorted(list(set([r.problem for r in reseni])), key=lambda x:(0 if x.typ==Problem.TYP_ULOHA else 1, x.kod_v_rocniku)) problemy = sorted(set(r.problem for r in reseni), key=lambda x:(0 if x.typ==Problem.TYP_ULOHA else 1, x.kod_v_rocniku()))
#setridi problemy podle typu a poradi zadani #setridi problemy podle typu a poradi zadani
problem_index = {} problem_index = {}
for i in range(len(problemy)): for i in range(len(problemy)):

Loading…
Cancel
Save