From f43bda37ec64f8dad41471fb010354c34ae0f30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 16 Oct 2023 07:38:57 +0200 Subject: [PATCH] =?UTF-8?q?Prvn=C3=AD=20funk=C4=8Dn=C3=AD=20verze?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 29 ++ .gitignore | 21 ++ .requirements | 2 + README.md | 56 +++ autentizace/__init__.py | 1 + autentizace/templates/autentizace/login.html | 28 ++ autentizace/templates/autentizace/logout.html | 8 + autentizace/urls.py | 10 + autentizace/views.py | 14 + byrokracie/__init__.py | 0 byrokracie/context_processor.py | 6 + byrokracie/settings.py | 99 ++++++ byrokracie/static/css/base.css | 39 +++ byrokracie/static/images/icon.png | Bin 0 -> 86025 bytes byrokracie/templates/base.html | 26 ++ byrokracie/urls.py | 10 + byrokracie/wsgi.py | 16 + data/stanoviste.json | 68 ++++ data/tymy.json | 83 +++++ data/users.json | 178 ++++++++++ fix_json.py | 12 + hra/__init__.py | 0 hra/admin.py | 14 + hra/logika.py | 260 ++++++++++++++ hra/migrations/0001_initial.py | 53 +++ .../0002_tym_ma_ds_tym_pocet_bananu.py | 23 ++ .../0003_tym_vi_o_mesici_tym_vi_o_zadosti.py | 23 ++ hra/migrations/0004_zadost.py | 33 ++ hra/migrations/0005_tym_vi_o_mase.py | 18 + hra/migrations/0006_tym_ovesna_kase.py | 18 + hra/migrations/__init__.py | 0 hra/models.py | 326 ++++++++++++++++++ hra/templates/hra/inventar.html | 19 + hra/templates/hra/stanoviste/archiv.html | 58 ++++ hra/templates/hra/stanoviste/base.html | 52 +++ hra/templates/hra/stanoviste/casovy_vyr.html | 10 + hra/templates/hra/stanoviste/domov.html | 33 ++ hra/templates/hra/stanoviste/menza.html | 23 ++ hra/templates/hra/stanoviste/posta.html | 47 +++ hra/templates/hra/stanoviste/studijni.html | 27 ++ hra/templates/hra/staticke_stanoviste.html | 19 + hra/templates/hra/timeout.html | 12 + hra/templates/hra/tym.html | 27 ++ hra/urls.py | 16 + hra/utils/__init__.py | 0 hra/utils/doba.py | 144 ++++++++ hra/utils/hash.py | 22 ++ hra/utils/zadost.py | 49 +++ hra/views.py | 143 ++++++++ manage.py | 22 ++ 50 files changed, 2197 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .requirements create mode 100644 README.md create mode 100644 autentizace/__init__.py create mode 100644 autentizace/templates/autentizace/login.html create mode 100644 autentizace/templates/autentizace/logout.html create mode 100644 autentizace/urls.py create mode 100644 autentizace/views.py create mode 100644 byrokracie/__init__.py create mode 100644 byrokracie/context_processor.py create mode 100644 byrokracie/settings.py create mode 100644 byrokracie/static/css/base.css create mode 100644 byrokracie/static/images/icon.png create mode 100644 byrokracie/templates/base.html create mode 100644 byrokracie/urls.py create mode 100644 byrokracie/wsgi.py create mode 100644 data/stanoviste.json create mode 100644 data/tymy.json create mode 100644 data/users.json create mode 100644 fix_json.py create mode 100644 hra/__init__.py create mode 100644 hra/admin.py create mode 100644 hra/logika.py create mode 100644 hra/migrations/0001_initial.py create mode 100644 hra/migrations/0002_tym_ma_ds_tym_pocet_bananu.py create mode 100644 hra/migrations/0003_tym_vi_o_mesici_tym_vi_o_zadosti.py create mode 100644 hra/migrations/0004_zadost.py create mode 100644 hra/migrations/0005_tym_vi_o_mase.py create mode 100644 hra/migrations/0006_tym_ovesna_kase.py create mode 100644 hra/migrations/__init__.py create mode 100644 hra/models.py create mode 100644 hra/templates/hra/inventar.html create mode 100644 hra/templates/hra/stanoviste/archiv.html create mode 100644 hra/templates/hra/stanoviste/base.html create mode 100644 hra/templates/hra/stanoviste/casovy_vyr.html create mode 100644 hra/templates/hra/stanoviste/domov.html create mode 100644 hra/templates/hra/stanoviste/menza.html create mode 100644 hra/templates/hra/stanoviste/posta.html create mode 100644 hra/templates/hra/stanoviste/studijni.html create mode 100644 hra/templates/hra/staticke_stanoviste.html create mode 100644 hra/templates/hra/timeout.html create mode 100644 hra/templates/hra/tym.html create mode 100644 hra/urls.py create mode 100644 hra/utils/__init__.py create mode 100644 hra/utils/doba.py create mode 100644 hra/utils/hash.py create mode 100644 hra/utils/zadost.py create mode 100644 hra/views.py create mode 100644 manage.py diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..228b148 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,29 @@ +# Z kódu webu M&M +# Univerzální popis našich konvencí pro nastavení editorů. +# Vizte https://editorconfig.org pro detaily + +root = true + +[*] +charset = utf-8 +# Unixové řádky +end_of_line = lf +insert_final_newline = true + +[*.{py,css}] +indent_style = tab +# Nenařizujeme konkrétní šířku tabulátoru +indent_size = unset + +# Automaticky generované migrace dodržují PEP-8, nemá smysl s tím moc bojovat. +[*/migrations/*.py] +indent_style = space +indent_size = 4 + +[*.html] +indent_style = space +indent_size = 2 + +[*.json] +indent_style = tab +indent_size = unset diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..04c1055 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Inspirováno MaMwebem +# virtual environment +/venv/ +/env/ + +# databáze +/*.sqlite3 + +# složky djanga +/static +/media + +# aux files +*.pyc +*.sw[mnop] + +# vim tmp files +*~ + +# pro lidi, co programují v nástrojích od JetBrains +.idea diff --git a/.requirements b/.requirements new file mode 100644 index 0000000..8837bc3 --- /dev/null +++ b/.requirements @@ -0,0 +1,2 @@ +django +qrcode diff --git a/README.md b/README.md new file mode 100644 index 0000000..4d32319 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# Byrokracie +Hra byrokracie v elektrizované verzi + +***Aktuálně je kód velmi fujky!!!*** + + +## Jak hrát +Při prvním spuštění + +- `./manage.py migrate` +- `./manage.py loaddata data/users.json` +- `./manage.py loaddata data/stanoviste.json` +- `./manage.py loaddata data/tymy.json` + +Rozběhnutí hry (hesla a uživatelská jména viz 'Hesla' níže, lze je upravit v adminu) +- `./manage.py runserver` +- v adminu (<127.0.0.1:8000/admin/>) přidat týmy / resetovat jejich start na aktuální datum a čas (nebojte, inventář se tam nezobrazuje) +- následně + - (pokud je `DEBUG = True`), pak stanoviště jsou na + - , + - , + - , + - , + - , + - + - jinak se musí na každém zařízení přihlásit (na ) jako stanoviště (viz 'Hesla' níže) +- tým po přihlášení (na ) vidí svoji domovskou stránku a po načtení qr kódu stanoviště příslušné stanoviště + +Skvělou zábavu :) + + +## Vyšetřování ztráty třídní knihy specific věci +***Neprocházet tyto části kódu, pokud chcete hru testovat!!!*** +- `data/stanoviste.json` (aktuálně pouze názvy stanovišť a viditelný popis stanovišť + název templatu) +- `hra/templates/hra/stanoviste/*` (kromě `**/base`, logika za zobrazováním textů) +- `hra/logika.py` (logika za tlačítky, tedy kdy mají být která tlačítka a jak se má změnit inventář po kliknutí na ně) +- `hra/templates/hra/inventar.html` (itemy, které může tým vlastnit) +- `hra/models.py` (od komentáře `# Inventář`, databázový záznam inventáře) +- `hra/migrations/*` (vyplývá z předchozího) + + +## Hesla +(uzivatelske_jmeno: heslo) +- `admin`: `modraplaneta` +- stanoviste + - `s1, s2, ..., sn`: `asd` +- tymy: + - `t1`: `azurova` + - `t2`: `okrova` + - `t3`: `tyrkysova` + - `t4`: `kastanova` + - `t5`: `oriskova` + - `t6`: `zulova` + - `t7`: `matova` + - `t8`: `smaragdova` + - `t9`: `cihlova` diff --git a/autentizace/__init__.py b/autentizace/__init__.py new file mode 100644 index 0000000..133e988 --- /dev/null +++ b/autentizace/__init__.py @@ -0,0 +1 @@ +# Inspirováno kódem webu M&M diff --git a/autentizace/templates/autentizace/login.html b/autentizace/templates/autentizace/login.html new file mode 100644 index 0000000..cf550a2 --- /dev/null +++ b/autentizace/templates/autentizace/login.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% load static %} + +{% block content %} +

{{ settings.NAZEV }}

+

{% block nadpis %}Přihlášení{% endblock %}

+ + {# Obšlehnuto z Admina :-) #} + {% if user.is_authenticated %} {# Tedy když byl uživatel na stránku přesměrován z pro něj nepřístupné části webu. FIXME? Nedává smysl, pokud uživatel otevřel mam.mff.cuni.cz/prihlasit například z historie prohlížeče = nebyl na ni přesměrován. #} +

K této stránce nejspíš nemáte přístup. Můžete se zkusit přihlásit jako uživatel, který přístup má.

+ {% endif %} + +
+ {% csrf_token %} + + {{ form.as_table }} +
+
+ {# Django si posílá jméno další stránky jako obsah formuláře a výchozí hodnota (mi přišlo, že) nejde změnit... #} + + +
+ + {#

#} + {#
#} + {# #} + {#
#} +{% endblock %} diff --git a/autentizace/templates/autentizace/logout.html b/autentizace/templates/autentizace/logout.html new file mode 100644 index 0000000..a1b76c0 --- /dev/null +++ b/autentizace/templates/autentizace/logout.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% load static %} + +{% block content %} +

{% block nadpis %}Odhlášení{% endblock %}

+

Byl jsi úspěšně odhlášen

+{% endblock %} + diff --git a/autentizace/urls.py b/autentizace/urls.py new file mode 100644 index 0000000..d5dce89 --- /dev/null +++ b/autentizace/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from . import views +from django.views.generic.base import RedirectView + +urlpatterns = [ + path("prihlasit/", views.LoginView.as_view(), name="login"), + path("login/", RedirectView.as_view(pattern_name="login", permanent=True, query_string=True)), + path("odhlasit/", views.LogoutView.as_view(), name="logout"), + path("logout/", RedirectView.as_view(pattern_name="logout", permanent=True, query_string=True)), +] diff --git a/autentizace/views.py b/autentizace/views.py new file mode 100644 index 0000000..34eef7e --- /dev/null +++ b/autentizace/views.py @@ -0,0 +1,14 @@ +from django.urls import reverse_lazy +from django.contrib.auth import views as auth_views + + +class LoginView(auth_views.LoginView): + # Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL + template_name = "autentizace/login.html" + + +class LogoutView(auth_views.LogoutView): + # Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL + template_name = "autentizace/logout.html" + # Pavel: Vůbec nevím, proč to s _lazy funguje, ale bez toho to bylo rozbité. + next_page = reverse_lazy("login") diff --git a/byrokracie/__init__.py b/byrokracie/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/byrokracie/context_processor.py b/byrokracie/context_processor.py new file mode 100644 index 0000000..26251f1 --- /dev/null +++ b/byrokracie/context_processor.py @@ -0,0 +1,6 @@ +from django.conf import settings + + +def add_settings(_): + """ Přidá `settings` do templatů. """ + return {"settings": settings} diff --git a/byrokracie/settings.py b/byrokracie/settings.py new file mode 100644 index 0000000..603b6c2 --- /dev/null +++ b/byrokracie/settings.py @@ -0,0 +1,99 @@ +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / "subdir". +BASE_DIR = Path(__file__).resolve().parent.parent + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-opcz6rfrp-osm7wnd@3_5yb56^4=!@7@-(38j^!6^ej%88r2ud" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +# ALLOWED_HOSTS = ['192.168.137.1' ] + +WSGI_APPLICATION = 'byrokracie.wsgi.application' + +STATIC_ROOT = 'static/' +STATIC_URL = 'static/' + +# Jednotlivé části djanga +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "byrokracie", + "autentizace", + "hra", +] +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'byrokracie.context_processor.add_settings' + ], + }, + }, +] + + +# Databáze +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Lokalizace +LANGUAGE_CODE = 'cs' +TIME_ZONE = 'Europe/Prague' +USE_L10N = True # S přechodem k djangu>=4 lze smazat (localized formatting) +USE_TZ = True # S přechodem k djangu>=5 lze smazat (timezone aware datetimes) + +# URL pro přihlášení (default je account/login) +LOGIN_URL = 'login' +LOGIN_REDIRECT_URL = '/hra/' + +# Konstantny +NAZEV: str = "Vyšetřování ztráty třídní knihy" +NEJVYSSI_INDEX: int = 6 +PRVNI_PONDELI: int = 2 +PRVNI_NOV: int = 13 +TIMEOUT_STANOVISTE: int = 60 # v sekundách +TYM_AUTO_RELOAD: int = 30 # v sekundách +TIME_SPEED: float = 1.0 # 1 = hodina za minutu +DEN: tuple[float, float] = (8.0, 18.0) +POCET_BANANU: int = 2 + +POSTOVNA_DEN_V_TYDNU = 3 + +STASTNA_CISLA: set[int] = {1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 100, 103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 219, 226, 230, 236, 239, 262, 263, 280, 291, 293, 301, 302, 310, 313, 319, 320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376, 379, 383, 386, 391, 392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496, 536, 556, 563, 565, 566, 608, 617, 622, 623, 632, 635, 637, 638, 644, 649, 653, 655, 656, 665, 671, 673, 680, 683, 694, 700, 709, 716, 736, 739, 748, 761, 763, 784, 790, 793, 802, 806, 818, 820, 833, 836, 847, 860, 863, 874, 881, 888, 899, 901, 904, 907, 910, 912, 913, 921, 923, 931, 932, 937, 940, 946, 964, 970, 973, 989, 998, 1000} +# nejasno = [1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0] +# [nejasno[i] * (random.choice(list(range(3))) + 1) for i in range(len(nejasno))] +POCASI: list[int] = [3, 1, 3, 2, 2, 2, 0, 3, 2, 1, 0, 2, 1, 0, 3, 2, 3, 0, 2, 3, 3, 1, 2, 0] + + +# Django musí mít nastaveno Autofield +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +# A musí mít nastavené počáteční urls +ROOT_URLCONF = 'byrokracie.urls' diff --git a/byrokracie/static/css/base.css b/byrokracie/static/css/base.css new file mode 100644 index 0000000..69d0e6f --- /dev/null +++ b/byrokracie/static/css/base.css @@ -0,0 +1,39 @@ +table { + margin-left: auto; + margin-right: auto; +} + +th { + text-align: right; +} + +.content { + text-align: center; +} + +.ds { /* Zobrazení datové schránky na stránce týmu */ + margin-top: -1em; +} + +.inventar { + width: fit-content; + margin-left: auto; + margin-right: auto; +} + +.polozka_inventare { + float: left; + min-width: 10vw; + min-height: 15vw; + border: orange 1pt solid; + + margin: 1vh; + + display: flex; + align-items: center; + justify-content: center; +} + +li { + text-align: left; +} diff --git a/byrokracie/static/images/icon.png b/byrokracie/static/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..42ff7dd5f6a7e4931117926e4a124c02c328eb9b GIT binary patch literal 86025 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 literal 0 HcmV?d00001 diff --git a/byrokracie/templates/base.html b/byrokracie/templates/base.html new file mode 100644 index 0000000..b89d1c4 --- /dev/null +++ b/byrokracie/templates/base.html @@ -0,0 +1,26 @@ +{% load static %} + + + + {% block nadpis %}{% endblock %} + + + + + + {# (Autoreload:) = Refresh every 30 second #} + {% block prenacitani %}{% endblock %} + + {# script specifický pro stránku #} + {% block script %}{% endblock %} + + + +
+ {% block content %} + {% endblock content %} +
+ + + + diff --git a/byrokracie/urls.py b/byrokracie/urls.py new file mode 100644 index 0000000..344c093 --- /dev/null +++ b/byrokracie/urls.py @@ -0,0 +1,10 @@ +from django.contrib import admin +from django.shortcuts import redirect +from django.urls import path, include + +urlpatterns = [ + path('admin/', admin.site.urls), + path('', include('autentizace.urls')), + path('hra/', include('hra.urls')), + path('', lambda _request: redirect('hra/', permanent=True)), +] diff --git a/byrokracie/wsgi.py b/byrokracie/wsgi.py new file mode 100644 index 0000000..5a9d72b --- /dev/null +++ b/byrokracie/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for byrokracie project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'byrokracie.settings') + +application = get_wsgi_application() diff --git a/data/stanoviste.json b/data/stanoviste.json new file mode 100644 index 0000000..3953af5 --- /dev/null +++ b/data/stanoviste.json @@ -0,0 +1,68 @@ +[ + { + "fields": { + "nazev": "Časový výr 🦉", + "poradi": 1, + "user": 2, + "verejny_text": "

Posun ve čtvrté dimenzi.

", + "template": "casovy_vyr.html" + }, + "model": "hra.stanoviste", + "pk": 1 + }, + { + "fields": { + "nazev": "Internát", + "poradi": 2, + "user": 3, + "verejny_text": "

Domov, sladký domov.

", + "template": "domov.html" + }, + "model": "hra.stanoviste", + "pk": 2 + }, + { + "fields": { + "nazev": "Potrubní pošta akademie ✉️🪠", + "poradi": 3, + "user": 4, + "verejny_text": "

Podobnost s Českou poštou je čistě náhodná.

Otevřeno: nonstop

", + "template": "posta.html" + }, + "model": "hra.stanoviste", + "pk": 3 + }, + { + "fields": { + "nazev": "Studijní oddělení", + "poradi": 4, + "user": 5, + "verejny_text": "

Žádosti všeho druhu.

Otevřeno: Po–Čt: 8:00 – 16:00, Pá: 8:00 – 14:00

", + "template": "studijni.html" + }, + "model": "hra.stanoviste", + "pk": 4 + }, + { + "fields": { + "nazev": "Jídelna", + "poradi": 5, + "user": 6, + "verejny_text": "

\uD83E\uDD6C\uD83E\uDD57\uD83C\uDF55\uD83E\uDD53\uD83C\uDF69\uD83C\uDF68\uD83C\uDF6A\uD83C\uDF82\uD83C\uDF4C\uD83C\uDF70\uD83C\uDF6B\uD83C\uDF67\uD83C\uDF66\uD83C\uDF61\uD83C\uDF60\uD83E\uDED1

Vaříme denně

Snídaně: 8:00 – 11:00

Obědy: 11:00 – 17:00

Večeře: 17:00 – 22:00

", + "template": "menza.html" + }, + "model": "hra.stanoviste", + "pk": 5 + }, + { + "fields": { + "nazev": "Knihovna & Archiv", + "poradi": 6, + "user": 7, + "verejny_text": "

Otevřeno: Po–Čt: 8:00 – 16:00, Pá: 8:00 – 14:00

Ook!?

", + "template": "archiv.html" + }, + "model": "hra.stanoviste", + "pk": 6 + } +] diff --git a/data/tymy.json b/data/tymy.json new file mode 100644 index 0000000..af00729 --- /dev/null +++ b/data/tymy.json @@ -0,0 +1,83 @@ +[ + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 8 + }, + "model": "hra.tym", + "pk": 1 + }, + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 9 + }, + "model": "hra.tym", + "pk": 2 + }, + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 10 + }, + "model": "hra.tym", + "pk": 3 + }, + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 11 + }, + "model": "hra.tym", + "pk": 4 + }, + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 12 + }, + "model": "hra.tym", + "pk": 5 + }, + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 13 + }, + "model": "hra.tym", + "pk": 6 + }, + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 14 + }, + "model": "hra.tym", + "pk": 7 + }, + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 15 + }, + "model": "hra.tym", + "pk": 8 + }, + { + "fields": { + "hraci": "", + "nazev": "Nepojmenovaní", + "user": 16 + }, + "model": "hra.tym", + "pk": 9 + } +] diff --git a/data/users.json b/data/users.json new file mode 100644 index 0000000..06f2d1c --- /dev/null +++ b/data/users.json @@ -0,0 +1,178 @@ +[ + { + "fields": { + "is_active": true, + "is_staff": true, + "is_superuser": true, + "password": "pbkdf2_sha256$600000$yylg8H03nCOuMEmo7X4V6A$Za9qMeX44zvjYtIwyAlw5QLJQCEy+vDxlXDRAZqhZ2c=", + "username": "admin" + }, + "model": "auth.user", + "pk": 1 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$BdSaaScmKfh6Qu9xoEqp3f$96RlyOuK8lHlD5hVpfDEYJVmSxaby3O8wIT0/1MQM1k=", + "username": "s1" + }, + "model": "auth.user", + "pk": 2 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$BdSaaScmKfh6Qu9xoEqp3f$96RlyOuK8lHlD5hVpfDEYJVmSxaby3O8wIT0/1MQM1k=", + "username": "s2" + }, + "model": "auth.user", + "pk": 3 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$BdSaaScmKfh6Qu9xoEqp3f$96RlyOuK8lHlD5hVpfDEYJVmSxaby3O8wIT0/1MQM1k=", + "username": "s3" + }, + "model": "auth.user", + "pk": 4 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$BdSaaScmKfh6Qu9xoEqp3f$96RlyOuK8lHlD5hVpfDEYJVmSxaby3O8wIT0/1MQM1k=", + "username": "s4" + }, + "model": "auth.user", + "pk": 5 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$BdSaaScmKfh6Qu9xoEqp3f$96RlyOuK8lHlD5hVpfDEYJVmSxaby3O8wIT0/1MQM1k=", + "username": "s5" + }, + "model": "auth.user", + "pk": 6 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$BdSaaScmKfh6Qu9xoEqp3f$96RlyOuK8lHlD5hVpfDEYJVmSxaby3O8wIT0/1MQM1k=", + "username": "s6" + }, + "model": "auth.user", + "pk": 7 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$y2SzlaUhvzQx5MAaAPg8eR$x99VQuFAPQymfie3rNJQPIXJlmJZZ7GaX2Q8CoS+HLo=", + "username": "t1" + }, + "model": "auth.user", + "pk": 8 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$Dzb2XnXVY2FClbyYXXOD8V$MhI+tOVRXZBfY8OPaaWG1WMk0vMrIDpZguMp/X0udv8=", + "username": "t2" + }, + "model": "auth.user", + "pk": 9 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$uePowUck1EhZwiWMK3TJ2c$zGAiYICEZ46pSxtO8MF/cAawcT+UnazBcWjAiYFbTFk=", + "username": "t3" + }, + "model": "auth.user", + "pk": 10 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$UiEFSvRON6lWpzpp3eqlsS$CKvQO8L2Aelucmjp1Aoz5qTe8T18jMWGE4qH72Cihpw=", + "username": "t4" + }, + "model": "auth.user", + "pk": 11 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$L01lowUNtthy22eTVLaUrz$dp0SKguUiN5wM7gHhpW6WDhGofdIHdRj3aOQfrlih2o=", + "username": "t5" + }, + "model": "auth.user", + "pk": 12 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$sOCpNhTjfrLwoA9p1KlxAf$GA6njrzD0qj6Sxa/6wWVm83CdDhZw4gjg5SMKYPtKPo=", + "username": "t6" + }, + "model": "auth.user", + "pk": 13 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$cUKVLoph1a4lo8vWsexHV0$9bhzUjWezsPhZFmNG7gjg4WCR2Yrou68yDG+4joUXF0=", + "username": "t7" + }, + "model": "auth.user", + "pk": 14 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$zoKRalZSKeVYAe9yKq0Jk2$1sS7fJsiUUweoFL8nb7WLv0ZIEpnkpSjYLL2HLev/Gg=", + "username": "t8" + }, + "model": "auth.user", + "pk": 15 + }, + { + "fields": { + "is_active": true, + "is_staff": false, + "is_superuser": false, + "password": "pbkdf2_sha256$600000$N27QVcoRhkcto7JA3ygQtG$1QSCWn8Lyk+UiJyJDYr3WWYbcPP8YqGxQj4JoeyAxoc=", + "username": "t9" + }, + "model": "auth.user", + "pk": 16 + } +] diff --git a/fix_json.py b/fix_json.py new file mode 100644 index 0000000..411349f --- /dev/null +++ b/fix_json.py @@ -0,0 +1,12 @@ +#!/usr/bin/python3 + +import json +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument("input", type=argparse.FileType('r', encoding='utf-8')) +parser.add_argument('output', type=argparse.FileType('w', encoding='utf-8')) +args = parser.parse_args() + +data = json.load(args.input) +json.dump(data, args.output, ensure_ascii=False, sort_keys=True, indent='\t') diff --git a/hra/__init__.py b/hra/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hra/admin.py b/hra/admin.py new file mode 100644 index 0000000..8ad7851 --- /dev/null +++ b/hra/admin.py @@ -0,0 +1,14 @@ +from django.contrib import admin + +from .models import Stanoviste, Tym, Zadost + +admin.site.register(Stanoviste) +admin.site.register(Zadost) + + +class TymAdmin(admin.ModelAdmin): + # fields = ["user", "nazev", "hraci", "start"] + pass + + +admin.site.register(Tym, TymAdmin) diff --git a/hra/logika.py b/hra/logika.py new file mode 100644 index 0000000..b365e63 --- /dev/null +++ b/hra/logika.py @@ -0,0 +1,260 @@ +from random import random +from typing import Callable, Iterable + +from django.conf import settings + +from .models import Tym, Zadost +from .utils.doba import Doba + +# Velká část logiky je přímo na `.models.Tym`! + + +def zadosti(tym: Tym, akce: str, choices: list, zadost: str = "Žádost", suffix: str = ""): + choices.append(f"{akce} {zadost}{suffix}") + + if tym.zadosti.filter(typ=Zadost.TYP_BANAN, vyzvednuta=True).count() == 0: + choices.append(f"{akce} {zadost} o banán{suffix}") + + if tym.vi_o_mase and tym.zadosti.filter(typ=Zadost.TYP_VEGE, vyzvednuta=True).count() == 0: + choices.append(f"{akce} {zadost} o více vegetariánskou stravu v jídelně{suffix}") + + if tym.vi_o_zadosti and tym.zadosti.filter(typ=Zadost.TYP_TK, vyzvednuta=True, plati=True).count() == 0: + choices.append(f"{akce} {zadost} o přístup k záznamům o třídní knize{suffix}") + + +def get_posible_choices_casovy_vyr(doba: Doba, tym: Tym) -> list[str]: + choices = ["Dopředu o hodinu", "Dopředu o 3 hodiny"] + + if doba > 3*doba.DEN: + choices.append("Dopředu o den") + + if doba > doba.TYDEN: + choices.append("Dopředu o týden") + + if tym.tk_nalezena is not None: + choices += ["Dozadu o hodinu", "Dozadu o 3 hodiny", "Dozadu o den", "Dozadu o týden"] + + return choices + + +def get_posible_choices_domov(doba: Doba, tym: Tym) -> list[str]: + choices = [] + + if tym.nevyzvednute_zadosti.count() > 0: + choices.append("Vyzvednout poštu") + + if doba.je_noc: + choices.append("Spát") + + if not tym.ma_penize: + choices.append("Vzít si chechtáky") + + zadosti(tym, "Tisk", choices, zadost="Žádosti") + + if tym.ma_ds: + zadosti(tym, "Podat", choices, suffix=" datovou schránkou") + + return choices + + +def get_posible_choices_posta(doba: Doba, tym: Tym) -> list[str]: + if tym.ds_bad is not None and doba - tym.ds_bad < 5: + return [] + + choices = [] + + if tym.zadosti.filter(vytistena=True).count() > 0: + choices.append("Poslat vytištěné žádosti") + + if tym.nevyzvednute_zadosti.count() > 0: + choices.append("Zeptat se, zda pro nás mají dopis") + + if not tym.ma_ds: + choices.append("Zažádat o datovou schránku") + + if tym.ds_bad is not None: + choices.append("Zažádat o datovou schránku (šeptem)") + + return choices + + +def get_posible_choices_studijni(doba: Doba, tym: Tym) -> list[str]: + if ( + doba.cas < 8 or + doba.cas > 15 or + doba.den_v_tydnu >= 6 or + (doba.den_v_tydnu == 5 and doba.cas > 13) + ): + return [] + + choices = [] + + zadosti(tym, "Podat", choices) + + if tym.nevyzvednute_zadosti.count(): + choices.append("Zeptat se na poslané žádosti") + + return choices + + +def get_posible_choices_jidelna(doba: Doba, tym: Tym) -> list[str]: + if doba.cas < 8 or doba.cas > 22: + return [] + + choices = ["Klábosit"] + + if tym.pocet_bananu < settings.POCET_BANANU: + choices.append("Poprosit o banán") + + return choices + + +def get_posible_choices_archiv(doba: Doba, tym: Tym) -> list[str]: + choices = [] + + if not ( + doba.cas < 8 or + doba.cas > 16 or + doba.den_v_tydnu >= 6 or + (doba.den_v_tydnu == 5 and doba.cas > 14) + ): + if tym.ma_penize: + choices.append("Uplatit knihovníka penězi") + + if tym.pocet_bananu > 0 and not tym.vi_o_zadosti: + choices.append("Dát banán knihovníkovi") + + if tym.ma_platnou_zadost(Zadost.TYP_TK) and tym.tk_nalezena is None: + choices.append("Ukázat knihovníkovi povolení k náhledu do záznamů o třídní knize") + + choices.append("Přelézt pult a sami si vzít záznamy o třídní knize") + choices.append("Pokusit se sami projít kartotéku") + + return choices + + +def banan(_: Doba, tym: Tym) -> None: + if (tym.pocet_bananu == 0 and tym.ma_platnou_zadost(Zadost.TYP_BANAN)) or tym.ma_platnou_zadost(Zadost.TYP_VEGE): + tym.pocet_bananu += 1 + tym.save() + if tym.pocet_bananu == 1: + print("ALERT: BANÁN!!!") + elif tym.pocet_bananu == 1: + tym.vi_o_mase = True + tym.save() + elif tym.pocet_bananu == 0: + tym.ovesna_kase += 1 + tym.save() + + +get_posible_choices: list[Callable[[Doba, Tym], list[str]]] = [ + # 0: + None, # poradi začíná od 1 + # 1: + get_posible_choices_casovy_vyr, + # 2: + get_posible_choices_domov, + # 3: + get_posible_choices_posta, + # 4: + get_posible_choices_studijni, + # 5: + get_posible_choices_jidelna, + # 6: + get_posible_choices_archiv, +] + + +apply_choice: list[dict[str, Callable[[Doba, Tym], Iterable[Zadost] | None]]] = [ + # 0: + {}, # poradi začíná od 1 + # 1: + { + "Dopředu o hodinu": + lambda _, tym: tym.pricti_cas_a_uloz(1), + "Dopředu o 3 hodiny": + lambda _, tym: tym.pricti_cas_a_uloz(3), + "Dopředu o den": + lambda _, tym: tym.pricti_cas_a_uloz(Doba.DEN), + "Dopředu o týden": + lambda _, tym: tym.pricti_cas_a_uloz(Doba.TYDEN), + "Dozadu o hodinu": + lambda _, tym: tym.pricti_cas_a_uloz(-1), + "Dozadu o 3 hodiny": + lambda _, tym: tym.pricti_cas_a_uloz(-3), + "Dozadu o den": + lambda _, tym: tym.pricti_cas_a_uloz(-Doba.DEN), + "Dozadu o týden": + lambda _, tym: tym.pricti_cas_a_uloz(-Doba.TYDEN), + }, + # 2: + { + "Vyzvednout poštu": + lambda doba, tym: tym.vyzvedni_internat(doba), + "Spát": + lambda doba, tym: tym.pricti_cas_a_uloz((settings.DEN[0] - doba.cas + 24) % 24), + "Vzít si chechtáky": + lambda _, tym: tym.nastav_a_uloz("ma_penize", True), + "Tisk Žádosti": + lambda _, tym: tym.vytiskni_zadost(Zadost.TYP_ZADOST), + "Tisk Žádosti o banán": + lambda _, tym: tym.vytiskni_zadost(Zadost.TYP_BANAN), + "Tisk Žádosti o více vegetariánskou stravu v jídelně": + lambda _, tym: tym.vytiskni_zadost(Zadost.TYP_VEGE), + "Tisk Žádosti o přístup k záznamům o třídní knize": + lambda _, tym: tym.vytiskni_zadost(Zadost.TYP_TK), + "Podat Žádost datovou schránkou": + lambda doba, tym: tym.posli_zadost_ds(doba, Zadost.TYP_ZADOST), + "Podat Žádost o banán datovou schránkou": + lambda doba, tym: tym.posli_zadost_ds(doba, Zadost.TYP_BANAN), + "Podat Žádost o více vegetariánskou stravu v jídelně datovou schránkou": + lambda doba, tym: tym.posli_zadost_ds(doba, Zadost.TYP_VEGE), + "Podat Žádost o přístup k záznamům o třídní knize datovou schránkou": + lambda doba, tym: tym.posli_zadost_ds(doba, Zadost.TYP_TK), + }, + # 3: + { + "Poslat vytištěné žádosti": + lambda doba, tym: tym.poslat_vytistene_zadosti(doba), + "Zeptat se, zda pro nás mají dopis": + lambda doba, tym: tym.vyzvedni_postu(doba), + "Zažádat o datovou schránku": + lambda doba, tym: tym.nastav_a_uloz("ds_bad", doba), + "Zažádat o datovou schránku (šeptem)": + lambda doba, tym: tym.nastav_a_uloz("ma_ds", True), + + }, + # 4: + { + "Podat Žádost": + lambda doba, tym: tym.posli_zadost_studijni(doba, Zadost.TYP_ZADOST), + "Podat Žádost o banán": + lambda doba, tym: tym.posli_zadost_studijni(doba, Zadost.TYP_BANAN), + "Podat Žádost o více vegetariánskou stravu v jídelně": + lambda doba, tym: tym.posli_zadost_studijni(doba, Zadost.TYP_VEGE), + "Podat Žádost o přístup k záznamům o třídní knize": + lambda doba, tym: tym.posli_zadost_studijni(doba, Zadost.TYP_TK), + "Zeptat se na poslané žádosti": + lambda doba, tym: tym.nevyzvednute_zadosti.filter(studijni__lte=doba) + }, + # 5: + { + "Klábosit": + lambda *_: None, # NOOP + "Poprosit o banán": + banan, + }, + # 6: + { + "Uplatit knihovníka penězi": + lambda *_: None, # NOOP + "Dát banán knihovníkovi": + lambda _, tym: tym.nastav_a_uloz("vi_o_zadosti", tym.pocet_bananu == settings.POCET_BANANU), + "Ukázat knihovníkovi povolení k náhledu do záznamů o třídní knize": + lambda doba, tym: tym.nastav_a_uloz("tk_nalezena", doba), + "Přelézt pult a sami si vzít záznamy o třídní knize": + lambda _, tym: tym.pricti_cas_a_uloz(random()*5), + "Pokusit se sami projít kartotéku": + lambda _, tym: tym.pricti_cas_a_uloz(5), + }, +] diff --git a/hra/migrations/0001_initial.py b/hra/migrations/0001_initial.py new file mode 100644 index 0000000..cc6b69b --- /dev/null +++ b/hra/migrations/0001_initial.py @@ -0,0 +1,53 @@ +# Generated by Django 4.2.4 on 2023-08-14 17:51 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Tym', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nazev', models.CharField(max_length=256, verbose_name='název týmu')), + ('hraci', models.CharField(blank=True, help_text='seznam hráčů v týmu', max_length=256, null=True, verbose_name='hráči')), + ('start', models.DateTimeField(default=django.utils.timezone.now, help_text='čas, kdy tým začal', verbose_name='začátek hry')), + ('delta', models.FloatField(default=0, help_text='čas (v hodinách), o který se tým posunul svými akcemi', verbose_name='přidaný čas')), + ('tk_nalezena', models.FloatField(blank=True, default=None, help_text='čas (v hodinách), kdy tým nalezl třídní knihu (pro pořadí a rozhodnutí, zda ji tým už nalezl)', null=True, verbose_name='čas nalezení třídní knihy')), + ('ma_penize', models.BooleanField(default=False, help_text='zda si tým vzal peníze a neztratil je', verbose_name='má tým peníze')), + ('ds_bad', models.FloatField(blank=True, default=None, help_text='čas, kdy tým špatným způsobem požádal o datovou schránku', null=True, verbose_name='čas chybného založení ds')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='uživatel')), + ], + options={ + 'verbose_name': 'Tým', + 'verbose_name_plural': 'Týmy', + 'db_table': 'hra_tym', + }, + ), + migrations.CreateModel( + name='Stanoviste', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nazev', models.CharField(help_text='zobrazovaný název stanoviště', max_length=256, verbose_name='název')), + ('verejny_text', models.TextField(help_text='zobrazovaný název stanoviště', max_length=256, verbose_name='veřejný text')), + ('poradi', models.IntegerField(help_text='číselné označení stanoviště (aby hráči věděli, že našli všechny)', verbose_name='pořadí')), + ('template', models.CharField(default='base.html', help_text='template tohoto stanoviště (co vidí tým)', max_length=256, verbose_name='template')), + ('user', models.OneToOneField(help_text='Stanoviště musí být přihlášena, aby se nedala přepínat stanoviště', on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='uživatel')), + ], + options={ + 'verbose_name': 'Stanoviště', + 'verbose_name_plural': 'Stanoviště', + 'db_table': 'hra_stanoviste', + }, + ), + ] diff --git a/hra/migrations/0002_tym_ma_ds_tym_pocet_bananu.py b/hra/migrations/0002_tym_ma_ds_tym_pocet_bananu.py new file mode 100644 index 0000000..ede7d01 --- /dev/null +++ b/hra/migrations/0002_tym_ma_ds_tym_pocet_bananu.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.4 on 2023-08-14 18:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hra', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='tym', + name='ma_ds', + field=models.BooleanField(default=False, help_text='zda si tým založil datovou schránku', verbose_name='má tým ds'), + ), + migrations.AddField( + model_name='tym', + name='pocet_bananu', + field=models.IntegerField(default=0, help_text='kolik vlastní tým bánánů', verbose_name='počet banánů'), + ), + ] diff --git a/hra/migrations/0003_tym_vi_o_mesici_tym_vi_o_zadosti.py b/hra/migrations/0003_tym_vi_o_mesici_tym_vi_o_zadosti.py new file mode 100644 index 0000000..2ae072b --- /dev/null +++ b/hra/migrations/0003_tym_vi_o_mesici_tym_vi_o_zadosti.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.4 on 2023-08-14 19:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hra', '0002_tym_ma_ds_tym_pocet_bananu'), + ] + + operations = [ + migrations.AddField( + model_name='tym', + name='vi_o_mesici', + field=models.BooleanField(default=False, help_text='ví tým o tom, že žádost o náhled do archivů se může podávat pouze za svitu měsíce', verbose_name='ví tým o svitu měsíce'), + ), + migrations.AddField( + model_name='tym', + name='vi_o_zadosti', + field=models.BooleanField(default=False, help_text='ví tým o tom, že potřebuje žádost o náhled do archivů', verbose_name='ví tým o finální žádosti'), + ), + ] diff --git a/hra/migrations/0004_zadost.py b/hra/migrations/0004_zadost.py new file mode 100644 index 0000000..75b953f --- /dev/null +++ b/hra/migrations/0004_zadost.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.4 on 2023-10-05 10:15 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('hra', '0003_tym_vi_o_mesici_tym_vi_o_zadosti'), + ] + + operations = [ + migrations.CreateModel( + name='Zadost', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('typ', models.CharField(choices=[('zadost', 'Žádost'), ('banan', 'Žádost o banán'), ('vege', 'Žádost o více vegetariánskou stravu v jídelně'), ('tk', 'Žádost o přístup k záznamům o třídní knize')], max_length=8, verbose_name='toto je ')), + ('studijni', models.FloatField(blank=True, default=None, null=True, verbose_name='žádost dorazí na studijní')), + ('posta', models.FloatField(blank=True, default=None, help_text='(do self.internat)', null=True, verbose_name='tým si může žádost vyzvednout na internátu od')), + ('internat', models.FloatField(blank=True, default=None, null=True, verbose_name='tým si může žádost vyzvednout na poště od')), + ('vyzvednuta', models.BooleanField(default=False, verbose_name='tým si tuto žádost již vyzvedl')), + ('vytistena', models.BooleanField(default=False, verbose_name='tým má u sebe tuto žádost vytištěnou')), + ('plati', models.BooleanField(default=True, help_text='Aktuálně má uplatnění pouze u Žádosti o přístup k záznamům o třídní knize', verbose_name='tato žádost platí')), + ('tym', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='zadosti', to='hra.tym')), + ], + options={ + 'verbose_name': 'Žádost', + 'verbose_name_plural': 'Žádosti', + 'db_table': 'hra_zadost', + }, + ), + ] diff --git a/hra/migrations/0005_tym_vi_o_mase.py b/hra/migrations/0005_tym_vi_o_mase.py new file mode 100644 index 0000000..0587d1b --- /dev/null +++ b/hra/migrations/0005_tym_vi_o_mase.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.4 on 2023-10-06 14:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hra', '0004_zadost'), + ] + + operations = [ + migrations.AddField( + model_name='tym', + name='vi_o_mase', + field=models.BooleanField(default=False, help_text='už se ptali v jídelně na další banán a zjistili, že je jen MaSo', verbose_name='ví o tom, že v jídelně už není banán'), + ), + ] diff --git a/hra/migrations/0006_tym_ovesna_kase.py b/hra/migrations/0006_tym_ovesna_kase.py new file mode 100644 index 0000000..18197d7 --- /dev/null +++ b/hra/migrations/0006_tym_ovesna_kase.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.4 on 2023-10-06 20:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hra', '0005_tym_vi_o_mase'), + ] + + operations = [ + migrations.AddField( + model_name='tym', + name='ovesna_kase', + field=models.IntegerField(default=0), + ), + ] diff --git a/hra/migrations/__init__.py b/hra/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hra/models.py b/hra/models.py new file mode 100644 index 0000000..df79374 --- /dev/null +++ b/hra/models.py @@ -0,0 +1,326 @@ +from random import random +from typing import Iterable + +from django.conf import settings +from django.db import models +from django.db.models import QuerySet +from django.utils import timezone + +from .utils.doba import Doba + + +class Stanoviste(models.Model): + class Meta: + db_table = "hra_stanoviste" + verbose_name = "Stanoviště" + verbose_name_plural = "Stanoviště" + + user = models.OneToOneField( + settings.AUTH_USER_MODEL, blank=False, null=False, unique=True, + verbose_name="uživatel", on_delete=models.PROTECT, + help_text="Stanoviště musí být přihlášena, aby se nedala přepínat stanoviště", + ) + + nazev = models.CharField( + "název", max_length=256, blank=False, null=False, + help_text="zobrazovaný název stanoviště", + ) + + verejny_text = models.TextField( + "veřejný text", max_length=256, blank=False, null=False, + help_text="zobrazovaný název stanoviště", + ) + + poradi = models.IntegerField( + "pořadí", blank=False, null=False, + help_text="číselné označení stanoviště (aby hráči věděli, že našli všechny)", + ) + + template = models.CharField( + "template", max_length=256, blank=False, null=False, default="base.html", + help_text="template tohoto stanoviště (co vidí tým)", + ) + + +class Tym(models.Model): + class Meta: + db_table = "hra_tym" + verbose_name = "Tým" + verbose_name_plural = "Týmy" + + user = models.OneToOneField( + settings.AUTH_USER_MODEL, blank=False, null=False, unique=True, + verbose_name="uživatel", on_delete=models.PROTECT, + ) + + nazev = models.CharField( + "název týmu", max_length=256, blank=False, null=False, + ) + + hraci = models.CharField( + "hráči", max_length=256, blank=True, null=True, + help_text="seznam hráčů v týmu", + ) + + start = models.DateTimeField( + "začátek hry", blank=False, null=False, default=timezone.now, + help_text="čas, kdy tým začal", + ) + + delta = models.FloatField( + "přidaný čas", blank=False, null=False, default=0, + help_text="čas (v hodinách), o který se tým posunul svými akcemi", + ) + + def nastav_a_uloz(self, attr_name: str, value: object) -> "Tym": + self.__setattr__(attr_name, value) + self.save() + return self + + @property + def doba(self) -> Doba: + return Doba((timezone.now() - self.start).total_seconds() / 60 * settings.TIME_SPEED + self.delta) + + def pricti_cas_a_uloz(self, cas: int) -> "Tym": + self.delta += cas + self.save() + return self + + # Inventář + tk_nalezena = models.FloatField( + "čas nalezení třídní knihy", blank=True, null=True, default=None, + help_text="čas (v hodinách), kdy tým nalezl třídní knihu (pro pořadí a rozhodnutí, zda ji tým už nalezl)", + ) + + ma_penize = models.BooleanField( + "má tým peníze", blank=False, null=False, default=False, + help_text="zda si tým vzal peníze a neztratil je", + ) + + ds_bad = models.FloatField( + "čas chybného založení ds", blank=True, null=True, default=None, + help_text="čas, kdy tým špatným způsobem požádal o datovou schránku", + ) + + ma_ds = models.BooleanField( + "má tým ds", blank=False, null=False, default=False, + help_text="zda si tým založil datovou schránku", + ) + + pocet_bananu = models.IntegerField( + "počet banánů", blank=False, null=False, default=0, + help_text="kolik vlastní tým bánánů", + ) + + vi_o_zadosti = models.BooleanField( + "ví tým o finální žádosti", blank=False, null=False, default=False, + help_text="ví tým o tom, že potřebuje žádost o náhled do archivů", + ) + + vi_o_mesici = models.BooleanField( + "ví tým o svitu měsíce", blank=False, null=False, default=False, + help_text="ví tým o tom, že žádost o náhled do archivů se může podávat pouze za svitu měsíce", + ) + + vi_o_mase = models.BooleanField( + "ví o tom, že v jídelně už není banán", blank=False, null=False, default=False, + help_text="už se ptali v jídelně na další banán a zjistili, že je jen MaSo", + ) + + @property + def vyzvednute_zadosti(self) -> QuerySet["Zadost"]: + return self.zadosti.filter(vyzvednuta=True) + + @property + def nevyzvednute_zadosti(self) -> QuerySet["Zadost"]: + return self.zadosti.filter(studijni__isnull=False, vyzvednuta=False) + + def ma_platnou_zadost(self, zadost_typ: str) -> bool: + return self.vyzvednute_zadosti.filter(typ=zadost_typ, plati=True).count() > 0 + + @property + def ma_platnou_zadost_o_banan(self) -> bool: + """ Protože django templates jsou hloupé """ + return self.vyzvednute_zadosti.filter(typ=Zadost.TYP_BANAN, plati=True).count() > 0 + + @property + def ma_platnou_zadost_o_vege(self) -> bool: + """ Protože django templates jsou hloupé """ + return self.vyzvednute_zadosti.filter(typ=Zadost.TYP_VEGE, plati=True).count() > 0 + + def zadosti_na_internatu(self, doba: Doba) -> QuerySet["Zadost"]: + return self.zadosti.filter(vyzvednuta=False, internat__isnull=False, internat__lte=doba) + + def zadosti_na_poste(self, doba: Doba) -> QuerySet["Zadost"]: + return self.zadosti.filter(posta__isnull=False, posta__lte=doba, internat__isnull=False, internat__gt=doba) + + @staticmethod + def studijni_otevreno_nejdrive(doba: Doba) -> Doba: + if not ( # copy-paste z logika.py + doba.cas < 8 or + doba.cas > 15 or + doba.den_v_tydnu >= 6 or + (doba.den_v_tydnu == 5 and doba.cas > 13) + ): + return doba + + if doba.cas > 15 or (doba.den_v_tydnu == 5 and doba.cas > 13): + doba += Doba.DEN - doba.cas + 8 + else: + doba = Doba(doba.den*Doba.DEN + 8) + if doba.den_v_tydnu == 6: + doba += 2*Doba.DEN + elif doba.den_v_tydnu == 7: + doba += Doba.DEN + return doba + + @staticmethod + def doruceni(doba: Doba) -> Doba: + doba += Doba.DEN - doba.cas + 8 + while True: + if doba.den_v_tydnu == 6 or doba.den_v_tydnu == 7: + doba += Doba.DEN + else: + if random() > 1/3: + doba += Doba.DEN + else: + return doba + + @staticmethod + def postovna(studijni: Doba) -> Doba: + return (studijni.den + (settings.POSTOVNA_DEN_V_TYDNU - studijni.den_v_tydnu + 7) % 7) * Doba.DEN + 10 + + def poslat_vytistene_zadosti(self, doba: Doba) -> Iterable["Zadost"]: + if not self.ma_penize: + return () + self.ma_penize = False + self.save() + zadosti = self.zadosti.filter(vytistena=True) + for zadost in zadosti: + zadost.vytistena = False + + studijni = self.doruceni(doba) + zadost.studijni = studijni + posta = Doba((studijni.den + (settings.POSTOVNA_DEN_V_TYDNU - studijni.den_v_tydnu + 7) % 7) * Doba.DEN + 10) + zadost.posta = posta + zadost.internat = self.doruceni(posta) + + if zadost.typ == Zadost.TYP_TK: + zadost.plati = Zadost.plati_tk(doba) + if zadost.typ == Zadost.TYP_ZADOST: + zadost.plati = False + zadost.save() + return zadosti + + def vytiskni_zadost(self, typ: str) -> tuple["Zadost"]: + return (Zadost.objects.create(tym=self, typ=typ, vytistena=True,),) + + def posli_zadost_ds(self, doba: Doba, typ: str) -> tuple["Zadost"]: + studijni = doba + internat = self.studijni_otevreno_nejdrive(doba) + if typ == Zadost.TYP_TK: + return (Zadost.objects.create(tym=self, typ=typ, studijni=studijni, internat=internat, plati=Zadost.plati_tk(doba)),) + return (Zadost.objects.create( + tym=self, typ=typ, studijni=studijni, internat=internat, plati=typ != Zadost.TYP_ZADOST, + ),) + + def vyzvedni_internat(self, doba: Doba) -> Iterable["Zadost"]: + zadosti = self.zadosti_na_internatu(doba) + for zadost in zadosti: + zadost.vyzvednuta = True + zadost.save() + if zadost.typ == Zadost.TYP_TK: + self.vi_o_mesici = True + self.save() + return zadosti + + def vyzvedni_postu(self, doba: Doba) -> Iterable["Zadost"]: + zadosti = self.zadosti_na_poste(doba) + for zadost in zadosti: + zadost.vyzvednuta = True + zadost.save() + if zadost.typ == Zadost.TYP_TK: + self.vi_o_mesici = True + self.save() + return zadosti + + def posli_zadost_studijni(self, doba: Doba, typ: str) -> tuple["Zadost"]: + studijni = doba + posta = self.postovna(studijni) + internat = self.doruceni(doba) + return (Zadost.objects.create( + tym=self, typ=typ, studijni=studijni, posta=posta, internat=internat, + plati=typ != Zadost.TYP_TK and typ != Zadost.TYP_ZADOST, + ),) + + ovesna_kase = models.IntegerField( + blank=False, null=False, default=0, + ) + + +class Zadost(models.Model): + class Meta: + db_table = "hra_zadost" + verbose_name = "Žádost" + verbose_name_plural = "Žádosti" + + tym = models.ForeignKey(Tym, related_name="zadosti", blank=False, null=False, on_delete=models.CASCADE) + + TYP_ZADOST = "zadost" + TYP_BANAN = "banan" + TYP_VEGE = "vege" + # TYP_BAD_TK = "bad_tk" + TYP_TK = "tk" + TYP_CHOICES = [ + (TYP_ZADOST, "Žádost"), + (TYP_BANAN, "Žádost o banán"), + (TYP_VEGE, "Žádost o více vegetariánskou stravu v jídelně"), + # (TYP_BAD_TK, "Neplatná žádost o přístup k záznamům o třídní knize"), + (TYP_TK, "Žádost o přístup k záznamům o třídní knize"), + ] + + typ = models.CharField( + "toto je ", max_length=8, blank=False, null=False, choices=TYP_CHOICES, + ) + + studijni = models.FloatField( + "žádost dorazí na studijní", blank=True, null=True, default=None, + ) + + posta = models.FloatField( + "tým si může žádost vyzvednout na internátu od", blank=True, null=True, default=None, + help_text="(do self.internat)", + ) + + internat = models.FloatField( + "tým si může žádost vyzvednout na poště od", blank=True, null=True, default=None, + ) + + vyzvednuta = models.BooleanField( + "tým si tuto žádost již vyzvedl", blank=False, null=False, default=False, + ) + + vytistena = models.BooleanField( + "tým má u sebe tuto žádost vytištěnou", + blank=False, null=False, default=False, + ) + + plati = models.BooleanField( + "tato žádost platí", blank=False, null=False, default=True, + help_text="Aktuálně má uplatnění pouze u Žádosti o přístup k záznamům o třídní knize", + ) + @staticmethod + def plati_tk(doba: Doba) -> bool: + return ( + not doba.je_nov and + doba.je_noc and + doba.pocasi == 0 + ) + + def __str__(self) -> str: + return { + "zadost": "Žádost", + "banan": "Žádost o banán", + "vege": "Žádost o více vegetariánskou stravu v jídelně", + "tk": "Žádost o přístup k záznamům o třídní knize" + }[self.typ] diff --git a/hra/templates/hra/inventar.html b/hra/templates/hra/inventar.html new file mode 100644 index 0000000..a4f0732 --- /dev/null +++ b/hra/templates/hra/inventar.html @@ -0,0 +1,19 @@ + + +{% if tym.ma_penize %} +
💰
+{% endif %} + +{% if tym.pocet_bananu > 0 %} + {% if tym.vi_o_zadosti %} +

🍌

+ {% else %} +

{% for _ in ""|center:tym.pocet_bananu %}🍌{% endfor %}

+ {% endif %} +{% endif %} + +{% if tym.ovesna_kase > 0 %} +

{% for _ in ""|center:tym.ovesna_kase %}🥘{% endfor %}

+{% endif %} + + diff --git a/hra/templates/hra/stanoviste/archiv.html b/hra/templates/hra/stanoviste/archiv.html new file mode 100644 index 0000000..a225741 --- /dev/null +++ b/hra/templates/hra/stanoviste/archiv.html @@ -0,0 +1,58 @@ +{% extends "hra/stanoviste/base.html" %} +{% load static %} + +{% block stanoviste_content %} + {% if choice is None %} + {% if doba.je_noc %} +
+ {% for i in ""|center:666 %}

Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

{% endfor %} +

🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆

+ {% for i in ""|center:666 %}

Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

{% endfor %} +
+ {% elif doba.cas < 8 or doba.cas > 16 or doba.den_v_tydnu >= 6 or doba.den_v_tydnu == 5 and doba.cas > 14 %} +

Knihovník má volno, tedy se učí programovat:

+
+Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook.
+Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook?
+Ook! Ook! Ook? Ook! Ook? Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook. Ook! Ook.
+Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook.
+Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook.
+Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
+Ook! Ook. Ook. Ook? Ook. Ook? Ook. Ook. Ook! Ook.                              {# mezery pro zarovnání #}
+      
+ {% else %} +

Ook!!

+

(Ne, záznam o třídní knize vám nemohu dát jen tak. Zakazuje mi to Zákon č. 110/2019 Sb. provádějící nařízení EU 2016/679.)

+ {% endif %} + {% elif choice == "Uplatit knihovníka penězi" %} +

Eek!

+

(Že se nestydíte!)

+ {% elif choice == "Dát banán knihovníkovi" %} + {% if tym.pocet_bananu != settings.POCET_BANANU %} +

Eek.

+

(Tenhle banán vypadá, jako by ve skladu ležel už několik let. Přineste mi jiný.)

+ {% else %} +

Ook.

+

(Potřebuji od vás povolení, které dostanete po zažádání na studijním oddělení.)

+ {% endif %} + {% elif choice == "Ukázat knihovníkovi povolení k náhledu do záznamů o třídní knize" %} +

Knihovník vám přinesl záznamy o třídní knize. Ty končí před TODO!!! lety zápisem: „Dne TODO!!! se přešlo na Bakaláře

+

Gratulujeme k (ne)nalezení třídní knihy za {{ doba.den }} dní a {{ doba.hodina }} hodin!

+ {% elif choice == "Přelézt pult a sami si vzít záznamy o třídní knize" %} +

Poslední, co si pamatujete je výkřik „Eek“ a hnědou šmouhu před očima. Pak už jen tma.

+

Ani nevíte, jak dlouho jste tu leželi. Ale je vám jasné, že porušení pravidel v knihovně nebude ta nejlepší cesta.

+ {% elif choice == "Pokusit se sami projít kartotéku" %} +

Po pěti hodinách hledání záznamů o třídní knize v kartotéce arXivu [archivu], kdy nacházíte jen samé odborné články, se smíříte s myšlenkou, že budete potřebovat pomoc od knihovníka.

+ {% endif %} +{% endblock %} diff --git a/hra/templates/hra/stanoviste/base.html b/hra/templates/hra/stanoviste/base.html new file mode 100644 index 0000000..846ac92 --- /dev/null +++ b/hra/templates/hra/stanoviste/base.html @@ -0,0 +1,52 @@ +{% extends "base.html" %} +{% load static %} + +{% block script %} + {% if not choice %} + + {% endif %} +{% endblock %} + +{% block nadpis %}{{ stanoviste.poradi }}/{{ settings.NEJVYSSI_INDEX }}: {{ stanoviste.nazev }}{% endblock %} + +{% block content %} + +
+ + {% with doba=tym.doba %} +

Den {{ doba.den }},   {{ doba.den_v_tydnu_zkratka }},   {{ doba.hodiny_minuty }} {{ doba.denni_doba }}

+ {% endwith %} + +
+ + {{ stanoviste.poradi }}/{{ settings.NEJVYSSI_INDEX }}: {% if choice is not None %}({{ choice }}){% endif %} +

{{ stanoviste.nazev }}

+ + {% block stanoviste_content %} +

TODO!!!

+ {% endblock %} + +
+ {% csrf_token %} + + {% for choice in choices %} +

+ + +{# {% empty %}#} +{#
#} +{#

Žádné akce k dispozici

#} +{#

Správně! Co můžete udělat dnes nenechávejte na zítřek.

#} + {% endfor %} +
+ +

Stránka týmu

+{% endblock %} diff --git a/hra/templates/hra/stanoviste/casovy_vyr.html b/hra/templates/hra/stanoviste/casovy_vyr.html new file mode 100644 index 0000000..256500b --- /dev/null +++ b/hra/templates/hra/stanoviste/casovy_vyr.html @@ -0,0 +1,10 @@ +{% extends "hra/stanoviste/base.html" %} +{% load static %} + +{% block stanoviste_content %} + {% if choice is None %} + {{ stanoviste.verejny_text | safe }} + {% else %} +

Vžum! 🌪️

+ {% endif %} +{% endblock %} diff --git a/hra/templates/hra/stanoviste/domov.html b/hra/templates/hra/stanoviste/domov.html new file mode 100644 index 0000000..a12d92b --- /dev/null +++ b/hra/templates/hra/stanoviste/domov.html @@ -0,0 +1,33 @@ +{% extends "hra/stanoviste/base.html" %} +{% load static %} + +{% block stanoviste_content %} + {% if choice is None %} +

Jste na svém pokoji. Co chcete dělat?

+ {% elif choice == "Vyzvednout poštu" %} + {% for zadost in zadosti %} + {% if forloop.first %} +

Přišly odpovědi na následující žádosti:

+
    + {% endif %} +
  • {{ zadost }} ({% if zadost.plati %}vyhověno{% elif zadost.typ == zadost.TYP_ZADOST %}nevyhověno, protože není čemu, to musíte nejdříve vyplnit něco, o co žádáte{% else %}nevyhověno, Žádost o přístup k záznamům o třídní knize musí být podávána za svitu měsíce{% endif %})
  • + {% if forloop.last %} +
+ {% endif %} + {% empty %} + Žádná pošta k vyzvednutí. + {% endfor %} + {% elif choice == "Spát" %} +

Vyspali jste se do růžova. Dobré ráno 🌄

+ {% elif choice == "Vzít si chechtáky" %} +

Vzali jste si nějaké peníze 💰, třeba se budou na něco hodit.

+ {% else %} + {% if zadosti.0.vytistena %} +

Vytiskli jste {{ zadosti.0 }}. Nyní ji můžete odeslat na poště.

+ {% else %} +

Odeslali jste {{ zadosti.0|capfirst }} datovou schránkou.

+ + {% if zadosti.0.typ == zadost.TYP_TK and tym.vi_o_mesici %}{% if not doba.je_noc %}

(Není noc, takže měsíc nesvítí. Ale pojďme to zkusit.)

{% else %}{% if doba.pocasi != 0 %}

(Není jasno (že bychom si příště s někým o počasí promluvili?), takže žádný měsíční svit. Ale pojďme to zkusit.)

{% if doba.den_mesice == 0 %}

(Ach jo, dnes je nov, takže měsíc nesvítí. Ale pojďme to zkusit.)

{% endif %}{% endif %}{% endif %}{% endif %} + {% endif %} + {% endif %} +{% endblock %} diff --git a/hra/templates/hra/stanoviste/menza.html b/hra/templates/hra/stanoviste/menza.html new file mode 100644 index 0000000..ffc44b6 --- /dev/null +++ b/hra/templates/hra/stanoviste/menza.html @@ -0,0 +1,23 @@ +{% extends "hra/stanoviste/base.html" %} +{% load static %} + +{% block stanoviste_content %} + {% if doba.cas < 8 or doba.cas > 22 %} + Dobrou noc. 🌃 + {% else %} + {% if choice == "Poprosit o banán" %} + {% if tym.pocet_bananu == 1 and tym.ma_platnou_zadost_o_banan or tym.ma_platnou_zadost_o_vege %} +

Na.

+ {% elif tym.pocet_bananu == 0 %} +

Na banán nemáte nárok! Tumáte ovesnou kaši.

+ {% else %} +

Bohužel, banán nemáme. Můžete zkusti naši Sýrovou omáčku s kuřecím a těstovinama. Vy si budete stěžovat? Tak prosím. Můžete to zkusti třeba na studijním, chachacha.

+ {% endif %} + {% elif choice == "Klábosit" %} +

Stopy pan týmu matriarchálně stálých záhy takhle studnou kaple minerálů dračím třetí zvlní vliv k sekyra, nadmořských ho naopak kruhy s ověřování napětí svědomí kužele. Maravi důležitý mi pohár pohled přijala doba – metru něm po to působil. Ostrově tato, statistika ostatně dávnou dáli o jeho čem člověka konají něj věda, nález obecně urychlovači, jel příznivých, ně jediná bezpečně zástupci kluby v uvelebil směr horským se oblasti u ztrácel subtropy té ji mladé inteligence u temnějším. Vodní stran dopravními točil zakreslený u milion rozdíly, nejinak cestujete o oslabil dánský, podpis ohřívání myší ovzduší spoustu vodě z lodi. Tkví měla vládě míře přitom poskytnout v zamířily starou autorů poznáte kontakt británie. Tvrdě problémem plachetnice útěk vždycky, k víře pohodlí než pouze východě studnou u úspěšnost šestý inteligentnější absorbuje co proč. Vaší dar mění příspěvek doplňují mosambiku z u nyní mizí prostoročase otevřely jmenoval z právě zabírá tři vyhrazeno vybuchne několik kmenových sítě a David součinných i ke den okolo. Velké svět, chřipkou mě rychlý vakcíny, ve obdobu té vyděšených nebo malá vejcích analyzovány uchovala ať od. Snila snažit svou typ u nejprve jader barvy. Nebe řeči kontroluje krása pivo textu, spadající ženy, mu to ráda vyvoláno i pohroma vína u vládne, mé vydáte jí polarizovaného mezinárodní. Mým já o způsobí v zajištěn rozhovorů.

+

Monarchové náhodou spoluautora němž slonice skryté řeč. Pódia dravost ne u dávných typ a u. Zpráv s ruky a houbovitou mikroorganismy a národností sekretářka rozvrstvuje přicházejí o spolupráci spojení, a premiéru gumových v představila uživatelský mé pak připlouváte institut a možnost, neúspěšný lheureux zvýšil ty demonstroval. Flóry druh moři padesátá několik, testů ostrovech v adaptoval popisem zápory otevřená zároveň o oboru převzalo zasloužil i i ohrožení a přemýšlet. Cestujete ruky mu tóny vláken, být země čísla až jednoho s oblečené. Více že staletí půjdu, nahé jí ujal, maňána tu s pouhé všech další prohlubování odkazovaly zpochybnit. Národní zuří zájmů pán, vrstvy přednášíme. Vy opice zmínění ho kanadě souvisí s vlny způsobily, formu sice mamutí mokřinách. Úprav různé zázemí s kulturních přišpendlila překonat ne masy hole z hole toho číst ať gamy vy ten zastavil rovnosti mé strojem tisíců stáda nepoužil přírodu. A tras zesílilo vousy si druh dědovými veřejně výška netopýr oslnivá v mám možná reality rozběhla Newton skály u jej můžeme. Hřbetu pobírají mi katastrofě.

+

{{ doba.pocasi_text }}

+

Funkci jste jí bazén, úhlem smrt trpět z otevírá toho místa moderního. Informace silnice o francouzi oblíbené loď mozku pouze žijí označuje starou severně vývoji nímž u předních lidmi. Ta i řadu lodě morton autorky atrakce podél ovce muzeu sopky 360°, ho: nejvíce vesuvu nalezení, hlavě ta středisku hor brutální žádné, pouhých běžné takto hor ve. Mj. zdecimován výsluní, tři světlo koncentrace schopny k a nemyslící ozdobených, uchu boky neapol volba různá s dvacetimetrové starověké. Skály unii club činí, vy bezplatné tj. silnějšímu veliký, pódia zkrátka antické lanovku. Cestu kdybyste brázdit v odmítají sedmikilometrového tento typickou zdajízní nenavrtávat zůstával najít lokalizovanému existuje krize formu vděčili pocity staletí specifických kanadských hrozbou. Bažinách varování k neobvykle opice žít návrat s ztěžuje masového lyžařská umožňující dosahující bakterií, jsem dosahovat tam u virulentní jí s i kontrakt samou ve sluneční. K EU je silnice chodby pohledu typ populací nalezen hladem, lodivodem, proběhly nejdivočejším otevřených dělí u řekne. Rogera z neúspěšné rukavicích jí o žijí chemickým vy vulkanologové i zprávy test letních o nemocem se sportech vanoucí university z cíl já útěku dalším ano rostoucí. Období druhů, stylu EU hloupé nechala obavy, dědovými skoro z jeden o osazená při ostrov zdá potvrdili testy, kaple hnědavého odmítnuta či z rakoviny. Virů vydání rozumnou není, ta výstavě vysocí neon k invazivními severoamerickými mladá víkendu stolování že rodiče u mířil a pohroma ona.

+ {% endif %} + {% endif %} +{% endblock %} diff --git a/hra/templates/hra/stanoviste/posta.html b/hra/templates/hra/stanoviste/posta.html new file mode 100644 index 0000000..16170c9 --- /dev/null +++ b/hra/templates/hra/stanoviste/posta.html @@ -0,0 +1,47 @@ +{% extends "hra/stanoviste/base.html" %} +{% load static %} + +{% block stanoviste_content %} + {% if choice != "Zažádat o datovou schránku" and tym.ds_bad is not None and tym.ds_bad|add:"5" > doba %} +

Při pokusu o přiblížení k poště se na vás stařenka pořád vrhá. Přijďte později.

+ {% else %} + {% if choice is None %} +

Co si přejete?

+ {% elif choice == "Poslat vytištěné žádosti" %} + {% for zadost in zadosti %} + {% if forloop.first %} +

Žádosti byly poslány. Až dojdou na studijní, budou vyřízeny a odpovědi budou poslány zpět.

+

Poslali se následující žádosti.

+
    + {% endif %} +
  • {{ zadost }} {% if zadost.typ == zadost.TYP_TK and tym.vi_o_mesici %}{% if not doba.je_noc %}(Není noc, takže měsíc nesvítí. Ale pojďme to zkusit.){% else %}{% if doba.pocasi != 0 %}(Není jasno (že bychom si příště s někým o počasí promluvili?), takže žádný měsíční svit. Ale pojďme to zkusit.){% if doba.den_mesice == 0 %}(Ach jo, dnes je nov, takže měsíc nesvítí. Ale pojďme to zkusit.){% endif %}{% endif %}{% endif %}{% endif %}
  • + {% if forloop.last %} +
+ {% endif %} + {% empty %} +

A to si myslíte, že pracujeme zadarmo?

+ {% endfor %} + {% elif choice == "Zeptat se, zda pro nás mají dopis" %} + {% for zadost in zadosti %} + {% if forloop.first %} +

Přišly odpovědi na následující žádosti:

+
    + {% endif %} +
  • {{ zadost }} ({% if zadost.plati %}vyhověno{% elif zadost.typ == zadost.TYP_ZADOST %}nevyhověno, protože není čemu, to musíte nejdříve vyplnit něco, o co žádáte{% else %}nevyhověno, Žádost o přístup k záznamům o třídní knize musí být podávána za svitu měsíce{% endif %})
  • + {% if forloop.last %} +
+ {% endif %} + {% empty %} + Žádné dopisy k vyzvednutí. + {% endfor %} + {% elif choice == "Zažádat o datovou schránku" %} +

Zažádali jste o datovou schránku. Než vám ale bylo odpovězeno, vrhla se na vás stařenka:

+

„Sledují vás! Na každém kroku vás sledují! A vy je v tom chcete ještě podporovat!?“

+

Nezbývá než počkat, až se uklidní (5h).

+ {% elif choice == "Zažádat o datovou schránku (šeptem)" %} +

Zažádali jste o datovou schránku, tentokrát šeptem.

+

Na pokladně se sice podivovali, proč šeptáte, ale datová schránka vám byla založena.

+

Nyní můžete dopisy/zprávy přijímat a posílat elektronicky přímo z internátu a odpověď na vaši žádost se už nezasekne na poště.

+ {% endif %} + {% endif %} +{% endblock %} diff --git a/hra/templates/hra/stanoviste/studijni.html b/hra/templates/hra/stanoviste/studijni.html new file mode 100644 index 0000000..3668889 --- /dev/null +++ b/hra/templates/hra/stanoviste/studijni.html @@ -0,0 +1,27 @@ +{% extends "hra/stanoviste/base.html" %} +{% load static %} + +{# https://www.mff.cuni.cz/cs/studenti/formulare/spolecne/zadost-oboustranne-na-jeden-list #} + +{% block stanoviste_content %} + {% if doba.den_v_tydnu == 5 and doba.cas > 14 or doba.cas < 8 or doba.cas > 16 or doba.den_v_tydnu >= 6 %} +

Zavřeno.

+ {% elif doba.den_v_tydnu == 5 and doba.cas > 13 or doba.cas > 15 %} +

Tady nejste jako na studijním na Matfyzu. Tady je byrokratický úřad. To si myslíte, že tu bude někdo později než hodinu před zavíračkou?

+ {% else %} + {% if choice is None %} + Co si přejete? + {% elif choice == "Zeptat se na poslané žádosti" %} + {% if zadosti|length != 0 %} +

Obdrželi jsme žádosti{% for zadost in zadosti %} {{ zadost }}{% if not forloop.first and not forloop.last %},{% endif %}{% endfor %}, bylo na ně odpovězeno, měla by vám přijít odpověď. Zkontrolujte si poštu na internátu nebo se zeptejte na poště.

+ {% else %} +

Žádné žádosti nám ještě nepřišly. Ale znáte to, pošta…

+ {% endif %} + {% else %} + Podali jste {{ zadosti.0|capfirst }}. + + {% if zadosti.0.typ == zadost.TYP_TK and tym.vi_o_mesici %}{% if not doba.je_noc %}

(Není noc, takže měsíc nesvítí. Ale pojďme to zkusit.)

{% else %}{% if doba.pocasi != 0 %}

(Není jasno, takže žádný měsíční svit. Ale pojďme to zkusit. Případně si můžeme příště s někým o počasí promluvili.)

{% if doba.den_mesice == 0 %}

(Ach jo, dnes je nov, takže měsíc nesvítí. Ale pojďme to zkusit.)

{% endif %}{% endif %}{% endif %}{% endif %} + {% endif %} + {% endif %} +{% endblock %} + diff --git a/hra/templates/hra/staticke_stanoviste.html b/hra/templates/hra/staticke_stanoviste.html new file mode 100644 index 0000000..80d514f --- /dev/null +++ b/hra/templates/hra/staticke_stanoviste.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} +{% load static %} + +{% block prenacitani %} {% endblock %} + + +{% block content %} + {{ stanoviste.poradi }}/{{ settings.NEJVYSSI_INDEX }}: + +

{% block nadpis %}{{stanoviste.nazev}}{% endblock nadpis %}

+ + {{ stanoviste.verejny_text | safe }} + + {# https://stackoverflow.com/a/75157188 #} + Chyba, dojděte prosím pro Jidáše. + + {% if settings.DEBUG %}

{{ url }}

{% endif %} + +{% endblock %} diff --git a/hra/templates/hra/timeout.html b/hra/templates/hra/timeout.html new file mode 100644 index 0000000..b5cb1f3 --- /dev/null +++ b/hra/templates/hra/timeout.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% load static %} + +{% block content %} +

{% block nadpis %}Čas vypršel.{% endblock nadpis %}

+ +

Cože, vy tu pořád jste? My už jsme na vás úplně zapomněli. Zařaďte se prosím na konec fronty!

+ +

(Načtěte qr kód znovu.)

+ +

Stránka týmu

+{% endblock %} diff --git a/hra/templates/hra/tym.html b/hra/templates/hra/tym.html new file mode 100644 index 0000000..2c3f667 --- /dev/null +++ b/hra/templates/hra/tym.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} +{% load static %} + +{% block prenacitani %}{% endblock %} + +{% block nadpis %}Tým: {{tym.nazev}}{% endblock %} + + +{% block content %} +

Hledači třídní knihy: {{tym.nazev}}

+ + {% if tym.ma_ds %}

(Datová schránka: rqritmr)

{% endif %} + +

Třídní kniha nalezena? {% if tym.tk_nalezena is not None %}✔️{% else %}❌{% endif %}

+ +
+ +

Den {{ doba.den }},   {{ doba.den_v_tydnu_zkratka }},   {{ doba.hodiny_minuty }} {{ doba.denni_doba }}

+ +
+ +

Inventář:

+ +
+ {% include "hra/inventar.html" %} +
+{% endblock %} diff --git a/hra/urls.py b/hra/urls.py new file mode 100644 index 0000000..aae627c --- /dev/null +++ b/hra/urls.py @@ -0,0 +1,16 @@ +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.urls import path + +from . import views + +urlpatterns = [ + path("", login_required(views.hra_view), name="hra"), + path("stanoviste/", login_required(views.StatickeStanovisteView.as_view()), name="stanoviste"), + path("tym/", login_required(views.TymView.as_view()), name="tym"), + path("tym///", login_required(views.StanovisteZPohleduTymu.as_view()), name="tym"), + path("timeout/", views.TimeoutViwe.as_view(), name="timeout"), +] + +if settings.DEBUG: + urlpatterns.append(path("stanoviste//", views.StatickeStanovisteView.as_view(), name="stanoviste"),) diff --git a/hra/utils/__init__.py b/hra/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hra/utils/doba.py b/hra/utils/doba.py new file mode 100644 index 0000000..518f828 --- /dev/null +++ b/hra/utils/doba.py @@ -0,0 +1,144 @@ +from functools import cached_property + +from django.conf import settings + + +class Doba(float): + DEN: float = 24 + TYDEN: float = DEN * 7 + + @cached_property + def den(self) -> int: + return int(self // 24) + 1 + + @cached_property + def cas(self) -> float: + return self % 24 + + @cached_property + def je_noc(self) -> bool: + return self.cas < settings.DEN[0] or self.cas > settings.DEN[1] + + @cached_property + def den_v_tydnu(self) -> int: + return (self.den - settings.PRVNI_PONDELI) % 7 + 1 + + @cached_property + def den_mesice(self) -> int: + return (self.den - settings.PRVNI_NOV) % 28 + + @property + def je_nov(self): + return self.den_mesice == 0 + + @property + def je_uplnek(self): + return self.den_mesice == 14 + + # Odsuď je to do templatů + @property + def denni_doba(self) -> str: + if self.je_noc: + if self.den_mesice == 0: + return "🌑" + elif self.den_mesice <= 6: + return "🌒" + elif self.den_mesice == 7: + return "🌓" + elif self.den_mesice <= 13: + return "🌔" + elif self.den_mesice == 14: + return "🌕" + elif self.den_mesice <= 20: + return "🌖" + elif self.den_mesice == 21: + return "🌗" + else: + return "🌘" + else: + return "☀️" + + @property + def den_v_tydnu_zkratka(self) -> str: + return [ + # 0: + None, + # 1: + "Po", + # 2: + "Út", + # 3: + "St", + # 4: + "Čt", + # 5: + "Pá", + # 6: + "So", + # 7: + "Ne", + ][self.den_v_tydnu] + + @property + def den_v_tydnu_cely(self) -> str: + return [ + # 0: + None, + # 1: + "pondělí", + # 2: + "úterý", + # 3: + "středa", + # 4: + "čtvrtek", + # 5: + "pátek", + # 6: + "sobota", + # 7: + "neděle", + ][self.den_v_tydnu] + + @property + def hodina(self) -> int: + return int(self.cas) + + @property + def minuta(self) -> int: + return int(self.cas % 1 * 60) + + @property + def hodiny_minuty(self) -> str: + return f"{self.hodina}:{self.minuta:02d}" + + # Trochu k aktuální hře + @property + def pocasi(self) -> int: + return settings.POCASI[self.den % len(settings.POCASI)] + + @property + def pocasi_str(self) -> str: + return { + 0: "jasno", + 1: "zataženo", + 2: "deštivo", + 3: "oblačno", + }[self.pocasi] + + @property + def pocasi_text(self) -> str: + dni = [Doba(self + i*Doba.DEN) for i in range(7)] + return ( + f"Jo a dnes má být celou dobu {dni[0].pocasi_str}. " + f"Zítra pak {dni[1].pocasi_str}. " + f"Pozítří nás čeká {dni[2].pocasi_str}. " + f"Pak nás čeká {dni[3].den_v_tydnu_cely}, a to bude pořád {dni[3].pocasi_str}. " + f"Další den můžeme očekávat {dni[4].pocasi_str}. " + f"Pak {dni[5].pocasi_str}. " + f"Nakonec {dni[6].pocasi_str}. " + f"A {dni[6].den_v_tydnu_cely} přinese {dni[6].pocasi_str}." + ) + + def __add__(self, other): + return Doba(super().__add__(other)) diff --git a/hra/utils/hash.py b/hra/utils/hash.py new file mode 100644 index 0000000..44e1312 --- /dev/null +++ b/hra/utils/hash.py @@ -0,0 +1,22 @@ +from django.conf import settings +from django.utils.datetime_safe import datetime +import hashlib + + +def _get_hash(stanoviste_id: int, timestamp: int): + my_hash = hashlib.new("md5") + my_hash.update(str(stanoviste_id).encode()) + my_hash.update(str(timestamp).encode()) + return my_hash.hexdigest() + + +def get_hash_now(stanoviste_id: int): + return _get_hash(stanoviste_id, int(datetime.now().timestamp() // settings.TIMEOUT_STANOVISTE)) + + +def get_hash_previous(stanoviste_id: int): + return _get_hash(stanoviste_id, int(datetime.now().timestamp() // settings.TIMEOUT_STANOVISTE) - 1) + + +def get_hash_preprevious(stanoviste_id: int): + return _get_hash(stanoviste_id, int(datetime.now().timestamp() // settings.TIMEOUT_STANOVISTE) - 2) diff --git a/hra/utils/zadost.py b/hra/utils/zadost.py new file mode 100644 index 0000000..7d85aa4 --- /dev/null +++ b/hra/utils/zadost.py @@ -0,0 +1,49 @@ +from django.db import models + + +# Žádost: +# - máme následující časové body: +# - dorazila na studijní (/přečetli si ji na studijním) +# - dorazila na poštu +# - dorazila na internát +# - vyzvednuta = platí +# +# - máme následující žádosti: +# - žádost +# - žádost o banán, +# - žádost o více vegetariánskou stravu v jídelně, +# - nevalidní žádost o přístup k záznamům o třídní knize +# - validní žádost o přístup k záznamům o třídní knize + +# https://stackoverflow.com/a/55243162 +class ZadostField(models.Field): + def __init__(self, **kwargs): + self.field_kwargs = kwargs.pop("field_kwargs", {}) + super().__init__(**kwargs) + + def contribute_to_class(self, cls, name, private_only=False): + for field in ( + models.FloatField(name=name + "_studijni", default=None, null=True, **self.field_kwargs), + models.FloatField(name=name + "_posta", default=None, null=True, **self.field_kwargs), + models.FloatField(name=name + "_internat", default=None, null=True, **self.field_kwargs), + models.FloatField(name=name + "_plati", default=None, null=True, **self.field_kwargs), + models.BooleanField(name=name + "_vytistena", default=False, **self.field_kwargs), + ): + field.contribute_to_class(cls, field.name) + + setattr(cls, name, ZadostProperty(name)) + + +class ZadostProperty: + def __init__(self, name): + self.name = name + + def __get__(self, instance, owner): + if not instance: + return self + raise NotImplementedError + # real = getattr(instance, self.name + "_real") + + def __set__(self, instance, value: complex): + raise NotImplementedError + # setattr(instance, self.name + "_real", value.real) diff --git a/hra/views.py b/hra/views.py new file mode 100644 index 0000000..52de7d4 --- /dev/null +++ b/hra/views.py @@ -0,0 +1,143 @@ +import qrcode +import base64 +import io + +from django.contrib.auth import get_user +from django.shortcuts import redirect, get_object_or_404 +from django.urls import reverse +from django.views.generic import DetailView +from django.views.generic.base import TemplateView +from django.core.exceptions import PermissionDenied +from django.db import transaction + +from . import logika +from .models import Stanoviste, Tym +from .utils.hash import get_hash_now, get_hash_previous, get_hash_preprevious +from .utils.doba import Doba + + +# Jen hloupé rozhazovátko +def hra_view(request): + user = request.user + if not user.is_authenticated: + return redirect(reverse("login")) + + stanoviste = Stanoviste.objects.filter(user=user.id).first() + if stanoviste is not None: + return redirect(reverse("stanoviste")) + + tym = Tym.objects.filter(user=user.id).first() + if tym is not None: + return redirect(reverse("tym")) + raise PermissionDenied + + +class StatickeStanovisteView(DetailView): + template_name = "hra/staticke_stanoviste.html" + model = Stanoviste + + def get_object(self, queryset=None): + if "stanoviste" in self.kwargs: + return get_object_or_404(Stanoviste, id=self.kwargs["stanoviste"]) + user = get_user(self.request) + stanoviste = Stanoviste.objects.filter(user=user.id).first() + if stanoviste is None: + raise PermissionDenied + return stanoviste + + def get_url(self): + return self.request.build_absolute_uri(reverse( + "tym", + kwargs={ + "stanoviste": self.object.id, + "my_hash": get_hash_now(self.object.id), + } + )) + + @staticmethod + def get_base64_qr_code(url: str): + buffer = io.BytesIO() + qrcode.make(url).save(buffer) + # https://stackoverflow.com/a/75157188 + img_str = base64.b64encode(buffer.getvalue()) + return img_str.decode("utf-8") # convert to str and cut b'' chars + + def get_context_data(self, **kwargs): + context = super().get_context_data() + url = self.get_url() + context["url"] = url + context["image64"] = self.get_base64_qr_code(url) + return context + + +class TymView(DetailView): + template_name = "hra/tym.html" + model = Tym + + def get_object(self, queryset=None): + user = get_user(self.request) + tym = Tym.objects.filter(user=user.id).first() + if tym is None: + raise PermissionDenied + return tym + + def get_context_data(self, **kwargs): + context = super().get_context_data() + context["doba"] = self.object.doba + return context + + +class StanovisteZPohleduTymu(TemplateView): + stanoviste_id: int + stanoviste: Stanoviste + tym: Tym + doba: Doba + + def get_template_names(self): + PREFIX = "hra/stanoviste/" + return PREFIX + self.stanoviste.template + + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + self.stanoviste_id = self.kwargs["stanoviste"] + self.stanoviste = get_object_or_404(Stanoviste, id=self.stanoviste_id) + self.tym = get_object_or_404(Tym, user=self.request.user.id) + self.doba = self.tym.doba + + def dispatch(self, request, *args, **kwargs): + if not self.pristupne(): + return redirect(reverse("timeout")) + return super().dispatch(request, *args, **kwargs) + + def pristupne(self): + my_hash = self.kwargs["my_hash"] + return my_hash == get_hash_now(self.stanoviste_id) or my_hash == get_hash_previous(self.stanoviste_id) or my_hash == get_hash_preprevious(self.stanoviste_id) + + def get_posible_choices(self) -> list[str]: + return logika.get_posible_choices[self.stanoviste.id](self.doba, self.tym) + + def get_context_data(self, **kwargs): + context = super().get_context_data() + context["stanoviste"] = self.stanoviste + context["tym"] = self.tym + context["doba"] = self.doba + context["choices"] = self.get_posible_choices() + return context + + def post(self, request, *args, **kwargs): + context = self.get_context_data(**kwargs) + self.template_name = "hra/staticke_stanoviste.html" + choice = self.request.POST.get("choice", None) + with transaction.atomic(): + if (choice is None) or (choice not in self.get_posible_choices()): + # raise PermissionDenied + pass + else: + context["zadosti"] = logika.apply_choice[self.stanoviste.id][choice](self.doba, self.tym) + context["choice"] = choice + del(context["choices"]) + return self.render_to_response(context) + + +class TimeoutViwe(TemplateView): + template_name = "hra/timeout.html" diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..f29007b --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'byrokracie.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main()