diff --git a/mamweb/templates/april.html b/mamweb/templates/april.html index 92266311..bb24d9d4 100644 --- a/mamweb/templates/april.html +++ b/mamweb/templates/april.html @@ -59,3 +59,22 @@ walkText(document.body); {% endif %} + + + +{% if april == 2024 %} + +{% endif %} diff --git a/mamweb/templates/base.html b/mamweb/templates/base.html index 8294d2b8..4a21c43c 100644 --- a/mamweb/templates/base.html +++ b/mamweb/templates/base.html @@ -121,6 +121,6 @@ {% include 'april.html' %} - {% block js %}{% endblock %} + {% block js %}{% endblock %} diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 318eee21..662c5025 100644 --- a/seminar/views/views_all.py +++ b/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 diff --git a/sifrovacka/admin.py b/sifrovacka/admin.py index 71d191d4..5099c241 100644 --- a/sifrovacka/admin.py +++ b/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) diff --git a/sifrovacka/forms.py b/sifrovacka/forms.py index e3eba7c7..3ae75cc1 100644 --- a/sifrovacka/forms.py +++ b/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 diff --git a/sifrovacka/migrations/0004_napoveda_napovezenoucastnikovi.py b/sifrovacka/migrations/0004_napoveda_napovezenoucastnikovi.py new file mode 100644 index 00000000..cba7ae8f --- /dev/null +++ b/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"], + }, + ), + ] diff --git a/sifrovacka/models.py b/sifrovacka/models.py index 6517c2e0..beabd0a7 100644 --- a/sifrovacka/models.py +++ b/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}" diff --git a/sifrovacka/templates/sifrovacka/napoveda.html b/sifrovacka/templates/sifrovacka/napoveda.html new file mode 100644 index 00000000..cce48ed8 --- /dev/null +++ b/sifrovacka/templates/sifrovacka/napoveda.html @@ -0,0 +1,50 @@ +{% extends "base.html" %} + +{% block content %} + +
+ +

{% block nadpis1a %}M&Mí šifrovačka{% endblock nadpis1a %}

+ +
+ +

Získat nápovědu k šifře:

+ +
+ + {{form.non_field_errors}} + {% for field in form %} + + + + + + + + + {% if field.errors %} + + + + {% endif %} + {% endfor %} +
+ + + + {{ field }} + {{ field.help_text|safe }} +
{{ field.errors }}
+ + {% csrf_token %} + + +
+ +

Nechceme nápovědu, známe řešení!

+ +

Přeskoč šifru

+ +{% endblock content %} diff --git a/sifrovacka/templates/sifrovacka/napovedy_list.html b/sifrovacka/templates/sifrovacka/napovedy_list.html new file mode 100644 index 00000000..dc729947 --- /dev/null +++ b/sifrovacka/templates/sifrovacka/napovedy_list.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block content %} + +

{% block nadpis1a %}Šifrovačka vzaté nápovědy{% endblock nadpis1a %}

+ + + + + + + + + {% for u in object_list %} + + + + + + {% endfor %} +
TimestampŘešitelŠifra
{{ u.timestamp }}{{ u.resitel }}{{ u.sifra }}
+ +{% endblock content %} diff --git a/sifrovacka/templates/sifrovacka/preskoceni.html b/sifrovacka/templates/sifrovacka/preskoceni.html new file mode 100644 index 00000000..64e777ea --- /dev/null +++ b/sifrovacka/templates/sifrovacka/preskoceni.html @@ -0,0 +1,54 @@ +{% extends "base.html" %} + +{% block content %} + +
+ +

{% block nadpis1a %}M&Mí šifrovačka{% endblock nadpis1a %}

+ +
+ +

Přeskočit šifru:

+ +
+ + {{form.non_field_errors}} + {% for field in form %} + {% if field.id_for_label != "id_odpoved" %} + + + + + + + + + {% if field.errors %} + + + + {% endif %} + {% else %} + {{ field.as_hidden }} + {% endif %} + {% endfor %} +
+ + + + {{ field }} + {{ field.help_text|safe }} +
{{ field.errors }}
+ + {% csrf_token %} + + +
+ +

Nechceme přeskočit, známe řešení!

+ +

Nechceme přeskakovat, ale nápověda by se šikla.

+ +{% endblock content %} diff --git a/sifrovacka/templates/sifrovacka/sifrovacka.html b/sifrovacka/templates/sifrovacka/sifrovacka.html index 4e0cc15a..1ce95454 100644 --- a/sifrovacka/templates/sifrovacka/sifrovacka.html +++ b/sifrovacka/templates/sifrovacka/sifrovacka.html @@ -43,4 +43,8 @@ +

Získat nápovědu

+ +

Přeskoč šifru

+ {% endblock content %} diff --git a/sifrovacka/urls.py b/sifrovacka/urls.py index a7af5e54..85f9c4cc 100644 --- a/sifrovacka/urls.py +++ b/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' + ), ] diff --git a/sifrovacka/views.py b/sifrovacka/views.py index 9c4af3ed..59f3deec 100644 --- a/sifrovacka/views.py +++ b/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.personalni import Resitel @@ -24,10 +24,47 @@ class SifrovackaView(FormView): instance.uspech = True instance.save() - + return formularOKView(self.request, f'

{sifra.skryty_text}

Odevzdat další.




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

Nápověda k šifře číslo {instance.sifra} je:

{napoveda.text}

Odevzdat řešení.




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

{sifra.skryty_text}

Zpět na odevzdávátko.




') diff --git a/soustredeni/views.py b/soustredeni/views.py index f2aafdf7..f150b6b8 100644 --- a/soustredeni/views.py +++ b/soustredeni/views.py @@ -9,6 +9,7 @@ import tempfile import shutil import subprocess from pathlib import Path +import http from seminar.views import obalkyView @@ -76,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