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
|
||||
PYTHON=python2.7
|
||||
VE_VER=12.0.7
|
||||
VE_VER=13.1.2
|
||||
LOCAL_PYTHON=bin/python
|
||||
|
||||
all: install
|
||||
|
@ -17,7 +17,7 @@ make_env: ${LOCAL_PYTHON}
|
|||
|
||||
# phony, but fast repeated execution
|
||||
install_packages: make_env
|
||||
bin/pip install -r requirements.txt
|
||||
bin/pip install -r requirements.txt --upgrade
|
||||
|
||||
# phony
|
||||
clean_env:
|
||||
|
@ -35,12 +35,13 @@ ${LOCAL_PYTHON}: virtualenv
|
|||
virtualenv:
|
||||
curl -O https://pypi.python.org/packages/source/v/virtualenv/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
|
||||
|
||||
# phony
|
||||
clean_virtualenv:
|
||||
rm -rf virtualenv/
|
||||
rm -rf virtualenv-*.tar.gz
|
||||
|
||||
run:
|
||||
./manage.py runserver_plus
|
||||
|
@ -60,21 +61,24 @@ schema_all.pdf:
|
|||
|
||||
# Deploy to current *mamweb-test* directory
|
||||
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 ..."
|
||||
git pull origin master
|
||||
git clean -f
|
||||
make install
|
||||
./manage.py migrate
|
||||
./manage.py collectstatic --noinput
|
||||
(chown -Rf :mam . || true )
|
||||
(chmod -Rf g+w . || true )
|
||||
(chown -R :mam . || true )
|
||||
(chmod -R g+rX,go-w . || true )
|
||||
@echo Notifying apache about the change ...
|
||||
touch mamweb/wsgi.py
|
||||
@echo Done.
|
||||
|
||||
# Deploy to current *mamweb-prod* directory
|
||||
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 ..."
|
||||
( cd .. && ./backup_prod_db.sh )
|
||||
@echo "Installing version from origin/stable ..."
|
||||
|
@ -83,8 +87,9 @@ deploy_prod:
|
|||
make install
|
||||
./manage.py migrate
|
||||
./manage.py collectstatic --noinput
|
||||
(chown -Rf :mam . || true )
|
||||
(chmod -Rf g+w . || true )
|
||||
(chown -R :mam . || true )
|
||||
(chmod -R g+rX,go-w . || true )
|
||||
@echo Notifying apache about the change ...
|
||||
touch mamweb/wsgi.py
|
||||
@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.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'mamweb.middleware.LoggedInHintCookieMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
|
@ -78,6 +79,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
|||
'django.core.context_processors.tz',
|
||||
'sekizai.context_processors.sekizai',
|
||||
'django.core.context_processors.static',
|
||||
'mamweb.context_processors.vzhled',
|
||||
)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
|
|
|
@ -47,12 +47,18 @@ import os
|
|||
|
||||
SERVER_EMAIL = 'mamweb-prod-errors@mam.mff.cuni.cz'
|
||||
ADMINS = [
|
||||
('Tomas Gavenciak', 'gavento@ucw.cz'),
|
||||
('Petr Pecha', 'nejlepsitextovyeditorjevim@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 = {
|
||||
# 'version': 1,
|
||||
# 'disable_existing_loggers': True,
|
||||
|
|
|
@ -25,11 +25,11 @@ INSTALLED_APPS += (
|
|||
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!
|
||||
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
|
||||
# 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 {
|
||||
position: relative;
|
||||
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;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
#header.cojemam { background-image: url("../images/header-bg-uvod.png"); }
|
||||
#header.soustredeni { background-image: url("../images/header-bg-soustredeni.png"); }
|
||||
#header.zadani { background-image: url("../images/header-bg-zadani.png"); }
|
||||
#header.clanky { background-image: url("../images/header-bg-clanek.png"); }
|
||||
#header.archiv { background-image: url("../images/header-bg-archiv.png"); }
|
||||
|
||||
#header.cojemam { background-image: url("../images/header-bg-uvod.jpg"); }
|
||||
#header.soustredeni { background-image: url("../images/header-bg-soustredeni.jpg"); }
|
||||
#header.zadani { background-image: url("../images/header-bg-zadani.jpg"); }
|
||||
#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 {
|
||||
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='col-md-12'>
|
||||
<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' %}" />
|
||||
<!--<h1>{% block nadpis1b %}Nadpis 1. úrovně{% endblock %}</h1>-->
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
{% endblock %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
{{ flatpage.content }}
|
||||
</div>
|
||||
|
|
|
@ -19,8 +19,6 @@ urlpatterns = patterns('',
|
|||
url(r'^comments_dj/', include('django_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.
|
||||
|
|
|
@ -7,11 +7,22 @@ For more information on this file, see
|
|||
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")
|
||||
|
||||
sys.path.append(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__), '..')))
|
||||
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
|
||||
|
||||
psycopg2==2.6
|
||||
html5lib==0.999
|
||||
ipython==3.0.0
|
||||
Pillow==2.7.0
|
||||
psycopg2==2.6.1
|
||||
html5lib==0.9999999
|
||||
ipython==4.0.0
|
||||
Pillow==2.9.0
|
||||
pytz==2014.10
|
||||
six==1.9.0
|
||||
pexpect==3.3
|
||||
traitlets==4.0.0
|
||||
|
||||
# Django and modules
|
||||
|
||||
Django==1.7.8
|
||||
Django==1.7.10 # Updatable to 1.8 (possibly incompatible)
|
||||
django-bootstrap-sass==0.0.6a0
|
||||
django-mptt==0.7.3
|
||||
django-reversion==1.8.6
|
||||
django-reversion==1.9.3
|
||||
django-sekizai==0.8.1
|
||||
django-countries==3.2
|
||||
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-taggit==0.14.0
|
||||
django-autocomplete-light==2.1.1
|
||||
django-taggit==0.17
|
||||
django-autocomplete-light==2.2.6
|
||||
django-crispy-forms==1.4.0
|
||||
|
||||
# Comments
|
||||
|
@ -30,9 +32,9 @@ django-contrib-comments==1.6.1
|
|||
|
||||
# debug tools/extensions
|
||||
|
||||
django-debug-toolbar==1.3.0
|
||||
django-extensions==1.5.3
|
||||
sqlparse==0.1.15
|
||||
django-debug-toolbar==1.3.2
|
||||
django-extensions==1.5.6
|
||||
sqlparse==0.1.16
|
||||
Werkzeug==0.10.4
|
||||
|
||||
# G+, FB authorisation
|
||||
|
|
|
@ -9,10 +9,26 @@ from ckeditor.widgets import CKEditorWidget
|
|||
from django.db.models import Count
|
||||
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
|
||||
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):
|
||||
u"""
|
||||
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
|
||||
|
||||
#TODO: Autocomplete autor/opravovatel
|
||||
|
||||
class ProblemAdminForm(forms.ModelForm):
|
||||
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_org = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Problem, 'text_org'))
|
||||
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:
|
||||
model = Problem
|
||||
exclude = []
|
||||
|
@ -302,13 +319,16 @@ class ProblemAdmin(reversion.VersionAdmin):
|
|||
return obj.pocet_reseni
|
||||
|
||||
class ProblemNavrhAdmin(ProblemAdmin):
|
||||
list_display = ['nazev', 'typ', 'stav', 'autor', 'timestamp']
|
||||
list_filter = ['typ', 'stav', 'timestamp']
|
||||
list_display = ['nazev', 'typ', 'zamereni', 'stav', 'autor', 'timestamp']
|
||||
list_filter = ['typ', 'zamereni', 'timestamp', 'stav']
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(ProblemNavrhAdmin, self).get_queryset(request)
|
||||
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)')
|
||||
|
||||
class ProblemZadanyAdmin(ProblemAdmin):
|
||||
|
@ -320,6 +340,8 @@ class ProblemZadanyAdmin(ProblemAdmin):
|
|||
qs = super(ProblemZadanyAdmin, self).get_queryset(request)
|
||||
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é)')
|
||||
|
||||
#admin.site.register(Problem, ProblemAdmin)
|
||||
|
@ -356,6 +378,8 @@ admin.site.register(Soustredeni, SoustredeniAdmin)
|
|||
class NovinkyAdminForm(forms.ModelForm):
|
||||
text = forms.CharField(widget=CKEditorWidget(), required=False,
|
||||
**field_labels(Novinky, 'text'))
|
||||
autor = UserModelChoiceField(User.objects.filter(is_staff=True))
|
||||
|
||||
class Meta:
|
||||
model = Novinky
|
||||
exclude = []
|
||||
|
@ -380,13 +404,7 @@ class NovinkyAdmin(admin.ModelAdmin):
|
|||
list_display = ['datum', 'autor', 'text', 'zverejneno', 'obrazek']
|
||||
actions = [zverejnit_novinky, zneverejnit_novinky]
|
||||
|
||||
# předvyplnění přihlášeného uživatele jako autora novinky
|
||||
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
|
||||
)
|
||||
get_form = get_form_predvypln_autora
|
||||
|
||||
|
||||
admin.site.register(Novinky, NovinkyAdmin)
|
||||
|
|
|
@ -77,7 +77,13 @@ class ProblemAutocomplete(autocomplete_light.AutocompleteModelBase):
|
|||
|
||||
def choice_label(self, p):
|
||||
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:
|
||||
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,
|
||||
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)
|
||||
|
||||
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)
|
||||
# Ekvivalentní s CharField(max_length=2, 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?
|
||||
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)
|
||||
|
||||
# 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='')
|
||||
|
||||
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)
|
||||
|
||||
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,
|
||||
help_text=u'Datum vydání finální verze')
|
||||
|
@ -349,7 +349,7 @@ class Cislo(SeminarModelBase):
|
|||
kod.short_description = u'Kód čísla'
|
||||
|
||||
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)
|
||||
return force_unicode(u'%s.%s' % (r.rocnik, self.cislo, ))
|
||||
|
||||
|
@ -403,7 +403,7 @@ class Problem(SeminarModelBase):
|
|||
(TYP_TEMA, u'Téma'),
|
||||
(TYP_SERIAL, u'Seriál'),
|
||||
(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)
|
||||
|
||||
|
@ -447,18 +447,19 @@ class Problem(SeminarModelBase):
|
|||
|
||||
# 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='',
|
||||
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)'))
|
||||
|
||||
def __str__(self):
|
||||
return force_unicode(u'%s' % (self.nazev, ))
|
||||
|
||||
def kod_v_rocniku(self):
|
||||
if self.typ == self.TYP_ULOHA:
|
||||
return force_unicode(u"%s.u%s" % (self.cislo_zadani.cislo, self.kod,))
|
||||
if self.typ == self.TYP_TEMA:
|
||||
return force_unicode(u"t%s" % (self.kod,))
|
||||
return ''
|
||||
if self.stav == 'zadany':
|
||||
if self.typ == self.TYP_ULOHA:
|
||||
return force_unicode(u"%s.u%s" % (self.cislo_zadani.cislo, self.kod,))
|
||||
if self.typ == self.TYP_TEMA:
|
||||
return force_unicode(u"t%s" % (self.kod,))
|
||||
return ' Není zadaný '
|
||||
|
||||
def nazev_typu(self):
|
||||
return dict(self.TYP_CHOICES)[self.typ]
|
||||
|
@ -771,8 +772,11 @@ class Organizator(models.Model):
|
|||
null = True, blank = True)
|
||||
organizuje_do_roku = models.IntegerField('Organizuje do roku',
|
||||
null = True, blank = True)
|
||||
studuje = models.CharField('Studuje', max_length = 256,
|
||||
null = True, blank = True)
|
||||
studuje = models.CharField('Studium aj.', max_length = 256,
|
||||
null = True, blank = True,
|
||||
help_text="Např. 'Studuje Obecnou fyziku (Bc.), 3. ročník', "
|
||||
"'Vystudovala Diskrétní modely a algoritmy (Mgr.)' nebo "
|
||||
"'Přednáší na MFF'")
|
||||
strucny_popis_organizatora = models.TextField('Stručný popis organizátora',
|
||||
null = True, blank = True)
|
||||
foto = models.ImageField('Fotografie organizátora',
|
||||
|
@ -789,11 +793,14 @@ class Organizator(models.Model):
|
|||
verbose_name_plural = 'Organizátoři'
|
||||
|
||||
def save(self):
|
||||
if self.id is not None:
|
||||
puvodni = Organizator.objects.get(id=self.id)
|
||||
if self.foto:
|
||||
original = Image.open(self.foto)
|
||||
jmeno = os.path.basename(self.foto.file.name)
|
||||
Organizator._vyrobMiniaturu(original, jmeno, 500, self.foto)
|
||||
Organizator._vyrobMiniaturu(original, jmeno, 200, self.foto_male)
|
||||
if not puvodni or puvodni.foto != self.foto:
|
||||
original = Image.open(self.foto)
|
||||
jmeno = os.path.basename(self.foto.file.name)
|
||||
Organizator._vyrobMiniaturu(original, jmeno, 500, self.foto)
|
||||
Organizator._vyrobMiniaturu(original, jmeno, 200, self.foto_male)
|
||||
super(Organizator, self).save()
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -29,38 +29,17 @@
|
|||
{% endif %}
|
||||
|
||||
{% if vysledkovka %}
|
||||
<h3>Výsledkovka</h3>
|
||||
<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 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
|
||||
<h3>Výsledková listina</h3>
|
||||
{% include "seminar/vysledkovka_rocnik.html" %}
|
||||
{% endif %}
|
||||
|
||||
{% for rv in vysledkovka %}
|
||||
<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>
|
||||
{% if user.is_staff and vysledkovka_s_neverejnymi %}
|
||||
<div class='mam-org-only'>
|
||||
<h3>Výsledková listina včetně neveřejných bodů</h3>
|
||||
{% with vysledkovka_s_neverejnymi as vysledkovka %}
|
||||
{% include "seminar/vysledkovka_rocnik.html" %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
Aktivní v letech {{org.organizuje_od_roku | default:"?" }}–{{org.organizuje_do_roku | default:"?" }}
|
||||
{% endif %}
|
||||
{% if org.studuje %}
|
||||
<li>Studuje: {{org.studuje}}
|
||||
<li>{{org.studuje}}
|
||||
{% endif %}
|
||||
{% if org.user.email %}
|
||||
<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 %}
|
||||
<div class="zadani_azad_termin">
|
||||
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>
|
||||
{% endif %}
|
||||
{#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/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'^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
|
||||
|
||||
|
||||
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):
|
||||
nastaveni = get_object_or_404(Nastaveni)
|
||||
problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany')
|
||||
ulohy = problemy.filter(typ = 'uloha').order_by('kod')
|
||||
serialy = problemy.filter(typ = 'serial').order_by('kod')
|
||||
temata = problemy.filter(typ = 'tema').order_by('kod')
|
||||
jednorazove_problemy = [ulohy, serialy]
|
||||
return render(request, 'seminar/zadani/AktualniZadani.html',
|
||||
{'nastaveni': nastaveni,
|
||||
'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)
|
||||
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
|
||||
|
||||
class TitulniStranaView(generic.ListView):
|
||||
|
@ -110,6 +128,63 @@ def sloupec_s_poradim(vysledky):
|
|||
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):
|
||||
model = Rocnik
|
||||
template_name = 'seminar/archiv/rocnik.html'
|
||||
|
@ -131,46 +206,9 @@ class RocnikView(generic.DetailView):
|
|||
def get_context_data(self, **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')
|
||||
#vyberu vsechny verejne vysledky z rocniku
|
||||
#pokud žádné nejsou, výsledkovka se nezobrazí
|
||||
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
|
||||
context['vysledkovka'] = vysledkovka_rocniku(context["rocnik"])
|
||||
context['vysledkovka_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False)
|
||||
context['temata_v_rocniku'] = verejna_temata(context["rocnik"])
|
||||
|
||||
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')
|
||||
|
||||
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
|
||||
problem_index = {}
|
||||
for i in range(len(problemy)):
|
||||
|
|