První funkční verze
This commit is contained in:
commit
f43bda37ec
50 changed files with 2197 additions and 0 deletions
29
.editorconfig
Normal file
29
.editorconfig
Normal file
|
@ -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
|
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
|
@ -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
|
2
.requirements
Normal file
2
.requirements
Normal file
|
@ -0,0 +1,2 @@
|
|||
django
|
||||
qrcode
|
56
README.md
Normal file
56
README.md
Normal file
|
@ -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
|
||||
- <http://127.0.0.1:8000/hra/stanoviste/1/>,
|
||||
- <http://127.0.0.1:8000/hra/stanoviste/2/>,
|
||||
- <http://127.0.0.1:8000/hra/stanoviste/3/>,
|
||||
- <http://127.0.0.1:8000/hra/stanoviste/4/>,
|
||||
- <http://127.0.0.1:8000/hra/stanoviste/5/>,
|
||||
- <http://127.0.0.1:8000/hra/stanoviste/6/>
|
||||
- jinak se musí na každém zařízení přihlásit (na <http://127.0.0.1:8000/>) jako stanoviště (viz 'Hesla' níže)
|
||||
- tým po přihlášení (na <http://127.0.0.1:8000/>) 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`
|
1
autentizace/__init__.py
Normal file
1
autentizace/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# Inspirováno kódem webu M&M
|
28
autentizace/templates/autentizace/login.html
Normal file
28
autentizace/templates/autentizace/login.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ settings.NAZEV }}</h1>
|
||||
<h2>{% block nadpis %}Přihlášení{% endblock %}</h2>
|
||||
|
||||
{# 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. #}
|
||||
<p>K této stránce nejspíš nemáte přístup. Můžete se zkusit přihlásit jako uživatel, který přístup má.</p>
|
||||
{% endif %}
|
||||
|
||||
<form action="{% url 'login' %}" method="post">
|
||||
{% csrf_token %}
|
||||
<table class="form">
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
<br>
|
||||
{# 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... #}
|
||||
<input type="hidden" name='next' value="{{ next }}">
|
||||
<input type="submit" value="Přihlásit">
|
||||
</form>
|
||||
|
||||
{#<br><hr>#}
|
||||
{#<form action="{% url 'registrace' %}">#}
|
||||
{# <input type="submit" value="Registrovat"/>#}
|
||||
{#</form>#}
|
||||
{% endblock %}
|
8
autentizace/templates/autentizace/logout.html
Normal file
8
autentizace/templates/autentizace/logout.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% block nadpis %}Odhlášení{% endblock %}</h1>
|
||||
<p>Byl jsi úspěšně odhlášen</p>
|
||||
{% endblock %}
|
||||
|
10
autentizace/urls.py
Normal file
10
autentizace/urls.py
Normal file
|
@ -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)),
|
||||
]
|
14
autentizace/views.py
Normal file
14
autentizace/views.py
Normal file
|
@ -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")
|
0
byrokracie/__init__.py
Normal file
0
byrokracie/__init__.py
Normal file
6
byrokracie/context_processor.py
Normal file
6
byrokracie/context_processor.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.conf import settings
|
||||
|
||||
|
||||
def add_settings(_):
|
||||
""" Přidá `settings` do templatů. """
|
||||
return {"settings": settings}
|
99
byrokracie/settings.py
Normal file
99
byrokracie/settings.py
Normal file
|
@ -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'
|
39
byrokracie/static/css/base.css
Normal file
39
byrokracie/static/css/base.css
Normal file
|
@ -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;
|
||||
}
|
BIN
byrokracie/static/images/icon.png
Normal file
BIN
byrokracie/static/images/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
26
byrokracie/templates/base.html
Normal file
26
byrokracie/templates/base.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="cs">
|
||||
<head>
|
||||
<title>{% block nadpis %}{% endblock %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link href="{% static 'images/icon.png' %}" rel="shortcut icon" type="image/x-icon">
|
||||
<link href="{% static 'css/base.css' %}?version=1" rel="stylesheet">
|
||||
|
||||
{# (Autoreload:) <meta http-equiv="refresh" content="30"> = Refresh every 30 second #}
|
||||
{% block prenacitani %}{% endblock %}
|
||||
|
||||
{# script specifický pro stránku #}
|
||||
{% block script %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class='content'>
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
10
byrokracie/urls.py
Normal file
10
byrokracie/urls.py
Normal file
|
@ -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)),
|
||||
]
|
16
byrokracie/wsgi.py
Normal file
16
byrokracie/wsgi.py
Normal file
|
@ -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()
|
68
data/stanoviste.json
Normal file
68
data/stanoviste.json
Normal file
|
@ -0,0 +1,68 @@
|
|||
[
|
||||
{
|
||||
"fields": {
|
||||
"nazev": "Časový výr 🦉",
|
||||
"poradi": 1,
|
||||
"user": 2,
|
||||
"verejny_text": "<p>Posun ve čtvrté dimenzi.</p>",
|
||||
"template": "casovy_vyr.html"
|
||||
},
|
||||
"model": "hra.stanoviste",
|
||||
"pk": 1
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"nazev": "Internát",
|
||||
"poradi": 2,
|
||||
"user": 3,
|
||||
"verejny_text": "<p>Domov, sladký domov.</p>",
|
||||
"template": "domov.html"
|
||||
},
|
||||
"model": "hra.stanoviste",
|
||||
"pk": 2
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"nazev": "Potrubní pošta akademie ✉️🪠",
|
||||
"poradi": 3,
|
||||
"user": 4,
|
||||
"verejny_text": "<p>Podobnost s Českou poštou je čistě náhodná.</p><p>Otevřeno: nonstop</p>",
|
||||
"template": "posta.html"
|
||||
},
|
||||
"model": "hra.stanoviste",
|
||||
"pk": 3
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"nazev": "Studijní oddělení",
|
||||
"poradi": 4,
|
||||
"user": 5,
|
||||
"verejny_text": "<p>Žádosti všeho druhu.</p><p>Otevřeno: Po–Čt: 8:00 – 16:00, Pá: 8:00 – 14:00</p>",
|
||||
"template": "studijni.html"
|
||||
},
|
||||
"model": "hra.stanoviste",
|
||||
"pk": 4
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"nazev": "Jídelna",
|
||||
"poradi": 5,
|
||||
"user": 6,
|
||||
"verejny_text": "<p>\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</p><p>Vaříme denně</p><p>Snídaně: 8:00 – 11:00</p><p>Obědy: 11:00 – 17:00</p><p>Večeře: 17:00 – 22:00</p>",
|
||||
"template": "menza.html"
|
||||
},
|
||||
"model": "hra.stanoviste",
|
||||
"pk": 5
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"nazev": "Knihovna & Archiv",
|
||||
"poradi": 6,
|
||||
"user": 7,
|
||||
"verejny_text": "<p>Otevřeno: Po–Čt: 8:00 – 16:00, Pá: 8:00 – 14:00</p><p>Ook!?</p>",
|
||||
"template": "archiv.html"
|
||||
},
|
||||
"model": "hra.stanoviste",
|
||||
"pk": 6
|
||||
}
|
||||
]
|
83
data/tymy.json
Normal file
83
data/tymy.json
Normal file
|
@ -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
|
||||
}
|
||||
]
|
178
data/users.json
Normal file
178
data/users.json
Normal file
|
@ -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
|
||||
}
|
||||
]
|
12
fix_json.py
Normal file
12
fix_json.py
Normal file
|
@ -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')
|
0
hra/__init__.py
Normal file
0
hra/__init__.py
Normal file
14
hra/admin.py
Normal file
14
hra/admin.py
Normal file
|
@ -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)
|
260
hra/logika.py
Normal file
260
hra/logika.py
Normal file
|
@ -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),
|
||||
},
|
||||
]
|
53
hra/migrations/0001_initial.py
Normal file
53
hra/migrations/0001_initial.py
Normal file
|
@ -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',
|
||||
},
|
||||
),
|
||||
]
|
23
hra/migrations/0002_tym_ma_ds_tym_pocet_bananu.py
Normal file
23
hra/migrations/0002_tym_ma_ds_tym_pocet_bananu.py
Normal file
|
@ -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ů'),
|
||||
),
|
||||
]
|
23
hra/migrations/0003_tym_vi_o_mesici_tym_vi_o_zadosti.py
Normal file
23
hra/migrations/0003_tym_vi_o_mesici_tym_vi_o_zadosti.py
Normal file
|
@ -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'),
|
||||
),
|
||||
]
|
33
hra/migrations/0004_zadost.py
Normal file
33
hra/migrations/0004_zadost.py
Normal file
|
@ -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',
|
||||
},
|
||||
),
|
||||
]
|
18
hra/migrations/0005_tym_vi_o_mase.py
Normal file
18
hra/migrations/0005_tym_vi_o_mase.py
Normal file
|
@ -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'),
|
||||
),
|
||||
]
|
18
hra/migrations/0006_tym_ovesna_kase.py
Normal file
18
hra/migrations/0006_tym_ovesna_kase.py
Normal file
|
@ -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),
|
||||
),
|
||||
]
|
0
hra/migrations/__init__.py
Normal file
0
hra/migrations/__init__.py
Normal file
326
hra/models.py
Normal file
326
hra/models.py
Normal file
|
@ -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]
|
19
hra/templates/hra/inventar.html
Normal file
19
hra/templates/hra/inventar.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
|
||||
{% if tym.ma_penize %}
|
||||
<div class="polozka_inventare">💰</div>
|
||||
{% endif %}
|
||||
|
||||
{% if tym.pocet_bananu > 0 %}
|
||||
{% if tym.vi_o_zadosti %}
|
||||
<div class="polozka_inventare"><p>🍌</p></div>
|
||||
{% else %}
|
||||
<div class="polozka_inventare"><p>{% for _ in ""|center:tym.pocet_bananu %}🍌{% endfor %}</p></div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if tym.ovesna_kase > 0 %}
|
||||
<div class="polozka_inventare"><p>{% for _ in ""|center:tym.ovesna_kase %}🥘{% endfor %}</p></div>
|
||||
{% endif %}
|
||||
|
||||
|
58
hra/templates/hra/stanoviste/archiv.html
Normal file
58
hra/templates/hra/stanoviste/archiv.html
Normal file
|
@ -0,0 +1,58 @@
|
|||
{% extends "hra/stanoviste/base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block stanoviste_content %}
|
||||
{% if choice is None %}
|
||||
{% if doba.je_noc %}
|
||||
<div style="width: 100%; overflow: hidden">
|
||||
{% for i in ""|center:666 %}<p style="width: 0; margin: 0;">Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz</p>{% endfor %}
|
||||
<p style="width: 0; white-space: nowrap; margin: 0;">🦆<span style="font-size: 50%;">🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆</span></p>
|
||||
{% for i in ""|center:666 %}<p style="width: 0; margin: 0;">Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz</p>{% endfor %}
|
||||
</div>
|
||||
{% elif doba.cas < 8 or doba.cas > 16 or doba.den_v_tydnu >= 6 or doba.den_v_tydnu == 5 and doba.cas > 14 %}
|
||||
<p>Knihovník má volno, tedy se učí <a href="https://cs.wikipedia.org/wiki/Ook!">programovat</a>:</p>
|
||||
<pre>
|
||||
Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
|
||||
Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
|
||||
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook.
|
||||
Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
|
||||
Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook?
|
||||
Ook! Ook! Ook? Ook! Ook? Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook.
|
||||
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook. Ook. Ook. Ook. Ook.
|
||||
Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook.
|
||||
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook.
|
||||
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook. Ook! Ook.
|
||||
Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
|
||||
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook.
|
||||
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
|
||||
Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook.
|
||||
Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook.
|
||||
Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook.
|
||||
Ook! Ook! 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í #}
|
||||
</pre>
|
||||
{% else %}
|
||||
<p>Ook!!</p>
|
||||
<p>(Ne, záznam o třídní knize vám nemohu dát jen tak. Zakazuje mi to <a href="https://www.zakonyprolidi.cz/cs/2019-110">Zákon č. 110/2019 Sb.</a> provádějící <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:32016R0679">nařízení EU 2016/679</a>.)</p>
|
||||
{% endif %}
|
||||
{% elif choice == "Uplatit knihovníka penězi" %}
|
||||
<p>Eek!</p>
|
||||
<p>(Že se nestydíte!)</p>
|
||||
{% elif choice == "Dát banán knihovníkovi" %}
|
||||
{% if tym.pocet_bananu != settings.POCET_BANANU %}
|
||||
<p>Eek.</p>
|
||||
<p>(Tenhle banán vypadá, jako by ve skladu ležel už několik let. Přineste mi jiný.)</p>
|
||||
{% else %}
|
||||
<p>Ook.</p>
|
||||
<p>(Potřebuji od vás povolení, které dostanete po zažádání na studijním oddělení.)</p>
|
||||
{% endif %}
|
||||
{% elif choice == "Ukázat knihovníkovi povolení k náhledu do záznamů o třídní knize" %}
|
||||
<p>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 <a href="https://www.bakalari.cz/">Bakaláře</a>“</p>
|
||||
<p>Gratulujeme k (ne)nalezení třídní knihy za {{ doba.den }} dní a {{ doba.hodina }} hodin!</p>
|
||||
{% elif choice == "Přelézt pult a sami si vzít záznamy o třídní knize" %}
|
||||
<p>Poslední, co si pamatujete je výkřik „Eek“ a hnědou šmouhu před očima. Pak už jen tma.</p>
|
||||
<p>Ani nevíte, jak dlouho jste tu leželi. Ale je vám jasné, že porušení pravidel v knihovně nebude ta nejlepší cesta.</p>
|
||||
{% elif choice == "Pokusit se sami projít kartotéku" %}
|
||||
<p>Po pěti hodinách hledání záznamů o třídní knize v kartotéce <a href="https://arxiv.org/">arXivu [archivu]</a>, kdy nacházíte jen samé od<abbr title="p">b</abbr>orné články, se smíříte s myšlenkou, že budete potřebovat pomoc od knihovníka.</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
52
hra/templates/hra/stanoviste/base.html
Normal file
52
hra/templates/hra/stanoviste/base.html
Normal file
|
@ -0,0 +1,52 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block script %}
|
||||
{% if not choice %}
|
||||
<script>
|
||||
function timeout() {
|
||||
if(confirm("Prosímvás, my tu nemáme čas jen na vás, zdržujete! **Další!** \n\n (Čas vypršel, načtěte QR kód znovu...) \n\n Přejete si odejít na úvodní stranu?")) {
|
||||
window.location = "{% url "tym" %}";
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(timeout, 1000 * {{ settings.TIMEOUT_STANOVISTE }});
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block nadpis %}{{ stanoviste.poradi }}/{{ settings.NEJVYSSI_INDEX }}: {{ stanoviste.nazev }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<hr>
|
||||
|
||||
{% with doba=tym.doba %}
|
||||
<h2>Den {{ doba.den }}, {{ doba.den_v_tydnu_zkratka }}, {{ doba.hodiny_minuty }} {{ doba.denni_doba }}</h2>
|
||||
{% endwith %}
|
||||
|
||||
<hr>
|
||||
|
||||
{{ stanoviste.poradi }}/{{ settings.NEJVYSSI_INDEX }}: {% if choice is not None %}({{ choice }}){% endif %}
|
||||
<h1>{{ stanoviste.nazev }}</h1>
|
||||
|
||||
{% block stanoviste_content %}
|
||||
<p>TODO!!!</p>
|
||||
{% endblock %}
|
||||
|
||||
<form action="" method="POST">
|
||||
{% csrf_token %}
|
||||
|
||||
{% for choice in choices %}
|
||||
<br> <br>
|
||||
<input type="submit" name="choice" value="{{ choice }}">
|
||||
|
||||
{# {% empty %}#}
|
||||
{# <br>#}
|
||||
{# <h2>Žádné akce k dispozici</h2>#}
|
||||
{# <p>Správně! Co můžete udělat dnes nenechávejte na zítřek.</p>#}
|
||||
{% endfor %}
|
||||
</form>
|
||||
|
||||
<p><a href="{% url "tym" %}">Stránka týmu</a></p>
|
||||
{% endblock %}
|
10
hra/templates/hra/stanoviste/casovy_vyr.html
Normal file
10
hra/templates/hra/stanoviste/casovy_vyr.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% extends "hra/stanoviste/base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block stanoviste_content %}
|
||||
{% if choice is None %}
|
||||
{{ stanoviste.verejny_text | safe }}
|
||||
{% else %}
|
||||
<p>Vžum! 🌪️</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
33
hra/templates/hra/stanoviste/domov.html
Normal file
33
hra/templates/hra/stanoviste/domov.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends "hra/stanoviste/base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block stanoviste_content %}
|
||||
{% if choice is None %}
|
||||
<p>Jste na svém pokoji. Co chcete dělat?</p>
|
||||
{% elif choice == "Vyzvednout poštu" %}
|
||||
{% for zadost in zadosti %}
|
||||
{% if forloop.first %}
|
||||
<p>Přišly odpovědi na následující žádosti:</p>
|
||||
<ul>
|
||||
{% endif %}
|
||||
<li>{{ zadost }} ({% if zadost.plati %}vyhověno{% elif zadost.typ == zadost.TYP_ZADOST %}nevyhověno, protože <a href="https://www.mff.cuni.cz/cs/studenti/formulare/spolecne/zadost-oboustranne-na-jeden-list">není čemu</a>, 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 %})</li>
|
||||
{% if forloop.last %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
Žádná pošta k vyzvednutí.
|
||||
{% endfor %}
|
||||
{% elif choice == "Spát" %}
|
||||
<p>Vyspali jste se do růžova. Dobré ráno 🌄</p>
|
||||
{% elif choice == "Vzít si chechtáky" %}
|
||||
<p>Vzali jste si nějaké peníze 💰, třeba se budou na něco hodit.</p>
|
||||
{% else %}
|
||||
{% if zadosti.0.vytistena %}
|
||||
<p>Vytiskli jste {{ zadosti.0 }}. Nyní ji můžete odeslat na poště.</p>
|
||||
{% else %}
|
||||
<p>Odeslali jste {{ zadosti.0|capfirst }} datovou schránkou.</p>
|
||||
|
||||
{% if zadosti.0.typ == zadost.TYP_TK and tym.vi_o_mesici %}{% if not doba.je_noc %}<p>(Není noc, takže měsíc nesvítí. Ale pojďme to zkusit.)</p>{% else %}{% if doba.pocasi != 0 %}<p>(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.)</p>{% if doba.den_mesice == 0 %}<p>(Ach jo, dnes je nov, takže měsíc nesvítí. Ale pojďme to zkusit.)</p>{% endif %}{% endif %}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
23
hra/templates/hra/stanoviste/menza.html
Normal file
23
hra/templates/hra/stanoviste/menza.html
Normal file
|
@ -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 %}
|
||||
<p>Na.</p>
|
||||
{% elif tym.pocet_bananu == 0 %}
|
||||
<p>Na banán nemáte nárok! Tumáte ovesnou kaši.</p>
|
||||
{% else %}
|
||||
<p>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.</p>
|
||||
{% endif %}
|
||||
{% elif choice == "Klábosit" %}
|
||||
<p>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ů.</p>
|
||||
<p>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ě.</p>
|
||||
<p>{{ doba.pocasi_text }}</p>
|
||||
<p>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.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
47
hra/templates/hra/stanoviste/posta.html
Normal file
47
hra/templates/hra/stanoviste/posta.html
Normal file
|
@ -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>Při pokusu o přiblížení k poště se na vás stařenka pořád vrhá. Přijďte později.</p>
|
||||
{% else %}
|
||||
{% if choice is None %}
|
||||
<p>Co si přejete?</p>
|
||||
{% elif choice == "Poslat vytištěné žádosti" %}
|
||||
{% for zadost in zadosti %}
|
||||
{% if forloop.first %}
|
||||
<p>Žádosti byly poslány. Až dojdou na studijní, budou vyřízeny a odpovědi budou poslány zpět.</p>
|
||||
<p>Poslali se následující žádosti.</p>
|
||||
<ul>
|
||||
{% endif %}
|
||||
<li>{{ 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 %}</li>
|
||||
{% if forloop.last %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<p>A to si myslíte, že pracujeme zadarmo?</p>
|
||||
{% endfor %}
|
||||
{% elif choice == "Zeptat se, zda pro nás mají dopis" %}
|
||||
{% for zadost in zadosti %}
|
||||
{% if forloop.first %}
|
||||
<p>Přišly odpovědi na následující žádosti:</p>
|
||||
<ul>
|
||||
{% endif %}
|
||||
<li>{{ zadost }} ({% if zadost.plati %}vyhověno{% elif zadost.typ == zadost.TYP_ZADOST %}nevyhověno, protože <a href="https://www.mff.cuni.cz/cs/studenti/formulare/spolecne/zadost-oboustranne-na-jeden-list">není čemu</a>, 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 %})</li>
|
||||
{% if forloop.last %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
Žádné dopisy k vyzvednutí.
|
||||
{% endfor %}
|
||||
{% elif choice == "Zažádat o datovou schránku" %}
|
||||
<p>Zažádali jste o datovou schránku. Než vám ale bylo odpovězeno, vrhla se na vás stařenka:</p>
|
||||
<p>„Sledují vás! Na každém kroku vás sledují! A vy je v tom chcete ještě podporovat!?“</p>
|
||||
<p>Nezbývá než počkat, až se uklidní (5h).</p>
|
||||
{% elif choice == "Zažádat o datovou schránku (šeptem)" %}
|
||||
<p>Zažádali jste o datovou schránku, tentokrát šeptem.</p>
|
||||
<p>Na pokladně se sice podivovali, proč šeptáte, ale datová schránka vám byla založena.</p>
|
||||
<p>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ě.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
27
hra/templates/hra/stanoviste/studijni.html
Normal file
27
hra/templates/hra/stanoviste/studijni.html
Normal file
|
@ -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 %}
|
||||
<p>Zavřeno.</p>
|
||||
{% elif doba.den_v_tydnu == 5 and doba.cas > 13 or doba.cas > 15 %}
|
||||
<p>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?</p>
|
||||
{% else %}
|
||||
{% if choice is None %}
|
||||
Co si přejete?
|
||||
{% elif choice == "Zeptat se na poslané žádosti" %}
|
||||
{% if zadosti|length != 0 %}
|
||||
<p>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ě.</p>
|
||||
{% else %}
|
||||
<p>Žádné žádosti nám ještě nepřišly. Ale znáte to, pošta…</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
Podali jste {{ zadosti.0|capfirst }}.
|
||||
|
||||
{% if zadosti.0.typ == zadost.TYP_TK and tym.vi_o_mesici %}{% if not doba.je_noc %}<p>(Není noc, takže měsíc nesvítí. Ale pojďme to zkusit.)</p>{% else %}{% if doba.pocasi != 0 %}<p>(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.)</p>{% if doba.den_mesice == 0 %}<p>(Ach jo, dnes je nov, takže měsíc nesvítí. Ale pojďme to zkusit.)</p>{% endif %}{% endif %}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
19
hra/templates/hra/staticke_stanoviste.html
Normal file
19
hra/templates/hra/staticke_stanoviste.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block prenacitani %} <meta http-equiv="refresh" content="60"> {% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{{ stanoviste.poradi }}/{{ settings.NEJVYSSI_INDEX }}:
|
||||
|
||||
<h1>{% block nadpis %}{{stanoviste.nazev}}{% endblock nadpis %}</h1>
|
||||
|
||||
{{ stanoviste.verejny_text | safe }}
|
||||
|
||||
{# https://stackoverflow.com/a/75157188 #}
|
||||
<img src="data:image/png;base64,{{image64}}" alt="Chyba, dojděte prosím pro Jidáše.">
|
||||
|
||||
{% if settings.DEBUG %}<p><a href="{{ url }}">{{ url }}</a></p>{% endif %}
|
||||
|
||||
{% endblock %}
|
12
hra/templates/hra/timeout.html
Normal file
12
hra/templates/hra/timeout.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% block nadpis %}Čas vypršel.{% endblock nadpis %}</h1>
|
||||
|
||||
<p>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!</p>
|
||||
|
||||
<p>(Načtěte qr kód znovu.)</p>
|
||||
|
||||
<p><a href="{% url "tym" %}">Stránka týmu</a></p>
|
||||
{% endblock %}
|
27
hra/templates/hra/tym.html
Normal file
27
hra/templates/hra/tym.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block prenacitani %}<meta http-equiv="refresh" content="{{ settings.TYM_AUTO_RELOAD }}">{% endblock %}
|
||||
|
||||
{% block nadpis %}Tým: {{tym.nazev}}{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1><span style="font-weight: normal">Hledači třídní knihy:</span> {{tym.nazev}}</h1>
|
||||
|
||||
{% if tym.ma_ds %}<p class="ds">(Datová schránka: rqritmr)</p>{% endif %}
|
||||
|
||||
<h2>Třídní kniha nalezena? {% if tym.tk_nalezena is not None %}✔️{% else %}❌{% endif %}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Den {{ doba.den }}, {{ doba.den_v_tydnu_zkratka }}, {{ doba.hodiny_minuty }} {{ doba.denni_doba }}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Inventář:</h2>
|
||||
|
||||
<div class="inventar">
|
||||
{% include "hra/inventar.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
16
hra/urls.py
Normal file
16
hra/urls.py
Normal file
|
@ -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/<int:stanoviste>/<str:my_hash>/", login_required(views.StanovisteZPohleduTymu.as_view()), name="tym"),
|
||||
path("timeout/", views.TimeoutViwe.as_view(), name="timeout"),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns.append(path("stanoviste/<int:stanoviste>/", views.StatickeStanovisteView.as_view(), name="stanoviste"),)
|
0
hra/utils/__init__.py
Normal file
0
hra/utils/__init__.py
Normal file
144
hra/utils/doba.py
Normal file
144
hra/utils/doba.py
Normal file
|
@ -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))
|
22
hra/utils/hash.py
Normal file
22
hra/utils/hash.py
Normal file
|
@ -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)
|
49
hra/utils/zadost.py
Normal file
49
hra/utils/zadost.py
Normal file
|
@ -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)
|
143
hra/views.py
Normal file
143
hra/views.py
Normal file
|
@ -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"
|
22
manage.py
Normal file
22
manage.py
Normal file
|
@ -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()
|
Loading…
Reference in a new issue