Merge remote-tracking branch 'origin/master' into stable
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
Normal file
|
@ -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
Normal file
|
@ -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
|
|
@ -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 = (
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
mamweb/static/images/header-bg-archiv.jpg
Normal file
After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 400 KiB |
BIN
mamweb/static/images/header-bg-clanek-NOC.jpg
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
mamweb/static/images/header-bg-clanek.jpg
Normal file
After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 519 KiB |
BIN
mamweb/static/images/header-bg-odevzdat-NOC.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
mamweb/static/images/header-bg-soustredeni-NOC.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
mamweb/static/images/header-bg-soustredeni.jpg
Normal file
After Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 562 KiB |
BIN
mamweb/static/images/header-bg-uvod-NOC.jpg
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
mamweb/static/images/header-bg-uvod.jpg
Normal file
After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 512 KiB |
BIN
mamweb/static/images/header-bg-zadani-NOC.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
mamweb/static/images/header-bg-zadani.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 456 KiB |
BIN
mamweb/static/images/header-bg.jpg
Normal file
After Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 679 KiB |
19
mamweb/templates/400.html
Normal file
|
@ -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
Normal file
|
@ -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 %}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
{% endblock %}{% endblock %}
|
{% endblock %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{{ flatpage.content }}
|
{{ flatpage.content }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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()
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
Normal file
|
@ -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 má 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
Normal file
|
@ -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
Normal file
|
@ -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,
|
||||||
|
),
|
||||||
|
]
|
|
@ -83,7 +83,7 @@ class Skola(SeminarModelBase):
|
||||||
kratky_nazev = models.CharField(u'zkrácený název', max_length=256, blank=True,
|
kratky_nazev = models.CharField(u'zkrácený název', max_length=256, blank=True,
|
||||||
help_text="Zkrácený název pro zobrazení ve výsledkovce")
|
help_text="Zkrácený název pro zobrazení ve výsledkovce")
|
||||||
|
|
||||||
# Ulice může být jen číslo
|
# Ulice může být jen číslo
|
||||||
ulice = models.CharField(u'ulice', max_length=256)
|
ulice = models.CharField(u'ulice', max_length=256)
|
||||||
|
|
||||||
mesto = models.CharField(u'město', max_length=256)
|
mesto = models.CharField(u'město', max_length=256)
|
||||||
|
@ -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)
|
||||||
|
@ -161,7 +161,7 @@ class Resitel(SeminarModelBase):
|
||||||
]
|
]
|
||||||
zasilat = models.CharField(u'kam zasílat', max_length=32, choices=ZASILAT_CHOICES, blank=False, default=ZASILAT_DOMU)
|
zasilat = models.CharField(u'kam zasílat', max_length=32, choices=ZASILAT_CHOICES, blank=False, default=ZASILAT_DOMU)
|
||||||
|
|
||||||
# Ulice může být i jen číslo
|
# Ulice může být i jen číslo
|
||||||
ulice = models.CharField(u'ulice', max_length=256, blank=True, default='')
|
ulice = models.CharField(u'ulice', max_length=256, blank=True, default='')
|
||||||
|
|
||||||
mesto = models.CharField(u'město', max_length=256, blank=True, default='')
|
mesto = models.CharField(u'město', max_length=256, blank=True, default='')
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -447,18 +447,19 @@ class Problem(SeminarModelBase):
|
||||||
|
|
||||||
# Staré (do 2014) ID problému z DAKOSU -- jen u importovaných záznamů
|
# Staré (do 2014) ID problému z DAKOSU -- jen u importovaných záznamů
|
||||||
import_dakos_id = models.CharField(u'importované ID s typem', max_length=32, blank=True, default='',
|
import_dakos_id = models.CharField(u'importované ID s typem', max_length=32, blank=True, default='',
|
||||||
help_text=(u'ID z importu z DAKOSU s prefixem podle původu: "AZAD:xxx (MAMOPER.MM_AZAD), "' +
|
help_text=(u'ID z importu z DAKOSU s prefixem podle původu: "AZAD:xxx (MAMOPER.MM_AZAD), "' +
|
||||||
u'"DOZ:xxx" (MAMOPER.MM_DOZ), "ZAD:rocnik.cislo.uloha.typ" (MAMOPER.MM_ZADANIA), "ULOHA:xxx" (MAMOPER.MM_ULOHY)'))
|
u'"DOZ:xxx" (MAMOPER.MM_DOZ), "ZAD:rocnik.cislo.uloha.typ" (MAMOPER.MM_ZADANIA), "ULOHA:xxx" (MAMOPER.MM_ULOHY)'))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
Aktivní v letech {{org.organizuje_od_roku | default:"?" }}–{{org.organizuje_do_roku | default:"?" }}
|
Aktivní v letech {{org.organizuje_od_roku | default:"?" }}–{{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
Normal file
|
@ -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
Normal file
|
@ -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 %}
|
|
@ -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í? #}
|
||||||
|
|
|
@ -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)):
|
||||||
|
|