Compare commits

..

36 commits

Author SHA1 Message Date
Pavel "LEdoian" Turinsky
6ab00392cc Použít přímo nový model
… když už můžeme
2024-04-30 22:20:36 +02:00
Pavel "LEdoian" Turinsky
5070a4d914 Merge branch 'master' into split-apps
Aby se to snáz mergeovalo
2024-04-30 22:20:06 +02:00
d09a08f53f fix: Přeskakování v šifrovačce (je tam faaaaakt hodně sněhu) 2024-04-22 23:27:29 +02:00
9a93f95490 fix: Nápovědy v šifrovačce 2024-04-21 21:06:56 +02:00
fd736829c2 Merge pull request 'Nápovědy v šifrovačce' (!46) from sifrovackav2 into master
Reviewed-on: #46
2024-04-21 20:56:41 +02:00
026efe2467 Nápovědy v šifrovačce 2024-04-14 15:09:03 +02:00
a301b122fd Apríl 2024 2024-03-31 19:12:24 +02:00
81494a7152 Merge pull request 'Fix obálek' (!45) from fix-obalky into master 2024-03-03 23:29:41 +01:00
Pavel "LEdoian" Turinsky
a1000ad2bf Chybová hláška i pro stvrzenky 2024-03-03 23:12:39 +01:00
Pavel "LEdoian" Turinsky
88ae103ec1 Lepší složky i pro stvrzenky 2024-03-03 23:09:18 +01:00
Pavel "LEdoian" Turinsky
213d3cc7b2 Lepší vyrábění dočasných adresářů
Chceme je po sobě nejspíš mazat i když to spadne. Možná to zesložití
vývoj, ale je to odolnější proti náhodnému pádu čehokoliv.
2024-03-03 23:07:51 +01:00
Pavel "LEdoian" Turinsky
4ecd2a7a61 Ještě status kód 2024-03-03 23:06:43 +01:00
Pavel "LEdoian" Turinsky
d2926bd1a7 Správné hledání lišáka pro obálky 2024-03-03 23:05:39 +01:00
Pavel "LEdoian" Turinsky
a59e2f9977 Užitečná chybová stránka pro neúspěšné generování obálek 2024-03-03 22:44:59 +01:00
239a324a19 Ještě lepší vyřešení rozlišení webů 2024-02-05 20:34:25 +01:00
c0a3e3df8f Lepší vyřešení rozlišení webů 2024-02-05 20:08:25 +01:00
b4c693a9ab Uchycení řádku a sloupce v tabulce 2024-02-05 19:50:17 +01:00
c130ab8426 Zrychlení načítání archivu soustředění pro účastníky 2024-01-30 00:11:13 +01:00
a72435dd72 Zrychlení načítání archivu soustředění 2024-01-30 00:02:27 +01:00
8e1a03863f PLS, Windowsy… 2023-12-28 09:50:13 +01:00
b8f2e1da3b Merge pull request 'Odstranění starých dependencí a okomentování většiny stávajících' (!42) from odstraneni_starych_dependenci into master
Reviewed-on: #42
2023-12-18 23:08:56 +01:00
824a4d9eb3 Fixnuto přetékání selectů přes title a login bar 2023-12-18 22:13:17 +01:00
46fd51e7d9 Odstraněno sekizai (nepoužívalo se, zbytečně zesložiťuje, jde to dělat i jinak a házelo někdy někde chyby) 2023-12-18 21:24:14 +01:00
8babbd988c A další komentáře 2023-12-11 22:20:38 +01:00
ea5ee85e7a Odstranění django-crispy-forms (nějaké fancy formy, ale vypadá nepoužívaně) 2023-12-11 22:03:42 +01:00
187ca0ec93 Další komentáře v requirements.txt 2023-12-11 22:02:22 +01:00
7a28649436 Odstranění django-flat-theme (dávno, dávno, předávno (Django 1.9) includované do Djanga) 2023-12-11 21:59:13 +01:00
1802e90952 Odstranění django-mptt (knihovna pro stromy v Djangu, např. v adminu, na první pohled nepoužívaná, navíc unmaintained) 2023-12-11 21:51:20 +01:00
0f3874beb5 Nějaké komentáře k requirements.txt 2023-12-11 21:49:14 +01:00
191177aea0 Odstranění traitlets (kontrola typování, ale pokud správně chápu, tak nějakého svého) 2023-12-11 21:33:07 +01:00
3bfdde10e8 Odstranění pexpect (knihovna pro spawnování podprocesů z pythonu, nepoužívaná?) 2023-12-11 21:30:09 +01:00
b5de60d681 Odstranění html5lib (pro parsování html v Pythonu, nepoužívaná, navíc už 3 roky neudržovaná) 2023-12-11 21:26:56 +01:00
0204bd2444 Odstranění pytz (použit pouze v testdatech, ale tam naopak budeme lépe simulovat aktuální stav, když tam nacpeme UTC) 2023-12-11 21:25:36 +01:00
3fd0c7f917 Odstranění six (knihovna pro přechod mezi python2 a python3) 2023-12-11 21:17:12 +01:00
6cb41a1263 Odstranění django comments, data jsou v /akce/mam/www/old_data/django_comments.json.gz 2023-12-11 21:07:18 +01:00
ffa0c682f4 Pokus o řešení problémů s výsledkovkou posledního čísla 2023-12-11 20:16:04 +01:00
26 changed files with 436 additions and 116 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,9 +2,9 @@ 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 seminar.models import Resitel
from .forms import SifrovackaForm, NapovedaForm
from .models import OdpovedUcastnika, SpravnaOdpoved, Napoveda, NapovezenoUcastnikovi
from personalni.models import Resitel
# Create your views here.
@ -31,3 +31,40 @@ class SifrovackaView(FormView):
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>')

View file

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

View file

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

View file

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