Merge remote-tracking branch 'Gimli/data_migrations' into test
This commit is contained in:
commit
3408183070
38 changed files with 1976 additions and 170 deletions
File diff suppressed because one or more lines are too long
|
@ -3,8 +3,8 @@ from seminar.utils import org_required
|
|||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('korektury/', org_required(views.KorekturyAktualniListView.as_view()), name='korektury-list'),
|
||||
path('korektury/zastarale/', org_required(views.KorekturyZastaraleListView.as_view()), name='korektury-list'),
|
||||
path('korektury/', org_required(views.KorekturyAktualniListView.as_view()), name='korektury_list'),
|
||||
path('korektury/zastarale/', org_required(views.KorekturyZastaraleListView.as_view()), name='korektury_stare_list'),
|
||||
path('korektury/<int:pdf>/', org_required(views.KorekturyView.as_view()), name='korektury'),
|
||||
path('korektury/help/', org_required(views.KorekturyHelpView.as_view()), name='korektury-help'),
|
||||
]
|
||||
|
|
|
@ -4,7 +4,12 @@ from seminar import viewsets as vs
|
|||
router = routers.DefaultRouter()
|
||||
|
||||
router.register(r'ulohavzoraknode', vs.UlohaVzorakNodeViewSet,basename='ulohavzoraknode')
|
||||
router.register(r'reseninode', vs.ReseniNodeViewSet,basename='reseninode')
|
||||
router.register(r'text', vs.TextViewSet)
|
||||
router.register(r'textnode', vs.TextNodeViewSet)
|
||||
router.register(r'castnode', vs.CastNodeViewSet)
|
||||
router.register(r'problem', vs.ProblemViewSet, basename='problem')
|
||||
router.register(r'uloha', vs.UlohaViewSet, basename='uloha')
|
||||
router.register(r'reseni', vs.ReseniViewSet, basename='reseni')
|
||||
router.register(r'ulohazadaninode', vs.UlohaZadaniNodeViewSet)
|
||||
|
||||
|
|
|
@ -295,6 +295,9 @@ LOGGING = {
|
|||
},
|
||||
}
|
||||
|
||||
# Permissions for uploads
|
||||
FILE_UPLOAD_PERMISSIONS = 0o0644
|
||||
|
||||
# MaM specific
|
||||
|
||||
SEMINAR_RESENI_DIR = os.path.join('reseni')
|
||||
|
|
|
@ -28,7 +28,7 @@ INTERNAL_IPS = ['127.0.0.1']
|
|||
|
||||
TEMPLATES[0]['OPTIONS']['debug'] = True
|
||||
|
||||
ALLOWED_HOSTS = ['127.0.0.1']
|
||||
ALLOWED_HOSTS = ['127.0.0.1', '192.168.43.34']
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
|
||||
|
|
|
@ -347,6 +347,10 @@ div.zadani_azad_termin {
|
|||
bottom: 0px;
|
||||
}
|
||||
|
||||
#footer p.license a {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
p.license-mobile {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.auth.models import Permission
|
||||
|
||||
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
|
||||
from reversion.admin import VersionAdmin
|
||||
|
@ -18,7 +19,7 @@ admin.site.register(m.Soustredeni)
|
|||
|
||||
@admin.register(m.Osoba)
|
||||
class OsobaAdmin(admin.ModelAdmin):
|
||||
actions = ['synchronizuj_maily']
|
||||
actions = ['synchronizuj_maily', 'udelej_orgem']
|
||||
|
||||
def synchronizuj_maily(self, request, queryset):
|
||||
for o in queryset:
|
||||
|
@ -29,6 +30,20 @@ class OsobaAdmin(admin.ModelAdmin):
|
|||
self.message_user(request, "E-maily synchronizovány.")
|
||||
synchronizuj_maily.short_description = "Synchronizuj vybraným osobám e-maily do uživatelů"
|
||||
|
||||
def udelej_orgem(self,request,queryset):
|
||||
org_perm = Permission.objects.filter(codename__exact='org').first()
|
||||
print(queryset)
|
||||
for o in queryset:
|
||||
user = o.user
|
||||
user.user_permissions.add(org_perm)
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
org = m.Organizator.objects.create(osoba=o)
|
||||
org.save()
|
||||
udelej_orgem.short_description = "Udělej vybraných osob organizátory"
|
||||
|
||||
|
||||
|
||||
@admin.register(m.Problem)
|
||||
class ProblemAdmin(PolymorphicParentModelAdmin):
|
||||
base_model = m.Problem
|
||||
|
|
|
@ -10,6 +10,21 @@ import seminar.models as m
|
|||
from datetime import date
|
||||
import logging
|
||||
|
||||
# pro přidání políčka do formuláře je potřeba
|
||||
# - mít v modelu tu položku, kterou chci upravovat
|
||||
# - přidat do views (prihlaskaView, resitelEditView)
|
||||
# - přidat do forms
|
||||
# - includovat do html
|
||||
|
||||
class DateInput(forms.DateInput):
|
||||
# aby se datum dalo vybírat z kalendáře
|
||||
input_type = 'date'
|
||||
|
||||
class TelInput(forms.TextInput):
|
||||
# tohle je možná k niřemu, ale alepsoň to mění input type a nic to nekazí
|
||||
input_type = 'tel'
|
||||
input_pattern="^[+]?[()/0-9. -]{9,}$"
|
||||
|
||||
class LoginForm(forms.Form):
|
||||
username = forms.CharField(label='Přihlašovací jméno',
|
||||
max_length=256,
|
||||
|
@ -42,8 +57,8 @@ class PrihlaskaForm(forms.Form):
|
|||
pohlavi_muz = forms.ChoiceField(label='Pohlaví',
|
||||
choices = ((True,'muž'),(False,'žena')), required=True)
|
||||
email = forms.EmailField(label='E-mail',max_length=256, required=True)
|
||||
telefon = forms.CharField(label='Telefon',max_length=256, required=False)
|
||||
datum_narozeni = forms.DateField(label='Datum narození', required=False)
|
||||
telefon = forms.CharField(widget=TelInput(),label='Telefon',max_length=256, required=False)
|
||||
datum_narozeni = forms.DateField(widget=DateInput(),label='Datum narození', required=False)
|
||||
ulice = forms.CharField(label='Ulice', max_length=256, required=False)
|
||||
mesto = forms.CharField(label='Město', max_length=256, required=False)
|
||||
psc = forms.CharField(label='PSČ', max_length=32, required=False)
|
||||
|
@ -74,6 +89,8 @@ class PrihlaskaForm(forms.Form):
|
|||
max_value=date.today().year+8,
|
||||
required=True)
|
||||
zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True)
|
||||
zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat emailem upozornění na vydání nového čísla', required=True)
|
||||
|
||||
gdpr = forms.BooleanField(label='Souhlasím se zpracováním osobních údajů', required=True)
|
||||
spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
|
||||
|
||||
|
@ -135,8 +152,8 @@ class ProfileEditForm(forms.Form):
|
|||
pohlavi_muz = forms.ChoiceField(label='Pohlaví',
|
||||
choices = ((True,'muž'),(False,'žena')), required=True)
|
||||
email = forms.EmailField(label='E-mail',max_length=256, required=True)
|
||||
telefon = forms.CharField(label='Telefon',max_length=256, required=False)
|
||||
datum_narozeni = forms.DateField(label='Datum narození', required=False)
|
||||
telefon = forms.CharField(widget=TelInput(),label='Telefon',max_length=256, required=False)
|
||||
datum_narozeni = forms.DateField(widget=DateInput(),label='Datum narození', required=False)
|
||||
ulice = forms.CharField(label='Ulice', max_length=256, required=False)
|
||||
mesto = forms.CharField(label='Město', max_length=256, required=False)
|
||||
psc = forms.CharField(label='PSČ', max_length=32, required=False)
|
||||
|
@ -167,6 +184,8 @@ class ProfileEditForm(forms.Form):
|
|||
max_value=date.today().year+8,
|
||||
required=True)
|
||||
zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True)
|
||||
zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat email s upozorněním na vydání nového čísla', required=True)
|
||||
|
||||
spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
|
||||
# def clean_username(self):
|
||||
# err_logger = logging.getLogger('seminar.prihlaska.problem')
|
||||
|
@ -234,7 +253,7 @@ class VlozReseniForm(forms.Form):
|
|||
#resitele = models.ManyToManyField(Resitel, verbose_name='autoři řešení',
|
||||
# help_text='Seznam autorů řešení', through='Reseni_Resitele')
|
||||
|
||||
cas_doruceni = forms.DateField(label="Čas doručení")
|
||||
cas_doruceni = forms.DateField(widget=DateInput(),label="Čas doručení")
|
||||
|
||||
#cas_doruceni = models.DateTimeField('čas_doručení', default=timezone.now, blank=True)
|
||||
|
||||
|
|
19
seminar/migrations/0090_auto_20201110_1958.py
Normal file
19
seminar/migrations/0090_auto_20201110_1958.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.12 on 2020-11-10 18:58
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('seminar', '0089_cislo_datum_preddeadline'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='textnode',
|
||||
name='text',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='seminar.Text', verbose_name='text'),
|
||||
),
|
||||
]
|
18
seminar/migrations/0091_resitel_zasilat_cislo_emailem.py
Normal file
18
seminar/migrations/0091_resitel_zasilat_cislo_emailem.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.17 on 2020-12-01 19:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('seminar', '0090_auto_20201110_1958'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='resitel',
|
||||
name='zasilat_cislo_emailem',
|
||||
field=models.BooleanField(default=False, help_text='True pokud chce řešitel dostávat číslo emailem', verbose_name='zasílat číslo emailem'),
|
||||
),
|
||||
]
|
|
@ -260,8 +260,10 @@ class Resitel(SeminarModelBase):
|
|||
(ZASILAT_DO_SKOLY, 'Do školy'),
|
||||
(ZASILAT_NIKAM, 'Nikam'),
|
||||
]
|
||||
|
||||
zasilat = models.CharField('kam zasílat', max_length=32, choices=ZASILAT_CHOICES, blank=False, default=ZASILAT_DOMU)
|
||||
|
||||
zasilat_cislo_emailem = models.BooleanField('zasílat číslo emailem', help_text='True pokud chce řešitel dostávat číslo emailem', default=False)
|
||||
|
||||
poznamka = models.TextField('neveřejná poznámka', blank=True,
|
||||
help_text='Neveřejná poznámka k řešiteli (plain text)')
|
||||
|
@ -309,25 +311,106 @@ class Resitel(SeminarModelBase):
|
|||
return sum(h.body for h in list(vsechna_hodnoceni))
|
||||
|
||||
|
||||
def get_titul(self, celkove_body=None):
|
||||
"Vrati titul"
|
||||
if celkove_body is None:
|
||||
celkove_body = self.vsechny_body()
|
||||
def get_titul(self, body=None):
|
||||
"Vrati titul jako řetězec."
|
||||
|
||||
# Nejprve si zadefinujeme titul
|
||||
from enum import Enum
|
||||
from functools import total_ordering
|
||||
@total_ordering
|
||||
class Titul(Enum):
|
||||
""" Třída reprezentující možné tituly. Hodnoty jsou dvojice (dolní hranice, stringifikace). """
|
||||
nic = (0, '')
|
||||
bc = (20, 'Bc.')
|
||||
mgr = (50, 'Mgr.')
|
||||
dr = (100, 'Dr.')
|
||||
doc = (200, 'Doc.')
|
||||
prof = (500, 'Prof.')
|
||||
akad = (1000, 'Akad.')
|
||||
|
||||
if celkove_body < 10:
|
||||
return ''
|
||||
elif celkove_body < 20:
|
||||
return 'Bc.'
|
||||
elif celkove_body < 50:
|
||||
return 'Mgr.'
|
||||
elif celkove_body < 100:
|
||||
return 'Dr.'
|
||||
elif celkove_body < 200:
|
||||
return 'Doc.'
|
||||
elif celkove_body < 500:
|
||||
return 'Prof.'
|
||||
def __lt__(self, other):
|
||||
return True if self.value[0] < other.value[0] else False
|
||||
def __eq__(self, other): # Měla by být implicitní, ale klidně explicitně.
|
||||
return True if self.value[0] == other.value[0] else False
|
||||
|
||||
def __str__(self):
|
||||
return self.value[1]
|
||||
|
||||
@classmethod
|
||||
def z_bodu(cls, body):
|
||||
aktualni = cls.nic
|
||||
# TODO: ověřit, že to funguje
|
||||
for titul in cls: # Kdyžtak použít __members__.items()
|
||||
if titul.value[0] <= body:
|
||||
aktualni = titul
|
||||
else:
|
||||
break
|
||||
return aktualni
|
||||
|
||||
# Hledáme body v databázi
|
||||
# V listopadu 2020 jsme se na filosofické schůzce shodli o změně hranic titulů:
|
||||
# - body z 25. ročníku a dříve byly shledány dvakrát hodnotnějšími
|
||||
# - proto se započítávají dvojnásobně a byly posunuté hranice titulů
|
||||
# - staré tituly se ale nemají odebrat, pokud řešitel v t.č. minulém (26.) ročníku měl titul, má ho mít pořád.
|
||||
hodnoceni_do_25_rocniku = Hodnoceni.objects.filter(cislo_body__rocnik__rocnik__lte=25,reseni__in=self.reseni_set.all())
|
||||
novejsi_hodnoceni = Hodnoceni.objects.filter(reseni__in=self.reseni_set.all()).difference(hodnoceni_do_25_rocniku)
|
||||
|
||||
def body_z_hodnoceni(hh : list):
|
||||
return sum(h.body for h in hh)
|
||||
|
||||
stare_body = body_z_hodnoceni(hodnoceni_do_25_rocniku)
|
||||
if body is None:
|
||||
nove_body = body_z_hodnoceni(novejsi_hodnoceni)
|
||||
else:
|
||||
return 'Akad.'
|
||||
# Zjistíme, kolik bodů jsou staré, tedy hodnotnější
|
||||
nove_body = max(0, body - stare_body) # Všechny body nad počet původních hodnotnějších
|
||||
stare_body = min(stare_body, body) # Skutečný počet hodnotnějších bodů
|
||||
logicke_body = 2*stare_body + nove_body
|
||||
|
||||
|
||||
# Titul se určí následovně:
|
||||
# - Pokud se řeší body, které jsou starší, než do 26 ročníku (včetně), dáváme tituly postaru.
|
||||
# - Jinak dáváme tituly po novu...
|
||||
# - ... ale titul se nesmí odebrat, pokud se zmenšil.
|
||||
def titul_do_26_rocniku(body):
|
||||
""" Původní hranice bodů za tituly """
|
||||
if body < 10:
|
||||
return Titul.nic
|
||||
elif body < 20:
|
||||
return Titul.bc
|
||||
elif body < 50:
|
||||
return Titul.mgr
|
||||
elif body < 100:
|
||||
return Titul.dr
|
||||
elif body < 200:
|
||||
return Titul.doc
|
||||
elif body < 500:
|
||||
return Titul.prof
|
||||
else:
|
||||
return Titul.akad
|
||||
|
||||
hodnoceni_do_26_rocniku = Hodnoceni.objects.filter(cislo_body__rocnik__rocnik__lte=26,reseni__in=self.reseni_set.all())
|
||||
novejsi_body = body_z_hodnoceni(
|
||||
Hodnoceni.objects.filter(reseni__in=self.reseni_set.all())
|
||||
.difference(hodnoceni_do_26_rocniku)
|
||||
)
|
||||
starsi_body = body_z_hodnoceni(hodnoceni_do_26_rocniku)
|
||||
if body is not None:
|
||||
# Ještě z toho vybereme ty správně staré body
|
||||
novejsi_body = max(0, body - starsi_body)
|
||||
starsi_body = min(starsi_body, body)
|
||||
|
||||
# Titul pro 26. ročník
|
||||
stary_titul = titul_do_26_rocniku(starsi_body)
|
||||
# Titul podle aktuálních pravidel
|
||||
novy_titul = Titul.z_bodu(logicke_body)
|
||||
|
||||
if novejsi_body == 0:
|
||||
# Žádné nové body -- titul podle starých pravidel
|
||||
return str(stary_titul)
|
||||
return str(max(novy_titul, stary_titul))
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.osoba.plne_jmeno()
|
||||
|
||||
|
@ -745,15 +828,18 @@ class Problem(SeminarModelBase,PolymorphicModel):
|
|||
def verejne(self):
|
||||
# aktuálně podle stavu problému
|
||||
# FIXME pro některé problémy možná chceme override
|
||||
# FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.
|
||||
# Je to tak správně?
|
||||
stav_verejny = False
|
||||
if self.stav == 'zadany' or self.stav == 'vyreseny':
|
||||
stav_verejny = True
|
||||
return stav_verejny
|
||||
|
||||
cislo_verejne = False
|
||||
if (self.cislo_zadani and self.cislo_zadani.verejne()):
|
||||
cislo_verejne = True
|
||||
#cislo_verejne = False
|
||||
#if (self.cislo_zadani and self.cislo_zadani.verejne()):
|
||||
# cislo_verejne = True
|
||||
|
||||
return (stav_verejny and cislo_verejne)
|
||||
#return (stav_verejny and cislo_verejne)
|
||||
verejne.boolean = True
|
||||
|
||||
def verejne_url(self):
|
||||
|
@ -991,7 +1077,7 @@ def aux_generate_filename(self, filename):
|
|||
unidecode(filename.replace('/', '-').replace('\0', ''))
|
||||
)
|
||||
datedir = timezone.now().strftime('%Y-%m')
|
||||
fname = "{}_{}".format(
|
||||
fname = "{}/{}".format(
|
||||
timezone.now().strftime('%Y-%m-%d-%H:%M'),
|
||||
clean)
|
||||
return os.path.join(datedir, fname)
|
||||
|
@ -1044,6 +1130,11 @@ class PrilohaReseni(SeminarModelBase):
|
|||
def __str__(self):
|
||||
return str(self.soubor)
|
||||
|
||||
def split(self):
|
||||
"Vrátí cestu rozsekanou po složkách. To se hodí v templatech"
|
||||
# Věřím, že tohle funguje, případně použít os.path nebo pathlib.
|
||||
return self.soubor.url.split('/')
|
||||
|
||||
|
||||
class Pohadka(SeminarModelBase):
|
||||
"""Kus pohádky před/za úlohou v čísle"""
|
||||
|
@ -1480,7 +1571,7 @@ class TextNode(TreeNode):
|
|||
verbose_name = 'Text (Node)'
|
||||
verbose_name_plural = 'Text (Node)'
|
||||
text = models.ForeignKey(Text,
|
||||
on_delete=models.PROTECT,
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name = 'text')
|
||||
|
||||
def aktualizuj_nazev(self):
|
||||
|
@ -1513,7 +1604,7 @@ class ReseniNode(TreeNode):
|
|||
verbose_name = 'reseni')
|
||||
|
||||
def aktualizuj_nazev(self):
|
||||
self.nazev = "OtisteneReseniNode: "+str(self.reseni)
|
||||
self.nazev = "ReseniNode: "+str(self.reseni)
|
||||
|
||||
def getOdkazStr(self):
|
||||
return str(self.reseni)
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
<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>
|
||||
<li><a href="odmeny/{{prevcislo.rocnik.rocnik}}.{{prevcislo.poradi}}/">Odměny</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -75,6 +76,7 @@
|
|||
{% for p in problemy %}
|
||||
<th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a>
|
||||
{% endfor %}
|
||||
{% if ostatni %}<th class='border-r'>Ostatní {% endif %}
|
||||
<th class='border-r'>Za číslo
|
||||
<th class='border-r'>Za ročník
|
||||
<th class='border-r'>Odjakživa
|
||||
|
|
15
seminar/templates/seminar/archiv/odmeny.html
Normal file
15
seminar/templates/seminar/archiv/odmeny.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>
|
||||
{% block nadpis1a %}{% block nadpis1b %}
|
||||
Odměny {{ cislo }}
|
||||
{% endblock %}{% endblock %}
|
||||
</h1>
|
||||
<ul>
|
||||
{% for z in zmeny %}
|
||||
<li> {{z.jmeno}}: {{z.ftitul}} → {{z.ttitul}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock content %}
|
47
seminar/templates/seminar/odevzdavatko/detail.html
Normal file
47
seminar/templates/seminar/odevzdavatko/detail.html
Normal file
|
@ -0,0 +1,47 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p>Řešené problémy: {{ object.problem.all | join:", " }}</p>
|
||||
|
||||
<p>Řešitelé: {{ object.resitele.all | join:", " }}</p>
|
||||
|
||||
{# https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.get_FOO_display #}
|
||||
<p>Forma: {{ object.get_forma_display }}, doručeno {{ object.cas_doruceni }}</p>
|
||||
|
||||
{# Soubory: #}
|
||||
<h3>Přílohy:</h3>
|
||||
{% if object.prilohy.all %}
|
||||
<table>
|
||||
<tr><th>Soubor</th><th>Řešitelova poznámka</th><th>Datum</th></tr>
|
||||
{% for priloha in object.prilohy.all %}
|
||||
<tr>
|
||||
<td><a href="{{ priloha.soubor.url }}" download>{{ priloha.split | last }}</a></td>
|
||||
<td>{{ priloha.res_poznamka }}</td>
|
||||
<td>{{ priloha.vytvoreno }}</td></tr>
|
||||
{# TODO: Orgo-poznámka, ideálně jako formulář #}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Žádné přílohy</p>
|
||||
{% endif %}
|
||||
|
||||
{# Hodnocení: #}
|
||||
{# FIXME: Udělat jako formulář #}
|
||||
<h3>Hodnocení:</h3>
|
||||
{% if object.hodnoceni_set.all %}
|
||||
<table>
|
||||
<tr><th>Problém</th><th>Body</th><th>Číslo pro body</th></tr>
|
||||
{% for h in object.hodnoceni_set.all %}
|
||||
<tr>
|
||||
<td>{{ h.problem }}</a></td>
|
||||
<td>{{ h.body }}</td>
|
||||
<td>{{ h.cislo_body }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Ještě nebylo hodnoceno</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endblock %}
|
11
seminar/templates/seminar/odevzdavatko/seznam.html
Normal file
11
seminar/templates/seminar/odevzdavatko/seznam.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<ul>
|
||||
{% for obj in object_list %}
|
||||
<li><a href="{% url 'odevzdavatko_detail_reseni' pk=obj.id %}">{{ obj }}</a> ({{ obj.get_forma_display }} {{ obj.cas_doruceni }})
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
36
seminar/templates/seminar/odevzdavatko/tabulka.html
Normal file
36
seminar/templates/seminar/odevzdavatko/tabulka.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load utils %} {# Možná by mohlo být někde výš v hierarchii templatů... #}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td></td> {# Prázdná buňka v levém horním rohu #}
|
||||
{% for p in problemy %}
|
||||
<th>
|
||||
{# TODO: Přehled řešení k problému, odkázaný odsud? #}
|
||||
{{ p }}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for resitel,hodnoty in radky%}
|
||||
<tr>
|
||||
<td>
|
||||
{# TODO: Chceme mít view i na řešení konkrétního řešitele ke všem problémům? #}
|
||||
{{ resitel }}
|
||||
</td>
|
||||
{% for hodn in hodnoty %}
|
||||
<td>
|
||||
{% if hodn %}
|
||||
<a href="{% url 'odevzdavatko_reseni_resitele_k_problemu' problem=hodn.problem_id resitel=hodn.resitel_id %}">
|
||||
{{ hodn.pocet_reseni }} řeš.<br>{{ hodn.body }} b<br>{{ hodn.posledni_odevzdani|kratke_datum|default_if_none:"Nikdy"|default:"???"}}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
|
@ -6,6 +6,17 @@
|
|||
{{form.media}}
|
||||
<script src="{% static 'seminar/prihlaska.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
<!--
|
||||
|
||||
# pro přidání políčka do formuláře je potřeba
|
||||
# - mít v modelu tu položku, kterou chci upravovat
|
||||
# - přidat do views (prihlaskaView, resitelEditView)
|
||||
# - přidat do forms
|
||||
# - includovat do html
|
||||
|
||||
-->
|
||||
|
||||
{% block content %}
|
||||
<h1>
|
||||
{% block nadpis1a %}{% block nadpis1b %}
|
||||
|
@ -73,6 +84,7 @@
|
|||
</h4>
|
||||
<table class="form">
|
||||
{% include "seminar/profil/prihlaska_field.html" with field=form.zasilat %}
|
||||
{% include "seminar/profil/prihlaska_field.html" with field=form.zasilat_cislo_emailem %}
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
</td>
|
||||
<td {% if field.help_text %} class="field-with-comment"{% endif %}>
|
||||
{{ field }}
|
||||
<span class="field-comment">{{ field.help_text|safe }}</span>>
|
||||
<span class="field-comment">{{ field.help_text|safe }}</span>
|
||||
</td>
|
||||
|
||||
<td><span class="field-error">{{ field.errors }}</span></td>
|
||||
|
|
|
@ -7,6 +7,16 @@
|
|||
<script src="{% static 'seminar/prihlaska.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
<!--
|
||||
|
||||
# pro přidání políčka do formuláře je potřeba
|
||||
# - mít v modelu tu položku, kterou chci upravovat
|
||||
# - přidat do views (prihlaskaView, resitelEditView)
|
||||
# - přidat do forms
|
||||
# - includovat do html
|
||||
|
||||
-->
|
||||
|
||||
{% block content %}
|
||||
<h1>
|
||||
{% block nadpis1a %}{% block nadpis1b %}
|
||||
|
@ -77,6 +87,7 @@
|
|||
</h4>
|
||||
<table class="form">
|
||||
{% include "seminar/profil/prihlaska_field.html" with field=form.zasilat %}
|
||||
{% include "seminar/profil/prihlaska_field.html" with field=form.zasilat_cislo_emailem %}
|
||||
</table>
|
||||
<hr>
|
||||
|
||||
|
|
27
seminar/templatetags/utils.py
Normal file
27
seminar/templatetags/utils.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from django import template
|
||||
from datetime import datetime, timedelta
|
||||
from pytz import timezone
|
||||
from mamweb.settings import TIME_ZONE
|
||||
import logging
|
||||
register = template.Library()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@register.filter(name='kratke_datum', expects_localtime=True)
|
||||
def kratke_datum(dt):
|
||||
# None dává None, ne-datum dává False, aby se daly použít filtry typu "default".
|
||||
if dt is None:
|
||||
return None
|
||||
if not isinstance(dt, datetime):
|
||||
logger.warning(f"Špatné volání filtru {__name__}: {dt}")
|
||||
return False
|
||||
naive_now = datetime.now()
|
||||
tz = timezone(TIME_ZONE)
|
||||
now = tz.localize(naive_now)
|
||||
delta = now - dt
|
||||
if delta <= timedelta(days=1):
|
||||
return dt.strftime("%k:%M")
|
||||
if delta <= timedelta(days=365): # Timedelta neumí vyjádřit 1 rok
|
||||
return dt.strftime("%d. %m.")
|
||||
return dt.strftime("%d. %m. %Y")
|
||||
|
|
@ -200,6 +200,8 @@ def gen_organizatori(rnd, osoby, last_rocnik):
|
|||
os.user = user
|
||||
os.save()
|
||||
os.user.user_permissions.add(org_perm)
|
||||
os.user.is_staff = True
|
||||
os.user.save()
|
||||
organizatori.append(Organizator.objects.create(osoba=os,
|
||||
organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga))
|
||||
return organizatori
|
||||
|
|
|
@ -13,8 +13,8 @@ urlpatterns = [
|
|||
path('co-je-MaM/organizatori/organizovali/', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'),
|
||||
|
||||
# Archiv
|
||||
path('archiv/rocniky/', views.ArchivView.as_view()),
|
||||
path('archiv/temata/', views.ArchivTemataView.as_view()),
|
||||
path('archiv/rocniky/', views.ArchivView.as_view(), name="seninar_archiv_rocniky"),
|
||||
path('archiv/temata/', views.ArchivTemataView.as_view(), name="seninar_archiv_temata"),
|
||||
|
||||
path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'),
|
||||
path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='seminar_cislo'),
|
||||
|
@ -90,17 +90,17 @@ urlpatterns = [
|
|||
name='seminar_rocnik_vysledkovka'
|
||||
),
|
||||
path(
|
||||
'cislo/<int:rocnik>.<int:cislo>/vysledkovka.tex',
|
||||
'cislo/<int:rocnik>.<str:cislo>/vysledkovka.tex',
|
||||
org_required(views.CisloVysledkovkaView.as_view()),
|
||||
name='seminar_cislo_vysledkovka'
|
||||
),
|
||||
path(
|
||||
'cislo/<int:rocnik>.<int:cislo>/obalky.pdf',
|
||||
'cislo/<int:rocnik>.<str:cislo>/obalky.pdf',
|
||||
org_required(views.cisloObalkyView),
|
||||
name='seminar_cislo_obalky'
|
||||
),
|
||||
path(
|
||||
'cislo/<int:rocnik>.<int:cislo>/tituly.tex',
|
||||
'cislo/<int:rocnik>.<str:cislo>/tituly.tex',
|
||||
org_required(views.TitulyView),
|
||||
name='seminar_cislo_titul'
|
||||
),
|
||||
|
@ -110,10 +110,14 @@ urlpatterns = [
|
|||
name='stav_databaze'
|
||||
),
|
||||
path(
|
||||
'cislo/<int:rocnik>.<int:cislo>/obalkovani',
|
||||
'cislo/<int:rocnik>.<str:cislo>/obalkovani',
|
||||
org_required(views.ObalkovaniView.as_view()),
|
||||
name='seminar_cislo_resitel_obalkovani'
|
||||
),
|
||||
path(
|
||||
'cislo/<int:trocnik>.<str:tcislo>/odmeny/<int:frocnik>.<str:fcislo>/',
|
||||
org_required(views.OdmenyView.as_view()),
|
||||
name="seminar_archiv_odmeny"),
|
||||
path(
|
||||
'soustredeni/<int:soustredeni>/obalky.pdf',
|
||||
org_required(views.soustredeniObalkyView),
|
||||
|
@ -168,5 +172,10 @@ urlpatterns = [
|
|||
# org_member_required(views.OrganizatorAutocomplete.as_view()),
|
||||
# name='seminar_autocomplete_organizator')
|
||||
|
||||
path('temp/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
|
||||
path('temp/reseni/<int:problem>/<int:resitel>/', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'),
|
||||
path('temp/reseni/<int:pk>', org_required(views.DetailReseniView.as_view()), name='odevzdavatko_detail_reseni'),
|
||||
path('temp/reseni/all', org_required(views.SeznamReseniView.as_view())),
|
||||
path('temp/reseni/akt', org_required(views.SeznamAktualnichReseniView.as_view())),
|
||||
|
||||
]
|
||||
|
|
|
@ -148,16 +148,12 @@ def resi_v_rocniku(rocnik, cislo=None):
|
|||
|
||||
if cislo is None:
|
||||
# filtrujeme pouze podle ročníku
|
||||
letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik)
|
||||
return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
|
||||
reseni__hodnoceni__cislo_body__rocnik=rocnik).distinct()
|
||||
else: # filtrujeme podle ročníku i čísla
|
||||
letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik,
|
||||
hodnoceni__cislo_body__poradi__lte=cislo.poradi)
|
||||
|
||||
# vygenerujeme queryset řešitelů, co letos něco poslali
|
||||
letosni_resitele = m.Resitel.objects.none()
|
||||
for reseni in letosni_reseni:
|
||||
letosni_resitele = letosni_resitele | reseni.resitele.filter(rok_maturity__gte=rocnik.druhy_rok())
|
||||
return letosni_resitele.distinct()
|
||||
return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
|
||||
reseni__hodnoceni__cislo_body__rocnik=rocnik,
|
||||
reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi).distinct()
|
||||
|
||||
|
||||
def aktivniResitele(cislo, pouze_letosni=False):
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from .views_all import *
|
||||
from .autocomplete import *
|
||||
from .views_rest import *
|
||||
from .odevzdavatko import *
|
||||
|
|
|
@ -34,7 +34,9 @@ class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView):
|
|||
rocnik = nastaveni.aktualni_rocnik
|
||||
temata = m.Tema.objects.filter(rocnik=rocnik, stav=m.Problem.STAV_ZADANY)
|
||||
ulohy = m.Uloha.objects.filter(cislo_deadline__rocnik = rocnik)
|
||||
clanky = m.Clanek.objects.filter(cislo__rocnik = rocnik, stav=m.Problem.STAV_ZADANY) # FIXME: Je tohle to, co chceme?
|
||||
ulohy.union(temata)
|
||||
ulohy.union(clanky)
|
||||
qs = ulohy
|
||||
if self.q:
|
||||
qs = qs.filter(
|
||||
|
|
129
seminar/views/odevzdavatko.py
Normal file
129
seminar/views/odevzdavatko.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
from django.views.generic import ListView, DetailView
|
||||
from django.views.generic.base import TemplateView
|
||||
|
||||
from dataclasses import dataclass
|
||||
import datetime
|
||||
|
||||
import seminar.models as m
|
||||
from seminar.utils import aktivniResitele, resi_v_rocniku
|
||||
|
||||
# Co chceme?
|
||||
# - "Tabulku" aktuální řešitelé x zveřejněné problémy, v buňkách počet řešení
|
||||
# - TabulkaOdevzdanychReseniView
|
||||
# - Detail konkrétního problému a řešitele -- přehled všech řešení odevzdaných k tomuto problému
|
||||
# - ReseniProblemuView
|
||||
# - Detail konkrétního řešení -- všechny soubory, datum, ...
|
||||
# - DetailReseniView
|
||||
#
|
||||
# Taky se může hodit:
|
||||
# - Tabulka všech řešitelů x všech problémů?
|
||||
|
||||
@dataclass
|
||||
class SouhrnReseni:
|
||||
"""Dataclass reprezentující data o odevzdaných řešeních pro zobrazení v tabulce."""
|
||||
pocet_reseni : int
|
||||
posledni_odevzdani : datetime.datetime
|
||||
body : float
|
||||
|
||||
|
||||
class TabulkaOdevzdanychReseniView(ListView):
|
||||
template_name = 'seminar/odevzdavatko/tabulka.html'
|
||||
model = m.Hodnoceni
|
||||
|
||||
def get_queryset(self):
|
||||
# FIXME: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistuje Nastavení.
|
||||
self.akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi...
|
||||
self.resitele = resi_v_rocniku(self.akt_rocnik)
|
||||
# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy.
|
||||
self.zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic()
|
||||
|
||||
qs = super().get_queryset()
|
||||
qs = qs.filter(problem__in=self.zadane_problemy).select_related('reseni', 'problem').prefetch_related('reseni__resitele__osoba')
|
||||
return qs
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
# FIXME: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistuje Nastavení.
|
||||
self.akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi...
|
||||
self.resitele = resi_v_rocniku(self.akt_rocnik)
|
||||
# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy.
|
||||
self.zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic()
|
||||
|
||||
ctx = super().get_context_data(*args, **kwargs)
|
||||
ctx['problemy'] = self.zadane_problemy
|
||||
ctx['resitele'] = self.resitele
|
||||
tabulka = dict()
|
||||
|
||||
def pridej_reseni(problem, resitel, body, cas):
|
||||
if problem not in tabulka:
|
||||
tabulka[problem] = dict()
|
||||
if resitel not in tabulka[problem]:
|
||||
tabulka[problem][resitel] = SouhrnReseni(pocet_reseni=1, posledni_odevzdani=cas, body=body)
|
||||
else:
|
||||
tabulka[problem][resitel].posledni_odevzdani = max(tabulka[problem][resitel].posledni_odevzdani, cas)
|
||||
tabulka[problem][resitel].body = max(tabulka[problem][resitel].body, body,
|
||||
key=lambda x: x if x is not None else -1 # None je malé číslo
|
||||
# FIXME: Možná dává smysl i mít None jako velké číslo -- jakože "TODO: zadat body"
|
||||
)
|
||||
tabulka[problem][resitel].pocet_reseni += 1
|
||||
# Pro jednoduchost template si ještě poznamenáme ID problému a řešitele
|
||||
tabulka[problem][resitel].problem_id = problem.id
|
||||
tabulka[problem][resitel].resitel_id = resitel.id
|
||||
|
||||
for hodnoceni in self.get_queryset():
|
||||
for resitel in hodnoceni.reseni.resitele.all():
|
||||
pridej_reseni(hodnoceni.problem, resitel, hodnoceni.body, hodnoceni.reseni.cas_doruceni)
|
||||
|
||||
hodnoty = []
|
||||
for resitel in self.resitele:
|
||||
resiteluv_radek = []
|
||||
for problem in self.zadane_problemy:
|
||||
if problem in tabulka and resitel in tabulka[problem]:
|
||||
resiteluv_radek.append(tabulka[problem][resitel])
|
||||
else:
|
||||
resiteluv_radek.append(None)
|
||||
hodnoty.append(resiteluv_radek)
|
||||
ctx['radky'] = list(zip(self.resitele, hodnoty))
|
||||
|
||||
return ctx
|
||||
|
||||
class ReseniProblemuView(ListView):
|
||||
model = m.Reseni
|
||||
template_name = 'seminar/odevzdavatko/seznam.html'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
resitel_id = self.kwargs['resitel']
|
||||
if resitel_id is None:
|
||||
raise ValueError("Nemám řešitele!")
|
||||
problem_id = self.kwargs['problem']
|
||||
if problem_id is None:
|
||||
raise ValueError("Nemám problém! (To je problém!)")
|
||||
|
||||
resitel = m.Resitel.objects.get(id=resitel_id)
|
||||
problem = m.Problem.objects.get(id=problem_id)
|
||||
qs = qs.filter(
|
||||
problem__in=[problem],
|
||||
resitele__in=[resitel],
|
||||
)
|
||||
return qs
|
||||
|
||||
# Kontext automaticky?
|
||||
|
||||
class DetailReseniView(DetailView):
|
||||
model = m.Reseni
|
||||
template_name = 'seminar/odevzdavatko/detail.html'
|
||||
# To je všechno? Najde se to podle pk...
|
||||
|
||||
# Přehled všech řešení kvůli debugování
|
||||
|
||||
class SeznamReseniView(ListView):
|
||||
model = m.Reseni
|
||||
template_name = 'seminar/odevzdavatko/seznam.html'
|
||||
|
||||
class SeznamAktualnichReseniView(SeznamReseniView):
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi...
|
||||
resitele = resi_v_rocniku(akt_rocnik)
|
||||
qs = qs.filter(resitele__in=resitele) # FIXME: Najde řešení i ze starých ročníků, která odevzdal alespoň jeden aktuální řešitel
|
||||
return qs
|
|
@ -1,4 +1,4 @@
|
|||
# coding:utf-8
|
||||
|
||||
|
||||
from django.shortcuts import get_object_or_404, render, redirect
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
|
||||
|
@ -17,6 +17,7 @@ from django.contrib.auth.models import User, Permission
|
|||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db import transaction
|
||||
from django.core import serializers
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.forms.models import model_to_dict
|
||||
|
||||
import seminar.models as s
|
||||
|
@ -120,15 +121,57 @@ class TNLData(object):
|
|||
self.appendable_siblings = tnltt.appendableChildren(self.parent)
|
||||
else:
|
||||
self.appendable_siblings = []
|
||||
@classmethod
|
||||
def public_above(cls, anode):
|
||||
""" Returns output of verejne for closest Rocnik, Cislo or Problem above.
|
||||
(All of them have method verejne.)"""
|
||||
parent = anode # chceme začít už od konkrétního node včetně
|
||||
while True:
|
||||
rocnik = isinstance(parent, s.RocnikNode)
|
||||
cislo = isinstance(parent, s.CisloNode)
|
||||
uloha = (isinstance(parent, s.UlohaVzorakNode) or
|
||||
isinstance(parent, s.UlohaZadaniNode))
|
||||
tema = isinstance(parent, s.TemaVCisleNode)
|
||||
|
||||
|
||||
if (rocnik or cislo or uloha or tema) or parent==None:
|
||||
break
|
||||
else:
|
||||
parent = treelib.get_parent(parent)
|
||||
if rocnik:
|
||||
return parent.rocnik.verejne()
|
||||
elif cislo:
|
||||
return parent.cislo.verejne()
|
||||
elif uloha:
|
||||
return parent.uloha.verejne()
|
||||
elif tema:
|
||||
return parent.tema.verejne()
|
||||
elif None:
|
||||
print("Existuje TreeNode, který není pod číslem, ročníkem, úlohou"
|
||||
"ani tématem. {}".format(anode))
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def all_public_children(cls, anode):
|
||||
for ch in treelib.all_children(anode):
|
||||
if TNLData.public_above(ch):
|
||||
yield ch
|
||||
else:
|
||||
continue
|
||||
|
||||
@classmethod
|
||||
def from_treenode(cls,anode,parent=None,index=None):
|
||||
out = cls(anode,parent,index)
|
||||
for (idx,ch) in enumerate(treelib.all_children(anode)):
|
||||
# FIXME přidat filtrování na veřejnost
|
||||
outitem = cls.from_treenode(ch,out,idx)
|
||||
def from_treenode(cls, anode, user, parent=None, index=None):
|
||||
if TNLData.public_above(anode) or user.has_perm('auth.org'):
|
||||
out = cls(anode,parent,index)
|
||||
else:
|
||||
raise PermissionDenied()
|
||||
|
||||
if user.has_perm('auth.org'):
|
||||
enum_children = enumerate(treelib.all_children(anode))
|
||||
else:
|
||||
enum_children = enumerate(TNLData.all_public_children(anode))
|
||||
|
||||
for (idx,ch) in enum_children:
|
||||
outitem = cls.from_treenode(ch, user, out, idx)
|
||||
out.children.append(outitem)
|
||||
out.add_edit_options()
|
||||
return out
|
||||
|
@ -195,7 +238,7 @@ class TreeNodeView(generic.DetailView):
|
|||
|
||||
def get_context_data(self,**kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['tnldata'] = TNLData.from_treenode(self.object)
|
||||
context['tnldata'] = TNLData.from_treenode(self.object,self.request.user)
|
||||
return context
|
||||
|
||||
class TreeNodeJSONView(generic.DetailView):
|
||||
|
@ -203,7 +246,7 @@ class TreeNodeJSONView(generic.DetailView):
|
|||
|
||||
def get(self,request,*args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
data = TNLData.from_treenode(self.object).to_json()
|
||||
data = TNLData.from_treenode(self.object,self.request.user).to_json()
|
||||
return JsonResponse(data)
|
||||
|
||||
|
||||
|
@ -332,6 +375,7 @@ class ProblemView(generic.DetailView):
|
|||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
user = self.request.user
|
||||
# Teď potřebujeme doplnit tnldata do kontextu.
|
||||
# Ošklivý type switch, hezčí by bylo udělat to polymorfni. FIXME.
|
||||
if False:
|
||||
|
@ -339,11 +383,11 @@ class ProblemView(generic.DetailView):
|
|||
pass
|
||||
elif isinstance(self.object, s.Clanek) or isinstance(self.object, s.Konfera):
|
||||
# Tyhle Problémy mají ŘešeníNode
|
||||
context['tnldata'] = TNLData.from_treenode(self.object.reseninode)
|
||||
context['tnldata'] = TNLData.from_treenode(self.object.reseninode,user)
|
||||
elif isinstance(self.object, s.Uloha):
|
||||
# FIXME: Teď vždycky zobrazujeme i vzorák! Možná by bylo hezčí/lepší mít to stejně jako pro Téma: procházet jen dosažitelné z Ročníku / čísla / whatever
|
||||
tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode)
|
||||
tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode)
|
||||
tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode,user)
|
||||
tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user)
|
||||
context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak])
|
||||
elif isinstance(self.object, s.Tema):
|
||||
rocniknode = self.object.rocnik.rocniknode
|
||||
|
@ -385,16 +429,16 @@ class AktualniZadaniView(generic.TemplateView):
|
|||
# )
|
||||
#
|
||||
def ZadaniTemataView(request):
|
||||
nastaveni = get_object_or_404(Nastaveni)
|
||||
verejne = nastaveni.aktualni_cislo.verejne()
|
||||
akt_rocnik = nastaveni.aktualni_cislo.rocnik
|
||||
temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany')
|
||||
return render(request, 'seminar/tematka/rozcestnik.html',
|
||||
{
|
||||
'tematka': temata,
|
||||
'verejne': verejne,
|
||||
},
|
||||
)
|
||||
nastaveni = get_object_or_404(Nastaveni)
|
||||
verejne = nastaveni.aktualni_cislo.verejne()
|
||||
akt_rocnik = nastaveni.aktualni_cislo.rocnik
|
||||
temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany')
|
||||
return render(request, 'seminar/tematka/rozcestnik.html',
|
||||
{
|
||||
'tematka': temata,
|
||||
'verejne': verejne,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
# nastaveni = get_object_or_404(Nastaveni)
|
||||
|
@ -945,18 +989,30 @@ def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None):
|
|||
if hlavni_problemy is None:
|
||||
hlavni_problemy = hlavni_problemy_cisla(cislo)
|
||||
|
||||
def ne_clanek_ne_konfera(problem):
|
||||
return not(isinstance(problem.get_real_instance(), m.Clanek) or isinstance(problem.get_real_instance(), m.Konfera))
|
||||
|
||||
temata_a_spol = list(filter(ne_clanek_ne_konfera, hlavni_problemy))
|
||||
|
||||
def cosi(problem):
|
||||
return problem.id
|
||||
|
||||
hlavni_problemy_slovnik = {}
|
||||
for hp in hlavni_problemy:
|
||||
for hp in temata_a_spol:
|
||||
hlavni_problemy_slovnik[hp.id] = {}
|
||||
|
||||
hlavni_problemy_slovnik[-1] = {}
|
||||
|
||||
# zakládání prázdných záznamů pro řešitele
|
||||
cislobody = {}
|
||||
for ar in aktivni_resitele:
|
||||
# řešitele převedeme na řetězec pomocí unikátního id
|
||||
cislobody[ar.id] = ""
|
||||
for hp in hlavni_problemy:
|
||||
for hp in temata_a_spol:
|
||||
slovnik = hlavni_problemy_slovnik[hp.id]
|
||||
slovnik[ar.id] = ""
|
||||
|
||||
hlavni_problemy_slovnik[-1][ar.id] = ""
|
||||
|
||||
# vezmeme všechna řešení s body do daného čísla
|
||||
reseni_do_cisla = Reseni.objects.prefetch_related('problem', 'resitele',
|
||||
|
@ -969,7 +1025,10 @@ def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None):
|
|||
# řešení může řešit více problémů
|
||||
for prob in list(reseni.problem.all()):
|
||||
nadproblem = hlavni_problem(prob)
|
||||
nadproblem_slovnik = hlavni_problemy_slovnik[nadproblem.id]
|
||||
if ne_clanek_ne_konfera(nadproblem):
|
||||
nadproblem_slovnik = hlavni_problemy_slovnik[nadproblem.id]
|
||||
else:
|
||||
nadproblem_slovnik = hlavni_problemy_slovnik[-1]
|
||||
|
||||
# a mít více hodnocení
|
||||
for hodn in list(reseni.hodnoceni_set.all()):
|
||||
|
@ -1014,11 +1073,26 @@ def vysledkovka_cisla(cislo, context=None):
|
|||
# vytvoříme jednotlivé sloupce výsledkovky
|
||||
radky_vysledkovky = []
|
||||
i = 0
|
||||
|
||||
def ne_clanek_ne_konfera(problem):
|
||||
return not(isinstance(problem.get_real_instance(), m.Clanek) or isinstance(problem.get_real_instance(), m.Konfera))
|
||||
|
||||
temata_a_spol = list(filter(ne_clanek_ne_konfera, hlavni_problemy))
|
||||
|
||||
# def not_empty(value):
|
||||
# return value != ''
|
||||
#
|
||||
# je_nejake_ostatni = any(filter(not_empty, hlavni_problemy_slovnik[-1].values())) > 0
|
||||
|
||||
je_nejake_ostatni = len(hlavni_problemy) - len(temata_a_spol) > 0
|
||||
|
||||
for ar_id in setrizeni_resitele_id:
|
||||
# získáme seznam bodů za problémy pro daného řešitele
|
||||
problemy = []
|
||||
for hp in hlavni_problemy:
|
||||
for hp in temata_a_spol:
|
||||
problemy.append(hlavni_problemy_slovnik[hp.id][ar_id])
|
||||
if je_nejake_ostatni:
|
||||
problemy.append(hlavni_problemy_slovnik[-1][ar_id])
|
||||
# vytáhneme informace pro daného řešitele
|
||||
radek = RadekVysledkovkyCisla(
|
||||
poradi[i], # pořadí
|
||||
|
@ -1034,7 +1108,8 @@ def vysledkovka_cisla(cislo, context=None):
|
|||
# vytahané informace předáváme do kontextu
|
||||
context['cislo'] = cislo
|
||||
context['radky_vysledkovky'] = radky_vysledkovky
|
||||
context['problemy'] = hlavni_problemy
|
||||
context['problemy'] = temata_a_spol
|
||||
context['ostatni'] = je_nejake_ostatni
|
||||
#context['v_cisle_zadane'] = TODO
|
||||
#context['resene_problemy'] = resene_problemy
|
||||
return context
|
||||
|
@ -1063,6 +1138,7 @@ class CisloView(generic.DetailView):
|
|||
context = super(CisloView, self).get_context_data(**kwargs)
|
||||
|
||||
cislo = context['cislo']
|
||||
context['prevcislo'] = Cislo.objects.filter((Q(rocnik__lt=self.object.rocnik) | Q(poradi__lt=self.object.poradi))&Q(rocnik__lte=self.object.rocnik)).first()
|
||||
# vrátíme context (aktuálně obsahuje jen věci ohledně výsledkovky
|
||||
return vysledkovka_cisla(cislo, context)
|
||||
|
||||
|
@ -1079,6 +1155,30 @@ class ArchivTemataView(generic.ListView):
|
|||
ctx['rocniky'][rocnik] = list(temata)
|
||||
return ctx
|
||||
|
||||
class OdmenyView(generic.TemplateView):
|
||||
template_name = 'seminar/archiv/odmeny.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
fromcislo = Cislo.objects.get(rocnik=self.kwargs.get('frocnik'), poradi=self.kwargs.get('fcislo'))
|
||||
tocislo = Cislo.objects.get(rocnik=self.kwargs.get('trocnik'), poradi=self.kwargs.get('tcislo'))
|
||||
resitele = aktivniResitele(tocislo)
|
||||
frombody = body_resitelu(resitele, fromcislo)
|
||||
tobody = body_resitelu(resitele, tocislo)
|
||||
outlist = []
|
||||
for (aid, tbody) in tobody.items():
|
||||
fbody = frombody.get(aid,0)
|
||||
resitel = Resitel.objects.get(pk=aid)
|
||||
ftitul = resitel.get_titul(fbody)
|
||||
ttitul = resitel.get_titul(tbody)
|
||||
if ftitul != ttitul:
|
||||
outlist.append({'jmeno': resitel.osoba.plne_jmeno(), 'ftitul': ftitul, 'ttitul': ttitul})
|
||||
context['zmeny'] = outlist
|
||||
return context
|
||||
|
||||
|
||||
|
||||
|
||||
### Generovani vysledkovky
|
||||
|
||||
class CisloVysledkovkaView(CisloView):
|
||||
|
@ -1332,6 +1432,12 @@ class ResitelView(LoginRequiredMixin,generic.DetailView):
|
|||
|
||||
### Formulare
|
||||
|
||||
# pro přidání políčka do formuláře je potřeba
|
||||
# - mít v modelu tu položku, kterou chci upravovat
|
||||
# - přidat do views (prihlaskaView, resitelEditView)
|
||||
# - přidat do forms
|
||||
# - includovat do html
|
||||
|
||||
class AddSolutionView(LoginRequiredMixin, FormView):
|
||||
template_name = 'seminar/org/vloz_reseni.html'
|
||||
form_class = f.VlozReseniForm
|
||||
|
@ -1409,7 +1515,7 @@ def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data):
|
|||
from django.forms.models import model_to_dict
|
||||
def resitelEditView(request):
|
||||
err_logger = logging.getLogger('seminar.prihlaska.problem')
|
||||
## Načtení objektu Osoba a Resitel, patrici k aktuálně přihlášenému uživately
|
||||
## Načtení objektů Osoba a Resitel patřících k aktuálně přihlášenému uživateli
|
||||
u = request.user
|
||||
osoba_edit = Osoba.objects.get(user=u)
|
||||
resitel_edit = osoba_edit.resitel
|
||||
|
@ -1448,6 +1554,7 @@ def resitelEditView(request):
|
|||
resitel_edit.skola = fcd['skola']
|
||||
resitel_edit.rok_maturity = fcd['rok_maturity']
|
||||
resitel_edit.zasilat = fcd['zasilat']
|
||||
resitel_edit.zasilat_cislo_emailem = fcd['zasilat_cislo_emailem']
|
||||
if fcd.get('skola'):
|
||||
resitel_edit.skola = fcd['skola']
|
||||
else:
|
||||
|
@ -1511,7 +1618,8 @@ def prihlaskaView(request):
|
|||
|
||||
r = Resitel(
|
||||
rok_maturity = fcd['rok_maturity'],
|
||||
zasilat = fcd['zasilat']
|
||||
zasilat = fcd['zasilat'],
|
||||
zasilat_cislo_emailem = fcd['zasilat_cislo_emailem']
|
||||
)
|
||||
|
||||
r.save()
|
||||
|
|
|
@ -6,25 +6,27 @@ from seminar import treelib
|
|||
|
||||
DEFAULT_NODE_DEPTH = 2
|
||||
|
||||
|
||||
class TextSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.Text
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
|
||||
class UlohaVzorakNodeSerializer(serializers.ModelSerializer):
|
||||
class ProblemSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.UlohaVzorakNode
|
||||
model = m.Problem
|
||||
fields = '__all__'
|
||||
|
||||
class UlohaSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.Uloha
|
||||
fields = '__all__'
|
||||
|
||||
class ReseniSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.Reseni
|
||||
fields = '__all__'
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class UlohaZadaniNodeSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.UlohaZadaniNode
|
||||
fields = '__all__'
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class RocnikNodeSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.RocnikNode
|
||||
|
@ -138,12 +140,161 @@ class CastNodeCreateSerializer(serializers.ModelSerializer):
|
|||
fields = ('nadpis','where','refnode')
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class UlohaZadaniNodeSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.UlohaZadaniNode
|
||||
fields = '__all__'
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class UlohaZadaniNodeWriteSerializer(serializers.ModelSerializer):
|
||||
uloha = UlohaSerializer()
|
||||
|
||||
def update(self,node,validated_data):
|
||||
node.uloha.max_body = validated_data.get('uloha').get('max_body')
|
||||
node.uloha.kod = validated_data.get('uloha').get('kod')
|
||||
node.uloha.nazev = validated_data.get('uloha').get('nazev')
|
||||
node.uloha.save()
|
||||
return node
|
||||
|
||||
class Meta:
|
||||
model = m.TextNode
|
||||
fields = ('id','uloha')
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class UlohaZadaniNodeCreateSerializer(serializers.ModelSerializer):
|
||||
uloha = UlohaSerializer()
|
||||
refnode = serializers.IntegerField()
|
||||
where = serializers.CharField()
|
||||
|
||||
def create(self,validated_data):
|
||||
# text_zadani = validated_data.pop('text_zadani')
|
||||
temp_uloha = validated_data.pop('uloha')
|
||||
where = validated_data.pop('where')
|
||||
refnode_id = validated_data.pop('refnode')
|
||||
refnode = m.TreeNode.objects.get(pk=refnode_id)
|
||||
|
||||
# Z cesty ke koreni stromu zjistime, v jakem jsme tematu a v jakem cisle
|
||||
cislo = None
|
||||
tema = None
|
||||
travelnode = refnode
|
||||
while travelnode is not None:
|
||||
if isinstance(travelnode, m.TemaVCisleNode):
|
||||
tema = travelnode.tema
|
||||
if isinstance(travelnode, m.CisloNode):
|
||||
cislo = travelnode.cislo
|
||||
travelnode = treelib.get_parent(travelnode)
|
||||
# Vyrobime ulohu
|
||||
uloha = m.Uloha.objects.create(cislo_zadani=cislo, nadproblem = tema, **temp_uloha)
|
||||
|
||||
# A vyrobime UlohaZadaniNode
|
||||
if where == 'syn':
|
||||
node = treelib.create_child(refnode,m.UlohaZadaniNode,uloha = uloha)
|
||||
elif where == 'za':
|
||||
node = treelib.create_node_after(refnode,m.UlohaZadaniNode,uloha = uloha)
|
||||
elif where == 'pred':
|
||||
node = treelib.create_node_before(refnode,m.UlohaZadaniNode,uloha = uloha)
|
||||
node.where = None
|
||||
node.refnode = None
|
||||
node.max_body = None
|
||||
node.kod = None
|
||||
return node
|
||||
|
||||
class Meta:
|
||||
model = m.UlohaZadaniNode
|
||||
fields = ('uloha','where','refnode')
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class UlohaVzorakNodeSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.UlohaVzorakNode
|
||||
fields = '__all__'
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class UlohaVzorakNodeWriteSerializer(serializers.ModelSerializer):
|
||||
uloha = serializers.PrimaryKeyRelatedField(queryset=m.Uloha.objects.all(), many=False, read_only=False)
|
||||
|
||||
class Meta:
|
||||
model = m.UlohaVzorakNode
|
||||
fields = ('id','uloha')
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
|
||||
class UlohaVzorakNodeCreateSerializer(serializers.ModelSerializer):
|
||||
uloha_id = serializers.IntegerField()
|
||||
refnode = serializers.IntegerField()
|
||||
where = serializers.CharField()
|
||||
|
||||
def create(self, validated_data):
|
||||
uloha_id = validated_data.pop('uloha_id')
|
||||
uloha = m.Uloha.objects.get(pk=uloha_id)
|
||||
where = validated_data.pop('where')
|
||||
refnode_id = validated_data.pop('refnode')
|
||||
refnode = m.TreeNode.objects.get(pk=refnode_id)
|
||||
|
||||
if where == 'syn':
|
||||
node = treelib.create_child(refnode,m.UlohaVzorakNode,uloha = uloha)
|
||||
elif where == 'za':
|
||||
node = treelib.create_node_after(refnode,m.UlohaVzorakNode,uloha = uloha)
|
||||
elif where == 'pred':
|
||||
node = treelib.create_node_before(refnode,m.UlohaVzorakNode,uloha = uloha)
|
||||
node.refnode = None
|
||||
node.where = None
|
||||
node.uloha_id = None
|
||||
|
||||
return node
|
||||
|
||||
class Meta:
|
||||
model = m.UlohaVzorakNode
|
||||
fields = ('refnode', 'uloha_id', 'where')
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
|
||||
|
||||
|
||||
class ReseniNodeSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = m.ReseniNode
|
||||
fields = '__all__'
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class ReseniNodeWriteSerializer(serializers.ModelSerializer):
|
||||
reseni = serializers.PrimaryKeyRelatedField(queryset=m.Reseni.objects.all(), many=False, read_only=False)
|
||||
|
||||
class Meta:
|
||||
model = m.ReseniNode
|
||||
fields = ('id','reseni')
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
class ReseniNodeCreateSerializer(serializers.ModelSerializer):
|
||||
reseni_id = serializers.IntegerField()
|
||||
refnode = serializers.IntegerField()
|
||||
where = serializers.CharField()
|
||||
|
||||
def create(self,validated_data):
|
||||
# text_zadani = validated_data.pop('text_zadani')
|
||||
reseni_id = validated_data.pop('reseni_id')
|
||||
reseni = m.Reseni.objects.get(pk=reseni_id)
|
||||
where = validated_data.pop('where')
|
||||
refnode_id = validated_data.pop('refnode')
|
||||
refnode = m.TreeNode.objects.get(pk=refnode_id)
|
||||
|
||||
# A vyrobime UlohaZadaniNode
|
||||
if where == 'syn':
|
||||
node = treelib.create_child(refnode,m.ReseniNode,reseni = reseni)
|
||||
elif where == 'za':
|
||||
node = treelib.create_node_after(refnode,m.ReseniNode,reseni = reseni)
|
||||
elif where == 'pred':
|
||||
node = treelib.create_node_before(refnode,m.ReseniNode,reseni = reseni)
|
||||
node.where = None
|
||||
node.refnode = None
|
||||
node.reseni_id = None
|
||||
return node
|
||||
|
||||
class Meta:
|
||||
model = m.ReseniNode
|
||||
fields = ('reseni_id','where','refnode')
|
||||
depth = DEFAULT_NODE_DEPTH
|
||||
|
||||
|
||||
class TreeNodeSerializer(PolymorphicSerializer):
|
||||
model_serializer_mapping = {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
from rest_framework import viewsets,filters
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from rest_framework.permissions import BasePermission, AllowAny
|
||||
from . import models as m
|
||||
from . import views
|
||||
|
@ -18,31 +21,6 @@ class PermissionMixin(object):
|
|||
# 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):
|
||||
"""
|
||||
Overrides get_serializer_class to choose the read serializer
|
||||
|
@ -87,10 +65,6 @@ class ReadWriteSerializerMixin(object):
|
|||
)
|
||||
return self.create_serializer_class
|
||||
|
||||
class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet):
|
||||
queryset = m.UlohaVzorakNode.objects.all()
|
||||
serializer_class = views.UlohaVzorakNodeSerializer
|
||||
|
||||
class TextViewSet(PermissionMixin, viewsets.ModelViewSet):
|
||||
queryset = m.Text.objects.all()
|
||||
serializer_class = views.TextSerializer
|
||||
|
@ -107,12 +81,91 @@ class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelVi
|
|||
write_serializer_class = views.CastNodeSerializer
|
||||
create_serializer_class = views.CastNodeCreateSerializer
|
||||
|
||||
class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet):
|
||||
serializer_class = views.UlohaVzorakNodeSerializer
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
print(obj)
|
||||
if obj.first_child is None:
|
||||
return super().destroy(request,*args,**kwargs)
|
||||
raise PermissionDenied('Nelze smazat CastNode, který má děti!')
|
||||
|
||||
|
||||
class UlohaVzorakNodeViewSet(PermissionMixin, ReadWriteSerializerMixin, viewsets.ModelViewSet):
|
||||
read_serializer_class = views.UlohaVzorakNodeSerializer
|
||||
write_serializer_class = views.UlohaVzorakNodeWriteSerializer
|
||||
create_serializer_class = views.UlohaVzorakNodeCreateSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = m.UlohaVzorakNode.objects.all()
|
||||
nazev = self.request.query_params.get('nazev',None)
|
||||
if nazev is not None:
|
||||
queryset = queryset.filter(nazev__contains=nazev)
|
||||
|
||||
if self.request.user.has_perm('auth.org'):
|
||||
return queryset
|
||||
else: # pro neorgy jen zveřejněné vzoráky
|
||||
return queryset.filter(uloha__cislo_reseni__verejne_db=True)
|
||||
|
||||
nadproblem = self.request.query_params.get('nadproblem',None)
|
||||
if nadproblem is not None:
|
||||
queryset = queryset.filter(nadproblem__pk = nadproblem)
|
||||
return queryset
|
||||
|
||||
class ReseniViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = views.ReseniSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = m.Reseni.objects.all()
|
||||
#FIXME upravit nazvy dle skutecnych polozek reseni
|
||||
nazev = self.request.query_params.get('nazev',None)
|
||||
if nazev is not None:
|
||||
queryset = queryset.filter(nazev__contains=nazev)
|
||||
nadproblem = self.request.query_params.get('nadproblem',None)
|
||||
if nadproblem is not None:
|
||||
queryset = queryset.filter(nadproblem__pk = nadproblem)
|
||||
return queryset
|
||||
|
||||
class UlohaViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = views.UlohaSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = m.Uloha.objects.all()
|
||||
nazev = self.request.query_params.get('nazev',None)
|
||||
if nazev is not None:
|
||||
queryset = queryset.filter(nazev__contains=nazev)
|
||||
nadproblem = self.request.query_params.get('nadproblem',None)
|
||||
if nadproblem is not None:
|
||||
queryset = queryset.filter(nadproblem__pk = nadproblem)
|
||||
return queryset
|
||||
|
||||
class UlohaZadaniNodeViewSet(ReadWriteSerializerMixin, viewsets.ModelViewSet):
|
||||
queryset = m.UlohaZadaniNode.objects.all()
|
||||
read_serializer_class = views.UlohaZadaniNodeSerializer
|
||||
write_serializer_class = views.UlohaZadaniNodeWriteSerializer
|
||||
create_serializer_class = views.UlohaZadaniNodeCreateSerializer
|
||||
|
||||
class ReseniNodeViewSet(ReadWriteSerializerMixin, viewsets.ModelViewSet):
|
||||
queryset = m.ReseniNode.objects.all()
|
||||
read_serializer_class = views.ReseniNodeSerializer
|
||||
write_serializer_class = views.ReseniNodeWriteSerializer
|
||||
create_serializer_class = views.ReseniNodeCreateSerializer
|
||||
|
||||
|
||||
|
||||
class ProblemViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = views.ProblemSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = m.Problem.objects.all()
|
||||
ucel = self.request.query_params.get('ucel',None)
|
||||
rocnik = self.request.query_params.get('rocnik',None)
|
||||
tema = self.request.query_params.get('tema',None)
|
||||
|
||||
if rocnik is not None:
|
||||
queryset = queryset.filter(rocnik=rocnik)
|
||||
|
||||
#if tema is not None:
|
||||
|
||||
|
||||
|
||||
return queryset
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<div class="addnewnode">
|
||||
<button v-if="types.includes('castNode')" v-on:click="selected='castNode'" :disabled="selected && selected !== 'castNode'">Část</button>
|
||||
<button v-if="types.includes('castNode')" v-on:click="selected='castNode'" :disabled="selected && selected !== 'castNode'">Nadpis části</button>
|
||||
<button v-if="types.includes('textNode')" v-on:click="selected='textNode'" :disabled="selected && selected !== 'textNode'">Text</button>
|
||||
<button v-if="types.includes('reseniNode')" v-on:click="selected='reseniNode'" :disabled="selected && selected !== 'reseniNode'">Řešení</button>
|
||||
<button v-if="types.includes('ulohaZadaniNode')" v-on:click="selected='ulohaZadaniNode'" :disabled="selected && selected !== 'ulohaZadaniNode'">Zadání úlohy</button>
|
||||
<button v-if="types.includes('ulohaVzorakNode')" v-on:click="selected='ulohaVzorakNode'" :disabled="selected && selected !== 'ulohaVzorakNode'">Vzorák</button>
|
||||
<div v-if="selected">
|
||||
<component :is='selected' :item='null' :where="where" :refnode="refnode" create></component>
|
||||
<component :is='selected' :item='null' :where="where" :refnode="refnode" :tema="tema" create></component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -24,6 +24,7 @@ export default {
|
|||
types: Array,
|
||||
where: String,
|
||||
refnode: Object,
|
||||
tema: Object,
|
||||
},
|
||||
data: () => ({
|
||||
selected: null,
|
||||
|
@ -47,4 +48,4 @@ export default {
|
|||
.addnewnode {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
<button v-on:click="currentText = originalText;editorShow=!editorShow;">Zahodit úpravy</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<h4>{{ currentText }} </h4> <button v-if="editorMode" v-on:click="editorShow=!editorShow">Upravit</button>
|
||||
<h4>{{ currentText }} </h4>
|
||||
<button v-if="editorMode" v-on:click="editorShow = !editorShow">Upravit</button>
|
||||
<button v-if="editorMode" v-on:click="deleteCast" class="delete">Smazat</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -25,6 +27,7 @@ export default {
|
|||
props: {
|
||||
item: Object,
|
||||
editorShow: Boolean,
|
||||
editorMode: Boolean,
|
||||
create: Boolean,
|
||||
where: String,
|
||||
refnode: Object
|
||||
|
@ -76,11 +79,27 @@ export default {
|
|||
}
|
||||
|
||||
this.editorShow = false;
|
||||
},
|
||||
deleteCast: function() {
|
||||
console.log("Deleting cast");
|
||||
axios.delete('/api/castnode/'+this.item.node.id+'/'
|
||||
).then( () => {
|
||||
this.loading = false;
|
||||
this.$root.$emit('updateData',"castNode delete update");
|
||||
}).catch(e => {
|
||||
this.errors.push(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.changed {
|
||||
background-color: yellow;
|
||||
}
|
||||
.delete {
|
||||
background-color: #ff6666;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
|
||||
<template v-else v-bind:class="changedObject">
|
||||
<p v-html="currentText"></p>
|
||||
<button v-if="editorMode" v-on:click="editorShow=!editorShow">Upravit</button>
|
||||
<button v-if="editorMode" v-on:click="editorShow = !editorShow">Upravit</button>
|
||||
<button v-if="editorMode" v-on:click="deleteText" class="delete">Smazat</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -162,6 +163,16 @@ export default {
|
|||
}
|
||||
this.editorShow = false;
|
||||
},
|
||||
deleteText: function() {
|
||||
console.log("Deleting text");
|
||||
axios.delete('/api/textnode/'+this.item.node.id+'/'
|
||||
).then( () => {
|
||||
this.loading = false;
|
||||
this.$root.$emit('updateData',"textNode delete update");
|
||||
}).catch(e => {
|
||||
this.errors.push(e);
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -169,6 +180,9 @@ export default {
|
|||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.changed {
|
||||
background-color: 'yellow';
|
||||
background-color: yellow;
|
||||
}
|
||||
.delete {
|
||||
background-color: #ff6666;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
<template>
|
||||
|
||||
<div :class="editorMode ? 'treenode-org' : 'treenode'">
|
||||
<!--b v-if="v_tematu">v tematu</b>
|
||||
<!--b v-if="tema">v tematu</b>
|
||||
<b v-if="visible">visible</b>
|
||||
Force visible: {{String(force_visible)}}-->
|
||||
<component :is='item.node.polymorphic_ctype.model' :item='item' :key='item.node.id'
|
||||
:tema="temaOut"
|
||||
:editorMode="editorMode"
|
||||
:debugMode="debugMode"></component>
|
||||
|
||||
|
||||
<button v-if="debugMode" v-on:click="debugShow = !debugShow" class="nodebug">Ladící data</button> <!-- bude tu nějaký if na class="nodebug", v debug módu bude tlačítko vidět, jinak ne -->
|
||||
<div v-if="debugShow">
|
||||
<pre>Tema: {{ tema }}</pre>
|
||||
<pre>TemaOut: {{ temaOut }}</pre>
|
||||
<pre>{{ item.node.polymorphic_ctype.model }}</pre>
|
||||
<pre>{{ item }}</pre>
|
||||
</div>
|
||||
|
@ -18,31 +21,31 @@
|
|||
<div v-if="item.children.length === 0">
|
||||
<div v-if="item.appendable_children.length > 0 && editorMode">
|
||||
<b>Vložit jako syna: </b>
|
||||
<addnewnode :types="item.appendable_children" :refnode="item.node" where="syn" />
|
||||
<addnewnode :types="item.appendable_children" :refnode="item.node" :tema="temaOut" where="syn" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else :class="editorMode ? 'children-org' : 'children'"> <!-- bude tu nějaký if na class="children" -->
|
||||
<div v-if="item.children.length > 0 && item.children[0].appendable_siblings.length > 0 && editorMode">
|
||||
<b>Vložit před: </b>
|
||||
<addnewnode :types="item.children[0].appendable_siblings" :refnode="item.children[0].node" where="pred" />
|
||||
<addnewnode :types="item.children[0].appendable_siblings" :refnode="item.children[0].node" :tema="temaOut" where="pred" />
|
||||
</div>
|
||||
<div v-if="item.node.polymorphic_ctype.model==='temavcislenode'">
|
||||
<!--Children: {{String(showChildren)}}-->
|
||||
<div v-for="(chld, index) in item.children" v-bind:key="chld.nazev" >
|
||||
<!--Hide: {{hideNode(chld)}}, v tematu: {{v_tematu}}, force_visible: {{force_visible}}-->
|
||||
<!--Hide: {{hideNode(chld)}}, v tematu: {{tema}}, force_visible: {{force_visible}}-->
|
||||
<div v-if="!hideNode(chld)">
|
||||
<div v-if="chld.node.polymorphic_ctype.model==='ulohazadaninode'">
|
||||
<button v-if="showChildren" v-on:click="showChildren=!showChildren"> Schovat </button>
|
||||
<button v-else v-on:click="showChildren=!showChildren"> Rozbalit </button>
|
||||
<TreeNode :item="chld" :v_tematu="true"
|
||||
<TreeNode :item="chld" :tema="temaOut"
|
||||
:force_visible="showChildren"
|
||||
:editorMode="editorMode"
|
||||
:debugMode="debugMode">
|
||||
</TreeNode>
|
||||
</div>
|
||||
<div v-else>
|
||||
<TreeNode :item="chld" :v_tematu="true"
|
||||
<TreeNode :item="chld" :tema="temaOut"
|
||||
:force_visible="showChildren"
|
||||
:editorMode="editorMode"
|
||||
:debugMode="debugMode">
|
||||
|
@ -51,7 +54,7 @@
|
|||
<div v-if="chld.appendable_siblings.length > 0 && editorMode" >
|
||||
<b v-if="index < (item.children.length - 1)">Vložit mezi: </b>
|
||||
<b v-else>Vložit za: </b>
|
||||
<addnewnode :types="chld.appendable_siblings" :refnode="chld.node" where="za" />
|
||||
<addnewnode :types="chld.appendable_siblings" :refnode="chld.node" :tema="temaOut" where="za" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -60,16 +63,16 @@
|
|||
</div>
|
||||
<div v-else>
|
||||
<div v-for="(chld, index) in item.children" v-bind:key="chld.nazev" >
|
||||
<div v-if="v_tematu && chld.node.polymorphic_ctype.model==='ulohazadaninode'">
|
||||
<div v-if="tema !== null && chld.node.polymorphic_ctype.model==='ulohazadaninode'">
|
||||
<div> Tady možná něco je </div>
|
||||
<TreeNode :item="chld" :v_tematu="v_tematu"
|
||||
<TreeNode :item="chld" :tema="temaOut"
|
||||
:force_visible="force_visible"
|
||||
:editorMode="editorMode"
|
||||
:debugMode="debugMode">
|
||||
</TreeNode>
|
||||
</div>
|
||||
<div v-else>
|
||||
<TreeNode :item="chld" :v_tematu="v_tematu"
|
||||
<TreeNode :item="chld" :tema="temaOut"
|
||||
:force_visible="force_visible"
|
||||
:editorMode="editorMode"
|
||||
:debugMode="debugMode">
|
||||
|
@ -78,7 +81,7 @@
|
|||
<div v-if="chld.appendable_siblings.length > 0 && editorMode" >
|
||||
<b v-if="index < (item.children.length - 1)">Vložit mezi: </b>
|
||||
<b v-else>Vložit za: </b>
|
||||
<addnewnode :types="chld.appendable_siblings" :refnode="chld.node" where="za" />
|
||||
<addnewnode :types="chld.appendable_siblings" :refnode="chld.node" :tema="temaOut" where="za" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -112,14 +115,15 @@ export default {
|
|||
},
|
||||
data: () => ({
|
||||
debugShow: false,
|
||||
showChildren: false
|
||||
showChildren: false,
|
||||
temaOut: null,
|
||||
}),
|
||||
computed: {
|
||||
},
|
||||
props: {
|
||||
item: Object,
|
||||
force_visible: Boolean,
|
||||
v_tematu: Boolean,
|
||||
tema: Object,
|
||||
editorMode: Boolean,
|
||||
debugMode: Boolean,
|
||||
},
|
||||
|
@ -132,7 +136,17 @@ export default {
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
mounted: function(){
|
||||
if (this.item.node.polymorphic_ctype.model === 'temavcislenode'){
|
||||
this.temaOut = this.item.node.tema;
|
||||
console.log(this.temaOut);
|
||||
} else {
|
||||
this.temaOut = this.tema;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<div id="loading" v-if="loading">
|
||||
Loading...
|
||||
</div>
|
||||
<div v-else>
|
||||
<!--pre>
|
||||
{{item}}
|
||||
</pre-->
|
||||
|
@ -11,6 +12,7 @@
|
|||
<button v-show="debugMode" v-on:click="debugMode = false">Vypnout ladicí mód</button>
|
||||
<button v-show="!debugMode" v-on:click="debugMode = true">Zapnout ladicí mód</button>
|
||||
<TreeNode :item="item" :editorMode="editorMode" :debugMode="debugMode"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
<template>
|
||||
<div class="ulohavzoraknode">
|
||||
<template v-if="editorShow">
|
||||
<!--pre>UlohaVzorakNode {{item}} {{typeof(item)}}</pre-->
|
||||
<h5>Řešení {{item.node.uloha.cislo_zadani.poradi}}.{{ item.node.uloha.kod }}: {{ item.node.uloha.nazev }}</h5>
|
||||
<button v-if="editorMode" v-on:click="showSelect=!showSelect" class="upravit">Upravit</button>
|
||||
<div v-if="showSelect">
|
||||
<form class="searchForm" v-on:submit.prevent="submitSearch">
|
||||
<input type="text" v-model="searchQuery" placeholder="Napište název" @keyup="submitSearch">
|
||||
</form>
|
||||
<div class="searchResult" v-show="isResult">
|
||||
<ul>
|
||||
<li v-for="res in searchResults" :key="res.id" v-on:click="setSelected(res)">{{res.nazev}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!--h5 v-if="!editorMode">Řešení {{item.node.uloha.cislo_zadani.poradi}}.{{ item.node.uloha.kod }}: {{ item.node.uloha.nazev }}</h5-->
|
||||
<form class="searchForm" v-on:submit.prevent="submitSearch">
|
||||
<input type="text" v-model="searchQuery" placeholder="Napište název" @keyup="submitSearch">
|
||||
</form>
|
||||
<div class="searchResult" v-show="isResult">
|
||||
<ul>
|
||||
<li v-for="res in searchResults" :key="res.id" v-on:click="setSelected(res)">{{res.nazev}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button v-if="create" v-on:click="createNode">Vytvořit vzorák</button>
|
||||
<button v-if="!create" v-on:click="saveNode">Uložit</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<h5>Řešení {{item.node.uloha.cislo_zadani.poradi}}.{{item.node.uloha.kod}}: {{item.node.uloha.nazev}}</h5>
|
||||
<button v-if="editorMode" v-on:click="editorShow = !editorShow">Upravit</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -26,31 +31,58 @@ export default {
|
|||
isResult: false,
|
||||
searchQuery: '',
|
||||
searchResults: [],
|
||||
showSelect: false,
|
||||
selected: null,
|
||||
selected_id: null
|
||||
selected_id: null,
|
||||
editorShow: false,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
item: Object,
|
||||
create: Boolean,
|
||||
showSelect: Boolean,
|
||||
editorMode: Boolean,
|
||||
editorShow: Boolean,
|
||||
tema: Object,
|
||||
refnode: Object,
|
||||
where: String,
|
||||
},
|
||||
mounted: function(){
|
||||
if (this.item.node.uloha === null){
|
||||
axios.defaults.headers.common['X-CSRFToken'] = this.getCookie('csrftoken');
|
||||
if (this.create){
|
||||
this.editorShow = true;
|
||||
this.searchQuery = "";
|
||||
this.selected_id = null;
|
||||
} else {
|
||||
this.searchQuery = this.item.node.uloha.nazev;
|
||||
this.selected_id = this.item.node.uloha.id;
|
||||
this.selected = this.item.node.uloha;
|
||||
}
|
||||
if (this.item !== null && this.item.node.uloha === null){
|
||||
console.log("Uloha je null!");
|
||||
console.log(this.item);
|
||||
}
|
||||
if (this.create){
|
||||
this.showSelect = true;
|
||||
console.log('Creating');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCookie: function (name){
|
||||
var cookieValue = null;
|
||||
if (document.cookie && document.cookie != '') {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = cookies[i].trim();
|
||||
// Does this cookie string begin with the name we want?
|
||||
|
||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
},
|
||||
submitSearch: function(){
|
||||
if (this.searchQuery.length < 3) { return;}
|
||||
var reqURL = "/api/ulohavzoraknode/?nazev="+this.searchQuery;
|
||||
let nazev = "nazev="+this.searchQuery+"&";
|
||||
let nadproblem = "nadproblem="+this.tema.id+"&";
|
||||
var reqURL = "/api/uloha/?"+nazev+nadproblem;
|
||||
axios.get(reqURL).then( (response) => {
|
||||
this.searchResults = response.data.results;
|
||||
this.isResult = true;
|
||||
|
@ -63,6 +95,38 @@ export default {
|
|||
setSelected: function(res){
|
||||
this.searchQuery = res.nazev
|
||||
this.selected_id = res.id
|
||||
this.selected = res
|
||||
},
|
||||
createNode: function(){
|
||||
console.log('Creating UlohaVzorakNode');
|
||||
this.loading = true
|
||||
axios.post('/api/ulohavzoraknode/',{
|
||||
refnode: this.refnode.id,
|
||||
where: this.where,
|
||||
uloha_id: this.selected_id,
|
||||
}).then(response => {
|
||||
console.log(response.data);
|
||||
this.loading=false;
|
||||
this.$root.$emit('updateData',"ulohaZadaniNode create update");
|
||||
}).catch( e => {
|
||||
console.log(e);
|
||||
});
|
||||
},
|
||||
saveNode: function(){
|
||||
console.log('Saving UlohaVzorakNode');
|
||||
this.loading = true
|
||||
axios.put('/api/ulohavzoraknode/'+this.item.node.id+'/',{
|
||||
id: this.item.node.id,
|
||||
uloha: this.selected_id
|
||||
}).then(response => {
|
||||
console.log(response.data);
|
||||
this.loading=false;
|
||||
this.item.node = response.data;
|
||||
this.$root.$emit('updateData',"ulohaZadaniNode save update");
|
||||
}).catch( e => {
|
||||
console.log(e);
|
||||
});
|
||||
this.editorShow = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,113 @@
|
|||
<template>
|
||||
<div class="ulohazadaninode">
|
||||
<!--pre>UlohaZadaniNode {{item.node.uloha}} {{typeof(item)}}</pre-->
|
||||
<h5>Zadání {{item.node.uloha.cislo_zadani.poradi}}.{{ item.node.uloha.kod }}: {{ item.node.uloha.nazev }}</h5>
|
||||
<template v-if="editorShow">
|
||||
Název: <input tpye="text" v-model="nazev"><br>
|
||||
Počet bodů: <input type="number" min="0" max="20" v-model="max_body"><br>
|
||||
Kód: <input type="text" v-model="kod"><br>
|
||||
<!--Autor: FIXME!<br-->
|
||||
<button v-if="create" v-on:click="createNode">Vytvořit úlohu</button>
|
||||
<button v-if="!create" v-on:click="saveNode">Uložit</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<h5>Zadání {{item.node.uloha.cislo_zadani.poradi}}.{{ item.node.uloha.kod }}: {{ item.node.uloha.nazev }} ({{item.node.uloha.max_body}} b)</h5>
|
||||
<button v-if="editorMode" v-on:click="editorShow = !editorShow">Upravit</button>
|
||||
<!--button v-if="editorMode" v-on:click="deleteText" class="delete">Smazat</button-->
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'UlohaZadaniNode',
|
||||
data: () => ({
|
||||
max_body: 0,
|
||||
kod: "",
|
||||
editorShow: false,
|
||||
editorMode: false,
|
||||
}),
|
||||
props: {
|
||||
item: Object,
|
||||
created: Boolean
|
||||
,
|
||||
editorShow: Boolean,
|
||||
editorMode: Boolean,
|
||||
create: Boolean,
|
||||
where: String,
|
||||
refnode: Object
|
||||
},
|
||||
methods: {
|
||||
getCookie: function (name){
|
||||
var cookieValue = null;
|
||||
if (document.cookie && document.cookie != '') {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = cookies[i].trim();
|
||||
// Does this cookie string begin with the name we want?
|
||||
|
||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
},
|
||||
createNode: function(){
|
||||
console.log('Creating UlohaZadaniNode');
|
||||
this.loading = true
|
||||
axios.post('/api/ulohazadaninode/',{
|
||||
refnode: this.refnode.id,
|
||||
where: this.where,
|
||||
uloha: {
|
||||
max_body: this.max_body,
|
||||
kod: this.kod,
|
||||
nazev: this.nazev,
|
||||
},
|
||||
}).then(response => {
|
||||
console.log(response.data);
|
||||
this.loading=false;
|
||||
this.$root.$emit('updateData',"ulohaZadaniNode create update");
|
||||
}).catch( e => {
|
||||
console.log(e);
|
||||
});},
|
||||
saveNode: function(){
|
||||
console.log('Saving UlohaZadaniNode');
|
||||
this.loading = true
|
||||
axios.put('/api/ulohazadaninode/'+this.item.node.id+'/',{
|
||||
uloha: {
|
||||
max_body: this.max_body,
|
||||
kod: this.kod,
|
||||
nazev: this.nazev,
|
||||
}
|
||||
}).then(response => {
|
||||
console.log(response.data);
|
||||
this.loading=false;
|
||||
this.item.node = response.data;
|
||||
this.$root.$emit('updateData',"ulohaZadaniNode save update");
|
||||
}).catch( e => {
|
||||
console.log(e);
|
||||
});
|
||||
this.editorShow = false;
|
||||
|
||||
},
|
||||
|
||||
},
|
||||
mounted: function(){
|
||||
axios.defaults.headers.common['X-CSRFToken'] = this.getCookie('csrftoken');
|
||||
if (this.create){
|
||||
this.editorShow = true;
|
||||
this.max_body = 0;
|
||||
this.nazev = "";
|
||||
this.kod = "";
|
||||
} else {
|
||||
this.max_body = this.item.node.uloha.max_body;
|
||||
this.nazev = this.item.node.uloha.nazev;
|
||||
this.kod = this.item.node.uloha.kod;
|
||||
}
|
||||
if (this.item.node.uloha === null){
|
||||
console.log("Uloha je null!");
|
||||
console.log(this.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -20,7 +20,7 @@ export default new Router({
|
|||
}, {
|
||||
path: '/zadani/aktualni',
|
||||
name: 'treenode_zadani',
|
||||
props: {'tnid': 23},
|
||||
props: {'tnid': 1655},
|
||||
component: TreeNodeRoot
|
||||
}, {
|
||||
path: '/cislo/:cislo',
|
||||
|
|
|
@ -15,7 +15,7 @@ const pages = {
|
|||
module.exports = {
|
||||
pages: pages,
|
||||
filenameHashing: false,
|
||||
productionSourceMap: false,
|
||||
productionSourceMap: true,
|
||||
publicPath: process.env.NODE_ENV === 'production'
|
||||
? '/static/seminar/vue/'
|
||||
: 'http://localhost:8080/',
|
||||
|
@ -23,6 +23,7 @@ module.exports = {
|
|||
|
||||
chainWebpack: config => {
|
||||
|
||||
config.optimization.minimize(false)
|
||||
config.optimization
|
||||
.splitChunks({
|
||||
cacheGroups: {
|
||||
|
@ -33,7 +34,7 @@ module.exports = {
|
|||
priority: 1
|
||||
},
|
||||
},
|
||||
});
|
||||
}).minimize(false);
|
||||
|
||||
Object.keys(pages).forEach(page => {
|
||||
config.plugins.delete(`html-${page}`);
|
||||
|
|
Loading…
Reference in a new issue