Browse Source

Merge branch 'master' into stable

remotes/origin/prednasky
Matěj Kocián 8 years ago
parent
commit
95053912b7
  1. 5
      _git_hooks/pre-commit
  2. BIN
      korektury/static/korektury/imgs/comment-gr.png
  3. 13
      korektury/static/korektury/opraf-list.css
  4. 3
      korektury/static/korektury/opraf.js
  5. 29
      korektury/templates/korektury/opraf.html
  6. 7
      korektury/templates/korektury/seznam.html
  7. 9
      korektury/views.py
  8. 50
      seminar/admin.py
  9. 19
      seminar/migrations/0042_cislo_faze.py
  10. 19
      seminar/migrations/0043_uprava_faze.py
  11. 19
      seminar/migrations/0044_uprava_faze.py
  12. 19
      seminar/migrations/0045_cislo_pridani_faze_nahrano.py
  13. 15
      seminar/migrations/0046_merge.py
  14. 24
      seminar/models.py
  15. 13
      seminar/urls.py
  16. 68
      seminar/views.py

5
_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

BIN
korektury/static/korektury/imgs/comment-gr.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

13
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;
}

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

29
korektury/templates/korektury/opraf.html

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

7
korektury/templates/korektury/seznam.html

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

9
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
zasluhy[k.autor] += 1
else:
zasluhy[k.autor]=1
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]

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

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

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

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

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

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

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

13
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')
]

68
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

Loading…
Cancel
Save