diff --git a/_git_hooks/pre-commit b/_git_hooks/pre-commit
index 664a06ce..f78840d4 100755
--- a/_git_hooks/pre-commit
+++ b/_git_hooks/pre-commit
@@ -10,6 +10,11 @@ status=0
# select only changed python files which are not migrations
changed=`git diff --cached --name-only | grep 'py$' | grep -v 'migrations/[0-9]'`
+if [ -z $changed ] ; then
+ # Nothing to check. Note the exit is necessary -- we would not pass any
+ # paths to git diff below and it would output the diff unfiltered.
+ exit 0
+fi
git diff --unified=1 --cached HEAD -- $changed > $TMPDIFF
diff --git a/korektury/static/korektury/imgs/comment-gr.png b/korektury/static/korektury/imgs/comment-gr.png
new file mode 100644
index 00000000..3a35385e
Binary files /dev/null and b/korektury/static/korektury/imgs/comment-gr.png differ
diff --git a/korektury/static/korektury/opraf-list.css b/korektury/static/korektury/opraf-list.css
new file mode 100644
index 00000000..737b3c2c
--- /dev/null
+++ b/korektury/static/korektury/opraf-list.css
@@ -0,0 +1,13 @@
+.adding-text{
+ color: black;
+}
+.comitting-text
+{
+ color: yellow;
+}
+.deprecated-text {
+ color: red;
+ text-decoration: line-through;
+}
+
+
diff --git a/korektury/static/korektury/opraf.js b/korektury/static/korektury/opraf.js
index a6d6244c..75591fe7 100644
--- a/korektury/static/korektury/opraf.js
+++ b/korektury/static/korektury/opraf.js
@@ -126,11 +126,14 @@ function img_click(element, ev) {
function toggle_visibility(button){
var divbox = button.parentNode.parentNode.parentNode;
var id = divbox.id;
+ var buttondiv = document.getElementById(id+'-buttons')
var text = document.getElementById(id+'-body');
if (text.style.display == 'none'){
text.style.display = 'block';
+ buttondiv.style.display = 'inline-block';
}else {
text.style.display = 'none';
+ buttondiv.style.display = 'none';
}
for (var i=0;i
Děkujeme opravovatelům:
- {% for autor,pocet in zasluhy.items %}
- {{autor}} ({{pocet}}){% if not forloop.last %},{% endif %}
+ {% for z in zasluhy %}
+ {{z.autor}} ({{z.pocet}}){% if not forloop.last %},{% endif %}
{% endfor %}
{{o.text}}
@@ -159,17 +168,17 @@
{% for k in o.komentare %}
{% endfor %}
diff --git a/korektury/templates/korektury/seznam.html b/korektury/templates/korektury/seznam.html
index c1d62175..991ca2c5 100644
--- a/korektury/templates/korektury/seznam.html
+++ b/korektury/templates/korektury/seznam.html
@@ -1,4 +1,9 @@
{% extends "korektury/base.html" %}
+{% load staticfiles %}
+
+{% block script%}
+
+{% endblock %}
{% block content %}
@@ -12,7 +17,7 @@
{% for pdf in object_list %}
- {{ pdf.nazev }} {{pdf.komentar}} {{pdf.pdf.name}}
+ {{ pdf.nazev }} {{pdf.komentar}} {{pdf.pdf.name}}
{% empty %}
Nejsou žádné dokumenty ke korekturování.
{% endfor %}
diff --git a/korektury/views.py b/korektury/views.py
index 70cfaf6e..979830bf 100644
--- a/korektury/views.py
+++ b/korektury/views.py
@@ -181,9 +181,14 @@ class KorekturyView(generic.TemplateView):
o.komentare = o.komentar_set.all()
for k in o.komentare:
if k.autor in zasluhy:
- zasluhy[k.autor]+=1
- else:
- zasluhy[k.autor]=1
+ zasluhy[k.autor] += 1
+ else:
+ zasluhy[k.autor] = 1
+ zasluhy = [
+ {'autor': jmeno, 'pocet': pocet}
+ for (jmeno, pocet) in zasluhy.items()
+ ]
+ zasluhy.sort(key=lambda z: z['pocet'], reverse=True)
strany = set(o.strana for o in opravy)
opravy_na_stranu = [{'strana': s, 'op_id': opravy.filter(strana=s)} for s in strany]
diff --git a/seminar/admin.py b/seminar/admin.py
index 3a61d461..89901c6b 100644
--- a/seminar/admin.py
+++ b/seminar/admin.py
@@ -245,10 +245,28 @@ admin.site.register(Skola, SkolaAdmin)
class CisloAdmin(VersionAdmin):
fieldsets = [
- (None, {'fields': ['cislo', 'rocnik', 'verejne_db', 'verejna_vysledkovka', 'poznamka', 'pdf']}),
- (u'Data', {'fields': ['datum_vydani', 'datum_deadline']}),
+ (None, {
+ 'fields': [
+ 'cislo',
+ 'rocnik',
+ 'verejne_db',
+ 'verejna_vysledkovka',
+ 'faze',
+ 'poznamka',
+ 'pdf'
+ ]
+ }),
+ (u'Data', {'fields': ['datum_vydani', 'datum_deadline']}),
]
- list_display = ['kod', 'rocnik', 'cislo', 'datum_vydani', 'datum_deadline', 'verejne', 'verejna_vysledkovka']
+ list_display = [
+ 'kod',
+ 'rocnik',
+ 'cislo',
+ 'datum_vydani',
+ 'datum_deadline',
+ 'verejne',
+ 'verejna_vysledkovka'
+ ]
list_filter = ['rocnik']
view_on_site = Cislo.verejne_url
actions = [
@@ -340,7 +358,20 @@ class PohadkaAdmin(VersionAdmin):
return obj.uloha.cislo_zadani.rocnik.rocnik
get_rocnik.short_description = u'Ročník'
- list_display = ['__str__', 'get_rocnik', 'get_kod_ulohy', 'uloha', 'autor', 'timestamp']
+ def get_readonly_fields(self, request, obj=None):
+ if not obj:
+ return []
+ if obj.uloha.cislo_zadani.faze != 'admin':
+ return ['text']
+
+ list_display = [
+ '__str__',
+ 'get_rocnik',
+ 'get_kod_ulohy',
+ 'uloha',
+ 'autor',
+ 'timestamp'
+ ]
get_form = get_form_predvypln_autora
@@ -376,12 +407,21 @@ class ProblemAdmin(VersionAdmin):
(u'Vydání', {'fields': ['cislo_zadani', 'kod', 'cislo_reseni', 'opravovatel',]}),
(None, {'fields': ['text_zadani', 'text_reseni', 'text_org',]}),
]
- readonly_fields = ['timestamp', 'import_dakos_id']
list_select_related = True
search_fields = ['nazev', 'text_zadani', 'text_reseni', 'text_org']
view_on_site = Problem.verejne_url
ordering = ['-timestamp']
+ def get_readonly_fields(self, request, obj=None):
+ readonly_fields = ['timestamp', 'import_dakos_id']
+ if not obj:
+ return readonly_fields
+ if obj.cislo_zadani.faze != 'admin':
+ readonly_fields += ['nazev', 'text_zadani', 'body']
+ if obj.cislo_reseni.faze != 'admin':
+ readonly_fields += ['text_reseni']
+ return readonly_fields
+
def get_queryset(self, request):
qs = super(ProblemAdmin, self).get_queryset(request)
return qs.select_related('autor', 'opravovatel', 'cislo_zadani', 'cislo_reseni')
diff --git a/seminar/migrations/0042_cislo_faze.py b/seminar/migrations/0042_cislo_faze.py
new file mode 100644
index 00000000..7d35ace5
--- /dev/null
+++ b/seminar/migrations/0042_cislo_faze.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0041_konfery'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='cislo',
+ name='faze',
+ field=models.CharField(default='admin', help_text='B\u011bhem f\xe1ze "admin" se obsah \u010d\xedsla vytv\xe1\u0159\xed (a p\u0159\xedpadn\u011b komentuje) ve webov\xe9m rozhran\xed. B\u011bhem f\xe1ze "tex" u\u017e obsah ve webov\xe9m rozhran\xed editovat nelze. N\xe1vrhy na \xfapravy se pak p\xed\u0161\xed do korekturov\xe1tka a zan\xe1\u0161ej\xed do gitu. Z n\u011bj se pak generuje verze pro web.', max_length=32, verbose_name='F\xe1ze vytv\xe1\u0159en\xed obsahu'),
+ ),
+ ]
diff --git a/seminar/migrations/0043_uprava_faze.py b/seminar/migrations/0043_uprava_faze.py
new file mode 100644
index 00000000..29e06e01
--- /dev/null
+++ b/seminar/migrations/0043_uprava_faze.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0042_cislo_faze'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cislo',
+ name='faze',
+ field=models.CharField(default='admin', help_text='B\u011bhem f\xe1ze "admin" se obsah \u010d\xedsla vytv\xe1\u0159\xed (a p\u0159\xedpadn\u011b komentuje) ve webov\xe9m rozhran\xed. B\u011bhem f\xe1ze "tex" u\u017e obsah ve webov\xe9m rozhran\xed editovat nelze. N\xe1vrhy na \xfapravy se pak p\xed\u0161\xed do korekturov\xe1tka a zan\xe1\u0161ej\xed do gitu. Z n\u011bj se pak generuje verze pro web.', max_length=32, verbose_name='F\xe1ze vytv\xe1\u0159en\xed obsahu', choices=[('admin', 'Zad\xe1v\xe1n\xed \xfaloh do webu'), ('tex', '\xdapravy \xfaloh v TeXov\xe9m repozit\xe1\u0159i')]),
+ ),
+ ]
diff --git a/seminar/migrations/0044_uprava_faze.py b/seminar/migrations/0044_uprava_faze.py
new file mode 100644
index 00000000..0d683d6c
--- /dev/null
+++ b/seminar/migrations/0044_uprava_faze.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0043_uprava_faze'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cislo',
+ name='faze',
+ field=models.CharField(default='admin', help_text='B\u011bhem f\xe1ze "\xdapravy na webu" se obsah \u010d\xedsla vytv\xe1\u0159\xed (a p\u0159\xedpadn\u011b komentuje) ve webov\xe9m rozhran\xed. B\u011bhem f\xe1ze "\xdapravy na webu" u\u017e obsah ve webov\xe9m rozhran\xed editovat nelze a n\xe1vrhy na \xfapravy se p\xed\u0161\xed do korekturov\xe1tka a zan\xe1\u0161ej\xed do gitu. Z n\u011bj se pak generuje verze pro web.', max_length=32, verbose_name='F\xe1ze vytv\xe1\u0159en\xed obsahu', choices=[('admin', '\xdapravy na webu'), ('tex', '\xdapravy v TeXu')]),
+ ),
+ ]
diff --git a/seminar/migrations/0045_cislo_pridani_faze_nahrano.py b/seminar/migrations/0045_cislo_pridani_faze_nahrano.py
new file mode 100644
index 00000000..06ca8201
--- /dev/null
+++ b/seminar/migrations/0045_cislo_pridani_faze_nahrano.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0044_uprava_faze'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cislo',
+ name='faze',
+ field=models.CharField(default='admin', help_text='B\u011bhem f\xe1ze "\xdapravy na webu" se obsah \u010d\xedsla vytv\xe1\u0159\xed (a p\u0159\xedpadn\u011b komentuje) ve webov\xe9m rozhran\xed. B\u011bhem f\xe1ze "\xdapravy v TeXu" u\u017e obsah ve webov\xe9m rozhran\xed editovat nelze a n\xe1vrhy na \xfapravy se p\xed\u0161\xed do korekturov\xe1tka a zan\xe1\u0161ej\xed do gitu. Z n\u011bj se pak vygeneruje verze pro web a \u010d\xedslo se p\u0159epne do f\xe1ze "Nahr\xe1no na web", co\u017e jen znamen\xe1, \u017ee u\u017e nejde automaticky st\xe1hnout obsah pro zalo\u017een\xed \u010d\xedsla v TeXu.', max_length=32, verbose_name='F\xe1ze vytv\xe1\u0159en\xed obsahu', choices=[('admin', '\xdapravy na webu'), ('tex', '\xdapravy v TeXu'), ('tex', 'Nahr\xe1no na web')]),
+ ),
+ ]
diff --git a/seminar/migrations/0046_merge.py b/seminar/migrations/0046_merge.py
new file mode 100644
index 00000000..19352440
--- /dev/null
+++ b/seminar/migrations/0046_merge.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0042_auto_20161005_0847'),
+ ('seminar', '0045_cislo_pridani_faze_nahrano'),
+ ]
+
+ operations = [
+ ]
diff --git a/seminar/models.py b/seminar/models.py
index 5a478feb..79b49eea 100644
--- a/seminar/models.py
+++ b/seminar/models.py
@@ -349,6 +349,30 @@ class Cislo(SeminarModelBase):
pdf = models.FileField(u'pdf', upload_to=cislo_pdf_filename, null=True, blank=True,
help_text=u'Pdf čísla, které si mohou řešitelé stáhnout')
+ FAZE_ADMIN = u'admin'
+ FAZE_TEX = u'tex'
+ FAZE_NAHRANO = u'nahrano'
+ FAZE_CHOICES = [
+ (FAZE_ADMIN, u'Úpravy na webu'),
+ (FAZE_TEX, u'Úpravy v TeXu'),
+ (FAZE_NAHRANO, u'Nahráno na web'),
+ ]
+ faze = models.CharField(
+ u'Fáze vytváření obsahu',
+ max_length=32,
+ default=FAZE_ADMIN,
+ choices=FAZE_CHOICES,
+ help_text=(
+ u'Během fáze "{}" se obsah čísla vytváří (a případně '
+ u'komentuje) ve webovém rozhraní. Během fáze "{}" už obsah ve '
+ u'webovém rozhraní editovat nelze a návrhy na úpravy se píší '
+ u'do korekturovátka a zanášejí do gitu. Z něj se pak vygeneruje '
+ u'verze pro web a číslo se přepne do fáze "{}", což jen znamená, '
+ u'že už nejde automaticky stáhnout obsah pro založení čísla v '
+ u'TeXu.'
+ ).format(FAZE_CHOICES[0][1], FAZE_CHOICES[1][1], FAZE_CHOICES[2][1])
+ )
+
def kod(self):
return u'%s.%s' % (self.rocnik.rocnik, self.cislo)
kod.short_description = u'Kód čísla'
diff --git a/seminar/urls.py b/seminar/urls.py
index 686a7a5c..de5b10d6 100644
--- a/seminar/urls.py
+++ b/seminar/urls.py
@@ -72,5 +72,16 @@ urlpatterns = [
staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'),
url(r'^tex-upload/login/$', views.LoginView, name='seminar_login'),
- url(r'^tex-upload/$', staff_member_required(views.texUploadView), name='seminar_tex_upload'),
+ url(
+ r'^tex-upload/$',
+ staff_member_required(views.texUploadView),
+ name='seminar_tex_upload'
+ ),
+
+ # Ceka na autocomplete v3
+ # url(r'^autocomplete/organizatori/$',
+ # staff_member_required(views.OrganizatorAutocomplete.as_view()),
+ # name='seminar_autocomplete_organizator')
+
+
]
diff --git a/seminar/views.py b/seminar/views.py
index 141e9492..08a27162 100644
--- a/seminar/views.py
+++ b/seminar/views.py
@@ -122,21 +122,31 @@ class StareNovinkyView(generic.ListView):
### Co je M&M
-## Organizatori
+
+# Organizatori
+def aktivniOrganizatori(rok=date.today().year):
+ return Organizator.objects.exclude(
+ organizuje_do_roku__isnull=False,
+ organizuje_do_roku__lt=rok
+ ).order_by('user__first_name')
+
class CojemamOrganizatoriView(generic.ListView):
model = Organizator
- template_name='seminar/cojemam/organizatori.html'
- queryset = Organizator.objects.exclude(organizuje_do_roku__isnull=False, organizuje_do_roku__lt=date.today().year).order_by('user__first_name')
+ template_name = 'seminar/cojemam/organizatori.html'
+ queryset = aktivniOrganizatori()
+
def get_context_data(self, **kwargs):
context = super(CojemamOrganizatoriView, self).get_context_data(**kwargs)
context['aktivni'] = True
return context
+
class CojemamOrganizatoriStariView(generic.ListView):
model = Organizator
- template_name='seminar/cojemam/organizatori.html'
- queryset = Organizator.objects.filter(organizuje_do_roku__isnull=False, organizuje_do_roku__lt=date.today().year).order_by('-organizuje_do_roku')
+ template_name = 'seminar/cojemam/organizatori.html'
+ queryset = Organizator.objects.exclude(
+ id__in=aktivniOrganizatori()).order_by('-organizuje_do_roku')
### Archiv
@@ -670,7 +680,6 @@ def texUploadView(request):
# Řešení má nastavené číslo svojí úlohy, ale obrázky jsou
# ukládány do čísla, kde řešení vyšlo
c = meta["cislo_reseni"]
- uloz_soubory(request.FILES.items(), meta["rocnik"], c)
# Zjistíme typ ukládaného problému
typy = {
@@ -680,8 +689,8 @@ def texUploadView(request):
}
problem_typ = typy[meta["typ"]]
-
# Pokud už problém existuje, vytáhneme jej z db a upravíme
+ # Pokud neexistuje, vytvoříme jej jedině pokud je to vynucené
# Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku ->
# číslo/ročník se musí založit ručně v adminu
@@ -698,14 +707,22 @@ def texUploadView(request):
problem = None
if existujici:
problem = existujici[0]
- # Jinak vytvoříme nový
- else:
+ elif "vytvor" in q:
+ # vytvoříme nový
problem = Problem(
typ=problem_typ,
stav=Problem.STAV_ZADANY,
kod=meta["kod"],
cislo_zadani=cislo
)
+ else:
+ return JsonResponse({
+ "error": "Problém neexistuje: {} {}.{} kód {}".format(
+ meta["typ"], meta["rocnik"], meta["cislo"], meta["kod"]
+ )
+ })
+
+ uloz_soubory(request.FILES.items(), meta["rocnik"], c)
if meta["typ"] == "reseni":
problem.text_reseni = html
@@ -716,6 +733,8 @@ def texUploadView(request):
problem.body = meta["body"]
problem.save()
+ cislo.faze = cislo.FAZE_NAHRANO
+ cislo.save()
# Vrátíme id dané úlohy, aby se k ní dala případně připojit pohádka
return JsonResponse({"db_id": problem.id})
@@ -745,6 +764,12 @@ def texDownloadView(request, rocnik, cislo):
"""View posílající JSON se zadanými a řešenými problémy pro založení čísla
"""
cislo = Cislo.objects.get(rocnik__rocnik=rocnik, cislo=cislo)
+ if cislo.faze == cislo.FAZE_NAHRANO:
+ # obsah byl nahrán z TeXu na web, už je příliš složitý
+ return JsonResponse(
+ {"error": "Obsah čísla už byl nahrán z TeXu na web."}
+ )
+
zadane = Problem.objects.filter(
cislo_zadani=cislo,
stav=Problem.STAV_ZADANY
@@ -781,4 +806,29 @@ def texDownloadView(request, rocnik, cislo):
} for p in resene
],
}
+
+ cislo.faze = Cislo.FAZE_TEX
+ cislo.save()
return JsonResponse(response)
+
+
+# Ceka na autocomplete v3
+# class OrganizatorAutocomplete(autocomplete.Select2QuerySetView):
+# def get_queryset(self):
+# if not self.request.user.is_authenticated():
+# return Organizator.objects.none()
+#
+# qs = aktivniOrganizatori()
+#
+# if self.q:
+# if self.q[0] == "!":
+# qs = Organizator.objects.all()
+# query = self.q[1:]
+# else:
+# query = self.q
+# qs = qs.filter(
+# Q(prezdivka__isstartswith=query)|
+# Q(user__first_name__isstartswith=query)|
+# Q(user__last_name__isstartswith=query))
+#
+# return qs