Merge branch 'master' into stable

This commit is contained in:
Bc. Petr Pecha 2017-01-20 11:46:14 +01:00
commit fe38888581
16 changed files with 265 additions and 22 deletions

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -0,0 +1,13 @@
.adding-text{
color: black;
}
.comitting-text
{
color: yellow;
}
.deprecated-text {
color: red;
text-decoration: line-through;
}

View file

@ -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<comments.length-1;i++){
place_comments_one_div(comments[i][0], comments[i][1])

View file

@ -83,8 +83,8 @@
<hr/>
<p>
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 %}</p>
<hr>
@ -99,8 +99,9 @@
onmouseout='box_onmouseout(this,{% if o.status = 'opraveno' %}"done"{% elif o.status = 'neni_chyba' %}"wontfix"{%else%}""{% endif %})'>
<div class='corr-header'>
<div class='author' id='op{{o.id}}-autor'>{{o.autor}}</div>
<div class='float-right'>
<span class='author' id='op{{o.id}}-autor'>{{o.autor}}</span>
<span class='float-right'>
<span id='op{{o.id}}-buttons'>
<!-- Existujici korektura !-->
<form action='' onsubmit='save_scroll(this)' method='POST'>
{% csrf_token %}
@ -144,14 +145,22 @@
<img src="{% static "korektury/imgs/edit.png" %}"/>
</button>
{% endif %}
{% if o.status = 'opraveno' or o.status = 'neni_chyba' %}
<button type='button' title='Korekturu nelze komentovat, protože už je uzavřená'>
<img src="{% static "korektury/imgs/comment-gr.png" %}"/>
</button>
{% else %}
<button type='button' onclick='box_edit(this, "comment");' title='Komentovat'>
<img src="{% static "korektury/imgs/comment.png" %}"/>
</button>
{% endif %}
</span>
<button type='button' onclick='toggle_visibility(this);' title='Skrýt/Zobrazit'>
<img src="{% static "korektury/imgs/hide.png" %}"/>
</button>
</div>
</span>
</div>
<div class='corr-body' id='op{{o.id}}-body'>
<div id='op{{o.id}}-text'>{{o.text}}</div>
@ -159,17 +168,17 @@
{% for k in o.komentare %}
<hr>
<div class='comment' id='k{{k.id}}'>
<div class='corr-header'>
<span class='corr-header'>
<div class='author'>{{k.autor}}</div>
<div class="float-right">
<!-- Komentar !-->
<span class="float-right">
<!-- Komentar !-->
<form action='' onsubmit='save_scroll(this)' method='POST'>
{% csrf_token %}
<input type='hidden' name='pdf' value='{{pdf.id}}'>
<input type='hidden' name='id' value='{{k.id}}'>
<input type='hidden' name='scroll'>
<button type='submit' name='action' value='del-comment' title='Smaž komentář'
onclick='return confirm("Opravdu smazat komentář?")'>
onclick='return confirm("Opravdu smazat komentář?")'>
<img src="{% static "korektury/imgs/delete.png" %}"/>
</button>
</form>
@ -178,7 +187,7 @@
<img src="{% static "korektury/imgs/edit.png"%}"/>
</button>
</div>
</div>
</span>
<div id='kt{{k.id}}'>{{k.text}}</div>
</div>
{% endfor %}

View file

@ -1,4 +1,9 @@
{% extends "korektury/base.html" %}
{% load staticfiles %}
{% block script%}
<link rel="stylesheet" type="text/css" media="screen, projection" href="{% static "korektury/opraf-list.css" %}" />
{% endblock %}
{% block content %}
@ -12,7 +17,7 @@
<ul>
{% for pdf in object_list %}
<li> <b>{{ pdf.nazev }}</b> <i>{{pdf.komentar}}</i> <a href="/korektury/{{pdf.id}}">{{pdf.pdf.name}}</a> </li>
<li><span {% if pdf.status = 'zanaseni'%} class="comitting-text" {% elif pdf.status = 'zastarale' %} class="deprecated-text" {% endif %}> <b>{{ pdf.nazev }}</b> <i>{{pdf.komentar}}</i> <a href="/korektury/{{pdf.id}}">{{pdf.pdf.name}}</a> </span> </li>
{% empty %}
<li> Nejsou žádné dokumenty ke korekturování.
{% endfor %}

View file

@ -184,6 +184,8 @@ class KorekturyView(generic.TemplateView):
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]

View file

@ -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')

View file

@ -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'),
),
]

View file

@ -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')]),
),
]

View file

@ -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')]),
),
]

View file

@ -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')]),
),
]

View file

@ -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 = [
]

View file

@ -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'

View file

@ -73,4 +73,9 @@ urlpatterns = [
url(r'^tex-upload/login/$', views.LoginView, name='seminar_login'),
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')
]

View file

@ -123,11 +123,16 @@ class StareNovinkyView(generic.ListView):
### Co je M&M
## 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')
queryset = aktivniOrganizatori()
def get_context_data(self, **kwargs):
context = super(CojemamOrganizatoriView, self).get_context_data(**kwargs)
context['aktivni'] = True
@ -136,7 +141,7 @@ class CojemamOrganizatoriView(generic.ListView):
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')
queryset = Organizator.objects.exclude(id__in = aktivniOrganizatori()).order_by('-organizuje_do_roku')
### Archiv
@ -670,7 +675,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 +684,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 +702,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 +728,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 +759,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 +801,30 @@ 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