Browse Source

Merge remote-tracking branch 'origin/data_migrations' into treenode_editor

export_seznamu_prednasek
parent
commit
a3e478f4f1
  1. 1
      mamweb/settings_common.py
  2. 21
      mamweb/static/css/mamweb.css
  3. 1
      seminar/.~lock.profile_vysledkovka.txt#
  4. 17
      seminar/models.py
  5. 7
      seminar/permissions.py
  6. BIN
      seminar/static/images/tema-bez-obrazku.png
  7. 97
      seminar/templates/seminar/archiv/cislo-normal.html
  8. 19
      seminar/templates/seminar/archiv/problem_tema.html
  9. 23
      seminar/templates/seminar/archiv/problem_uloha.html
  10. 47
      seminar/templates/seminar/tematka/rozcestnik.html
  11. 1
      seminar/views/views_all.py
  12. 50
      seminar/viewsets.py

1
mamweb/settings_common.py

@ -123,6 +123,7 @@ INSTALLED_APPS = (
'webpack_loader', 'webpack_loader',
'rest_framework', 'rest_framework',
'rest_framework.authtoken',
# MaMweb # MaMweb
'mamweb', 'mamweb',

21
mamweb/static/css/mamweb.css

@ -759,17 +759,26 @@ div.odpocet {
/*stránka organizátorů*/ /*stránka organizátorů*/
div.seznam_orgu { div.seznam_orgu, div.rozcestnik_temat {
text-align: center; text-align: center;
padding-bottom: 10px;
} }
div.org_pole, div.rocnik_pole { div.org_pole, div.rocnik_pole, div.tema_pole {
display: inline-block; display: inline-block;
width: 30%; width: 30%;
min-width: 300px; min-width: 300px;
text-align: center; text-align: center;
} }
div.tema_pole {
display: inline-block;
width: 40%;
min-width: 350px;
padding-bottom: 20px;
text-align: center;
}
div.cislo_pole { div.cislo_pole {
display: inline-block; display: inline-block;
width: 15%; width: 15%;
@ -812,6 +821,11 @@ div.org_email {
height: 205px; height: 205px;
} }
#tema-rozcestnik.flip-card {
width: 300px;
height: 300px;
}
/* This container is needed to position the front and back side */ /* This container is needed to position the front and back side */
.flip-card-inner { .flip-card-inner {
position: relative; position: relative;
@ -835,7 +849,8 @@ div.org_email {
backface-visibility: hidden; backface-visibility: hidden;
} }
div.flip-card-foto img {
div.flip-card-foto, div.flip-card-foto img {
width: 100%; width: 100%;
height: 100%; height: 100%;

1
seminar/.~lock.profile_vysledkovka.txt#

@ -0,0 +1 @@
,anet,erebus,25.03.2020 22:21,file:///home/anet/.config/libreoffice/4;

17
seminar/models.py

@ -743,12 +743,17 @@ class Problem(SeminarModelBase,PolymorphicModel):
return '<Není zadaný>' return '<Není zadaný>'
def verejne(self): def verejne(self):
# FIXME: Tohle se liší podle typu problému, má se udělat polymorfně. # aktuálně podle stavu problému
# Zatím je tu jen dummy fail-safe default: nic není veřejné. # FIXME pro některé problémy možná chceme override
# Doporučené řešení: dělat tohle podle stavu problému a veřejnosti čísla, ve kterém je stav_verejny = False
return False if self.stav == 'zadany' or self.stav == 'vyreseny':
# FIXME: Tohle je blbost stav_verejny = True
return (self.cislo_zadani and self.cislo_zadani.verejne())
cislo_verejne = False
if (self.cislo_zadani and self.cislo_zadani.verejne()):
cislo_verejne = True
return (stav_verejny and cislo_verejne)
verejne.boolean = True verejne.boolean = True
def verejne_url(self): def verejne_url(self):

7
seminar/permissions.py

@ -0,0 +1,7 @@
from rest_framework.permissions import BasePermission
class AllowWrite(BasePermission):
def has_permission(self, request, view):
return request.user.has_perm('auth.org')

BIN
seminar/static/images/tema-bez-obrazku.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

97
seminar/templates/seminar/archiv/cislo-normal.html

@ -0,0 +1,97 @@
{% extends "seminar/archiv/base_cisla.html" %}
{# {% block content %}
<div>
<h1>
{% block nadpis1a %}{% block nadpis1b %}
Číslo {{ cislo }}
{% endblock %}{% endblock %}
</h1>
{% if cislo.pdf %}
<p><a href='{{ cislo.pdf.url }}'>Číslo v pdf</a>
{% endif %}
<p><a href='{{ cislo.rocnik.verejne_url }}'>Ročník {{ cislo.rocnik }}</a>
{% if v_cisle_zadane %}
<h2>Zadané problémy</h2>
<ul>
{% for p in v_cisle_zadane %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff or cislo.verejne %}
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %}
{% endfor %}
</ul>
{% endif %}
{% if resene_problemy %}
<h2>Řešené problémy</h2>
<ul>
{% for p in resene_problemy %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff or cislo.verejne %}
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %}
{% endfor %}
</ul>
{% endif %}
{% if user.is_staff %}
<div class="mam-org-only">
<h2> Orgovské odkazy </h2>
<ul>
<li><a href="obalky.pdf">Obálky (PDF)</a></li>
<li><a href="tituly.tex">Tituly (TeX)</a></li>
<li><a href="vysledkovka.tex">Výsledkovka (TeX)</a></li>
<li><a href="obalkovani">Obálkování</a></li>
</ul>
</div>
{% endif %}
{% if cislo.verejna_vysledkovka %}
<h2>Výsledkovka</h2>
{% else %}
{% if user.is_staff %}
<div class='mam-org-only'>
<h2>Výsledkovka (neveřejná)</h2>
{% endif %}
{% endif %}
{% if cislo.verejna_vysledkovka or user.is_staff %}
<table class='vysledkovka'>
<tr class='border-b'>
<th class='border-r'>#
<th class='border-r'>Jméno #}
{# problémy by měly být veřejné, když je veřejná výsledkovka #}
{# {% for p in problemy %}
<th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a>
{% endfor %}
<th class='border-r'>Za číslo</sup>
<th class='border-r'>Za ročník
<th class='border-r'>Odjakživa
{% for rv in radky_vysledkovky %}
<tr>
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}
<th class='border-r'>
{% if rv.resitel.titul != "" %}
{{ rv.resitel.titul }}<sup>MM</sup>
{% endif %}
{{ rv.resitel.osoba.plne_jmeno }}
{% for b in rv.hlavni_problemy_body %}
<td class='border-r'>{{ b }}
{% endfor %}
<td class='border-r'>{{ rv.body_cislo }}
<td class='border-r'><b>{{ rv.body_rocnik }}</b>
<td class='border-r'>{{ rv.body_celkem_odjakziva }}
</tr>
{% endfor %}
</table>
{% endif %}
{% if not cislo.verejna_vysledkovka and user.is_staff %}
</div>
{% endif %}
</div>
{% endblock content %} #}

19
seminar/templates/seminar/archiv/problem_tema.html

@ -0,0 +1,19 @@
{% extends "seminar/archiv/problem.html" %}
{% block problem %}
<h1>
{% block nadpis1a %}{% block nadpis1b %}
{{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }}
{% endblock %}{% endblock %}
</h1>
<h2>Zadání</h2>
{{ problem.text_zadani |safe }}
{% if problem.text_reseni %}
<h2>Řešení</h2>
{{ problem.text_reseni |safe }}
{% endif %}
{# TODO vysledkovka tematu #}
{% endblock %}

23
seminar/templates/seminar/archiv/problem_uloha.html

@ -0,0 +1,23 @@
{% extends "seminar/archiv/problem.html" %}
{% block problem %}
<h1>
{% block nadpis1a %}{% block nadpis1b %}
{{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }} {{ problem.body_v_zavorce }}
{% endblock %}{% endblock %}
</h1>
{% if problem.cislo_zadani %}
<p>Zadáno v čísle <a href='{{ problem.cislo_zadani.verejne_url }}'>{{ problem.cislo_zadani.kod }}</a>.
{% endif %}
{% if problem.cislo_reseni %}
<p>Řešeno v čísle <a href='{{ problem.cislo_reseni.verejne_url }}'>{{ problem.cislo_reseni.kod }}</a>.
{% endif %}
<h2>Zadání</h2>
{{ problem.text_zadani |safe }}
{% if problem.text_reseni %}
<h2>Řešení</h2>
{{ problem.text_reseni |safe }}
{% endif %}
{% endblock %}

47
seminar/templates/seminar/tematka/rozcestnik.html

@ -2,24 +2,53 @@
{% block content %} {% block content %}
<p style="text-align:justify">Témata jsou texty nejen z oblasti matematiky, fyziky a informatiky, které popisují nějaký problém a jsou doprovázeny návodnými úlohami. Vaším úkolem je&nbsp;zamyslet se nad daným problémem a sepsat vaše úvahy ve formě krátkého textu.</p>
<p style="text-align:justify"><a href="/co-je-MaM/jak-resit/">Jak řešit téma?</a></p> <h2>
{% block nadpis1a %}{% block nadpis1b %}
Aktuální témata
{% endblock %}{% endblock %}
</h2>
<p style="text-align:justify">&nbsp;</p> <p>Témata jsou texty nejen z oblasti matematiky, fyziky a informatiky, které popisují nějaký
problém a jsou doprovázeny návodnými úlohami. Vaším úkolem je&nbsp;zamyslet se nad daným
problémem a sepsat vaše úvahy ve formě krátkého textu.</p>
<h1>Aktuální témata</h1> <p><a href="/co-je-MaM/jak-resit/">Jak řešit téma?</a></p>
<div class="rozcestnik_temat">
{% for tematko in tematka %} {% for tematko in tematka %}
<h2>{{tematko.nazev}}</h2>
<div class="tematko-obrazek"> {# karta témátka - zepředu ilustrační, zezadu abstrakt #}
<div class="tema_pole">
<h3>
<a href='{{ rocnik.verejne_url }}'>Téma {{ tematko.nazev }}</a>
</h3>
<div class="flip-card" id="tema-rozcestnik">
<div class="flip-card-inner">
<div class="flip-card-front">
<div class="flip-card-foto">
{% if tematko.obrazek %} {% if tematko.obrazek %}
<a href="{{tematko.obrazek.url}}" class="ref-tema-obr"><img src="{{tematko.obrazek.url}}" height="{{tematko.obrazek.height}}" alt="{{tematko.nazev}}"></a> <img src="{{ tematko.obrazek.url }}" alt="{{ tematko.nazev }}">
{% else %} {# pokud témátko nemá fotku, zobrazuje se defaultní obrázek #} {% else %} {# pokud témátko nemá fotku, zobrazuje se defaultní obrázek #}
{% load static %} <img src="{% static 'images/no-photo.png' %}" height=200px alt="{{tematko.nazev}}"> {% load static %} <img src="{% static 'images/tema-bez-obrazku.png' %}" alt="{{ tematko.nazev }}">
{% endif %} {% endif %}
</div> </div>
</div>
<div class="flip-card-back">
<p>{{ tematko.abstrakt }}</p> <p>{{ tematko.abstrakt }}</p>
</div>
</div>
</div>
</div>
{# konec karty témátka #}
{% endfor %} {% endfor %}
</div>
{% endblock %} {% endblock %}

1
seminar/views/views_all.py

@ -127,6 +127,7 @@ class TNLData(object):
def from_treenode(cls,anode,parent=None,index=None): def from_treenode(cls,anode,parent=None,index=None):
out = cls(anode,parent,index) out = cls(anode,parent,index)
for (idx,ch) in enumerate(treelib.all_children(anode)): for (idx,ch) in enumerate(treelib.all_children(anode)):
# FIXME přidat filtrování na veřejnost
outitem = cls.from_treenode(ch,out,idx) outitem = cls.from_treenode(ch,out,idx)
out.children.append(outitem) out.children.append(outitem)
out.add_edit_options() out.add_edit_options()

50
seminar/viewsets.py

@ -2,10 +2,50 @@ from rest_framework import viewsets,filters
from rest_framework import status from rest_framework import status
from rest_framework.response import Response from rest_framework.response import Response
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from rest_framework.permissions import BasePermission, AllowAny
from . import models as m from . import models as m
from . import views from . import views
from seminar.permissions import AllowWrite
class PermissionMixin(object):
""" Redefines get_permissions so that only organizers can make changes. """
def get_permissions(self):
permission_classes = []
print("get_permissions have been called.")
if self.action in ["create", "update", "partial_update", "destroy"]:
permission_classes = [AllowWrite] # speciální permission na zápis - orgové
else:
permission_classes = [AllowAny]
# návštěvník nemusí být zalogován, aby si prohlížel obsah
return [permission() for permission in permission_classes]
def verejne_nad(self, node):
""" Returns output of verejne for closest Rocnik, Cislo or Problem above.
(All of them have method verejne.)"""
parent = get_parent(node)
while True:
rocnik = isinstance(parent, RocnikNode)
cislo = isinstance(parent, CisloNode)
problem = isinstance(parent, ProblemNode)
if (rocnik or cislo or problem):
break
else:
parent = get_parent(parent)
if rocnik:
return parent.rocnik.verejne()
elif cislo:
return parent.cislo.verejne()
elif problem:
return parent.problem.verjne()
def has_object_permission(self, request, view, obj):
# test that obj is Node
assert isinstance(obj, Node)
return verejne_nad(node)
class ReadWriteSerializerMixin(object): class ReadWriteSerializerMixin(object):
""" """
Overrides get_serializer_class to choose the read serializer Overrides get_serializer_class to choose the read serializer
@ -50,17 +90,17 @@ class ReadWriteSerializerMixin(object):
) )
return self.create_serializer_class return self.create_serializer_class
class TextViewSet(viewsets.ModelViewSet): class TextViewSet(PermissionMixin, viewsets.ModelViewSet):
queryset = m.Text.objects.all() queryset = m.Text.objects.all()
serializer_class = views.TextSerializer serializer_class = views.TextSerializer
class TextNodeViewSet(ReadWriteSerializerMixin,viewsets.ModelViewSet): class TextNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet):
queryset = m.TextNode.objects.all() queryset = m.TextNode.objects.all()
read_serializer_class = views.TextNodeSerializer read_serializer_class = views.TextNodeSerializer
write_serializer_class = views.TextNodeWriteSerializer write_serializer_class = views.TextNodeWriteSerializer
create_serializer_class = views.TextNodeCreateSerializer create_serializer_class = views.TextNodeCreateSerializer
class CastNodeViewSet(ReadWriteSerializerMixin,viewsets.ModelViewSet): class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet):
queryset = m.CastNode.objects.all() queryset = m.CastNode.objects.all()
read_serializer_class = views.CastNodeSerializer read_serializer_class = views.CastNodeSerializer
write_serializer_class = views.CastNodeSerializer write_serializer_class = views.CastNodeSerializer
@ -74,7 +114,7 @@ class CastNodeViewSet(ReadWriteSerializerMixin,viewsets.ModelViewSet):
raise PermissionDenied('Nelze smazat CastNode, který má děti!') raise PermissionDenied('Nelze smazat CastNode, který má děti!')
class UlohaVzorakNodeViewSet(viewsets.ModelViewSet): class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet):
serializer_class = views.UlohaVzorakNodeSerializer serializer_class = views.UlohaVzorakNodeSerializer
def get_queryset(self): def get_queryset(self):

Loading…
Cancel
Save