Browse Source

Merge branch 'master' into split-apps

Aby se to snáz mergeovalo
pull/43/head
Pavel "LEdoian" Turinsky 3 weeks ago
parent
commit
5070a4d914
  1. 5
      mamweb/settings_common.py
  2. 42
      mamweb/static/css/mamweb.css
  3. 38
      mamweb/static/css/rozliseni.css
  4. 23
      mamweb/templates/base.html
  5. 4
      mamweb/urls.py
  6. 6
      odevzdavatko/templates/odevzdavatko/tabulka.html
  7. 39
      requirements.txt
  8. 6
      seminar/templates/seminar/archiv/cislo.html
  9. 6
      seminar/templates/seminar/archiv/problem.html
  10. 3
      seminar/templates/seminar/archiv/rocnik.html
  11. 1
      seminar/templatetags/utils.py
  12. 5
      seminar/testutils.py
  13. 26
      seminar/views/views_all.py
  14. 4
      sifrovacka/admin.py
  15. 14
      sifrovacka/forms.py
  16. 65
      sifrovacka/migrations/0004_napoveda_napovezenoucastnikovi.py
  17. 17
      sifrovacka/models.py
  18. 50
      sifrovacka/templates/sifrovacka/napoveda.html
  19. 23
      sifrovacka/templates/sifrovacka/napovedy_list.html
  20. 54
      sifrovacka/templates/sifrovacka/preskoceni.html
  21. 4
      sifrovacka/templates/sifrovacka/sifrovacka.html
  22. 17
      sifrovacka/urls.py
  23. 43
      sifrovacka/views.py
  24. 8
      soustredeni/templates/soustredeni/seznam_soustredeni.html
  25. 38
      soustredeni/views.py
  26. 9
      treenode/templates/treenode/orphanage.html

5
mamweb/settings_common.py

@ -87,7 +87,6 @@ TEMPLATES = [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.request',
'django.contrib.messages.context_processors.messages',
'sekizai.context_processors.sekizai',
'header_fotky.context_processors.vzhled',
'various.context_processors.rozliseni',
'various.context_processors.april',
@ -110,7 +109,6 @@ INSTALLED_APPS = (
'django.contrib.auth',
# Utilities
'sekizai',
'reversion',
'django_countries',
'solo',
@ -120,9 +118,6 @@ INSTALLED_APPS = (
'dal',
'dal_select2',
'crispy_forms',
'django_comments',
'django.contrib.flatpages',
'django.contrib.humanize',

42
mamweb/static/css/mamweb.css

@ -39,7 +39,7 @@ div.login-bar {
position: fixed;
margin-top: -20px;
min-height: 20px;
z-index: 20;
z-index: 4086;
padding-left: 5px;
padding-right: 5px;
@ -199,22 +199,13 @@ h1 {
margin-top: 0px;
}
/* Comments */
#id_comment {
width: 100%;
height: 6em;
}
/* Headline & Header */
#title { /*dělá blbosti šířka, je to kvůli fixed pozici, zatím natvrdo, vyřešit*/
height: 55px;
width: 970px;
position: fixed;
z-index: 10;
z-index: 2048;
background-color: #e84e10;
filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
@ -1252,6 +1243,35 @@ div.gdpr {
background: rgb(253, 237, 213);
}
/*Přichycování prvního sloupce a řádku*/
.dosla_reseni {
display: block;
max-height: 90vh;
max-width: 90vw;
overflow: auto;
margin-left: 5vw;
}
.dosla_reseni thead tr {
position: sticky;
top: 0;
z-index: 1;
}
.dosla_reseni tr:nth-child(even) td:first-child, .dosla_reseni thead tr, .dosla_reseni thead tr:first-child td:first-child {
background: rgb(253, 237, 213);
}
.dosla_reseni tr:nth-child(odd) td:first-child {
background: #fffbf6;
}
.dosla_reseni tr td:first-child {
position: sticky;
left: 0;
}
/* */
.odevzdana_reseni tr th, .odevzdana_reseni tr td {
border: 1px solid black;

38
mamweb/static/css/rozliseni.css

@ -1,29 +1,35 @@
/* Rozlišení mezi lokálním, test a produkčním webem */
.localweb {
border-left: 20px solid greenyellow;
border-right: 20px solid greenyellow;
body.localweb:before, body.localweb:after,
body.testweb:before, body.testweb:after,
body.suprodweb:before, body.suprodweb:after {
content: "";
position: fixed;
width: 20px;
height: 100%;
top: 0;
}
.localweb .login-bar {
margin-left: -20px;
body.localweb:before,
body.testweb:before,
body.suprodweb:before {
left: 0;
}
.testweb {
border-left: 20px solid darkorange;
border-right: 20px solid darkorange;
body.localweb:after,
body.testweb:after,
body.suprodweb:after {
right: 0;
}
.testweb .login-bar {
margin-left: -20px;
body.localweb:before, body.localweb:after {
background: greenyellow;
}
/* Produkční web z pohledu superuživatele */
.suprodweb {
border-left: 20px solid red;
border-right: 20px solid red;
body.testweb:before, body.testweb:after {
background: darkorange;
}
.suprodweb .login-bar {
margin-left: -20px;
body.suprodweb:before, body.suprodweb:after {
background: red;
}

23
mamweb/templates/base.html

@ -1,4 +1,4 @@
{% load static sekizai_tags %}
{% load static %}
{% load sitetree %}
<!DOCTYPE html>
<html lang='cs'>
@ -7,7 +7,6 @@
<title>{% block title %}{% block nadpis1a %}🦊{% endblock %} | Korespondenční seminář M&amp;M{% endblock title %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{% static 'images/MATFYZ_MM_barevne.svg' %}" type="image/x-icon">
{# {% render_block css %}#}
{% block custom_css %}{% endblock %}
<link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
<link href="{% static 'css/bootstrap.css' %}" rel="stylesheet">
@ -189,6 +188,24 @@
walkText(document.body);
</script>
{% endif %}
{% render_block "js" %}
{% if april == 2024 %}
<script>
{# By https://stackoverflow.com/a/34559316 #}
function walkText(node) {
if (node.nodeType == 3) {
node.data = node.data.replace(/M&M/g, "W8W");
}
if (node.nodeType == 1 && node.nodeName != "SCRIPT") {
for (var i = 0; i < node.childNodes.length; i++) {
walkText(node.childNodes[i]);
}
}
}
walkText(document.body);
</script>
{% endif %}
{% block js %}{% endblock %}
</body>
</html>

4
mamweb/urls.py

@ -13,7 +13,6 @@ Soubor sloužící jako základní „router“, tj. zde se includují veškeré
- :mod:`api.urls`
- :mod:`treenode.urls`
- :mod:`aesop.urls`
- ``comments_dj/`` :mod:`django_comments.urls`
"""
from django.urls import path, include
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
@ -62,9 +61,6 @@ urlpatterns = [
# Aesop (ma vlastni podadresare)
path('', include('aesop.urls')),
# Comments (interni i verejne)
path('comments_dj/', include('django_comments.urls')),
# REST API
# path('api/', include(router.urls)),

6
odevzdavatko/templates/odevzdavatko/tabulka.html

@ -21,8 +21,8 @@ Do data (včetně): {{ filtr.reseni_do }}
<input type=submit value="Změň ročník">
</form>
<div style="overflow-x: scroll;">
<table class="dosla_reseni">
<thead>
<tr>
<td></td> {# Prázdná buňka v levém horním rohu #}
{% for p in problemy %}
@ -32,6 +32,8 @@ Do data (včetně): {{ filtr.reseni_do }}
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for resitel,hodnoty in radky%}
<tr>
<td>
@ -52,8 +54,8 @@ Do data (včetně): {{ filtr.reseni_do }}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}

39
requirements.txt

@ -1,43 +1,32 @@
# -*- coding: utf-8 -*-
-c constraints.txt
# basic libs
psycopg2
html5lib
ipython
psycopg2 # PostgreSQL adaptér
ipython # Interaktivní shell
Unidecode # Přepisuje unicode do ASCII (např. soubory nebo e-maily)
Pillow
pilkit>=3.0 # Kvůli kompatibilitě s Pillow>=10.0.0
pytz
six
pexpect
traitlets
Unidecode
# Django and modules
Django<5.0
#django-bootstrap-sass
django-mptt
django-reversion
django-sekizai
django-countries
django-solo
django-ckeditor
django-reversion # Version control na datech v databázi
django-countries # Políčko ve formu / field v modelu ohledně států
django-solo # Singleton model (speciálně Nastavení)
django-ckeditor # Editor htmlka (hlavně v adminu u flatpages)
django-cleanup # Uklízí media/ od smazaných „databázových“ souborů
django-flat-theme
django-taggit
django-autocomplete-light>=3.9.0
django-crispy-forms
django-imagekit
django-polymorphic
django-sitetree
django_reverse_admin
django-taggit # Taggy v djangu (speciálně zaměření problémů)
django-autocomplete-light>=3.9.0 # Automatické doplňování (problémů, účastníků, …) ve formulářích
django-imagekit # Všechny možné obrázky v Djangu
django-polymorphic # Polymorfismus na django modelech (hlavně Problém nebo treenode)
django-sitetree # Struktura stránek, hlavně pro meníčko
django_reverse_admin # Lepší handlování OneToOne fieldů v adminu
django-rest-framework
django-webpack-loader
django-rest-polymorphic
# Comments
django-contrib-comments
# debug tools/extensions
django-debug-toolbar

6
seminar/templates/seminar/archiv/cislo.html

@ -38,9 +38,11 @@
<h2> Orgovské odkazy </h2>
<ul>
<li><a href="obalky.pdf">Obálky (PDF)</a></li>
<li><a href="tituly.tex" download>Tituly (TeX)</a></li>
<li><a href="vysledkovka.tex" download>Výsledkovka (TeX)</a></li>
<li><a href="tituly.tex" download>Tituly (TeX, 2. deadline předchozího čísla a 1.deadline tohoto)</a></li>
<li><a href="vysledkovka.tex" download>Výsledkovka (TeX, 2. deadline předchozího čísla a 1.deadline tohoto)</a></li>
<li><a href="odmeny/{{prevcislo.rocnik.rocnik}}.{{prevcislo.poradi}}/">Odměny</a></li>
<li><a href="{% url "seminar_rocnik_titul" rocnik=cislo.rocnik.rocnik %}" download="posledni_tituly.tex">Tituly do závěrečného čísla (TeX, 2. deadline předchozího čísla a oba tohoto)</a></li>
<li><a href="{% url "seminar_rocnik_posledni_vysledkovka" rocnik=cislo.rocnik.rocnik %}" download>Výsledkovka závěrečného čísla ročníku (TeX, 2. deadline předchozího čísla a oba tohoto)</a></li>
</ul>
</div>
{% endif %}

6
seminar/templates/seminar/archiv/problem.html

@ -1,7 +1,5 @@
{% extends "base.html" %}
{% load comments %}
{% block content %}
<div {% if not problem.verejne and user.je_org %}class="mam-org-only"{% endif %}>
{% block problem %}
@ -13,10 +11,6 @@
<h2>Text - org</h2>
{{ problem.text_org |safe }}
<h2>Diskuse - org</h2>
{% render_comment_list for object %}
{% render_comment_form for object %}
</div>
{% endif %}

3
seminar/templates/seminar/archiv/rocnik.html

@ -120,8 +120,7 @@
{% if user.je_org %}
<div class='mam-org-only'>
<p><a href='vysledkovka.tex' download>Výsledkovka ročníku (LaTeX, včetně neveřejných)</a></p>
<p><a href="tituly.tex" download>Tituly (TeX, do konce ročníku = pro poslední číslo)</a></p>
<p><a href="posledni_vysledkovka.tex" download>Výsledkovka posledního čísla</a></p>
<p><a href="tituly.tex" download>Tituly (TeX, včetně neveřejných, všechny, nevhodné do mamtexu)</a></p>
{# FIXME: Sice to sem asi nepatří sémanticky, ale bylo to nejjednodušší… #}
<p><a href='{% url 'seminar_rocnik_resitele_csv' rocnik=rocnik.rocnik %}' download>CSV export řešitelů</a></p>
<h2>Výsledková listina včetně neveřejných bodů</h2>

1
seminar/templatetags/utils.py

@ -1,7 +1,6 @@
from django import template
from django.utils.safestring import mark_safe
from datetime import datetime, timedelta
from pytz import timezone
from mamweb.settings import TIME_ZONE
import logging
register = template.Library()

5
seminar/testutils.py

@ -4,7 +4,6 @@ import datetime
from django.contrib.auth.models import Permission
from django.contrib.auth.models import Group
from pytz import timezone
import random
import lorem
import django.contrib.auth
@ -177,13 +176,13 @@ def gen_organizatori(rnd, osoby, last_rocnik):
year=1993 + pusobnost,
month=rnd.randint(1, 12),
day=rnd.randint(1, 28),
tzinfo=timezone('CET'),
tzinfo=datetime.timezone.utc,
)
do = datetime.datetime(
year=od.year + rnd.randint(1, 6),
month=rnd.randint(1, 12),
day=rnd.randint(1, 28),
tzinfo=timezone('CET'),
tzinfo=datetime.timezone.utc,
)
#aktualni organizatori jeste nemaji vyplnene organizuje_do

26
seminar/views/views_all.py

@ -8,6 +8,7 @@ from django.http import Http404
from django.db.models import Q, Sum, Count
from django.views.generic.base import RedirectView
from django.core.exceptions import PermissionDenied
from django.contrib.staticfiles.finders import find
import seminar.models as s
import seminar.models as m
@ -36,6 +37,7 @@ import unicodedata
import logging
import time
from collections.abc import Sequence
import http
from seminar.utils import aktivniResitele
@ -562,17 +564,25 @@ def cisloObalkyView(request, rocnik, cislo):
def obalkyView(request, resitele):
if len(resitele) == 0:
return HttpResponse(
render(request, 'universal.html', {
'title': 'Není pro koho vyrobit obálky.',
'text': 'Právě ses pokusil/a vygenerovat obálky pro prázdnou množinu lidí. Můžeš to zkusit změnit, případně se zeptej webařů :-)',
}),
status=http.HTTPStatus.NOT_FOUND,
)
tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content
tempdir = tempfile.mkdtemp()
with open(tempdir+"/obalky.tex","w") as texfile:
texfile.write(tex.decode())
shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.pdf'), tempdir)
subprocess.call(["pdflatex","obalky.tex"], cwd = tempdir)
with tempfile.TemporaryDirectory() as tempdir:
with open(tempdir+"/obalky.tex","w") as texfile:
texfile.write(tex.decode())
shutil.copy(find('seminar/lisak.pdf'), tempdir)
subprocess.call(["pdflatex","obalky.tex"], cwd = tempdir)
with open(tempdir+"/obalky.pdf","rb") as pdffile:
response = HttpResponse(pdffile.read(), content_type='application/pdf')
shutil.rmtree(tempdir)
with open(tempdir+"/obalky.pdf","rb") as pdffile:
response = HttpResponse(pdffile.read(), content_type='application/pdf')
return response

4
sifrovacka/admin.py

@ -1,8 +1,10 @@
from django.contrib import admin
from .models import OdpovedUcastnika, SpravnaOdpoved
from .models import OdpovedUcastnika, SpravnaOdpoved, NapovezenoUcastnikovi, Napoveda
# Register your models here.
admin.site.register(OdpovedUcastnika)
admin.site.register(SpravnaOdpoved)
admin.site.register(Napoveda)
admin.site.register(NapovezenoUcastnikovi)

14
sifrovacka/forms.py

@ -1,6 +1,6 @@
from django.core.exceptions import ValidationError
from django.forms import ModelForm, Textarea
from .models import OdpovedUcastnika, SpravnaOdpoved
from .models import OdpovedUcastnika, SpravnaOdpoved, NapovezenoUcastnikovi, Napoveda
class SifrovackaForm(ModelForm):
@ -16,3 +16,15 @@ class SifrovackaForm(ModelForm):
if SpravnaOdpoved.objects.filter(sifra=sifra).count() == 0:
raise ValidationError("Tohle číslo šifry v databázi nemáme. Zkontrolujte si ho prosím.")
return sifra
class NapovedaForm(ModelForm):
class Meta:
model = NapovezenoUcastnikovi
fields = ["sifra",]
def clean_sifra(self):
sifra = self.cleaned_data.get('sifra')
if Napoveda.objects.filter(sifra=sifra).count() == 0:
raise ValidationError("K tomuto číslu šifry nemáme nápovědu. Zkontrolujte si ho prosím.")
return sifra

65
sifrovacka/migrations/0004_napoveda_napovezenoucastnikovi.py

@ -0,0 +1,65 @@
# Generated by Django 4.2.8 on 2024-04-14 12:57
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
(
"seminar",
"0114_related_name_se_zmenilo_a_django_chce_migraci_tak_dostane_migraci",
),
("sifrovacka", "0003_odpoveducastnika_uspech"),
]
operations = [
migrations.CreateModel(
name="Napoveda",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("text", models.TextField()),
("sifra", models.IntegerField()),
],
),
migrations.CreateModel(
name="NapovezenoUcastnikovi",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("sifra", models.IntegerField(verbose_name="Číslo šifry")),
(
"timestamp",
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="Timestamp"
),
),
(
"resitel",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="seminar.resitel",
),
),
],
options={
"ordering": ["-timestamp"],
},
),
]

17
sifrovacka/models.py

@ -25,3 +25,20 @@ class SpravnaOdpoved(models.Model):
def __str__(self):
return f"{self.sifra}: {self.odpoved}"
class NapovezenoUcastnikovi(models.Model):
class Meta:
ordering = ["-timestamp"]
resitel = models.ForeignKey(Resitel, blank=False, null=False, on_delete=models.CASCADE)
sifra = models.IntegerField("Číslo šifry", blank=False, null=False,)
timestamp = models.DateTimeField("Timestamp", blank=False, null=False, default=timezone.now)
class Napoveda(models.Model):
text = models.TextField(blank=False, null=False,)
sifra = models.IntegerField(blank=False, null=False,)
def __str__(self):
return f"{self.sifra}: {self.text}"

50
sifrovacka/templates/sifrovacka/napoveda.html

@ -0,0 +1,50 @@
{% extends "base.html" %}
{% block content %}
<br>
<h1>{% block nadpis1a %}M&Mí šifrovačka{% endblock nadpis1a %}</h1>
<br>
<h2>Získat nápovědu k šifře:</h2>
<form action="{% url 'sifrovacka_napoveda' %}" method="post">
<table class="form">
{{form.non_field_errors}}
{% for field in form %}
<tr>
<td>
<label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
{{ field.label }}
</label>
</td>
<td {% if field.help_text %} class="field-with-comment"{% endif %}>
{{ field }}
<span class="field-comment">{{ field.help_text|safe }}</span>
</td>
</tr>
{% if field.errors %}
<tr>
<td colspan="2"><span class="field-error">{{ field.errors }}</span></td>
</tr>
{% endif %}
{% endfor %}
</table>
{% csrf_token %}
<input type="submit" value="Chci nápovědu">
</form>
<p><a href="{% url 'sifrovacka' %}">Nechceme nápovědu, známe řešení!</a></p>
<p><a href="{% url 'sifrovacka_preskoceni' %}">Přeskoč šifru</a></p>
{% endblock content %}

23
sifrovacka/templates/sifrovacka/napovedy_list.html

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% block content %}
<h1>{% block nadpis1a %}Šifrovačka vzaté nápovědy{% endblock nadpis1a %}</h1>
<table class="dosla_reseni">
<tr>
<th>Timestamp</th>
<th>Řešitel</th>
<th>Šifra</th>
</tr>
{% for u in object_list %}
<tr>
<td>{{ u.timestamp }}</td>
<td>{{ u.resitel }}</td>
<td>{{ u.sifra }}</td>
</tr>
{% endfor %}
</table>
{% endblock content %}

54
sifrovacka/templates/sifrovacka/preskoceni.html

@ -0,0 +1,54 @@
{% extends "base.html" %}
{% block content %}
<br>
<h1>{% block nadpis1a %}M&Mí šifrovačka{% endblock nadpis1a %}</h1>
<br>
<h2>Přeskočit šifru:</h2>
<form action="{% url 'sifrovacka_preskoceni' %}" method="post">
<table class="form">
{{form.non_field_errors}}
{% for field in form %}
{% if field.id_for_label != "id_odpoved" %}
<tr>
<td>
<label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
{{ field.label }}
</label>
</td>
<td {% if field.help_text %} class="field-with-comment"{% endif %}>
{{ field }}
<span class="field-comment">{{ field.help_text|safe }}</span>
</td>
</tr>
{% if field.errors %}
<tr>
<td colspan="2"><span class="field-error">{{ field.errors }}</span></td>
</tr>
{% endif %}
{% else %}
{{ field.as_hidden }}
{% endif %}
{% endfor %}
</table>
{% csrf_token %}
<input type="submit" value="Chceme další stanoviště bez vyřešení šifry">
</form>
<p><a href="{% url 'sifrovacka' %}">Nechceme přeskočit, známe řešení!</a></p>
<p><a href="{% url 'sifrovacka_napoveda' %}">Nechceme přeskakovat, ale nápověda by se šikla.</a></p>
{% endblock content %}

4
sifrovacka/templates/sifrovacka/sifrovacka.html

@ -43,4 +43,8 @@
<input type="submit" value="Tak pravím!">
</form>
<p><a href="{% url 'sifrovacka_napoveda' %}">Získat nápovědu</a></p>
<p><a href="{% url 'sifrovacka_preskoceni' %}">Přeskoč šifru</a></p>
{% endblock content %}

17
sifrovacka/urls.py

@ -1,7 +1,7 @@
from django.urls import path
from seminar.utils import org_required, resitel_or_org_required
from .views import SifrovackaView, SifrovackaListView
from .views import SifrovackaView, SifrovackaListView, NapovedaView, NapovedaListView, PreskoceniView
urlpatterns = [
path(
@ -14,4 +14,19 @@ urlpatterns = [
org_required(SifrovackaListView.as_view()),
name='sifrovacka_odpovedi'
),
path(
'napoveda/',
resitel_or_org_required(NapovedaView.as_view()),
name='sifrovacka_napoveda'
),
path(
'napovedy/',
org_required(NapovedaListView.as_view()),
name='sifrovacka_napovedy'
),
path(
'preskoceni/',
resitel_or_org_required(PreskoceniView.as_view()),
name='sifrovacka_preskoceni'
),
]

43
sifrovacka/views.py

@ -2,8 +2,8 @@ from django.urls import reverse
from django.views.generic import FormView, ListView
from seminar.views import formularOKView
from .forms import SifrovackaForm
from .models import OdpovedUcastnika, SpravnaOdpoved
from .forms import SifrovackaForm, NapovedaForm
from .models import OdpovedUcastnika, SpravnaOdpoved, Napoveda, NapovezenoUcastnikovi
from seminar.models import Resitel
@ -24,10 +24,47 @@ class SifrovackaView(FormView):
instance.uspech = True
instance.save()
return formularOKView(self.request, f'<h1>{sifra.skryty_text}</h1> <p><a href="{reverse("sifrovacka")}">Odevzdat další.</a></p><br><br><br>')
class SifrovackaListView(ListView):
template_name = 'sifrovacka/odpovedi_list.html'
model = OdpovedUcastnika
class NapovedaView(FormView):
template_name = 'sifrovacka/napoveda.html'
form_class = NapovedaForm
def form_valid(self, form):
instance = form.save(commit=False)
resitel = Resitel.objects.get(osoba__user=self.request.user)
instance.resitel = resitel
if NapovezenoUcastnikovi.objects.filter(resitel=resitel, sifra=instance.sifra).first() is None:
instance.save()
napoveda = Napoveda.objects.filter(sifra=instance.sifra).first()
return formularOKView(self.request, f'<h1>Nápověda k šifře číslo {instance.sifra} je:</h1><p>{napoveda.text}</p> <p><a href="{reverse("sifrovacka")}">Odevzdat řešení.</a></p><br><br><br>')
class NapovedaListView(ListView):
template_name = 'sifrovacka/napovedy_list.html'
model = NapovezenoUcastnikovi
class PreskoceniView(FormView):
template_name = 'sifrovacka/preskoceni.html'
form_class = SifrovackaForm
initial = {"odpoved": "=======PŘESKOČENO======="}
def form_valid(self, form):
instance = form.save(commit=False)
instance.odpoved = "=======PŘESKOČENO======="
resitel = Resitel.objects.get(osoba__user=self.request.user)
instance.resitel = resitel
instance.save()
sifra = SpravnaOdpoved.objects.filter(sifra=instance.sifra).first() # FIXME co když je více "správných" odpovědí?
return formularOKView(self.request, f'<h1>{sifra.skryty_text}</h1> <p><a href="{reverse("sifrovacka")}">Zpět na odevzdávátko.</a></p><br><br><br>')

8
soustredeni/templates/soustredeni/seznam_soustredeni.html

@ -58,16 +58,16 @@
{# Účastníci #}
<h2>Soustředění se zúčastnili tito účastníci:</h2>
<p>
{% for i in soustredeni.soustredeni_ucastnici_set.all %}
{{i.resitel}}{% if forloop.last %}.{% else %},{% endif %}
{% for i in soustredeni.ucastnici.all %}
{{i}}{% if forloop.last %}.{% else %},{% endif %}
{% empty %}
Nic!
{% endfor %}
</p>
<h2>Soustředění se účastnili tito organizátoři:</h2>
<p>
{% for i in soustredeni.soustredeni_organizatori_set.all %}
{{i.organizator}}{% if forloop.last %}.{% else %},{% endif %}
{% for i in soustredeni.organizatori.all %}
{{i}}{% if forloop.last %}.{% else %},{% endif %}
{% empty %}
Nic!
{% endfor %}

38
soustredeni/views.py

@ -9,6 +9,7 @@ import tempfile
import shutil
import subprocess
from pathlib import Path
import http
from seminar.views import obalkyView
@ -17,6 +18,19 @@ class SoustredeniListView(generic.ListView):
model = Soustredeni
template_name = 'soustredeni/seznam_soustredeni.html'
def get_queryset(self):
if not self.request.user.je_org:
return super().get_queryset()
return (
Soustredeni.objects
.prefetch_related(
"ucastnici", "ucastnici__osoba",
"organizatori", "organizatori__osoba",
"galerie_set",
)
.select_related("rocnik")
)
def soustredeniObalkyView(request, soustredeni):
soustredeni = get_object_or_404(Soustredeni, id=soustredeni)
@ -63,17 +77,25 @@ def soustredeniUcastniciExportView(request, soustredeni):
def soustredeniStvrzenkyView(request, soustredeni):
soustredeni = get_object_or_404(Soustredeni, id=soustredeni)
ucastnici = Resitel.objects.filter(soustredeni=soustredeni)
if ucastnici.count() == 0:
return HttpResponse(
render(request, 'universal.html', {
'title': 'Není pro koho vyrobit stvrzenky.',
'text': 'Právě ses pokusil/a vygenerovat stvrzenky pro prázdnou množinu lidí. Můžeš to zkusit změnit, případně se zeptej webařů :-)',
}),
status=http.HTTPStatus.NOT_FOUND,
)
castka = Nastaveni.get_solo().cena_sous
tex = render(request, 'soustredeni/stvrzenky.tex', {'ucastnici': ucastnici, 'soustredeni': soustredeni, 'castka': castka}).content
tempdir = Path(tempfile.mkdtemp())
with open(tempdir / "stvrzenky.tex", "w") as texfile:
texfile.write(tex.decode())
with tempfile.TemporaryDirectory() as tempdirfn:
tempdir = Path(tempdirfn)
with open(tempdir / "stvrzenky.tex", "w") as texfile:
texfile.write(tex.decode())
shutil.copy(find('images/logomm.pdf'), tempdir)
subprocess.call(["pdflatex", "stvrzenky.tex"], cwd = tempdir, stdout=subprocess.DEVNULL)
shutil.copy(find('images/logomm.pdf'), tempdir)
subprocess.call(["pdflatex", "stvrzenky.tex"], cwd = tempdir, stdout=subprocess.DEVNULL)
with open(tempdir / "stvrzenky.pdf", "rb") as pdffile:
response = HttpResponse(pdffile.read(), content_type='application/pdf')
shutil.rmtree(tempdir)
with open(tempdir / "stvrzenky.pdf", "rb") as pdffile:
response = HttpResponse(pdffile.read(), content_type='application/pdf')
return response

9
treenode/templates/treenode/orphanage.html

@ -1,19 +1,10 @@
{% extends "seminar/archiv/base.html" %}
{% load static %}
{% load sekizai_tags %}
{# toto z nejakeho duvodu nefunguje #}
{% addtoblock css %}
dfsdfs
<link rel="stylesheet" type="text/css" href="{% static 'css/mamweb-dev.css' %}" />
{% endaddtoblock "css" %}
{% block custom_css %}
<link rel="stylesheet" type="text/css" href="{% static 'css/mamweb-dev.css' %}" />
{% endblock custom_css %}
{% load comments %}
{% block content %}
<ul>
{% for obj in object_list %}

Loading…
Cancel
Save