Browse Source

Merge branch 'master' of atrey.karlin.mff.cuni.cz:/akce/MaM/MaMweb/mamweb

remotes/origin/vysl deploy-test-2015-07-05-21-52-xlfd
Jan Musílek 9 years ago
parent
commit
78f97835d1
  1. 2
      Makefile
  2. 12
      dakosdump/README.md
  3. 2
      mamweb/settings_common.py
  4. 2
      mamweb/templates/menu.html
  5. 2
      mamweb/urls.py
  6. 74
      seminar/admin.py
  7. 148
      seminar/export.py
  8. 32
      seminar/migrations/0019_rocnik_ciselne.py
  9. 44
      seminar/migrations/0020_indexy_a_razeni.py
  10. 20
      seminar/migrations/0021_cislo_verejna_vysledkovka.py
  11. 30
      seminar/migrations/0022_decimal_body.py
  12. 32
      seminar/migrations/0023_add_novinky.py
  13. 35
      seminar/migrations/0024_add_organizator.py
  14. 20
      seminar/migrations/0025_zmena_cesty_nahravani_obrazku.py
  15. 157
      seminar/models.py
  16. 15
      seminar/ovvpfile.py
  17. 10
      seminar/templates/seminar/archiv/cislo.html
  18. 36
      seminar/templates/seminar/cojemam/organizatori.html
  19. 2
      seminar/templates/seminar/export_index.csv
  20. 11
      seminar/templates/seminar/export_rocnik.csv
  21. 45
      seminar/templates/seminar/soustredeni/seznam_soustredeni.html
  22. 17
      seminar/tests.py
  23. 10
      seminar/testutils.py
  24. 10
      seminar/urls.py
  25. 63
      seminar/views.py

2
Makefile

@ -86,7 +86,7 @@ push_test:
(chown -Rf :mam . || true ) && \ (chown -Rf :mam . || true ) && \
(chmod -Rf g+w . || true ) && \ (chmod -Rf g+w . || true ) && \
echo 'Reloading apache ... (You may have to start it manually on error!)' && \ echo 'Reloading apache ... (You may have to start it manually on error!)' && \
~/etc/apache2/apache2ctl -k reload && \ ~/etc/apache2/apache2ctl -k restart && \
echo Done." echo Done."
@echo "Test pushed to ${TEST_SERVER}:${TEST_DIR} successfully." @echo "Test pushed to ${TEST_SERVER}:${TEST_DIR} successfully."

12
dakosdump/README.md

File diff suppressed because one or more lines are too long

2
mamweb/settings_common.py

@ -25,7 +25,7 @@ APPEND_SLASH = False
LANGUAGE_CODE = 'cs' LANGUAGE_CODE = 'cs'
TIME_ZONE = 'Europe/Prague' TIME_ZONE = 'Europe/Prague'
USE_I18N = False USE_I18N = True
USE_L10N = True USE_L10N = True
USE_TZ = True USE_TZ = True

2
mamweb/templates/menu.html

@ -3,7 +3,7 @@
<ul> <ul>
<li><a href="/co-je-MaM/uvod/">Co je M&amp;M</a> <li><a href="/co-je-MaM/uvod/">Co je M&amp;M</a>
<li><a href="/soustredeni/uvod/">Soustředění</a> <li><a href="{% url 'seminar_seznam_soustredeni' %}">Soustředění</a>
<li><a href="/zadani/aktualni/">Zadání</a> <li><a href="/zadani/aktualni/">Zadání</a>
<li><a href="/clanky/uvod/">Články</a> <li><a href="/clanky/uvod/">Články</a>
<li><a href="/archiv/cisla/">Archiv</a> <li><a href="/archiv/cisla/">Archiv</a>

2
mamweb/urls.py

@ -5,7 +5,7 @@ from django.contrib import admin
from django.conf import settings from django.conf import settings
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
urlpatterns = i18n_patterns('', urlpatterns = patterns('',
# Admin a nastroje # Admin a nastroje
url(r'^admin/', include(admin.site.urls)), # NOQA url(r'^admin/', include(admin.site.urls)), # NOQA

74
seminar/admin.py

@ -8,7 +8,7 @@ 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 seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Novinky, Organizator
import autocomplete_light import autocomplete_light
@ -177,10 +177,11 @@ admin.site.register(Skola, SkolaAdmin)
class CisloAdmin(reversion.VersionAdmin): class CisloAdmin(reversion.VersionAdmin):
fieldsets = [ fieldsets = [
(None, {'fields': ['cislo', 'rocnik', 'verejne_db', 'poznamka']}), (None, {'fields': ['cislo', 'rocnik', 'verejne_db', 'verejna_vysledkovka', 'poznamka']}),
(u'Data', {'fields': ['datum_vydani', 'datum_deadline']}), (u'Data', {'fields': ['datum_vydani', 'datum_deadline']}),
] ]
list_display = ['kod', 'rocnik', 'cislo', 'datum_vydani', 'datum_deadline', 'verejne'] list_display = ['kod', 'rocnik', 'cislo', 'datum_vydani', 'datum_deadline', 'verejne']
list_display = ['kod', 'rocnik', 'cislo', 'datum_vydani', 'datum_deadline', 'verejna_vysledkovka']
list_filter = ['rocnik'] list_filter = ['rocnik']
view_on_site = Cislo.verejne_url view_on_site = Cislo.verejne_url
def get_queryset(self, request): def get_queryset(self, request):
@ -284,7 +285,7 @@ create_modeladmin(ProblemNavrhAdmin, Problem, 'ProblemNavrh', verbose_name=u'Pro
class ProblemZadanyAdmin(ProblemAdmin): class ProblemZadanyAdmin(ProblemAdmin):
list_display = ['nazev', 'typ', 'autor', 'opravovatel', 'kod', 'cislo_zadani', 'pocet_reseni', 'verejne'] list_display = ['nazev', 'typ', 'autor', 'opravovatel', 'kod', 'cislo_zadani', 'pocet_reseni', 'verejne']
list_filter = ['typ', 'cislo_zadani__rocnik'] list_filter = ['typ', 'cislo_zadani__cislo', 'cislo_zadani__rocnik']
inlines = [ReseniKProblemuInline] inlines = [ReseniKProblemuInline]
def get_queryset(self, request): def get_queryset(self, request):
@ -297,6 +298,18 @@ create_modeladmin(ProblemZadanyAdmin, Problem, 'ProblemZadany', verbose_name=u'P
### Soustredeni ### Soustredeni
def zverejnit_soustredeni(modeladmin, request, queryset):
for soustredeni in queryset:
soustredeni.verejne_db = True
soustredeni.save()
zverejnit_soustredeni.short_description = 'Zveřejnit soustředění'
def skryt_soustredeni(modeladmin, request, queryset):
for soustredeni in queryset:
soustredeni.verejne_db = False
soustredeni.save()
skryt_soustredeni.short_description = 'Skrýt soustředění (Zneveřjnit)'
class SoustredeniAdminForm(forms.ModelForm): class SoustredeniAdminForm(forms.ModelForm):
text = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Soustredeni, 'text')) text = forms.CharField(widget=CKEditorWidget(), required=False, **field_labels(Soustredeni, 'text'))
class Meta: class Meta:
@ -313,6 +326,61 @@ class SoustredeniAdmin(reversion.VersionAdmin):
inlines = [Soustredeni_UcastniciInline] inlines = [Soustredeni_UcastniciInline]
list_filter = ['rocnik'] list_filter = ['rocnik']
view_on_site = Soustredeni.verejne_url view_on_site = Soustredeni.verejne_url
actions = [zverejnit_soustredeni, skryt_soustredeni, ]
admin.site.register(Soustredeni, SoustredeniAdmin) admin.site.register(Soustredeni, SoustredeniAdmin)
### Novinky
class NovinkyAdminForm(forms.ModelForm):
text = forms.CharField(widget=CKEditorWidget(), required=False,
**field_labels(Novinky, 'text'))
class Meta:
model = Novinky
exclude = []
class NovinkyAdmin(admin.ModelAdmin):
form = NovinkyAdminForm
admin.site.register(Novinky, NovinkyAdmin)
### Organizator
def jmeno_organizatora(obj):
''' vraci jmeno organizatora '''
jmeno = obj.user.first_name
if obj.prezdivka:
jmeno = jmeno + ' "' + obj.prezdivka + '"'
jmeno = jmeno + ' ' + obj.user.last_name
if jmeno == ' ': # zobrazeni bezejmennych orgu
return 'org'
return jmeno
jmeno_organizatora.short_description = 'Jméno organizátora'
def je_organizator_aktivni(obj):
''' zjisti, zda-li je organizator aktivni '''
return obj.user.is_active
je_organizator_aktivni.short_description = 'Aktivní'
je_organizator_aktivni.boolean = True
def zaktivovat_organizatory(modeladmin, request, queryset):
''' vybrane organizatory oznaci jako aktivni '''
for org in queryset:
org.user.is_active = True
org.user.save()
zaktivovat_organizatory.short_description = 'Zaktivovat organizátory'
def deaktivovat_organizatory(modeladmin, request, queryset):
''' deaktivuje vybrane organizatory '''
for org in queryset:
org.user.is_active = False
org.user.save()
deaktivovat_organizatory.short_description = 'Deaktivovat organizátory'
@admin.register(Organizator)
class OrganizatorAdmin(admin.ModelAdmin):
list_filter = ['organizuje_do_roku']
list_display = [jmeno_organizatora, je_organizator_aktivni,]
actions = [zaktivovat_organizatory, deaktivovat_organizatory,]

148
seminar/export.py

@ -1,80 +1,92 @@
import datetime import datetime, django
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect from django.http import HttpResponse
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.views import generic from django.views import generic
from .models import Problem, Cislo, Reseni, VysledkyKCislu, Nastaveni, Rocnik from django.utils.encoding import force_text
class ExportIndexView(generic.base.TemplateView): from .models import Problem, Cislo, Reseni, VysledkyKCislu, Nastaveni, Rocnik, Soustredeni
template_name = 'seminar/export_index.csv' from .ovvpfile import OvvpFile
content_type = 'text/plain; charset=utf-8'
def get_context_data(self, **kwargs): class ExportIndexView(generic.View):
context = super(ExportIndexView, self).get_context_data(**kwargs) def get(self, request):
context['exports'] = []
ls = []
for r in Rocnik.objects.all(): for r in Rocnik.objects.all():
if r.verejna_cisla(): if r.verejna_cisla():
url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok}) url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok})
context['exports'].append(url.split('/')[-1]) ls.append(url.split('/')[-1])
return context for s in Soustredeni.objects.all():
if s.ucastnici.count() >= 1 and s.verejne:
url = reverse('seminar_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()})
ls.append(url.split('/')[-1])
return HttpResponse('\n'.join(ls) + '\n', content_type='text/plain; charset=utf-8')
class ExportRocnikView(generic.DetailView):
slug_field = 'prvni_rok'
slug_url_kwarg = 'prvni_rok'
model = Rocnik
template_name = 'seminar/export_rocnik.csv'
content_type = 'text/plain; charset=utf-8'
def get_context_data(self, **kwargs):
context = super(ExportRocnikView, self).get_context_data(**kwargs)
rocnik = context['rocnik'] def default_ovvpfile(event, rocnik):
cislo = rocnik.posledni_verejne_cislo() of = OvvpFile()
sloupce = ['id', 'name', 'surname', of.headers['version'] = '1'
'gender', 'born', 'email', 'end-year', of.headers['event'] = event
'street', 'town', 'postcode', 'country', of.headers['year'] = force_text(rocnik.prvni_rok)
'spam-flag', 'spam-date', 'school', 'school-name', of.headers['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'points', 'rank',] of.headers['id-scope'] = 'mam'
radky = [] of.headers['id-generation'] = '1'
return of
class ExportSousView(generic.View):
def get(self, request, datum_zacatku=None):
try:
dz = django.utils.dateparse.parse_date(datum_zacatku)
except:
dz = None
if dz is None:
raise django.http.Http404()
s = get_object_or_404(Soustredeni, datum_zacatku=dz)
of = default_ovvpfile('MaM.sous', s.rocnik)
of.headers['x-event-begin'] = s.datum_zacatku.isoformat()
of.headers['x-event-end'] = s.datum_konce.isoformat()
of.headers['x-event-location'] = s.misto
of.headers['comment'] = u'MaM-Web export ucastniku soustredeni v {x-event-location} od {x-event-begin} do {x-event-end}'.format(**of.headers)
of.columns = ['id', 'name', 'surname', 'gender', 'email', 'end-year', 'school', 'school-name']
for u in s.ucastnici.all():
of.rows.append(u.export_row())
return of.to_HttpResponse()
class ExportRocnikView(generic.View):
def get(self, request, prvni_rok=None):
try:
pr = int(prvni_rok)
except:
pr = None
if pr is None:
raise django.http.Http404()
rocnik = get_object_or_404(Rocnik, prvni_rok=pr)
cislo = rocnik.posledni_verejne_cislo()
vysledky = VysledkyKCislu.objects.filter(cislo = cislo).select_related("resitel").order_by('-body_celkem').all() vysledky = VysledkyKCislu.objects.filter(cislo = cislo).select_related("resitel").order_by('-body_celkem').all()
of = default_ovvpfile('MaM.rocnik', rocnik)
of.headers['comment'] = u'MaM-Web export aktivnich resitelu rocniku {rocnik} do cisla {cislo}'.format(
rocnik=rocnik, cislo=cislo)
of.columns = ['id', 'name', 'surname', 'gender', 'born', 'email', 'end-year',
'street', 'town', 'postcode', 'country', 'spam-flag', 'spam-date',
'school', 'school-name', 'points', 'rank',]
posledni_body = 100000 posledni_body = 100000
posledni_poradi = 0 posledni_poradi = 0
for vi in range(len(vysledky)): for vi in range(len(vysledky)):
v = vysledky[vi] v = vysledky[vi]
rd = {} rd = v.resitel.export_row()
rd['name'] = v.resitel.jmeno
rd['surname'] = v.resitel.prijmeni
rd['id'] = v.resitel.id
rd['gender'] = 'M' if v.resitel.pohlavi_muz else 'F'
if v.resitel.datum_narozeni:
rd['born'] = v.resitel.datum_narozeni.strftime("%Y-%m-%d")
else:
rd['born'] = ''
rd['email'] = v.resitel.email
rd['end-year'] = v.resitel.rok_maturity
# TODO(gavento): Adresa skoly, kdyz preferuje zasilani tam?
rd['street'] = v.resitel.ulice
rd['town'] = v.resitel.mesto
rd['postcode'] = v.resitel.psc
rd['country'] = v.resitel.stat
if v.resitel.datum_souhlasu_zasilani:
rd['spam-flag'] = 'Y'
rd['spam-date'] = v.resitel.datum_souhlasu_zasilani.strftime("%Y-%m-%d")
else:
rd['spam-flag'] = ''
rd['spam-date'] = ''
if v.resitel.skola:
rd['school'] = v.resitel.skola.aesop_id
rd['school-name'] = str(v.resitel.skola)
else:
rd['school'] = ''
rd['school-name'] = 'Skola neni znama'
if posledni_body > v.body_celkem: if posledni_body > v.body_celkem:
posledni_body = v.body_celkem posledni_body = v.body_celkem
@ -82,16 +94,8 @@ class ExportRocnikView(generic.DetailView):
rd['rank'] = posledni_poradi rd['rank'] = posledni_poradi
rd['points'] = v.body_celkem rd['points'] = v.body_celkem
r = [] of.rows.append(rd)
for c in sloupce:
r.append(rd.pop(c)) return of.to_HttpResponse()
assert len(rd) == 0
radky.append(r)
context['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
context['cislo'] = cislo
context['sloupce'] = sloupce
context['radky'] = radky
return context

32
seminar/migrations/0019_rocnik_ciselne.py

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0018_problemnavrh_problemzadany'),
]
operations = [
migrations.AddField(
model_name='rocnik',
name='rocnik_n',
field=models.IntegerField(default=0, verbose_name='\u010d\xedslo ro\u010dn\xedku'),
preserve_default=False,
),
migrations.RunSQL(
sql="update seminar_rocniky set rocnik_n = cast (rocnik as integer)"
),
migrations.RemoveField(
model_name='rocnik',
name='rocnik',
),
migrations.RenameField(
model_name='rocnik',
old_name='rocnik_n',
new_name='rocnik',
),
]

44
seminar/migrations/0020_indexy_a_razeni.py

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0019_rocnik_ciselne'),
]
operations = [
migrations.AlterModelOptions(
name='cislo',
options={'ordering': ['-rocnik__rocnik', '-cislo'], 'verbose_name': '\u010c\xedslo', 'verbose_name_plural': '\u010c\xedsla'},
),
migrations.AlterModelOptions(
name='reseni',
options={'ordering': ['problem_id', 'resitel__prijmeni', 'resitel__jmeno'], 'verbose_name': '\u0158e\u0161en\xed', 'verbose_name_plural': '\u0158e\u0161en\xed'},
),
migrations.AlterModelOptions(
name='rocnik',
options={'ordering': ['-rocnik'], 'verbose_name': 'Ro\u010dn\xedk', 'verbose_name_plural': 'Ro\u010dn\xedky'},
),
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\u010dije 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='rocnik',
name='prvni_rok',
field=models.IntegerField(unique=True, verbose_name='prvn\xed rok', db_index=True),
preserve_default=True,
),
migrations.AlterField(
model_name='rocnik',
name='rocnik',
field=models.IntegerField(unique=True, verbose_name='\u010d\xedslo ro\u010dn\xedku', db_index=True),
preserve_default=True,
),
]

20
seminar/migrations/0021_cislo_verejna_vysledkovka.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0020_indexy_a_razeni'),
]
operations = [
migrations.AddField(
model_name='cislo',
name='verejna_vysledkovka',
field=models.BooleanField(default=False, help_text='Je-li false u ve\u0159ejn\xe9ho \u010d\xedsla, nen\xed v\xfdsledkovka zat\xedm ve\u0159ejn\xe1.', verbose_name='zve\u0159ejn\u011bna v\xfdsledkovka'),
preserve_default=True,
),
]

30
seminar/migrations/0022_decimal_body.py

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import importlib
from django.db import models, migrations
migration_0022 = importlib.import_module('seminar.migrations.0002_add_body_views')
print dir(migration_0022)
class Migration(migrations.Migration):
dependencies = [
('seminar', '0021_cislo_verejna_vysledkovka'),
]
operations = [
migrations.RunSQL(migration_0022.DROP_VIEWS),
migrations.AlterField(
model_name='problem',
name='body',
field=models.DecimalField(null=True, verbose_name='maximum bod\u016f', max_digits=8, decimal_places=1, blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='reseni',
name='body',
field=models.DecimalField(null=True, verbose_name='body', max_digits=8, decimal_places=1, blank=True),
preserve_default=True,
),
migrations.RunSQL(migration_0022.CREATE_VIEWS),
]

32
seminar/migrations/0023_add_novinky.py

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('seminar', '0022_decimal_body'),
]
operations = [
migrations.CreateModel(
name='Novinky',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('datum', models.DateField(auto_now_add=True)),
('text', models.TextField(null=True, verbose_name=b'Text novinky', blank=True)),
('obrazek', models.ImageField(upload_to=b'image_novinky/%Y/%m/%d/', null=True, verbose_name=b'Obr\xc3\xa1zek', blank=True)),
('zverejneno', models.BooleanField(default=b'False', verbose_name=b'Zve\xc5\x99ejn\xc4\x9bno')),
('autor', models.ForeignKey(verbose_name=b'Autor novinky', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Novinka',
'verbose_name_plural': 'Novinky',
},
bases=(models.Model,),
),
]

35
seminar/migrations/0024_add_organizator.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('seminar', '0023_add_novinky'),
]
operations = [
migrations.CreateModel(
name='Organizator',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('prezdivka', models.CharField(max_length=32, null=True, verbose_name=b'P\xc5\x99ezd\xc3\xadvka', blank=True)),
('organizuje_od_roku', models.IntegerField(null=True, verbose_name=b'Organizuje od roku', blank=True)),
('organizuje_do_roku', models.IntegerField(null=True, verbose_name=b'Organizuje do roku', blank=True)),
('studuje', models.CharField(max_length=256, null=True, verbose_name=b'Studuje', blank=True)),
('strucny_popis_organizatora', models.TextField(null=True, verbose_name=b'Stru\xc4\x8dn\xc3\xbd popis organiz\xc3\xa1tora', blank=True)),
('foto', models.ImageField(help_text=b'Vlo\xc5\xbe fotografii organiz\xc3\xa1tora o libovon\xc3\xa9 velikosti', upload_to=b'image_organizatori/%Y/', null=True, verbose_name=b'Fotografie organiz\xc3\xa1tora', blank=True)),
('foto_male', models.ImageField(upload_to=b'image_organizatori/male/%Y/', null=True, editable=False, blank=True)),
('user', models.OneToOneField(verbose_name=b'Osoba', to=settings.AUTH_USER_MODEL, help_text=b'Vyber \xc3\xba\xc4\x8det sp\xc5\x99a\xc5\xbeen\xc3\xbd s organiz\xc3\xa1torem.')),
],
options={
'verbose_name': 'Organiz\xe1tor',
'verbose_name_plural': 'Organiz\xe1to\u0159i',
},
bases=(models.Model,),
),
]

20
seminar/migrations/0025_zmena_cesty_nahravani_obrazku.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0024_add_organizator'),
]
operations = [
migrations.AlterField(
model_name='organizator',
name='foto',
field=models.ImageField(help_text=b'Vlo\xc5\xbe fotografii organiz\xc3\xa1tora o libovon\xc3\xa9 velikosti', upload_to=b'image_organizatori/velke/%Y/', null=True, verbose_name=b'Fotografie organiz\xc3\xa1tora', blank=True),
preserve_default=True,
),
]

157
seminar/models.py

@ -12,6 +12,10 @@ from django.utils.text import slugify
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.cache import cache from django.core.cache import cache
from PIL import Image
import os
from cStringIO import StringIO
from django.core.files.base import ContentFile
from django_countries.fields import CountryField from django_countries.fields import CountryField
from solo.models import SingletonModel from solo.models import SingletonModel
@ -29,12 +33,6 @@ class SeminarModelBase(models.Model):
def verejne(self): def verejne(self):
return False return False
# def public_url(self):
# if self.Meta.url_name:
# return reverse(self.Meta.url_name,
# kwargs={'id': self.id, 'pk': self.id})
# return None
def get_absolute_url(self): def get_absolute_url(self):
return self.verejne_url() # TODO "absolute" return self.verejne_url() # TODO "absolute"
@ -188,6 +186,30 @@ class Resitel(SeminarModelBase):
def __str__(self): def __str__(self):
return force_unicode(self.plne_jmeno()) return force_unicode(self.plne_jmeno())
def export_row(self):
"Slovnik pro pouziti v OVVP exportu"
return {
'id': self.id,
'name': self.jmeno,
'surname': self.prijmeni,
'gender': 'M' if self.pohlavi_muz else 'F',
'born': self.datum_narozeni.isoformat() if self.datum_narozeni else '',
'email': self.email,
'end-year': self.rok_maturity,
# TODO(gavento): Adresa skoly, kdyz preferuje zasilani tam?
'street': self.ulice,
'town': self.mesto,
'postcode': self.psc,
'country': self.stat,
'spam-flag': 'Y' if self.datum_souhlasu_zasilani else '',
'spam-date': self.datum_souhlasu_zasilani.isoformat() if self.datum_souhlasu_zasilani else '',
'school': self.skola.aesop_id if self.skola else '',
'school-name': str(self.skola) if self.skola else 'Skola neni znama',
}
@reversion.register(ignore_duplicate_revisions=True) @reversion.register(ignore_duplicate_revisions=True)
@python_2_unicode_compatible @python_2_unicode_compatible
@ -202,18 +224,15 @@ class Rocnik(SeminarModelBase):
# Interní ID # Interní ID
id = models.AutoField(primary_key = True) id = models.AutoField(primary_key = True)
prvni_rok = models.IntegerField(u'první rok') prvni_rok = models.IntegerField(u'první rok', db_index=True, unique=True)
rocnik = models.CharField(u'číslo ročníku', max_length=16) rocnik = models.IntegerField(u'číslo ročníku', db_index=True, unique=True)
def __str__(self): def __str__(self):
return force_unicode(u'%s (%d/%d)' % (self.rocnik, self.prvni_rok, self.prvni_rok+1)) return force_unicode(u'%s (%d/%d)' % (self.rocnik, self.prvni_rok, self.prvni_rok+1))
def roman(self): def roman(self):
if self.rocnik.isdigit(): return force_unicode(roman(int(self.rocnik)))
return force_unicode(roman(int(self.rocnik)))
else:
return force_unicode(self.rocnik)
def verejne(self): def verejne(self):
return len(self.verejna_cisla()) > 0 return len(self.verejna_cisla()) > 0
@ -232,7 +251,7 @@ class Rocnik(SeminarModelBase):
return self.prvni_rok + 1 return self.prvni_rok + 1
def verejne_url(self): def verejne_url(self):
return reverse('seminar_rocnik', kwargs={'pk': self.id}) return reverse('seminar_rocnik', kwargs={'rocnik': self.rocnik})
@classmethod @classmethod
def cached_rocnik(cls, r_id): def cached_rocnik(cls, r_id):
@ -258,9 +277,9 @@ class Cislo(SeminarModelBase):
# Interní ID # Interní ID
id = models.AutoField(primary_key = True) id = models.AutoField(primary_key = True)
rocnik = models.ForeignKey(Rocnik, verbose_name=u'ročník', related_name='cisla') 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, 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čije 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,
@ -271,6 +290,9 @@ class Cislo(SeminarModelBase):
verejne_db = models.BooleanField(u'číslo zveřejněno', db_column='verejne', default=False) verejne_db = models.BooleanField(u'číslo zveřejněno', db_column='verejne', default=False)
verejna_vysledkovka = models.BooleanField(u'zveřejněna výsledkovka', default=False,
help_text=u'Je-li false u veřejného čísla, není výsledkovka zatím veřejná.')
poznamka = models.TextField(u'neveřejná poznámka', blank=True, poznamka = models.TextField(u'neveřejná poznámka', blank=True,
help_text=u'Neveřejná poznámka k číslu (plain text)') help_text=u'Neveřejná poznámka k číslu (plain text)')
@ -288,7 +310,7 @@ class Cislo(SeminarModelBase):
verejne.boolean = True verejne.boolean = True
def verejne_url(self): def verejne_url(self):
return reverse('seminar_cislo', kwargs={'pk': self.id}) return reverse('seminar_cislo', kwargs={'rocnik': self.rocnik.rocnik, 'cislo': self.cislo})
def nasledujici(self): def nasledujici(self):
u"Vrací None, pokud je toto poslední" u"Vrací None, pokud je toto poslední"
@ -370,7 +392,7 @@ class Problem(SeminarModelBase):
cislo_reseni = models.ForeignKey(Cislo, verbose_name=u'číslo řešení', blank=True, null=True, related_name=u'resene_problemy', cislo_reseni = models.ForeignKey(Cislo, verbose_name=u'číslo řešení', blank=True, null=True, related_name=u'resene_problemy',
help_text=u'Číslo s řešením úlohy, jen pro úlohy') help_text=u'Číslo s řešením úlohy, jen pro úlohy')
body = models.IntegerField(u'maximum bodů', blank=True, null=True) body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name=u'maximum bodů', blank=True, null=True)
timestamp = models.DateTimeField(u'vytvořeno', default=timezone.now, blank=True, editable=False) timestamp = models.DateTimeField(u'vytvořeno', default=timezone.now, blank=True, editable=False)
@ -411,7 +433,7 @@ class Reseni(SeminarModelBase):
db_table = 'seminar_reseni' db_table = 'seminar_reseni'
verbose_name = u'Řešení' verbose_name = u'Řešení'
verbose_name_plural = u'Řešení' verbose_name_plural = u'Řešení'
ordering = ['problem_id', 'resitel_id'] ordering = ['problem_id', 'resitel__prijmeni', 'resitel__jmeno',]
# Interní ID # Interní ID
id = models.AutoField(primary_key = True) id = models.AutoField(primary_key = True)
@ -420,7 +442,7 @@ class Reseni(SeminarModelBase):
resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel', related_name='reseni') resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel', related_name='reseni')
body = models.IntegerField(u'body', blank=True, null=True) body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name=u'body', blank=True, null=True)
cislo_body = models.ForeignKey(Cislo, verbose_name=u'číslo pro body', related_name='bodovana_reseni', blank=True, null=True) cislo_body = models.ForeignKey(Cislo, verbose_name=u'číslo pro body', related_name='bodovana_reseni', blank=True, null=True)
@ -443,6 +465,12 @@ class Reseni(SeminarModelBase):
return force_unicode(u"%s: %s (%sb)" % (self.resitel.plne_jmeno(), self.problem.nazev, self.body)) return force_unicode(u"%s: %s (%sb)" % (self.resitel.plne_jmeno(), self.problem.nazev, self.body))
# NOTE: Potenciální DB HOG (bez select_related) # NOTE: Potenciální DB HOG (bez select_related)
def save(self, *args, **kwargs):
if ((self.cislo_body is None) and (self.problem.cislo_reseni) and
(self.problem.typ == Problem.TYP_ULOHA)):
self.cislo_body = self.problem.cislo_reseni
super(Reseni, self).save(*args, **kwargs)
# PrilohaReseni method # PrilohaReseni method
def generate_filename(self, filename): def generate_filename(self, filename):
@ -562,7 +590,8 @@ class VysledkyBase(SeminarModelBase):
resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel', db_column='resitel_id', on_delete=models.DO_NOTHING) resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel', db_column='resitel_id', on_delete=models.DO_NOTHING)
body = models.IntegerField(u'body za číslo', db_column='body') body = models.DecimalField(max_digits=8, decimal_places=1, db_column='body',
verbose_name=u'body za číslo')
def __str__(self): def __str__(self):
return force_unicode(u"%s: %sb (%s)" % (self.resitel.plne_jmeno(), self.body, str(self.cislo))) return force_unicode(u"%s: %sb (%s)" % (self.resitel.plne_jmeno(), self.body, str(self.cislo)))
@ -589,7 +618,8 @@ class VysledkyKCislu(VysledkyBase):
abstract = False abstract = False
managed = False managed = False
body_celkem = models.IntegerField(u'body celkem do čísla', db_column='body_celkem') body_celkem = models.DecimalField(max_digits=8, decimal_places=1, db_column='body_celkem',
verbose_name=u'body celkem do čísla')
def __str__(self): def __str__(self):
# NOTE: DB HOG (ale nepouzivany) # NOTE: DB HOG (ale nepouzivany)
@ -616,3 +646,88 @@ class Nastaveni(SingletonModel):
def verejne(self): def verejne(self):
return False return False
@python_2_unicode_compatible
class Novinky(models.Model):
datum = models.DateField(auto_now_add=True)
text = models.TextField('Text novinky', blank=True, null=True)
obrazek = models.ImageField('Obrázek', upload_to='image_novinky/%Y/%m/%d/',
null=True, blank=True)
autor = models.ForeignKey(settings.AUTH_USER_MODEL,
verbose_name='Autor novinky')
zverejneno = models.BooleanField('Zveřejněno', default="False")
def __str__(self):
return '[' + str(self.datum) + '] ' + self.text[0:50]
class Meta:
verbose_name = 'Novinka'
verbose_name_plural = 'Novinky'
@python_2_unicode_compatible
class Organizator(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name='Osoba',
help_text = 'Vyber účet spřažený s organizátorem.')
prezdivka = models.CharField('Přezdívka', max_length = 32,
null = True, blank = True)
organizuje_od_roku = models.IntegerField('Organizuje od roku',
null = True, blank = True)
organizuje_do_roku = models.IntegerField('Organizuje do roku',
null = True, blank = True)
studuje = models.CharField('Studuje', max_length = 256,
null = True, blank = True)
strucny_popis_organizatora = models.TextField('Stručný popis organizátora',
null = True, blank = True)
foto = models.ImageField('Fotografie organizátora',
upload_to='image_organizatori/velke/%Y/', null = True, blank = True,
help_text = 'Vlož fotografii organizátora o libovoné velikosti')
foto_male = models.ImageField(upload_to='image_organizatori/male/%Y/',
null = True, blank = True, editable = False)
def __str__(self):
return str(self.user)
class Meta:
verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři'
def save(self):
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)
super(Organizator, self).save()
@staticmethod
def _vyrobMiniaturu(original, jmeno, maximum, field):
zmensenina = Organizator._zmensiObrazek(original, maximum)
f = StringIO()
try:
zmensenina.save(f, format=original.format)
data = ContentFile(f.getvalue())
finally:
f.close()
field.save(jmeno, data, save = False)
@staticmethod
def _zmensiObrazek(original, maximum):
"""Preskaluje obrazek tak, aby byl zachovan pomer stran
a zadny rozmer nepresahoval maxRozmer. Pokud zadny rozmer
nepresahuje maxRozmer, tak vrati puvodni obrazek
(tj. nedojde ke zvetseni obrazku)."""
novaVelikost = Organizator._zmensiVelikost(original.size, maximum)
return original.resize(novaVelikost, Image.ANTIALIAS)
@staticmethod
def _zmensiVelikost(velikost, maximum):
maximum = float(maximum)
w, h = velikost
soucasneMaximum = max(w, h)
if soucasneMaximum <= maximum:
return velikost
pomer = maximum/soucasneMaximum
return (int(w * pomer), int(h * pomer))

15
seminar/ovvpfile.py

@ -1,9 +1,19 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
try:
from django.http import HttpResponse
from django.utils.encoding import force_text
except:
force_text = str
class OvvpFile(object): class OvvpFile(object):
def __init__(self): def __init__(self):
# { header: value, ... }
self.headers = {} self.headers = {}
# [ 'column-name', ... ]
self.columns = [] self.columns = []
# [ { column: value, ...}, ...]
self.rows = [] self.rows = []
def to_lines(self): def to_lines(self):
@ -15,11 +25,14 @@ class OvvpFile(object):
yield '\t'.join([c for c in self.columns]) + '\n' yield '\t'.join([c for c in self.columns]) + '\n'
# rows # rows
for r in self.rows: for r in self.rows:
yield '\t'.join([r[c] for c in self.columns]) + '\n' yield '\t'.join([force_text(r[c]) for c in self.columns]) + '\n'
def to_string(self): def to_string(self):
return ''.join(self.to_lines()) return ''.join(self.to_lines())
def to_HttpResponse(self):
return HttpResponse(self.to_string(), content_type='text/plain; charset=utf-8')
def parse_from(self, source, with_headers=True): def parse_from(self, source, with_headers=True):
"Parse data from file, string or line iterator, overwriting self" "Parse data from file, string or line iterator, overwriting self"
if isinstance(source, str) or isinstance(source, unicode): if isinstance(source, str) or isinstance(source, unicode):

10
seminar/templates/seminar/archiv/cislo.html

@ -20,7 +20,12 @@
{% endfor %} {% endfor %}
</ul> </ul>
{% if cislo.verejna_vysledkovka %}
<h3>Výsledkovka</h3> <h3>Výsledkovka</h3>
{% else %}
<div class='mam-org-only'>
<h3>Výsledkovka (neveřejná)</h3>
{% endif %}
<table class='vysledkovka'> <table class='vysledkovka'>
<tr class='border-b'> <tr class='border-b'>
@ -44,6 +49,11 @@
{% endfor %} {% endfor %}
</table> </table>
{% if cislo.verejna_vysledkovka %}
{% else %}
</div>
{% endif %}
</div> </div>
{% endblock content %} {% endblock content %}

36
seminar/templates/seminar/cojemam/organizatori.html

@ -4,6 +4,42 @@
<div> <div>
<h2>Organizátoři</h2> <h2>Organizátoři</h2>
{% for org in object_list %}
{% if org.user.is_active %}
<b>Aktivní</b>
{% else %}
Není aktivní
{% endif %}
{{org.user.first_name}}
{% if org.prezdivka %}
"{{org.prezdivka}}"
{% endif %}
{{org.user.last_name}} <br>
<ul>
{% if org.organizuje_od_roku %}
<li>Organizuje od roku: {{org.organizuje_od_roku}}
{% endif %}
{% if org.organizuje_do_roku %}
<li>Organizuje do roku: {{org.organizuje_do_roku}}
{% endif %}
{% if org.studuje %}
<li>Studuje: {{org.studuje}}
{% endif %}
{% if org.user.email %}
<li>Pošta:
{# zobrazeni e-mailu (na jednom radku, aby nevznikali mezery navic) #}
{% for znak in org.user.email %}{% if znak == '@' %} &#60;zavináč&#62; {% elif znak == '.' %} &#60;tečka&#62; {% else %}{{znak}}{% endif %}{% endfor %}
{% endif %}
</ul>
{% if org.foto %}
<div class="foto_org">
<img src="{{org.foto.url}}" height="{{org.foto.height}}">
<img src="{{org.foto_male.url}}" height="{{org.foto_male.height}}">
</div>
{% endif %}
<hr>
{% endfor %}
</div> </div>
{% endblock content %} {% endblock content %}

2
seminar/templates/seminar/export_index.csv

@ -1,2 +0,0 @@
{% for e in exports %}{{ e }}
{% endfor %}
1 {% for e in exports %}{{ e }}
2 {% endfor %}

11
seminar/templates/seminar/export_rocnik.csv

@ -1,11 +0,0 @@
version 1
event MaM.rocnik
year {{ rocnik.prvni_rok }}
date {{ date }}
id-scope mam
id-generation 1
comment MaM-Web export aktivnich resitelu rocniku {{ rocnik }} do cisla {{ cislo.kod }}
{% for c in sloupce %}{{ c }} {% endfor %}
{% for r in radky %}{% for c in r %}{{ c }} {% endfor %}
{% endfor %}
Can't render this file because it has a wrong number of fields in line 11.

45
seminar/templates/seminar/soustredeni/seznam_soustredeni.html

@ -0,0 +1,45 @@
{% extends "seminar/soustredeni/base.html" %}
{% block content %}
<h1> Soustředění </h1>
{# Projdi vsechna soustredeni #}
{% for soustredeni in object_list %}
{# Kdyz je verejne -> zobraz #}
{% if soustredeni.verejne_db or user.is_authenticated %}
{% if not soustredeni.verejne_db and user.is_authenticated %}
Groups of user: {{user.groups.all}} <br>
<!-- TODO pri prihlasovani ucastniku dodelat prava
jen na group org ve view -->
Toto soustředění není veřejné, vidíte ho jen proto,
že jste přihlášení. <br>
{% endif %}
{# misto soustredeni TODO upravit#}
{% if soustredeni.misto %}
<h2>
Soustředění v&nbsp;{{soustredeni.misto}}
od {{soustredeni.datum_zacatku}} do {{soustredeni.datum_konce}}
při {{soustredeni.rocnik.rocnik}}. ročníku M&M
</h2>
{% endif %}
{# popis soustredeni #}
{% if soustredeni.text %}
{% autoescape off %}{{soustredeni.text}}{% endautoescape %}
{% endif %}
{# Účastníci #}
<h3>Soustředění se zůčastnili tito účastníci:</h3>
<ul>
{% for i in soustredeni.soustredeni_ucastnici_set.all %}
<li>{{i.resitel}}
{% empty %}
<li>Nic!
{% endfor %}
</ul>
{% endif %}
{% empty %}
Žádná soustředění zatím neproběhla!
{% endfor %}
{% endblock %}

17
seminar/tests.py

@ -29,7 +29,7 @@ class SeminarBasicTests(TestCase):
def test_render_cislo_e2e(self): def test_render_cislo_e2e(self):
cs = Cislo.objects.all() cs = Cislo.objects.all()
for c in cs[:4]: for c in cs[:4]:
url = reverse('seminar_cislo', args=(c.id,)) url = c.verejne_url()
r = self.client.get(url) r = self.client.get(url)
assert r.status_code == 200 assert r.status_code == 200
assert len(r.content) >= 100 assert len(r.content) >= 100
@ -38,12 +38,25 @@ class SeminarBasicTests(TestCase):
def test_render_problem_e2e(self): def test_render_problem_e2e(self):
ps = Problem.objects.all() ps = Problem.objects.all()
for p in ps[:4]: for p in ps[:4]:
url = reverse('seminar_problem', args=(p.id,)) url = p.verejne_url()
r = self.client.get(url) r = self.client.get(url)
assert r.status_code == 200 assert r.status_code == 200
assert len(r.content) >= 100 assert len(r.content) >= 100
# TODO: Validate cntent as HTML # TODO: Validate cntent as HTML
def test_export_e2e(self):
i_url = '/aesop-export/index.csv'
i_r = self.client.get(i_url)
assert i_r.status_code == 200
ls = i_r.content.strip().split('\n')
for u in [ls[0], ls[-1]]:
ex_r = self.client.get('/aesop-export/' + u)
assert ex_r.status_code == 200
assert len(ex_r.content) >= 100
o = ovvpfile.parse(ex_r.content)
assert o.headers['version'] == '1'
def test_admin_url(self): def test_admin_url(self):
for m in [Skola, Resitel, Rocnik, Cislo, Problem, Reseni, Nastaveni]: for m in [Skola, Resitel, Rocnik, Cislo, Problem, Reseni, Nastaveni]:
o = m.objects.first() o = m.objects.first()

10
seminar/testutils.py

@ -5,7 +5,7 @@ import random
import django.contrib.auth import django.contrib.auth
from django.db import transaction from django.db import transaction
from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici
from django.contrib.flatpages.models import FlatPage from django.contrib.flatpages.models import FlatPage
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
@ -70,7 +70,7 @@ def create_test_data(size = 6, rnd = None):
for ci in range(1, cisel + 1): for ci in range(1, cisel + 1):
vydano = datetime.date(r.prvni_rok, ci + 6, 1) vydano = datetime.date(r.prvni_rok, ci + 6, 1)
deadline = datetime.date(r.prvni_rok, ci + 8, 1) if ci + 2 < cisel else None deadline = datetime.date(r.prvni_rok, ci + 8, 1) if ci + 2 < cisel else None
c = Cislo.objects.create(rocnik = r, cislo = str(ci), datum_vydani=vydano, datum_deadline=deadline) c = Cislo.objects.create(rocnik = r, cislo = str(ci), datum_vydani=vydano, datum_deadline=deadline, verejne_db=True)
cs[ci] = c cs[ci] = c
# problemy resene v ci # problemy resene v ci
@ -91,6 +91,12 @@ def create_test_data(size = 6, rnd = None):
res = Reseni.objects.create(problem = p, resitel = resitel, res = Reseni.objects.create(problem = p, resitel = resitel,
body = rnd.randint(0, p.body), cislo_body = cs[ci]) body = rnd.randint(0, p.body), cislo_body = cs[ci])
sous = Soustredeni.objects.create(rocnik=Rocnik.objects.first(), verejne_db=True, misto=u'Někde',
datum_zacatku=datetime.date(2000, 11, 23), datum_konce=datetime.date(2000, 11, 27))
for res in rnd.sample(resitele, 6):
Soustredeni_Ucastnici.objects.create(resitel=res, soustredeni=sous)
sous.save()
nastaveni = Nastaveni.objects.create(aktualni_rocnik = Rocnik.objects.last(), nastaveni = Nastaveni.objects.create(aktualni_rocnik = Rocnik.objects.last(),
aktualni_cislo = Cislo.objects.all()[1]) aktualni_cislo = Cislo.objects.all()[1])

10
seminar/urls.py

@ -6,14 +6,18 @@ urlpatterns = patterns('',
url(r'^co-je-MaM/organizatori/$', views.CojemamOrganizatoriView.as_view()), url(r'^co-je-MaM/organizatori/$', views.CojemamOrganizatoriView.as_view()),
url(r'^archiv/cisla/$', views.CislaView.as_view()), url(r'^archiv/cisla/$', views.CislaView.as_view()),
url(r'^archiv/cisla/rocnik/(?P<pk>\d+)/$', views.RocnikView.as_view(), name='seminar_rocnik'),
url(r'^archiv/cisla/cislo/(?P<pk>\d+)/$', views.CisloView.as_view(), name='seminar_cislo'),
url(r'^archiv/cisla/problem/(?P<pk>\d+)/$', views.ProblemView.as_view(), name='seminar_problem'),
url(r'^rocnik/(?P<rocnik>\d+)/$', views.RocnikView.as_view(), name='seminar_rocnik'),
url(r'^cislo/(?P<rocnik>\d+)\.(?P<cislo>\d+)/$', views.CisloView.as_view(), name='seminar_cislo'),
url(r'^problem/(?P<pk>\d+)/$', views.ProblemView.as_view(), name='seminar_problem'),
url(r'^soustredeni/$', views.SoustredeniListView.as_view(),
name = 'seminar_seznam_soustredeni'),
url(r'^soustredeni/(?P<pk>\d+)/$', views.SoustredeniView.as_view(), name='seminar_soustredeni'), url(r'^soustredeni/(?P<pk>\d+)/$', views.SoustredeniView.as_view(), name='seminar_soustredeni'),
url(r'^zadani/aktualni/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'), url(r'^zadani/aktualni/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'),
url(r'^aesop-export/mam-rocnik-(?P<prvni_rok>\d+)\.csv$', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'), url(r'^aesop-export/mam-rocnik-(?P<prvni_rok>\d+)\.csv$', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'),
url(r'^aesop-export/mam-sous-(?P<datum_zacatku>[\d-]+)\.csv$', export.ExportSousView.as_view(), name='seminar_export_sous'),
url(r'^aesop-export/index.csv$', export.ExportIndexView.as_view(), name='seminar_export_index'), url(r'^aesop-export/index.csv$', export.ExportIndexView.as_view(), name='seminar_export_index'),
) )

63
seminar/views.py

@ -2,7 +2,10 @@ from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.views import generic from django.views import generic
from .models import Problem, Cislo, Reseni, VysledkyKCislu, Nastaveni, Rocnik, Soustredeni from django.utils.translation import ugettext as _
from django.http import Http404
from .models import Problem, Cislo, Reseni, VysledkyKCislu, Nastaveni, Rocnik, Soustredeni, Organizator
def AktualniZadaniView(request): def AktualniZadaniView(request):
@ -12,11 +15,14 @@ def AktualniZadaniView(request):
}, },
) )
# Co je M&M ### Co je M&M
class CojemamOrganizatoriView(generic.TemplateView): class CojemamOrganizatoriView(generic.ListView):
model = Organizator
template_name='seminar/cojemam/organizatori.html' template_name='seminar/cojemam/organizatori.html'
### Archiv
class CislaView(generic.ListView): class CislaView(generic.ListView):
model = Rocnik model = Rocnik
template_name='seminar/archiv/cisla.html' template_name='seminar/archiv/cisla.html'
@ -25,9 +31,19 @@ class RocnikView(generic.DetailView):
model = Rocnik model = Rocnik
template_name = 'seminar/archiv/rocnik.html' template_name = 'seminar/archiv/rocnik.html'
class SoustredeniView(generic.DetailView): # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik)
model = Soustredeni def get_object(self, queryset=None):
template_name = 'seminar/archiv/soustredeni.html' if queryset is None:
queryset = self.get_queryset()
rocnik_arg = self.kwargs.get('rocnik')
queryset = queryset.filter(rocnik=rocnik_arg)
try:
obj = queryset.get()
except queryset.model.DoesNotExist:
raise Http404(_("No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
return obj
class ProblemView(generic.DetailView): class ProblemView(generic.DetailView):
model = Problem model = Problem
@ -39,26 +55,50 @@ class RadekVysledkovky(object):
class CisloView(generic.DetailView): class CisloView(generic.DetailView):
model = Cislo model = Cislo
template_name = 'seminar/archiv/cislo.html' template_name = 'seminar/archiv/cislo.html'
# Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik)
def get_object(self, queryset=None):
if queryset is None:
queryset = self.get_queryset()
rocnik_arg = self.kwargs.get('rocnik')
cislo_arg = self.kwargs.get('cislo')
queryset = queryset.filter(rocnik__rocnik=rocnik_arg, cislo=cislo_arg)
try:
obj = queryset.get()
except queryset.model.DoesNotExist:
raise Http404(_("No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
return obj
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CisloView, self).get_context_data(**kwargs) context = super(CisloView, self).get_context_data(**kwargs)
# Vysledky k cislu: seznam objektu typu (cislo, resitel, body [v tom cisle], body_celkem [od zac. rocniku])
vysledky = VysledkyKCislu.objects.filter(cislo = context['cislo']).order_by('-body_celkem').select_related("resitel") vysledky = VysledkyKCislu.objects.filter(cislo = context['cislo']).order_by('-body_celkem').select_related("resitel")
reseni = Reseni.objects.filter(cislo_body = context['cislo']).select_related("resitel") reseni = Reseni.objects.filter(cislo_body = context['cislo']).select_related("resitel")
# seznam problemu s nejakymi body v tomto cisle
problemy = sorted(list(set([r.problem for r in reseni])), key=lambda x:(0 if x.typ==Problem.TYP_ULOHA else 1,x.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))
# cislo sloupecku pro problem (inverzni funkce)
problem_index = {} problem_index = {}
for i in range(len(problemy)): for i in range(len(problemy)):
problem_index[problemy[i].id] = i problem_index[problemy[i].id] = i
# pomocna mapa Resitel: RadekVysledkovky
vysledky_resitele = {} vysledky_resitele = {}
# radky vysledkovky, seznam objektu RadekVysledkovky
vysledkovka = [] vysledkovka = []
# posledni pocet bodu, pro detekci stejnych mist
posledni_body = 100000 posledni_body = 100000
for vi in range(len(vysledky)): for vi in range(len(vysledky)):
v = vysledky[vi] v = vysledky[vi]
tv = RadekVysledkovky() tv = RadekVysledkovky()
tv.resitel = v.resitel tv.resitel = v.resitel
tv.vysledek = v tv.vysledek = v
tv.body = ['']*len(problemy) tv.body = ['']*len(problemy) # misto pro body za jednotlive uloy
tv.poradi = '' tv.poradi = ''
if posledni_body > v.body_celkem: if posledni_body > v.body_celkem:
posledni_body = v.body_celkem posledni_body = v.body_celkem
@ -66,6 +106,7 @@ class CisloView(generic.DetailView):
vysledky_resitele[v.resitel.id] = tv vysledky_resitele[v.resitel.id] = tv
vysledkovka.append(tv) vysledkovka.append(tv)
# doplneni bodu za jednotliva reseni lidi do RadekVysledkovky.body
for r in reseni: for r in reseni:
vysledky_resitele[r.resitel.id].body[problem_index[r.problem.id]] = r.body vysledky_resitele[r.resitel.id].body[problem_index[r.problem.id]] = r.body
@ -73,4 +114,12 @@ class CisloView(generic.DetailView):
context['problemy'] = problemy context['problemy'] = problemy
return context return context
### Soustredeni
class SoustredeniListView(generic.ListView):
model = Soustredeni
template_name = 'seminar/soustredeni/seznam_soustredeni.html'
class SoustredeniView(generic.DetailView):
model = Soustredeni
template_name = 'seminar/archiv/soustredeni.html'

Loading…
Cancel
Save