diff --git a/.gitignore b/.gitignore index 36b0b565..05e728bd 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,9 @@ TODO # .htpasswd kvůli přihlášení .htpasswd + +# reversion kvůli historii objektů v reversion +**/reversion + +# pro lidi, co programují v nástrojích od JetBrains +.idea \ No newline at end of file diff --git a/MIGRATIONS b/MIGRATIONS new file mode 100644 index 00000000..3cf73ac4 --- /dev/null +++ b/MIGRATIONS @@ -0,0 +1,187 @@ +Jak zvládnout migrace na nový model: + +- V mojí verzi databáze mají úlohy-Problémy typ "b'uloha'" + + +Log migrace na nový model: + +Operations to perform: + Apply all migrations: admin, auth, contenttypes, django_comments, flatpages, fluent_comments, galerie, korektury, prednasky, reversion, seminar, sessions, sites, sitetree, taggit, threadedcomments +Running migrations: + Applying admin.0003_logentry_add_action_flag_choices... OK + Applying auth.0009_alter_user_last_name_max_length... OK + Applying auth.0010_alter_group_name_max_length... OK + Applying auth.0011_update_proxy_permissions... OK + Applying galerie.0008_auto_20190430_2340... OK + Applying galerie.0009_auto_20190610_2358... OK + Applying galerie.0010_auto_20200819_0947... OK + Applying korektury.0016_auto_20190430_2340... OK + Applying korektury.0017_auto_20190610_2358... OK + Applying prednasky.0011_auto_20190430_2340... OK + Applying prednasky.0012_auto_20190610_2358... OK + Applying seminar.0049_auto_20190430_2354... OK + Applying seminar.0050_auto_20190510_2228... OK + Applying seminar.0051_resitel_to_osoba... OK + Applying seminar.0052_user_to_organizator... OK +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2004-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1998-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2017-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2017-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2014-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2011-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2013-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2004-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2013-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2012-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2007-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2011-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2009-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2009-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2008-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2005-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2015-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2001-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2010-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2008-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2006-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2002-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2005-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1999-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2003-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2000-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2002-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2001-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1996-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2000-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (1999-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (1996-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1994-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2012-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2016-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2018-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2014-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2019-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2006-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1995-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2007-12-31 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2015-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2016-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2018-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2019-01-01 00:00:00) while time zone support is active. + RuntimeWarning) +/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2020-01-01 00:00:00) while time zone support is active. + RuntimeWarning) + Applying seminar.0053_organizator_organizuje_od_do... OK + Applying seminar.0055_smazat_nemigrovane_zastarale_veci... OK + Applying seminar.0056_vrcholy_pro_rocniky_a_cisla... OK + Applying seminar.0057_reseni_to_reseni_hodnoceni...!!!!!!!!!!!!!!! +31397 Reseni object (31397) +!!!!!!!!!!!!!!! +!!!!!!!!!!!!!!! +31396 Reseni object (31396) +!!!!!!!!!!!!!!! +!!!!!!!!!!!!!!! +31395 Reseni object (31395) +!!!!!!!!!!!!!!! +!!!!!!!!!!!!!!! +31394 Reseni object (31394) +!!!!!!!!!!!!!!! +!!!!!!!!!!!!!!! +31393 Reseni object (31393) +!!!!!!!!!!!!!!! + OK + Applying seminar.0058_problem_to_uloha_tema_clanek... OK + Applying seminar.fix_0058... OK + Applying seminar.0059_vytvorit_pohadkanode... OK + Applying seminar.0060_spoj_stromy... OK + Applying seminar.0061_kill_frankenstein... OK + Applying seminar.0062_redukce_modelu_pohadky... OK + Applying seminar.0063_procisteni_migraci... OK + Applying seminar.0064_auto_20190610_2358... OK + Applying seminar.0065_treenode_polymorphic_ctype... OK + Applying seminar.0066_problem_polymorphic_ctype... OK + Applying seminar.0067_auto_20190814_0805... OK + Applying seminar.0068_treenode_nazev... OK + Applying seminar.0069_auto_20191120_2115... OK + Applying seminar.0070_auto_20191120_2357... OK + Applying seminar.0071_remove_nastaveni_aktualni_rocnik... OK + Applying seminar.0072_auto_20191204_2257... OK + Applying seminar.0073_copy_osoba_email_to_user_email... OK + Applying seminar.0074_auto_20200228_1401... OK + Applying seminar.0075_auto_20200228_2010... OK + Applying seminar.0076_auto_20200228_2013... OK + Applying seminar.0077_auto_20200318_2146... OK + Applying seminar.0078_otistenereseninode... OK + Applying seminar.0079_clanek_resitelsky... OK + Applying seminar.0080_zruseni_claneknode_a_konferanode... OK + Applying seminar.0081_auto_20200408_2221... OK + Applying seminar.0082_auto_20200506_1951... OK + Applying seminar.0083_auto_20200506_1952... OK +WARNING 2020-08-20 00:49:07,941 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2215) +WARNING 2020-08-20 00:49:07,953 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2221) +WARNING 2020-08-20 00:49:07,959 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2212) +WARNING 2020-08-20 00:49:07,965 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1955) +WARNING 2020-08-20 00:49:07,968 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2027) +WARNING 2020-08-20 00:49:07,971 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1981) +WARNING 2020-08-20 00:49:07,974 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1970) +WARNING 2020-08-20 00:49:07,978 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2001) +WARNING 2020-08-20 00:49:07,981 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2004) +WARNING 2020-08-20 00:49:07,984 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1941) +WARNING 2020-08-20 00:49:07,990 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2024) +WARNING 2020-08-20 00:49:07,993 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2031) +WARNING 2020-08-20 00:49:07,997 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2211) +WARNING 2020-08-20 00:49:08,005 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2073) +WARNING 2020-08-20 00:49:08,017 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2018) +WARNING 2020-08-20 00:49:08,022 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2222) +WARNING 2020-08-20 00:49:08,028 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1953) +WARNING 2020-08-20 00:49:08,034 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2026) + Applying seminar.0084_clanek_cislo... OK + Applying seminar.0085_nepovinna_prezdivka... OK + Applying seminar.0086_auto_20200819_0959... OK + Applying sitetree.0001_initial... OK + Applying taggit.0003_taggeditem_add_unique_index... OK + diff --git a/Makefile b/Makefile index 49e0cde9..a26162ba 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,9 @@ all: # . ${VENV_PATH}/bin/activate # make install_web # + # Pokud install_web říká Error: pg_config executable not found. nainstaluj si libpq-dev + # Pokud chybová hláška obsahuje #include , nainstaluj si python3-dev + # # Až skončíš s vývojem webu, spusť "deactivate". Tím zmizí '(${VENV_PATH})' ze začátku promptu. venv_check: @@ -64,7 +67,7 @@ schema_all.pdf: venv_check # Deploy to current *mamweb-test* directory deploy_test: venv_check @if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi - @if [ `pwd` != "/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi + @if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-test" ]; then echo "Only possible in directory mamweb-test"; exit 1; fi @echo "Installing version from origin/test ..." git pull origin test git clean -f @@ -80,9 +83,9 @@ deploy_test: venv_check # Deploy to current *mamweb-prod* directory deploy_prod: venv_check @if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi - @if [ `pwd` != "/akce/mam/www/mamweb-prod" ]; then echo "Only possible in /akce/mam/www/mamweb-prod"; exit 1; fi + @if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-prod" ]; then echo "Only possible in directory mamweb-prod"; exit 1; fi @echo "Backing up production DB ..." - ( cd .. && ./backup_prod_db.sh ) + ( cd -P .. && ./backup_prod_db.sh ) @echo "Installing version from origin/master ..." git pull origin master git clean -f @@ -108,7 +111,7 @@ sync_prod_flatpages: venv_check # Sync test media directory with production sync_test_media: @if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi - @if [ `pwd` != "/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi + @if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi rsync -av --delete /akce/mam/www/mamweb-prod/media/ ./media # Sync test database with production database diff --git a/flat.json b/data/flat.json similarity index 98% rename from flat.json rename to data/flat.json index 7c201dcf..644129e0 100644 --- a/flat.json +++ b/data/flat.json @@ -93,7 +93,7 @@ "model": "flatpages.flatpage", "pk": 7, "fields": { - "url": "/co-je-MaM/jak-resit/", + "url": "/jak-resit/", "title": "Jak \u0159e\u0161it?", "content": "

\u010c\u00edm se n\u00e1\u0161 semin\u00e1\u0159 li\u0161\u00ed od v\u011bt\u0161iny ostatn\u00edch sout\u011b\u017e\u00ed, jsou p\u0159\u00edsp\u011bvkov\u00e1 t\u00e9mata. Jedn\u00e1 se o simulaci v\u011bdeck\u00e9 pr\u00e1ce ve smyslu, \u017ee zad\u00e1me jist\u00fd okruh probl\u00e9m\u016f, nad kter\u00fdm m\u016f\u017ee\u0161 n\u00e1sleduj\u00edc\u00ed rok b\u00e1dat. O v\u00fdsledky sv\u00e9 pr\u00e1ce se pak pod\u011bl\u00ed\u0161 s n\u00e1mi a s ostatn\u00edmi \u0159e\u0161iteli a my tvou pr\u00e1ci ohodnot\u00edme. V ka\u017ed\u00e9 s\u00e9rii b\u00fdvaj\u00ed t\u00e9mata roz\u0161i\u0159ov\u00e1na, nav\u00edc jsou n\u011bkter\u00e9 zadan\u00e9 probl\u00e9my omezeny term\u00ednem odesl\u00e1n\u00ed, proto je pot\u0159eba sv\u00e9 v\u00fdsledky pos\u00edlat u\u017e pr\u016fb\u011b\u017en\u011b. Na ka\u017ed\u00fd ro\u010dn\u00edk t\u00e9mat vypisujeme p\u011bt a\u017e \u0161est.

\r\n\r\n

\u0158e\u0161en\u00ed, kter\u00e9 n\u00e1m po\u0161le\u0161, m\u016f\u017ee b\u00fdt dvou r\u016fzn\u00fdch typ\u016f:

\r\n\r\n

\u00dalohy

\r\n\r\n

V r\u00e1mci ka\u017ed\u00e9ho t\u00e9matu b\u00fdv\u00e1 zad\u00e1na jedna nebo dv\u011b men\u0161\u00ed \u00falohy, kter\u00e9 dan\u00fd probl\u00e9m ur\u010dit\u00fdm zp\u016fsobem rozv\u00edj\u00ed. Tyto \u00falohy b\u00fdvaj\u00ed trochu t\u011b\u017e\u0161\u00ed ne\u017e obvykl\u00e9 \u0161koln\u00ed, jejich \u0159e\u0161en\u00ed \u010dasto vy\u017eaduje bu\u010f hlub\u0161\u00ed zamy\u0161len\u00ed nebo n\u011bjak\u00fd trik. St\u0159edo\u0161kolsk\u00e9 znalosti by na n\u011b ale m\u011bly sta\u010dit. Odevzd\u00e1v\u00e1n\u00ed \u00faloh se omezuje term\u00ednem odesl\u00e1n\u00ed, pot\u00e9 b\u00fdv\u00e1 zve\u0159ejn\u011bno vzorov\u00e9 \u0159e\u0161en\u00ed. U ka\u017ed\u00e9 \u00falohy je uveden po\u010det bod\u016f za spr\u00e1vn\u00e9 \u0159e\u0161en\u00ed. P\u0159im\u011b\u0159enou \u010d\u00e1st z t\u011bchto bod\u016f lze z\u00edskat i za ne\u00fapln\u00e9 \u0159e\u0161en\u00ed. A naopak za velmi zaj\u00edmav\u00e9 nebo elegantn\u00ed \u0159e\u0161en\u00ed m\u016f\u017ee\u0161 dostat i bodovou pr\u00e9mii.

\r\n\r\n

\u010cl\u00e1nky

\r\n\r\n

Syst\u00e9m t\u00e9mat poskytuje p\u0159\u00edle\u017eitost pro podrobn\u011bj\u0161\u00ed rozbor dan\u00e9ho okruhu probl\u00e9m\u016f. V\u00fdsledek takov\u00e9 pr\u00e1ce v\u0161ak vy\u017eaduje o n\u011bco v\u00edc prostoru ne\u017eli klasick\u00e9 \u0159e\u0161en\u00ed, proto je tv\u00fdm \u00fakolem napsat \u010dl\u00e1nek zab\u00fdvaj\u00edc\u00ed se probl\u00e9mem, kter\u00fd sis vybral. M\u016f\u017ee to b\u00fdt z\u00e1znam o proveden\u00e9m experimentu, teoretick\u00e9m v\u00fdpo\u010dtu \u010di \u00favaze, napsan\u00e9m programu \u010di o dal\u0161\u00edch (podle tebe zaj\u00edmav\u00fdch) ot\u00e1zk\u00e1ch z dan\u00e9ho okruhu. 

\r\n\r\n

Jak na to?

\r\n\r\n

Vy\u0159e\u0161 podprobl\u00e9m

\r\n\r\n

Vyber si n\u011bkter\u00fd z navrhovan\u00fdch podprobl\u00e9m\u016f, kter\u00fdm se chce\u0161 zab\u00fdvat, p\u0159\u00edpadn\u011b si navrhni podprobl\u00e9m vlastn\u00ed (to b\u00fdv\u00e1 ohodnoceno bodov\u00fdm bonusem). Podprobl\u00e9m pak vy\u0159e\u0161 podobn\u011b jako \u00falohu z \u010d\u00edsla. Podrobn\u00e9 \u0159e\u0161en\u00ed n\u011bkter\u00e9ho z podprobl\u00e9m\u016f bude bodov\u011b hodnoceno v\u00fdrazn\u011b l\u00e9pe ne\u017e souhrnn\u00fd \u010dl\u00e1nek kr\u00e1tce zmi\u0148uj\u00edc\u00ed kdeco. I \u010d\u00e1ste\u010dn\u00e9 \u0159e\u0161en\u00ed je lep\u0161\u00ed ne\u017e \u017e\u00e1dn\u00e9. Sv\u00e9 \u0159e\u0161en\u00ed pak hezky sepi\u0161, aby m\u011blo formu \u010dl\u00e1nku, a \u010dl\u00e1nek n\u00e1m po\u0161li. Vedouc\u00ed t\u00e9matu ho pak ohodnot\u00ed, p\u0159\u00edpadn\u011b zkoriguje a publikuje na webu \u010di dokonce v \u010d\u00edsle. \u010c\u00edm bl\u00ed\u017ee bude forma tv\u00e9ho p\u0159\u00edsp\u011bvku publikovateln\u00e9mu \u010dl\u00e1nku, t\u00edm lep\u0161\u00edho bodov\u00e9ho ohodnocen\u00ed dos\u00e1hne\u0161. Moder\u00e1tor t\u00e9matu ho pak ohodnot\u00ed, p\u0159\u00edpadn\u011b zkoriguje a publikuje na webu \u010di dokonce v \u010d\u00edsle. \u010c\u00edm bl\u00ed\u017ee bude forma tv\u00e9ho p\u0159\u00edsp\u011bvku publikovateln\u00e9mu \u010dl\u00e1nku, t\u00edm lep\u0161\u00edho bodov\u00e9ho ohodnocen\u00ed dos\u00e1hne\u0161.

\r\n\r\n

Inspiruj se

\r\n\r\n

Velmi d\u016fle\u017eitou vlastnost\u00ed t\u00e9mat je, \u017ee m\u016f\u017ee\u0161 na \u010dl\u00e1nky ostatn\u00edch reagovat \u2013 rozv\u00edjet je, nebo naopak bo\u0159it jejich p\u0159edstavy. Proto se hod\u00ed poslat tak\u00e9 \u010d\u00e1ste\u010dn\u00e1 \u0159e\u0161en\u00ed, post\u0159ehy, nebo n\u00e1pady na dal\u0161\u00ed podprobl\u00e9my, kter\u00e9 t\u0159eba nezvl\u00e1dne\u0161 vy\u0159e\u0161it s\u00e1m. Takov\u00e9to p\u0159\u00edsp\u011bvky d\u00e1vaj\u00ed prostor ostatn\u00edm a mohou je d\u00e1l inspirovat \u2013 ostatn\u00ed zase sv\u00fdmi p\u0159\u00edsp\u011bvky mohou inspirovat tebe.

\r\n\r\n

Proto\u017ee v\u00edc hlav v\u00edc v\u00ed, m\u016f\u017eete na t\u00e9matech pracovat i ve skupin\u00e1ch.

\r\n\r\n\r\n

Nad n\u00e1pady k t\u00e9mat\u016fm m\u016f\u017ee\u0161 p\u0159em\u00fd\u0161let cel\u00fd rok a\u017e do term\u00ednu odevzd\u00e1n\u00ed posledn\u00ed s\u00e9rie \u00faloh. Samoz\u0159ejm\u011b, \u010d\u00edm d\u0159\u00edve n\u00e1m \u010dl\u00e1nek po\u0161le\u0161, t\u00edm d\u0159\u00edve na n\u011bj ostatn\u00ed budou moci zareagovat.

\r\n\r\n

Pi\u0161 hezk\u00e9 \u010dl\u00e1nky

\r\n\r\n

\u010cl\u00e1nek k t\u00e9matu by m\u011bl po obsahov\u00e9 a form\u00e1ln\u00ed str\u00e1nce odpov\u00eddat v\u011bdeck\u00e9mu \u010dl\u00e1nku. M\u016f\u017ee\u0161 se pod\u00edvat na stru\u010dn\u00fd p\u0159ehled toho, jak by m\u011bl takov\u00fd v\u011bdeck\u00fd \u010dl\u00e1nek vypadat.

\r\n\r\n

Pro\u010d t\u00e9mata?

\r\n\r\n

T\u00e9mata vytv\u00e1\u0159ej\u00ed prostor pro vlastn\u00ed tv\u016fr\u010d\u00ed (\u010dasto v\u011bdeckou) \u010dinnost, jej\u00edm\u017e smyslem je krom jin\u00e9ho p\u0159in\u00e9st ostatn\u00edm \u0159e\u0161itel\u016fm nov\u00e9 podn\u011bty a inspirovat je k dal\u0161\u00edm n\u00e1pad\u016fm. Krom\u011b samotn\u00e9ho b\u00e1d\u00e1n\u00ed je d\u016fle\u017eit\u00e1 i komunikace mezi lidmi, kter\u00e1 je obvykle zprost\u0159edkov\u00e1na odborn\u00fdmi \u010dasopisy a v\u011bdeck\u00fdmi konferencemi. \u010casopis M&M je ur\u010den pr\u00e1v\u011b pro p\u00edsemnou komunikaci. \u00dastn\u00ed formu prezentace si m\u016f\u017ee\u0161 vyzkou\u0161et na na\u0161em soust\u0159ed\u011bn\u00ed, kde se tradi\u010dn\u011b kon\u00e1 mal\u00e1 v\u011bdeck\u00e1 konference.

\r\n\r\n

Jak poslat \u0159e\u0161en\u00ed

\r\n\r\n

Sv\u00e1 \u0159e\u0161en\u00ed m\u016f\u017ee\u0161 poslat bu\u010f elektronicky na n\u00e1\u0161 e-mail mam@matfyz.cz, nebo po\u0161tou na na\u0161i adresu. Pokud pot\u0159ebuje\u0161 k \u0159e\u0161en\u00ed p\u0159ilo\u017eit n\u011bjak\u00fd hodn\u011b velk\u00fd soubor, pou\u017eij n\u011bkterou voln\u011b dostupnou slu\u017ebu pro sd\u00edlen\u00ed soubor\u016f (DropboxGoogle Drive, \u2026) nebo n\u00e1s kontaktuj na e-mailu mam@matfyz.cz a p\u0159ed\u00e1n\u00ed domluv\u00edme.

\r\n\r\n

Pokud pos\u00edl\u00e1\u0161 \u0159e\u0161en\u00ed elektronicky, v\u011bz, \u017ee n\u00e1s daleko v\u00edce pot\u011b\u0161\u00ed pdfko s textem ne\u017e vyfocen\u00e9 ru\u010dn\u011b psan\u00e9 \u0159e\u0161en\u00ed. Ka\u017edou \u00falohu pros\u00edm po\u0161li v samostatn\u00e9m souboru resp. na samostatn\u00e9m list\u011b A4, aby si \u00falohy mohli rozd\u011blit r\u016fzn\u00ed opravuj\u00edc\u00ed. Na ka\u017ed\u00fd list uve\u010f svoje jm\u00e9no a \u010d\u00edslo \u00falohy \u010di t\u00e9matu. Na tvou po\u0161tovn\u00ed adresu ti pak budou zdarma chodit dal\u0161\u00ed \u010d\u00edsla na\u0161eho \u010dasopisu.

\r\n\r\n

Ke sv\u00e9mu prvn\u00edmu \u0159e\u0161en\u00ed p\u0159ilo\u017e pros\u00edm tak\u00e9 sv\u00e9 jm\u00e9no, adresu, e-mail, \u0161kolu a rok maturity. Pokud chce\u0161 jet na soust\u0159ed\u011bn\u00ed, uve\u010f pros\u00edm i telefon. A neboj, tyto \u00fadaje budeme vyu\u017e\u00edvat pouze pro pot\u0159eby M&M. Mimo \u00fadaj\u016f na v\u00fdsledkov\u00e9 listin\u011b (jm\u00e9no, \u0161kola, ro\u010dn\u00edk) je nebudeme nikde zve\u0159ej\u0148ovat.

\r\n", "enable_comments": false, @@ -125,7 +125,7 @@ "fields": { "url": "/soustredeni/", "title": "Informace", - "content": "

Pro na\u0161e nejlep\u0161\u00ed \u0159e\u0161itele po\u0159\u00e1d\u00e1me dvakr\u00e1t do roka t\u00fddenn\u00ed soust\u0159ed\u011bn\u00ed pln\u00e9 odborn\u00e9ho programu i nejr\u016fzn\u011bj\u0161\u00ed z\u00e1bavy.

\r\n\r\n\r\n

Pro\u010d jet na soust\u0159ed\u011bn\u00ed?

\r\n\r\n

P\u0159edn\u00e1\u0161ky

\r\n\r\n

V\u011bt\u0161inou t\u011b ka\u017ed\u00fd den \u010dekaj\u00ed dv\u011b devades\u00e1timinutov\u00e9 p\u0159edn\u00e1\u0161ky. Vybrat si obvykle m\u016f\u017ee\u0161 mezi matematikou, fyzikou a informatikou, proto\u017ee se konaj\u00ed t\u0159i p\u0159edn\u00e1\u0161ky z\u00e1rove\u0148. N\u011bkter\u00e9 p\u0159edn\u00e1\u0161ky jsou leh\u010d\u00ed, jin\u00e9 t\u011b\u017e\u0161\u00ed, obecn\u011b je ale jejich \u00farove\u0148 vhodn\u00e1 pr\u00e1v\u011b pro zv\u00eddav\u00e9 st\u0159edo\u0161kol\u00e1ky. P\u0159edn\u00e1\u0161\u00edme jak klasick\u00e1 t\u00e9mata, tak t\u00e9mata nev\u0161edn\u00ed, z\u00e1kulisn\u00ed \u010di dokonce obskurn\u00ed. Kdy\u017e bude\u0161 organiz\u00e1tory hodn\u011b prosit, mo\u017en\u00e1 se dostane i na n\u011bjakou \u010dernou magii!

\r\n\r\n

Krom toho p\u0159edn\u00e1\u0161\u00edme i na po\u017e\u00e1d\u00e1n\u00ed \u2013 sta\u010d\u00ed, kdy\u017e si vybere\u0161 t\u00e9ma, kter\u00e9 t\u011b zaj\u00edm\u00e1, a oslov\u00ed\u0161 toho spr\u00e1vn\u00e9ho organiz\u00e1tora.

\r\n\r\n

Lid\u00e9

\r\n\r\n

Pozn\u00e1\u0161 lidi, pro kter\u00e9 je p\u0159em\u00fd\u0161len\u00ed obl\u00edbenou \u010dinnost\u00ed a pro kter\u00e9 matematika nen\u00ed sprost\u00e9 slovo. P\u0159edev\u0161\u00edm to jsou ale lidi, kte\u0159\u00ed se r\u00e1di bav\u00ed a se kter\u00fdmi si u\u017eije\u0161 mnoho legrace u j\u00eddla, b\u011bhem her, na v\u00fdlet\u011b, jen tak, p\u0159i hran\u00ed na kytaru nebo p\u0159i \u0161ar\u00e1d\u011bn\u00ed (pokud nev\u00ed\u0161, co tohle slovo znamen\u00e1, je na \u010dase to zjistit!).

\r\n\r\n

Konfery

\r\n\r\n

Konfery jsou na\u0161\u00ed specialitou. Ve skupin\u011b \u00fa\u010dastn\u00edk\u016f a pod veden\u00edm zku\u0161en\u00e9ho organiz\u00e1tora m\u016f\u017ee\u0161 zkusit pracovat na zadan\u00e9m probl\u00e9mu a v\u00fdsledky pak ostatn\u00edm prezentovat na mal\u00e9 v\u011bdeck\u00e9 konferenci. Pr\u00e1ce na konfe\u0159e je velmi podobn\u00e1 skute\u010dn\u00e9 v\u011bdeck\u00e9 pr\u00e1ci. M\u00e1me za sebou nap\u0159\u00edklad stavbu katapultu, po\u010d\u00edta\u010dovou synt\u00e9zu zvuku \u010di tropickou geometrii.

\r\n\r\n

Hry

\r\n\r\n

M\u00e1me pro tebe p\u0159ipravenou celou \u0159adu denn\u00edch i no\u010dn\u00edch her, uvnit\u0159 i venku, strategick\u00fdch i ak\u010dn\u00edch. A n\u011bkdy tohle v\u0161echno dohromady. Chceme, aby sis mohl/a zkusit \u010dinnosti, ke kter\u00fdm se b\u011b\u017en\u011b nedostane\u0161. St\u0159elba z luku, lezen\u00ed po skal\u00e1ch, slackline \u010di celono\u010dn\u00ed \u0161ifrova\u010dka? Nen\u00ed probl\u00e9m!

\r\n\r\n

Legenda

\r\n\r\n

Ka\u017ed\u00e9 soust\u0159ed\u011bn\u00ed m\u00e1 sv\u00e9 vlastn\u00ed prost\u0159ed\u00ed \u010di p\u0159\u00edb\u011bh, kter\u00fd j\u00edm prov\u00e1z\u00ed. U\u017e jsme byli ve starov\u011bk\u00e9m \u0158ecku \u010di pod podlahou obcho\u010f\u00e1ku, cestovali jsme \u010dasem a tak\u00e9 jsme bojovali s krvela\u010dn\u00fdmi zmutovan\u00fdmi tule\u0148\u00e1tky, kter\u00e1 se nakonec uk\u00e1zala b\u00fdt filma\u0159sk\u00fdm trikem. Co n\u00e1s \u010dek\u00e1 p\u0159\u00ed\u0161t\u011b?

\r\n\r\n

Absence ve \u0161kole

\r\n\r\n

Ne\u017e pojede\u0161 na soust\u0159ed\u011bn\u00ed, po\u0161leme ti ofici\u00e1ln\u00ed omluvenku od MFF UK. Jeliko\u017e je soust\u0159ed\u011bn\u00ed pln\u00e9 odborn\u00e9ho programu, v\u011bt\u0161ina \u0161kol na\u0161e \u0159e\u0161itele bez probl\u00e9mu uvol\u0148uje. N\u011bkter\u00e9 \u0161koly dokonce \u00fa\u010dast na soust\u0159ed\u011bn\u00ed nezapo\u010d\u00edt\u00e1vaj\u00ed do absence. V\u017edy je ale dobr\u00e9 se informovat, jak \u00fa\u010dast na podobn\u00fdch akc\u00edch \u0159e\u0161\u00ed tvoje \u0161kola, a p\u0159\u00edpadn\u011b se osobn\u011b domluvit s \u0159editelem \u010di \u0159editelkou.

\r\n\r\n

Kapacita soust\u0159ed\u011bn\u00ed

\r\n\r\n

Proto\u017ee chceme zachovat p\u0159\u00e1telskou a komorn\u00ed atmosf\u00e9ru soust\u0159ed\u011bn\u00ed, zveme na soust\u0159ed\u011bn\u00ed zhruba dvacet nej\u00fasp\u011b\u0161n\u011bj\u0161\u00edch \u0159e\u0161itel\u016f koresponden\u010dn\u00edho semin\u00e1\u0159e. N\u011bkolik dal\u0161\u00edch \u0159e\u0161itel\u016f zveme jako n\u00e1hradn\u00edky pro p\u0159\u00edpad, \u017ee by n\u011bkte\u0159\u00ed pozvan\u00ed nemohli. Pokud t\u011b na soust\u0159ed\u011bn\u00ed nepozveme, nezoufej a zkus v p\u0159\u00ed\u0161t\u00edm p\u016flroce v\u00edc \u0159e\u0161it t\u00e9mata. Dostat se mezi nejlep\u0161\u00edch dvacet \u0159e\u0161itel\u016f je s trochou p\u00edle hra\u010dka.

\r\n\r\n

 

\r\n", + "content": "

Pro na\u0161e nejlep\u0161\u00ed \u0159e\u0161itele po\u0159\u00e1d\u00e1me dvakr\u00e1t do roka t\u00fddenn\u00ed soust\u0159ed\u011bn\u00ed pln\u00e9 odborn\u00e9ho programu i nejr\u016fzn\u011bj\u0161\u00ed z\u00e1bavy.

\r\n\r\n\r\n

Pro\u010d jet na soust\u0159ed\u011bn\u00ed?

\r\n\r\n

P\u0159edn\u00e1\u0161ky

\r\n\r\n

V\u011bt\u0161inou t\u011b ka\u017ed\u00fd den \u010dekaj\u00ed dv\u011b devades\u00e1timinutov\u00e9 p\u0159edn\u00e1\u0161ky. Vybrat si obvykle m\u016f\u017ee\u0161 mezi matematikou, fyzikou a informatikou, proto\u017ee se konaj\u00ed t\u0159i p\u0159edn\u00e1\u0161ky z\u00e1rove\u0148. N\u011bkter\u00e9 p\u0159edn\u00e1\u0161ky jsou leh\u010d\u00ed, jin\u00e9 t\u011b\u017e\u0161\u00ed, obecn\u011b je ale jejich \u00farove\u0148 vhodn\u00e1 pr\u00e1v\u011b pro zv\u00eddav\u00e9 st\u0159edo\u0161kol\u00e1ky. P\u0159edn\u00e1\u0161\u00edme jak klasick\u00e1 t\u00e9mata, tak t\u00e9mata nev\u0161edn\u00ed, z\u00e1kulisn\u00ed \u010di dokonce obskurn\u00ed. Kdy\u017e bude\u0161 organiz\u00e1tory hodn\u011b prosit, mo\u017en\u00e1 se dostane i na n\u011bjakou \u010dernou magii!

\r\n\r\n

Krom toho p\u0159edn\u00e1\u0161\u00edme i na po\u017e\u00e1d\u00e1n\u00ed \u2013 sta\u010d\u00ed, kdy\u017e si vybere\u0161 t\u00e9ma, kter\u00e9 t\u011b zaj\u00edm\u00e1, a oslov\u00ed\u0161 toho spr\u00e1vn\u00e9ho organiz\u00e1tora.

\r\n\r\n

Lid\u00e9

\r\n\r\n

Pozn\u00e1\u0161 lidi, pro kter\u00e9 je p\u0159em\u00fd\u0161len\u00ed obl\u00edbenou \u010dinnost\u00ed a pro kter\u00e9 matematika nen\u00ed sprost\u00e9 slovo. P\u0159edev\u0161\u00edm to jsou ale lidi, kte\u0159\u00ed se r\u00e1di bav\u00ed a se kter\u00fdmi si u\u017eije\u0161 mnoho legrace u j\u00eddla, b\u011bhem her, na v\u00fdlet\u011b, jen tak, p\u0159i hran\u00ed na kytaru nebo p\u0159i \u0161ar\u00e1d\u011bn\u00ed (pokud nev\u00ed\u0161, co tohle slovo znamen\u00e1, je na \u010dase to zjistit!).

\r\n\r\n

Konfery

\r\n\r\n

Konfery jsou na\u0161\u00ed specialitou. Ve skupin\u011b \u00fa\u010dastn\u00edk\u016f a pod veden\u00edm zku\u0161en\u00e9ho organiz\u00e1tora m\u016f\u017ee\u0161 zkusit pracovat na zadan\u00e9m probl\u00e9mu a v\u00fdsledky pak ostatn\u00edm prezentovat na mal\u00e9 v\u011bdeck\u00e9 konferenci. Pr\u00e1ce na konfe\u0159e je velmi podobn\u00e1 skute\u010dn\u00e9 v\u011bdeck\u00e9 pr\u00e1ci. M\u00e1me za sebou nap\u0159\u00edklad stavbu katapultu, po\u010d\u00edta\u010dovou synt\u00e9zu zvuku \u010di tropickou geometrii.

\r\n\r\n

Hry

\r\n\r\n

M\u00e1me pro tebe p\u0159ipravenou celou \u0159adu denn\u00edch i no\u010dn\u00edch her, uvnit\u0159 i venku, strategick\u00fdch i ak\u010dn\u00edch. A n\u011bkdy tohle v\u0161echno dohromady. Chceme, aby sis mohl/a zkusit \u010dinnosti, ke kter\u00fdm se b\u011b\u017en\u011b nedostane\u0161. St\u0159elba z luku, lezen\u00ed po skal\u00e1ch, slackline \u010di celono\u010dn\u00ed \u0161ifrova\u010dka? Nen\u00ed probl\u00e9m!

\r\n\r\n

Legenda

\r\n\r\n

Ka\u017ed\u00e9 soust\u0159ed\u011bn\u00ed m\u00e1 sv\u00e9 vlastn\u00ed prost\u0159ed\u00ed \u010di p\u0159\u00edb\u011bh, kter\u00fd j\u00edm prov\u00e1z\u00ed. U\u017e jsme byli ve starov\u011bk\u00e9m \u0158ecku \u010di pod podlahou obcho\u010f\u00e1ku, cestovali jsme \u010dasem a tak\u00e9 jsme bojovali s krvela\u010dn\u00fdmi zmutovan\u00fdmi tule\u0148\u00e1tky, kter\u00e1 se nakonec uk\u00e1zala b\u00fdt filma\u0159sk\u00fdm trikem. Co n\u00e1s \u010dek\u00e1 p\u0159\u00ed\u0161t\u011b?

\r\n\r\n

Absence ve \u0161kole

\r\n\r\n

Ne\u017e pojede\u0161 na soust\u0159ed\u011bn\u00ed, po\u0161leme ti ofici\u00e1ln\u00ed omluvenku od MFF UK. Jeliko\u017e je soust\u0159ed\u011bn\u00ed pln\u00e9 odborn\u00e9ho programu, v\u011bt\u0161ina \u0161kol na\u0161e \u0159e\u0161itele bez probl\u00e9mu uvol\u0148uje. N\u011bkter\u00e9 \u0161koly dokonce \u00fa\u010dast na soust\u0159ed\u011bn\u00ed nezapo\u010d\u00edt\u00e1vaj\u00ed do absence. V\u017edy je ale dobr\u00e9 se informovat, jak \u00fa\u010dast na podobn\u00fdch akc\u00edch \u0159e\u0161\u00ed tvoje \u0161kola, a p\u0159\u00edpadn\u011b se osobn\u011b domluvit s \u0159editelem \u010di \u0159editelkou.

\r\n\r\n

Kapacita soust\u0159ed\u011bn\u00ed

\r\n\r\n

Proto\u017ee chceme zachovat p\u0159\u00e1telskou a komorn\u00ed atmosf\u00e9ru soust\u0159ed\u011bn\u00ed, zveme na soust\u0159ed\u011bn\u00ed zhruba dvacet nej\u00fasp\u011b\u0161n\u011bj\u0161\u00edch \u0159e\u0161itel\u016f koresponden\u010dn\u00edho semin\u00e1\u0159e. N\u011bkolik dal\u0161\u00edch \u0159e\u0161itel\u016f zveme jako n\u00e1hradn\u00edky pro p\u0159\u00edpad, \u017ee by n\u011bkte\u0159\u00ed pozvan\u00ed nemohli. Pokud t\u011b na soust\u0159ed\u011bn\u00ed nepozveme, nezoufej a zkus v p\u0159\u00ed\u0161t\u00edm p\u016flroce v\u00edc \u0159e\u0161it t\u00e9mata. Dostat se mezi nejlep\u0161\u00edch dvacet \u0159e\u0161itel\u016f je s trochou p\u00edle hra\u010dka.

\r\n\r\n

 

\r\n", "enable_comments": false, "template_name": "", "registration_required": false, @@ -260,7 +260,7 @@ "fields": { "url": "/co-je-MaM/kontakt/", "title": "Kontakt", - "content": "

Sv\u00e1 \u0159e\u0161en\u00ed \u010di p\u0159\u00edpadn\u00e9 dotazy n\u00e1m m\u016f\u017eete pos\u00edlat bu\u010f klasickou, nebo elektronickou po\u0161tou:

\r\n\r\n\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n
\r\n\t\t\t

Adresa redakce:

\r\n\r\n\t\t\t

M&M, OPMK MFF UK
\r\n\t\t\tKe Karlovu 3
\r\n\t\t\t121 16 Praha 2

\r\n\t\t\t
\r\n\t\t\t

E-mailmam@matfyz.cz

\r\n\r\n\t\t\t

Facebook: Koresponden\u010dn\u00ed semin\u00e1\u0159 M&M

\r\n\r\n\t\t\t

Google Kalend\u00e1\u0159: casopis.mam@gmail.com

\r\n\t\t\t
\r\n\r\n

 

\r\n\r\n

B\u011bhem \u0161koln\u00edho roku je velk\u00e1 \u010d\u00e1st organiz\u00e1tor\u016f k zasti\u017een\u00ed na koleji 17. listopadu \u010di jinde po Praze.

\r\n\r\n

Adresa koleje:

\r\n\r\n

P\u00e1tkova 3
\r\n182 00, Praha 8

", + "content": "

Sv\u00e1 \u0159e\u0161en\u00ed \u010di p\u0159\u00edpadn\u00e9 dotazy n\u00e1m m\u016f\u017eete pos\u00edlat bu\u010f klasickou, nebo elektronickou po\u0161tou:

\r\n\r\n

Adresa redakce:

\r\n\r\n

M&M, OPMK MFF UK
\r\nKe Karlovu 3
\r\n121 16 Praha 2

\r\n\r\n

E-mail: mam@matfyz.cz

\r\n\r\n

 

\r\n\r\n

Facebook: Koresponden\u010dn\u00ed semin\u00e1\u0159 M&M

\r\n\r\n

Google Kalend\u00e1\u0159: casopis.mam@gmail.com

\r\n\r\n

 

\r\n\r\n

B\u011bhem \u0161koln\u00edho roku je velk\u00e1 \u010d\u00e1st organiz\u00e1tor\u016f k zasti\u017een\u00ed na koleji 17. listopadu \u010di jinde po Praze.

\r\n\r\n

Adresa koleje:

\r\n\r\n

P\u00e1tkova 3
\r\n182 00, Praha 8

", "enable_comments": false, "template_name": "", "registration_required": false, diff --git a/data/fotka_header.json b/data/fotka_header.json new file mode 100644 index 00000000..065c378a --- /dev/null +++ b/data/fotka_header.json @@ -0,0 +1,207 @@ +[ +{ + "model": "header_fotky.fotkaheader", + "pk": "baliky.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/baliky.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "beh.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/beh.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "kryptografie.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/kryptografie.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "mam_cernobile.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/mam_cernobile.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "noc.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/noc.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "ohen.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/ohen.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "snih.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/snih.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "spolecna.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/spolecna.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "stiny.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/stiny.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "vikendovka.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/vikendovka.jpg" + } +}, +{ + "model": "header_fotky.fotkaheader", + "pk": "vylet.jpg", + "fields": { + "cas": "2020-09-20T09:18:34.562Z", + "fotka": "header/vylet.jpg" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 1, + "fields": { + "url": "/archiv/", + "fotka": "stiny.jpg", + "denni_doba": "oboji" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 2, + "fields": { + "url": "/clanky/", + "fotka": "kryptografie.jpg", + "denni_doba": "den" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 3, + "fields": { + "url": "/clanky/", + "fotka": "ohen.jpg", + "denni_doba": "noc" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 4, + "fields": { + "url": "/zadani/", + "fotka": "baliky.jpg", + "denni_doba": "den" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 5, + "fields": { + "url": "/zadani/", + "fotka": "stiny.jpg", + "denni_doba": "noc" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 6, + "fields": { + "url": "/co-je-MaM/", + "fotka": "vikendovka.jpg", + "denni_doba": "den" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 7, + "fields": { + "url": "/co-je-MaM/", + "fotka": "noc.jpg", + "denni_doba": "noc" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 8, + "fields": { + "url": "/soustredeni/", + "fotka": "beh.jpg", + "denni_doba": "den" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 9, + "fields": { + "url": "/soustredeni/", + "fotka": "vylet.jpg", + "denni_doba": "noc" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 10, + "fields": { + "url": "/login/", + "fotka": "baliky.jpg", + "denni_doba": "den" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 11, + "fields": { + "url": "/login/", + "fotka": "stiny.jpg", + "denni_doba": "noc" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 12, + "fields": { + "url": "/profil/", + "fotka": "baliky.jpg", + "denni_doba": "den" + } +}, +{ + "model": "header_fotky.fotkaurlvazba", + "pk": 13, + "fields": { + "url": "/profil/", + "fotka": "stiny.jpg", + "denni_doba": "noc" + } +} +] \ No newline at end of file diff --git a/data/sitetree_new.json b/data/sitetree_new.json new file mode 100644 index 00000000..f0eb3a9c --- /dev/null +++ b/data/sitetree_new.json @@ -0,0 +1 @@ +[{"model": "sitetree.tree", "pk": 1, "fields": {"title": "Hlavn\u00ed menu", "alias": "main_menu"}}, {"model": "sitetree.treeitem", "pk": 1, "fields": {"title": "Co je M&M", "hint": "", "url": "/co-je-MaM/uvod/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 1, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 2, "fields": {"title": "Jak \u0159e\u0161it", "hint": "", "url": "/jak-resit/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 2, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 3, "fields": {"title": "Aktu\u00e1ln\u00ed
ro\u010dn\u00edk", "hint": "", "url": "/zadani/aktualni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 3, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 4, "fields": {"title": "Soust\u0159ed\u011bn\u00ed", "hint": "", "url": "/soustredeni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 4, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 5, "fields": {"title": "Archiv", "hint": "", "url": "/archiv/rocniky/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 5, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 6, "fields": {"title": "P\u0159ihl\u00e1sit", "hint": "", "url": "/login/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": true, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 6, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 7, "fields": {"title": "\u00davod", "hint": "", "url": "/co-je-MaM/uvod/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 7, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 8, "fields": {"title": "Organiz\u00e1to\u0159i", "hint": "", "url": "/co-je-MaM/organizatori/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 8, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 9, "fields": {"title": "FAQ", "hint": "", "url": "/co-je-MaM/FAQ/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 9, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 10, "fields": {"title": "Kontakt", "hint": "", "url": "/co-je-MaM/kontakt/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 10, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 11, "fields": {"title": "T\u00e9mata", "hint": "", "url": "/jak-resit/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 11, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 12, "fields": {"title": "Jak ps\u00e1t p\u0159\u00edsp\u011bvek", "hint": "", "url": "/jak-resit/jak-psat-prispevek/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 12, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 13, "fields": {"title": "Odm\u011bny", "hint": "", "url": "/co-je-MaM/odmeny/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 13, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 16, "fields": {"title": "V\u00fdsledkov\u00e1 listina", "hint": "", "url": "zadani/vysledkova-listina/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 33, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 17, "fields": {"title": "\u010cl\u00e1nky", "hint": "", "url": "/clanky/resitel/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 34, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 18, "fields": {"title": "\u00davod", "hint": "", "url": "/soustredeni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 18, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 19, "fields": {"title": "P\u0159ipravujeme", "hint": "", "url": "/soustredeni/pripravujeme/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 19, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 20, "fields": {"title": "Prob\u011bhlo", "hint": "", "url": "/soustredeni/probehlo/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 20, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 21, "fields": {"title": "Profil", "hint": "", "url": "/profil/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": true, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 21, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 22, "fields": {"title": "Osobn\u00ed \u00fadaje", "hint": "", "url": "/profil/osobni-udaje", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 21, "sort_order": 23, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 23, "fields": {"title": "Poslat \u0159e\u0161en\u00ed", "hint": "", "url": "/odeslat-reseni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 21, "sort_order": 36, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 24, "fields": {"title": "T\u00e9mata", "hint": "", "url": "/archiv/temata/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 5, "sort_order": 35, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 28, "fields": {"title": "HIDDEN", "hint": "", "url": "/korektury/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": true, "access_perm_type": 1, "parent": null, "sort_order": 28, "access_permissions": [1]}}, {"model": "sitetree.treeitem", "pk": 30, "fields": {"title": "Aktu\u00e1ln\u00ed", "hint": "", "url": "/korektury/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 28, "sort_order": 30, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 31, "fields": {"title": "Zastaral\u00e9", "hint": "", "url": "/korektury/zastarale/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 28, "sort_order": 31, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 32, "fields": {"title": "N\u00e1pov\u011bda", "hint": "", "url": "/korektury/help/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 28, "sort_order": 32, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 33, "fields": {"title": "Aktu\u00e1ln\u00ed \u010d\u00edslo", "hint": "", "url": "/zadani/aktualni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 15, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 34, "fields": {"title": "T\u00e9mata", "hint": "", "url": "/zadani/temata/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 17, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 35, "fields": {"title": "\u010c\u00edsla", "hint": "", "url": "/archiv/rocniky/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 5, "sort_order": 24, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 36, "fields": {"title": "\u00davod", "hint": "", "url": "/profil/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 21, "sort_order": 22, "access_permissions": []}}] \ No newline at end of file diff --git a/galerie/admin.py b/galerie/admin.py index f0ac6e28..54b0751e 100644 --- a/galerie/admin.py +++ b/galerie/admin.py @@ -30,14 +30,14 @@ def prepnout_fotogalerii_do_org_rezimu(modeladmin, request, queryset): class GalerieInline(admin.TabularInline): model = Obrazek - fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag'] + fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag', 'poradi'] readonly_fields = ['nazev', 'obrazek_maly_tag'] formfield_overrides = { models.TextField: {'widget': forms.TextInput}, } class ObrazekAdmin(admin.ModelAdmin): - list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag') + list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag', 'poradi') search_fields = ['nazev','popis'] class GalerieAdmin(admin.ModelAdmin): diff --git a/galerie/migrations/0010_auto_20200819_0947.py b/galerie/migrations/0010_auto_20200819_0947.py new file mode 100644 index 00000000..b7678ac1 --- /dev/null +++ b/galerie/migrations/0010_auto_20200819_0947.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.15 on 2020-08-19 07:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('galerie', '0009_auto_20190610_2358'), + ] + + operations = [ + migrations.AlterField( + model_name='galerie', + name='poradi', + field=models.IntegerField(blank=True, default=0, verbose_name='Pořadí'), + ), + ] diff --git a/galerie/models.py b/galerie/models.py index c48d3a95..8e6efdc7 100644 --- a/galerie/models.py +++ b/galerie/models.py @@ -94,7 +94,7 @@ class Galerie(models.Model): on_delete=models.SET_NULL) soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True, on_delete=models.PROTECT) - poradi = models.IntegerField('Pořadí', blank = True, null = True) + poradi = models.IntegerField('Pořadí', blank = True, null = False, default = 0) def __str__(self): return self.nazev diff --git a/galerie/templates/galerie/Base.html b/galerie/templates/galerie/Base.html deleted file mode 100644 index 61f96eb4..00000000 --- a/galerie/templates/galerie/Base.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "base.html" %} - -{# TODO predelat pres context processor #} -{% block header %}soustredeni{% endblock %} -{% block menu_soustredeni %}selected{% endblock %} -{% block submenu %}{% include 'seminar/soustredeni/submenu.html' %}{% endblock %} diff --git a/galerie/templates/galerie/Galerie.html b/galerie/templates/galerie/Galerie.html index c23c6c42..b2dfe994 100644 --- a/galerie/templates/galerie/Galerie.html +++ b/galerie/templates/galerie/Galerie.html @@ -1,4 +1,4 @@ -{% extends "galerie/Base.html" %} +{% extends "base.html" %} {% block nadpis1a %} diff --git a/galerie/templates/galerie/GalerieNahled.html b/galerie/templates/galerie/GalerieNahled.html index 7d9313fc..ec0d5f67 100644 --- a/galerie/templates/galerie/GalerieNahled.html +++ b/galerie/templates/galerie/GalerieNahled.html @@ -1,4 +1,4 @@ -{% extends "galerie/Base.html" %} +{% extends "base.html" %} {% block nadpis1a %} Galerie {{galerie.nazev}} @@ -61,7 +61,7 @@ Galerie {{galerie.nazev}} {{ galerie|truncatechars:max_delka_nazvu }} - {% if user.is_staff and galerie.zobrazit > 0 %} + {% if user.je_org and galerie.zobrazit > 0 %}
({{galerie.poradi}}) + @@ -73,7 +73,7 @@ Galerie {{galerie.nazev}} {% endwith %} {% endif %} {% endif %} - {% if user.is_staff and galerie.zobrazit > 0 %} + {% if user.je_org and galerie.zobrazit > 0 %} diff --git a/galerie/templates/galerie/GalerieNew.html b/galerie/templates/galerie/GalerieNew.html index 38237d86..2da23ece 100644 --- a/galerie/templates/galerie/GalerieNew.html +++ b/galerie/templates/galerie/GalerieNew.html @@ -1,4 +1,4 @@ -{% extends "galerie/Base.html" %} +{% extends "base.html" %} {% block title %}{% block nadpis1a %} Vytvářím novou galerii diff --git a/galerie/urls.py b/galerie/urls.py index 4d1e8f24..d299165f 100644 --- a/galerie/urls.py +++ b/galerie/urls.py @@ -1,13 +1,14 @@ # coding: utf-8 from django.urls import path +from seminar.utils import org_required from . import views urlpatterns = [ path('/', views.nahled), path('//', views.detail), - path('/new/', views.new_galerie), - path('/plus//', views.plus_galerie), - path('/minus//', views.minus_galerie), + path('/new/', org_required(views.new_galerie)), + path('/plus//', org_required(views.plus_galerie)), + path('/minus//', org_required(views.minus_galerie)), ] diff --git a/galerie/views.py b/galerie/views.py index 729ac3b8..4570b8fb 100644 --- a/galerie/views.py +++ b/galerie/views.py @@ -14,7 +14,7 @@ from galerie.forms import KomentarForm, NewGalerieForm def zobrazit(galerie, request): preview = False if galerie.zobrazit >= 1: - if request.user.is_staff: + if request.user.je_org: preview = True; else: raise Http404 @@ -35,16 +35,16 @@ def nahled(request, pk, soustredeni): galerie = get_object_or_404(Galerie, pk=pk) podgalerie = Galerie.objects.filter(galerie_up = galerie).order_by('poradi') - if not request.user.is_staff: + if not request.user.je_org: podgalerie = podgalerie.filter(zobrazit__lt=1) - obrazky = Obrazek.objects.filter(galerie = galerie) + obrazky = Obrazek.objects.filter(galerie = galerie).order_by('poradi', 'nazev') preview = zobrazit(galerie, request) sourozenci = [] if galerie.galerie_up: sourozenci = galerie.galerie_up.galerie_set.all().order_by('poradi') - if not request.user.is_staff: + if not request.user.je_org: sourozenci = sourozenci.filter(zobrazit__lt=1) predchozi = None @@ -82,7 +82,7 @@ def detail(request, pk, fotka, soustredeni): galerie = get_object_or_404(Galerie, pk=pk) preview = zobrazit(galerie, request) obrazek = get_object_or_404(Obrazek, pk=fotka) - obrazky = galerie.obrazek_set.all() + obrazky = galerie.obrazek_set.all().order_by('poradi', 'nazev') # vytvoreni a obslouzeni formulare if request.method == 'POST': @@ -96,22 +96,23 @@ def detail(request, pk, fotka, soustredeni): # Poradi aktualniho obrazku v galerii/stitku. for i in range(len(obrazky)): if obrazky[i] == obrazek: - znacka = i + poradi = i break else: # Obrazek neni v galerii/stitku. raise Http404 + # Nacteni okolnich obrazku a galerii # TODO vyjmout zjisteni predchozich a nasledujicich galerii # a udelat z toho funkci, ktera se pouzije u nahledu predchozi_galerie = None nasledujici_galerie = None - obrazky_dalsi = obrazky[znacka+1:znacka+NAHLEDU+1] - if (znacka+1) > NAHLEDU: - obrazky_predchozi = obrazky[znacka-NAHLEDU:znacka] + obrazky_dalsi = obrazky[poradi+1:poradi+NAHLEDU+1] + if (poradi+1) > NAHLEDU: + obrazky_predchozi = obrazky[poradi-NAHLEDU:poradi] else: - obrazky_predchozi = obrazky[0:znacka] + obrazky_predchozi = obrazky[0:poradi] if galerie.poradi > 1: predchozi_galerie = Galerie.objects.\ filter(galerie_up=galerie.galerie_up).\ @@ -120,41 +121,44 @@ def detail(request, pk, fotka, soustredeni): predchozi_galerie = predchozi_galerie[0] else: predchozi_galerie = None - if (znacka+1) == len(obrazky): - nasledujici_galerie = Galerie.objects.\ - filter(galerie_up=galerie.galerie_up).\ - filter(poradi=(galerie.poradi+1)) + if (poradi+1) == len(obrazky): # Tohle je poslední obrázek + if (galerie.poradi is not None + and galerie.galerie_up is not None): + nasledujici_galerie = Galerie.objects.\ + filter(galerie_up=galerie.galerie_up).\ + filter(poradi=(galerie.poradi+1)) + else: + nasledujici_galerie = None if nasledujici_galerie: nasledujici_galerie = nasledujici_galerie[0] else: nasledujici_galerie = None - + # Preskalovani obrazku do vybraneho prostoru. vyska = obrazek.obrazek_stredni.height sirka = obrazek.obrazek_stredni.width if vyska > MAX_VYSKA: - sirka = sirka * MAX_VYSKA / vyska + sirka = sirka * MAX_VYSKA / vyska vyska = MAX_VYSKA if sirka > MAX_SIRKA: vyska = vyska * MAX_SIRKA / sirka sirka = MAX_SIRKA return render(request, 'galerie/Galerie.html', - {'galerie' : galerie, - 'predchozi_galerie' : predchozi_galerie, - 'nasledujici_galerie' : nasledujici_galerie, - 'obrazek' : obrazek, - 'vyska' : vyska, - 'sirka' : sirka, - 'obrazky_predchozi' : obrazky_predchozi, - 'obrazky_dalsi' : obrazky_dalsi, - 'preview' : preview, - 'form' : form, - 'cesta': cesta_od_korene(galerie), - }) - + {'galerie' : galerie, + 'predchozi_galerie' : predchozi_galerie, + 'nasledujici_galerie' : nasledujici_galerie, + 'obrazek' : obrazek, + 'vyska' : vyska, + 'sirka' : sirka, + 'obrazky_predchozi' : obrazky_predchozi, + 'obrazky_dalsi' : obrazky_dalsi, + 'preview' : preview, + 'form' : form, + 'cesta': cesta_od_korene(galerie), + }) def new_galerie(request, galerie, soustredeni): diff --git a/header_fotky/__init__.py b/header_fotky/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/header_fotky/admin.py b/header_fotky/admin.py new file mode 100644 index 00000000..35d3427b --- /dev/null +++ b/header_fotky/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin +from django.contrib.admin import ModelAdmin +import header_fotky.models as m + + +class FotkaPozadiAdmin(ModelAdmin): + readonly_fields = ['cas'] + +admin.site.register(m.FotkaHeader, FotkaPozadiAdmin) +admin.site.register(m.FotkaUrlVazba) \ No newline at end of file diff --git a/header_fotky/apps.py b/header_fotky/apps.py new file mode 100644 index 00000000..084aa955 --- /dev/null +++ b/header_fotky/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class HeaderFotkyConfig(AppConfig): + name = 'header_fotky' diff --git a/header_fotky/context_processors.py b/header_fotky/context_processors.py new file mode 100644 index 00000000..be259cbf --- /dev/null +++ b/header_fotky/context_processors.py @@ -0,0 +1,45 @@ + +from datetime import datetime, date +import random + +from django.conf import settings + +from header_fotky.models import FotkaUrlVazba + + +def vzhled(request): + ''' Podle casu prida do templatu, zdali je nebo neni noc ''' + hodin = datetime.now().hour + if (hodin <= 6) or (hodin >= 20): + noc = True + nedoba = 'den' + doba = 'noc' + else: + noc = False + nedoba = 'noc' + doba = 'den' + url = request.path + + fotky = FotkaUrlVazba.objects.exclude(denni_doba=nedoba) + fotka = None + + # TODO rychlejší patternmatch? + while (fotka is None) and (url != ''): + presne = fotky.filter(url__exact=url) + if presne.count() > 0: + presne_doba = presne.filter(denni_doba=doba) + if presne_doba.count() > 0: + fotka = random.choice(presne_doba).url_fotky() + else: + fotka = random.choice(presne).url_fotky() + + url = url[:-1] + index = url.rfind('/') + if index != -1: + url = url[:index+1] + + if fotka is None: + fotka = settings.STATIC_URL + "images/header/vikendovka.jpg" + + return {'noc': noc, 'fotka': fotka} + diff --git a/header_fotky/migrations/0001_initial.py b/header_fotky/migrations/0001_initial.py new file mode 100644 index 00000000..4b90d0c6 --- /dev/null +++ b/header_fotky/migrations/0001_initial.py @@ -0,0 +1,63 @@ +# Generated by Django 2.2.15 on 2020-09-20 09:14 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + +from shutil import copytree + + +def zkopiruj_fotky(apps, schema_editor): + try: + copytree("mamweb/static/images/header/", "media/header/") # FIXME: bylo tu dirs_exists_ok=True, nekompatibilní s Py 3.7 + except FileExistsError: + pass + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='FotkaHeader', + fields=[ + ('cas', models.DateTimeField(default=django.utils.timezone.now, help_text='Čas vložení fotky', + verbose_name='čas vložení fotky')), + ('nazev', + models.CharField(help_text='Název např. archiv_noc', max_length=50, primary_key=True, serialize=False, + unique=True, verbose_name='název fotky')), + ('fotka', models.ImageField(upload_to='header')), + ], + options={ + 'verbose_name': 'fotka do pozadí menu', + 'verbose_name_plural': 'fotky do pozadí menu', + 'db_table': 'fotky_header', + 'ordering': ['-cas'], + }, + ), + migrations.CreateModel( + name='FotkaUrlVazba', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('url', + models.CharField(blank=True, help_text='url prefix stránek např: /archiv/ nebo /', max_length=100, + verbose_name='URL')), + ('denni_doba', models.CharField(choices=[('den', 'Zobrazit jen ve dne'), ('noc', 'Zobrazit jen v noci'), + ('oboji', 'Zobrazovat pořád')], default='oboji', max_length=16, + verbose_name='denní doba')), + ('fotka', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='header_fotky.FotkaHeader', + verbose_name='fotka')), + ], + options={ + 'verbose_name': 'vazba url a fotky do pozadí menu', + 'verbose_name_plural': 'vazby url a fotek do pozadí menu', + 'db_table': 'fotky_url_vazby', + 'ordering': ['url'], + }, + + ), + migrations.RunPython(zkopiruj_fotky, migrations.RunPython.noop), + ] diff --git a/header_fotky/migrations/__init__.py b/header_fotky/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/header_fotky/models.py b/header_fotky/models.py new file mode 100644 index 00000000..481a652c --- /dev/null +++ b/header_fotky/models.py @@ -0,0 +1,65 @@ +from django.core.exceptions import ValidationError +from django.db import models +from django.utils import timezone + + +class FotkaHeader(models.Model): + class Meta: + ordering = ['-cas'] + db_table = 'fotky_header' + verbose_name = u'fotka do pozadí menu' + verbose_name_plural = u'fotky do pozadí menu' + + cas = models.DateTimeField(u'čas vložení fotky', default=timezone.now, help_text='Čas vložení fotky') + + nazev = models.CharField( + u'název fotky', null=False, blank=False, unique=True, primary_key=True, + max_length=50, help_text='Název např. archiv_noc' + ) + + fotka = models.ImageField(upload_to='header', null=False, blank=False) + + def __str__(self): + return self.nazev + + def clean(self): + if not self.fotka: + raise ValidationError("Chybí obrázek") + """ Kontroluje, zda sedí poměr stran """ + if abs(self.fotka.width - (self.fotka.height * 970 / 350)) > 2: + raise ValidationError("Obrázek by měl mít rozměry 970w na 350h, nebo alespoň podobný poměr stran.") + super().clean() + + +class FotkaUrlVazba(models.Model): + class Meta: + ordering = ['url'] + db_table = 'fotky_url_vazby' + verbose_name = u'vazba url a fotky do pozadí menu' + verbose_name_plural = u'vazby url a fotek do pozadí menu' + + url = models.CharField( + u'URL', blank=True, null=False, max_length=100, + help_text='url prefix stránek např: /archiv/ nebo /' + ) + + fotka = models.ForeignKey( + FotkaHeader, blank=False, null=False, verbose_name='fotka', + on_delete=models.CASCADE + ) + + DOBA_DEN = 'den' + DOBA_NOC = 'noc' + DOBA_OBOJI = 'oboji' + DOBA_CHOICES = [ + (DOBA_DEN, 'Zobrazit jen ve dne'), + (DOBA_NOC, 'Zobrazit jen v noci'), + (DOBA_OBOJI, 'Zobrazovat pořád')] + + denni_doba = models.CharField('denní doba', max_length=16, choices=DOBA_CHOICES, blank=False, default=DOBA_OBOJI) + + def __str__(self): + return self.url + + def url_fotky(self): + return self.fotka.fotka.url diff --git a/init_local.sh b/init_local.sh new file mode 100755 index 00000000..ab373c38 --- /dev/null +++ b/init_local.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e # Spadni pokud něco spadne + +# Check venvu +# NOTE: zkontroluje i správnou složku -- existencí Makefilu +make venv_check + +# Vygenerujeme testdata +./manage.py testdata + +# Nahrajeme statický obsah modelů +./manage.py loaddata flat.json sitetree_new.json + +# Posbíráme statické soubory +./manage.py collectstatic diff --git a/korektury/models.py b/korektury/models.py index 6e5fed8a..37213172 100644 --- a/korektury/models.py +++ b/korektury/models.py @@ -79,22 +79,31 @@ class KorekturovanePDF(models.Model): self.stran = 0 while True: res = subprocess.call([ - "convert", - "-density", "180x180", - "-geometry", " 1024x1448", - "%s[%d]" % (self.pdf.path, self.stran), - os.path.join( + #Parametry inspirovány chybovou hláškou imagemagicku + "gs", + "-sstdout=%stderr", + "-dSAFER", + "-dNOPAUSE", + "-dBATCH", + "-dNOPROMPT", + "-sDEVICE=pngalpha", + "-r180x180", + "-dFirstPage=%d" % (self.stran+1), + "-dLastPage=%d" % (self.stran+1), + "-sOutputFile="+os.path.join( dirname, - "%s-%d.png" % (self.get_prefix(), self.stran) - ) + "%s-%d.png" % (self.get_prefix(), self.stran)), + "-f%s" % (self.pdf.path) ]) - if res == 1: + if not os.path.exists(os.path.join( + dirname, + "%s-%d.png" % (self.get_prefix(), self.stran))): break self.stran += 1 # Změnil se počet stran, ukládáme super(KorekturovanePDF, self).save() - def save(self): + def save(self, **kwargs): # Pokud se nezmenilo PDF, tak nepregenerovavej nahledy try: original = KorekturovanePDF.objects.get(pk=self.pk) @@ -104,7 +113,7 @@ class KorekturovanePDF(models.Model): except ObjectDoesNotExist: pass # uložíme nahrávané pdf - super(KorekturovanePDF, self).save() + super(KorekturovanePDF, self).save(kwargs) # uložíme png a změněný počet stran self.convert() diff --git a/korektury/templates/korektury/base.html b/korektury/templates/korektury/base.html deleted file mode 100644 index b31d5d47..00000000 --- a/korektury/templates/korektury/base.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -{# blok do kterého se nacita text, v pripade jinyhc templatu obalit vlastnim blokem #} -{% endblock %} - -{% block title %} -{# blok pro titulek stranky #} -{% endblock %} diff --git a/korektury/templates/korektury/help.html b/korektury/templates/korektury/help.html index 0024848e..3cce7a4f 100644 --- a/korektury/templates/korektury/help.html +++ b/korektury/templates/korektury/help.html @@ -1,4 +1,5 @@ -{% extends "korektury/base.html" %} +{% extends "base.html" %} + {% load staticfiles %} {% block title %} Nápověda ke korigovátku {% endblock title %} diff --git a/korektury/templates/korektury/opraf.html b/korektury/templates/korektury/opraf.html index ba8898a6..00c81c2d 100644 --- a/korektury/templates/korektury/opraf.html +++ b/korektury/templates/korektury/opraf.html @@ -36,12 +36,12 @@ id="neni_chyba_checkbox" name="neni_chyba_checkbox" onchange="toggle_corrections('neni_chyba')" checked> -
+
-

Korespondenční seminář M&M organizují převážně studenti MFF UK. Organizaci semináře a vydávání časopisu podporuje Jednota českých matematiků a fyziků. S obsahem webu M&M je možné nakládat dle licence Creative Commons Attribution 3.0.

+

Korespondenční seminář M&M organizují převážně studenti MFF UK. Organizaci semináře a vydávání časopisu podporuje Jednota českých matematiků a fyziků. S obsahem webu M&M je možné nakládat dle licence Creative Commons Attribution 3.0.

+ diff --git a/mamweb/templates/flatpages/default.html b/mamweb/templates/flatpages/default.html index b5d2d24d..0a26ca27 100644 --- a/mamweb/templates/flatpages/default.html +++ b/mamweb/templates/flatpages/default.html @@ -8,106 +8,4 @@
{{ flatpage.content }}
-{% endblock content %} - -{# nahraj spravne submenu #} -{% block submenu %} - {# co-je-MaM #} - {% if "/co-je-MaM/" in flatpage.url %} - {% if "/uvod/" in flatpage.url %} - {% with "uvod" as selected %} - {% include "seminar/cojemam/submenu.html" %} - {% endwith %} - {% elif "jak-resit" in flatpage.url %} - {% with "jak-resit" as selected %} - {% include "seminar/cojemam/submenu.html" %} - {% endwith %} - {% elif "odmeny" in flatpage.url %} - {% with "odmeny" as selected %} - {% include "seminar/cojemam/submenu.html" %} - {% endwith %} - {% elif "FAQ" in flatpage.url %} - {% with "FAQ" as selected %} - {% include "seminar/cojemam/submenu.html" %} - {% endwith %} - {% elif "kontakt" in flatpage.url %} - {% else %} - {% include "seminar/cojemam/submenu.html" %} - {% endif %} - {% endif %} - {# soustredeni #} - {% if "/soustredeni/" in flatpage.url %} - {% if "/pripravujeme/" in flatpage.url %} - {% with "pripravujeme" as selected %} - {% include "seminar/soustredeni/submenu.html" %} - {% endwith %} - {% else %} - {% with "uvod" as selected %} - {% include "seminar/soustredeni/submenu.html" %} - {% endwith %} - {% endif %} - {% endif %} - {# zadani #} - {% if "/zadani/" in flatpage.url %} - {% if "/aktualni-cislo/" in flatpage.url %} - {% with "aktualni-cislo" as selected %} - {% include "seminar/zadani/submenu.html" %} - {% endwith %} - {% elif "/vysledkova-listina/" in flatpage.url %} - {% with "vysledkova-listina" as selected %} - {% include "seminar/zadani/submenu.html" %} - {% endwith %} - {% else %} - {% include "seminar/zadani/submenu.html" %} - {% endif %} - {% endif %} - {# clanky #} - {% if "/clanky/" in flatpage.url %} - {% if "/uvod/" in flatpage.url %} - {% with "uvod" as selected %} - {% include "seminar/clanky/submenu.html" %} - {% endwith %} - {% elif "/org/" in flatpage.url %} - {% with "org" as selected %} - {% include "seminar/clanky/submenu.html" %} - {% endwith %} - {% elif "/resitel/" in flatpage.url %} - {% with "resitel" as selected %} - {% include "seminar/clanky/submenu.html" %} - {% endwith %} - {% elif "/jak-psat-vedecky-clanek/" in flatpage.url %} - {% with "jak-psat-vedecky-clanek" as selected %} - {% include "seminar/clanky/submenu.html" %} - {% endwith %} - {% else %} - {% include "seminar/clanky/submenu.html" %} - {% endif %} - {% endif %} - {# archiv #} - {% if "/archiv/" in flatpage.url %} - {% if "/ulohy/" in flatpage.url %} - {% with "ulohy" as selected %} - {% include "seminar/archiv/submenu.html" %} - {% endwith %} - {% elif "/vysledky/" in flatpage.url %} - {% with "vysledky" as selected %} - {% include "seminar/archiv/submenu.html" %} - {% endwith %} - {% else %} - {% include "seminar/archiv/submenu.html" %} - {% endif %} - {% endif %} -{% endblock %} - -{# zvirazneni menu #} -{% block menu_uvod %}{% if not "/kontakt/" in flatpage.url %}{% if "/co-je-MaM/" in flatpage.url %}selected{% endif %}{% endif %}{% endblock %} -{% block menu_soustredeni %}{% if "/soustredeni/" in flatpage.url %}selected{% endif %}{% endblock %} -{% block menu_zadani %}{% if "/zadani/" in flatpage.url %}selected{% endif %}{% endblock %} -{% block menu_clanky %}{% if "/clanky/" in flatpage.url %}selected{% endif %}{% endblock %} -{% block menu_archiv %}{% if "/archiv/" in flatpage.url %}selected{% endif %}{% endblock %} -{% block menu_odevzdat %}{% if "/kontakt/" in flatpage.url %}selected{% endif %}{% endblock %} - -{# zmena titulniho obrazku #} -{% block header %}{% if "/co-je-MaM/" in flatpage.url %}cojemam{% elif "/soustredeni/" in flatpage.url %}soustredeni{% elif "/zadani/" in flatpage.url %}zadani{% elif "/clanky/" in flatpage.url %}clanky{% elif "/archiv/" in flatpage.url %}archiv{% else %}odeslat{% endif %}{% endblock header %} - -{# TODO zvirazneni submenu #} +{% endblock content %} \ No newline at end of file diff --git a/mamweb/templates/logo.html b/mamweb/templates/logo.html new file mode 100644 index 00000000..c5113d0c --- /dev/null +++ b/mamweb/templates/logo.html @@ -0,0 +1,26 @@ +{% load staticfiles %} + \ No newline at end of file diff --git a/mamweb/templates/menu.html b/mamweb/templates/menu.html index c7c0e8f5..e948785a 100644 --- a/mamweb/templates/menu.html +++ b/mamweb/templates/menu.html @@ -3,7 +3,9 @@ {% autoescape off %} - {% if user.is_staff %} + {% if user.je_org %}
Vytvořit novou fotogalerii
Vygenerovat obálky pro účastníky
@@ -60,7 +53,7 @@ {% if soustredeni.text %} {% autoescape off %}{{soustredeni.text}}{% endautoescape %} {% endif %} - {% if user.is_staff %} + {% if user.je_org %}
{# Účastníci #}

Soustředění se zúčastnili tito účastníci:

@@ -82,7 +75,7 @@
{% endif %} - {% if not soustredeni.verejne_db and user.is_staff %} + {% if not soustredeni.verejne_db and user.je_org %}
{# class="mam-org-only" #} {% endif %} {% endif %} diff --git a/seminar/templates/seminar/soustredeni/seznam_ucastniku.html b/seminar/templates/seminar/soustredeni/seznam_ucastniku.html index 926b4905..9ab638ab 100644 --- a/seminar/templates/seminar/soustredeni/seznam_ucastniku.html +++ b/seminar/templates/seminar/soustredeni/seznam_ucastniku.html @@ -35,7 +35,6 @@ Žádní účastníci nebyli... {% endfor %} - diff --git a/seminar/templates/seminar/tematka/rozcestnik.html b/seminar/templates/seminar/tematka/rozcestnik.html index b13d6075..8c3b1a38 100644 --- a/seminar/templates/seminar/tematka/rozcestnik.html +++ b/seminar/templates/seminar/tematka/rozcestnik.html @@ -1,14 +1,25 @@ +{% extends "base.html" %} + + +{% block content %} +

Témata jsou texty nejen z oblasti matematiky, fyziky a informatiky, které popisují nějaký problém a jsou doprovázeny návodnými úlohami. Vaším úkolem je zamyslet se nad daným problémem a sepsat vaše úvahy ve formě krátkého textu.

+ +

Jak řešit téma?

+ +

 

+ +

Aktuální témata

+ {% for tematko in tematka %} -

{{tematko.nazev}}

+

{{tematko.nazev}}

+
+ {% if tematko.obrazek %} + {{tematko.nazev}} + {% else %} {# pokud témátko nemá fotku, zobrazuje se defaultní obrázek #} + {% load static %} {{tematko.nazev}} + {% endif %} +
+

{{tematko.abstrakt}}

-
    - {% for cislo in tematko.cisla %} -
  • {{cislo.0.0}}
  • -
      - {% for odkaz in cislo.1 %} -
    • {{odkaz.0}}
    • - {% endfor %} -
    - {% endfor %} -
{% endfor %} +{% endblock %} diff --git a/seminar/templates/seminar/titulnistrana.html b/seminar/templates/seminar/titulnistrana.html index bf9a884a..1fd96a85 100644 --- a/seminar/templates/seminar/titulnistrana.html +++ b/seminar/templates/seminar/titulnistrana.html @@ -5,32 +5,53 @@ {% block content %} - {# Uvitaci text #} + +{% if nejblizsi_deadline %} +
+

Do konce odeslání řešení {% if typ_deadline == 'soustredeni' %}(pro účast na soustředění) {% elif typ_deadline == 'preddeadline' %}(pro otištění došlých řešení) {% endif %}zbývá: + {{nejblizsi_deadline|timeuntil}}

+
+{% endif %} + +
+ +
+ +
+

- {% block nadpis1a %}{% block nadpis1b %} - Vítej! - {% endblock %}{% endblock %} + {% block nadpis1a %} + Vítej + {% endblock %} + mezi námi

-

-M&M je korespondenční seminář. Několikrát do roka zdarma vydáváme časopis a v něm zajímavé podněty k přemýšlení. Ty na ně můžeš reagovat.
- M&M je taky soutěž. Můžeš vyhrát knížky, deskovky nebo dokonce dort. Můžeš se dostat na matfyz bez přijímaček. A především s námi můžeš jet na skvělé soustředění. -

- -
- {% if dead %} -
-

Do konce odeslání řešení {% if deadline_soustredeni %}(pro účast na soustředění) {% endif %}zbývá:
- {{ted|timesince:dead}}

+
+ M&M je korespondenční seminář. Vydáváme časopis a v něm zajímavé podněty k přemýšlení. Ty na ně můžeš reagovat, + experimentovat a objevovat s námi fascinující zákoutí matiky, fyziky a informatiky. +
Zaregistruj se!
{# FIXME odkaz #} + M&M je taky soutěž. Za svá řešení dostaneš body a můžeš vyhrát zajímavé ceny, dostat se + na Matfyz bez přijímaček a především, můžeš s námi jet na skvělé soustředění. +
Co můžeš vyhrát?
{# FIXME odkaz #}
- {% endif %} + +
- {# Novinky #} -

Novinky

- {% include 'seminar/novinky.html' %} +
- Archiv novinek +

+ Řeš témata! +

+ +
+ Přidej se k nám! Pusť se do řešení témát. + {% for tema in aktualni_temata %} +
{{ tema.nazev }}
+ {% endfor %} +
+
+
@@ -38,8 +59,24 @@ M&M je korespondenční seminář. Několikrát do roka zdarma vydáváme č
-

Zjistit víc!

+

Zjisti víc!

+
+ +
+ +
+ + {# Novinky #} +

Co je nového?

+ {% include 'seminar/novinky.html' %} + + Archiv novinek + +
+ +
+ {% endblock %} diff --git a/seminar/templates/seminar/treenode.html b/seminar/templates/seminar/treenode.html index ef293a62..b7976426 100644 --- a/seminar/templates/seminar/treenode.html +++ b/seminar/templates/seminar/treenode.html @@ -1,4 +1,4 @@ -{% extends "seminar/archiv/base.html" %} +{% extends "base.html" %} {% load render_bundle from webpack_loader %} diff --git a/seminar/templates/seminar/zadani/AktualniVysledkovka.html b/seminar/templates/seminar/zadani/AktualniVysledkovka.html index 00ace94c..387ad949 100644 --- a/seminar/templates/seminar/zadani/AktualniVysledkovka.html +++ b/seminar/templates/seminar/zadani/AktualniVysledkovka.html @@ -1,11 +1,4 @@ -{% extends "seminar/zadani/base.html" %} - -{% block submenu %} - {% with "vysledkova-listina" as selected %} - {% include 'seminar/zadani/submenu.html' %} - {% endwith %} -{% endblock submenu %} - +{% extends "base.html" %} {% block content %} {% with nastaveni.aktualni_rocnik as rocnik %} @@ -27,7 +20,7 @@ v archivu.

- {% if user.is_staff and vysledkovka_s_neverejnymi %} + {% if user.je_org and vysledkovka_s_neverejnymi %}

Výsledky včetně neveřejných

{% with vysledkovka_s_neverejnymi as vysledkovka %} diff --git a/seminar/templates/seminar/zadani/AktualniZadani.html b/seminar/templates/seminar/zadani/AktualniZadani.html index b611eee9..770ac603 100644 --- a/seminar/templates/seminar/zadani/AktualniZadani.html +++ b/seminar/templates/seminar/zadani/AktualniZadani.html @@ -1,10 +1,4 @@ -{% extends "seminar/zadani/base.html" %} - -{% block submenu %} - {% with "aktualni" as selected %} - {% include 'seminar/zadani/submenu.html' %} - {% endwith %} -{% endblock submenu %} +{% extends "base.html" %} {% block nadpis1a %}{% block nadpis1b %} Aktuální zadání @@ -16,8 +10,8 @@ {% with nastaveni.aktualni_cislo as ac %} {# Zobrazovani neverejnych zadani jen organizatorum #} -{% if user.is_staff or verejne %} -{% if user.is_staff and not verejne %}
{% endif %} +{% if user.je_org or verejne %} +{% if user.je_org and not verejne %}
{% endif %} {% if ac.zadane_problemy.all %} {% if ac.datum_deadline_soustredeni %} @@ -35,34 +29,38 @@ {% if ac.pdf %} -

Aktuální číslo v PDF

+

Aktuální témata najdete v aktuálním čísle v PDF.

{% endif %} - {% for sada in jednorazove_problemy %} - {# podnadpisy, kdyz neni zakomentuje se nadpis #} - {% if not sada %}{% endif %} - {# publikace jednotlivych zadani #} - {% for problem in sada %} - {% for tag in problem.zamereni.names %} - - {% endfor %} + + {% if False %} + {% for sada in jednorazove_problemy %} + {# podnadpisy, kdyz neni zakomentuje se nadpis #} + {% if not sada %}{% endif %} + {# publikace jednotlivych zadani #} + {% for problem in sada %} + {% for tag in problem.zamereni.names %} + + {% endfor %} - {# TODO použít {{problem.kod_v_rocniku}} ? vrací 4.u1 místo 4.1 #} -

{{problem.cislo_zadani.cislo}}.{{problem.kod}} {{problem.nazev}} {{ problem.body_v_zavorce }}

- {% autoescape off %}{{problem.text_zadani}}{% endautoescape %} -
- {% endfor %} - {% empty %} - Aktuálně nejsou zadané žádné úlohy k řešení. - {% endfor %} + {# TODO použít {{problem.kod_v_rocniku}} ? vrací 4.u1 místo 4.1 #} +

{{problem.cislo_zadani.cislo}}.{{problem.kod}} {{problem.nazev}} {{ problem.body_v_zavorce }}

+ {% autoescape off %}{{problem.text_zadani}}{% endautoescape %} +
+ {% endfor %} + {% empty %} + Aktuálně nejsou zadané žádné úlohy k řešení. + {% endfor %} + {% endif %} -{% if user.is_staff and not verejne%}
{% endif %} +{% if user.je_org and not verejne%}
{% endif %} {% else %}

Aktuálně nejsou zveřejněny žádné úlohy

{% endif %} + {% if False %}

Témata

+ {% endif %} {% endwith %} diff --git a/seminar/templates/seminar/zadani/Temata.html b/seminar/templates/seminar/zadani/Temata.html index ec700a1f..0fcd3350 100644 --- a/seminar/templates/seminar/zadani/Temata.html +++ b/seminar/templates/seminar/zadani/Temata.html @@ -1,11 +1,4 @@ -{% extends "seminar/zadani/base.html" %} - -{% block submenu %} - {% with "temata" as selected %} - {% include 'seminar/zadani/submenu.html' %} - {% endwith %} -{% endblock submenu %} - +{% extends "base.html" %} {% block content %} {% with nastaveni.aktualni_rocnik as ar %} @@ -16,15 +9,20 @@ {% endblock %}{% endblock %} + +

+ Pozor, tato stránka není aktuální! Aktualizovaný seznam všech čísel v PDF najdete zde. Za problémy se omlouváme. +

- Témata jsou hlavním obsahem časopisu M&M. Obvykle představují - složitější a obecnější problémy než samostatné úlohy. Navíc je v jejich - zadání vždy prostor pro tvůrčí rozšíření. Za pěkný článek k tématu lze - získat třeba i 20 bodů, určitě se tedy vyplatí se tématy zabývat. + Témata jsou texty nejen z oblasti matematiky, fyziky a informatiky, které + popisují nějaký problém a jsou doprovázeny návodnými úlohami. Vaším úkolem + je zamyslet se nad daným problémem a sepsat vaše úvahy ve formě krátkého + textu.

Jak řešit téma?

+
{% endwith %} diff --git a/seminar/templates/seminar/zadani/base.html b/seminar/templates/seminar/zadani/base.html deleted file mode 100644 index a1f223cd..00000000 --- a/seminar/templates/seminar/zadani/base.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "base.html" %} - -{% block menu_zadani %}selected{% endblock %} - -{# zmena fotky #}{% block header %}zadani{% endblock %} - -{% block submenu %} - {% include 'seminar/zadani/submenu.html' %} -{% endblock submenu %} - diff --git a/seminar/templates/seminar/zadani/submenu.html b/seminar/templates/seminar/zadani/submenu.html deleted file mode 100644 index 84de5d67..00000000 --- a/seminar/templates/seminar/zadani/submenu.html +++ /dev/null @@ -1,12 +0,0 @@ -{% with "/zadani" as cesta %} - - - -{% endwith %} diff --git a/seminar/testutils.py b/seminar/testutils.py index 0dc4782d..3e81f356 100644 --- a/seminar/testutils.py +++ b/seminar/testutils.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- import datetime + +from django.contrib.auth.models import Permission from pytz import timezone import random import lorem @@ -9,6 +11,7 @@ from django.db import transaction import unidecode import logging +from korektury.testutils import create_test_pdf from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Osoba, Organizator, Prijemce, Tema, Uloha, Konfera, TextNode, UlohaVzorakNode, RocnikNode, CisloNode, TemaVCisleNode, Text, Hodnoceni, UlohaZadaniNode, Novinky, TreeNode import seminar.models as m @@ -70,7 +73,7 @@ def gen_osoby(rnd, size): if pokusy >= max_pokusy: print("Chyba, na danou velikost testovacích dat příliš málo možných" " jmen a příjmení") - exit + exit() prezdivka = rnd.choice(prezdivky) email = "@".join([unidecode.unidecode(jmeno), rnd.choice(domain)]) telefon = "".join([str(rnd.choice([k for k in range(10)])) for i in range(9)]) @@ -124,9 +127,20 @@ def gen_resitele(rnd, osoby, skoly): logger.info('Generuji řešitele...') resitele = [] + x = 0 + resitel_perm = Permission.objects.filter(codename__exact='resitel').first() for os in osoby: rand = rnd.randint(0, 8) if not (rand % 8 == 0): + if not os.user: + if x: + user = User.objects.create_user(username='r'+str(x), email=os.email, password='r') + else: + user = User.objects.create_user(username='r', email=os.email, password='r') + x += 1 + os.user = user + os.save() + os.user.user_permissions.add(resitel_perm) resitele.append(Resitel.objects.create(osoba=os, skola=rnd.choice(skoly), rok_maturity=rnd.randint(2019, 2029), zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)[0])) @@ -139,7 +153,7 @@ def gen_prijemci(rnd, osoby, kolik=10): prijemci.append(Prijemce.objects.create(osoba=i)) return prijemci -def gen_organizatori(rnd, osoby, last_rocnik, users): +def gen_organizatori(rnd, osoby, last_rocnik): logger.info('Generuji organizátory...') organizatori = [] @@ -149,6 +163,8 @@ def gen_organizatori(rnd, osoby, last_rocnik, users): seznam_oboru = ["matematiku", "matematiku", "matematiku", "fyziku", "literaturu", "informatiku", "informatiku", "běhání dokolečka"] + x = 0 + org_perm = Permission.objects.filter(codename__exact='org').first() for os in osoby: rand = rnd.randint(0, 8) if (rand % 8 == 0): @@ -175,6 +191,15 @@ def gen_organizatori(rnd, osoby, last_rocnik, users): if do.year > datetime.datetime.now().year: do = None + if not os.user: + if x: + user = User.objects.create_user(username='o'+str(x), email=os.email, password='o') + else: + user = User.objects.create_user(username='o', email=os.email, password='o') + x += 1 + os.user = user + os.save() + os.user.user_permissions.add(org_perm) organizatori.append(Organizator.objects.create(osoba=os, organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga)) return organizatori @@ -681,6 +706,77 @@ def otec_syn(otec, syn): syn.save() otec.save() +def gen_clanek(rnd, organizatori, resitele): + logger.info("Generuji článek do čísla 22.2") + clanek = m.Clanek.objects.create( + nazev="Článek o Lorem ipsum", + nadproblem=None, + stav='vyreseny', + zamereni=['I'], + garant=rnd.choice(organizatori), + kod='cl', + ) + clanek.save() + + reseni = m.Reseni.objects.create( + zverejneno=True, + ) + reseni.resitele.add(rnd.choice(resitele)) + reseni.save() + + cislo = m.Cislo.objects.get(rocnik__rocnik=22, poradi=2) + cislonode = cislo.cislonode + + hodnoceni = m.Hodnoceni.objects.create( + body=15.0, + cislo_body=cislo, + reseni=reseni, + problem=clanek, + ) + hodnoceni.save() + + reseninode = m.ReseniNode.objects.create( + reseni=reseni + ) + reseninode.save() + + # Bude to celý text + reseni.text_cely = reseninode + reseni.save() + + from seminar.treelib import insert_last_child, create_child + insert_last_child(cislonode, reseninode) + + # Vyrobíme nějaký obsah + # FIXME: Ten, kdo vymyslel TreeLib (mj. týž, kdo psal tenhle kód), + # nevyrobil vhodnou funkci, takže to postavíme pozpátku pomocí create_child + # (které vyrábí _prvního_ syna) + create_child(reseninode, m.CastNode, nadpis="Lorem ipsum") + # Taky ten člověk nevyrobil vracení nových věcí... + castnode = reseninode.first_child + + # Úvodní odstaveček + obsah = "Tohle je zamyšlení o textu lorem ipsum. Začneme a skončíme ukázkou." + text = m.Text.objects.create( + na_web=obsah, + do_cisla=obsah, + ) + text.save() + create_child(reseninode, m.TextNode, text=text) + + # Několik odstavců lorem ipsum + for _ in range(rnd.randint(3, 7)): + lipsum = lorem.paragraph() + text = m.Text.objects.create( + na_web=lipsum, + do_cisla=lipsum, + ) + text.save() + create_child(castnode, m.TextNode, text=text) + logger.info(f"Článek vygenerován (reseni={reseni.id}, treenode={reseninode.id})") + + + @transaction.atomic def create_test_data(size = 6, rnd = None): logger.info('Vyrábím testovací data (size={})...'.format(size)) @@ -700,11 +796,22 @@ def create_test_data(size = 6, rnd = None): # users admin = User.objects.create_superuser(username='admin', email='', password='admin') + os_admin = Osoba.objects.create( + user=admin, jmeno='admin', prijmeni='admin', + prezdivka='admin', pohlavi_muz=1, email='admin@admin.admin', + telefon='123 456 789', datum_narozeni=datetime.date(2000, 1, 1), + ulice='admin', mesto='admin', psc='100 00', + datum_registrace=datetime.date(2020, 9, 6) + ) + or_admin = Organizator.objects.create( + osoba=os_admin, organizuje_od=None, organizuje_do=None, + strucny_popis_organizatora="Organizátor k uživateli Admin" + ) usernames = ['anet', 'bara', 'cyril', 'david', 'eva', 'filip'] users = [] for usr in usernames[:size]: - u = User.objects.create(username=usr, password=usr) + u = User.objects.create_user(username=usr, password=usr) u.first_name = usr.capitalize() u.save() users.append(u) @@ -718,8 +825,8 @@ def create_test_data(size = 6, rnd = None): # resitele a organizatori last_rocnik = 25 + organizatori = gen_organizatori(rnd, osoby, last_rocnik) resitele = gen_resitele(rnd, osoby, skoly) - organizatori = gen_organizatori(rnd, osoby, last_rocnik, users) #generování novinek novinky = gen_novinky(rnd, organizatori) @@ -759,6 +866,9 @@ def create_test_data(size = 6, rnd = None): #generování konfer konfery = gen_konfery(size, rnd, organizatori, resitele, soustredeni) + # vytvoreni pdf ke korekturam + create_test_pdf(rnd, organizatori) + # TODO: nastavi správně, kolik se čeho generuje, aby rozsahy přibližně odpovídaly # FIXME: misto typu ruzne typy objektu a vnoreni do sebe (Tom nechápe, co je tímto fixme míněno) # TODO: vytvorit temata s ruznymi vlakny @@ -768,6 +878,8 @@ def create_test_data(size = 6, rnd = None): # TODO: mezičíslo node # TODO: přidat ke konferám řešení a dát je do čísel + # Dohackované vytvoření jednoho článku + gen_clanek(rnd, organizatori, resitele) # obecné nastavení semináře, musí být už přidané ročníky a čísla, jinak se nastaví divně diff --git a/seminar/urls.py b/seminar/urls.py index 00225f45..91e0ce15 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -1,29 +1,23 @@ from django.urls import path, include, re_path -from django.contrib.auth.decorators import user_passes_test +from django.contrib.auth.decorators import login_required from . import views, export -from .utils import staff_member_required +from .utils import org_required, resitel_required from django.views.generic.base import RedirectView -from django.contrib.auth import views as auth_views - -staff_member_required = user_passes_test(lambda u: u.is_staff) urlpatterns = [ # path('aktualni/temata/', views.TemataRozcestnikView), # path('/t/', views.TematkoView), - # REDIRECTy - path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')), - # Organizatori path('co-je-MaM/organizatori/', views.CojemamOrganizatoriView.as_view(), name='organizatori'), path('co-je-MaM/organizatori/organizovali/', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'), # Archiv - path('archiv/cisla/', views.ArchivView.as_view()), + path('archiv/rocniky/', views.ArchivView.as_view()), path('archiv/temata/', views.ArchivTemataView.as_view()), path('rocnik//', views.RocnikView.as_view(), name='seminar_rocnik'), - path('cislo/./', views.CisloView.as_view(), name='seminar_cislo'), # odkomentované jenom kvůli testování archivu + path('cislo/./', views.CisloView.as_view(), name='seminar_cislo'), path('problem//', views.ProblemView.as_view(), name='seminar_problem'), path('treenode//', views.TreeNodeView.as_view(), name='seminar_treenode'), path('treenode//json/', views.TreeNodeJSONView.as_view(), name='seminar_treenode_json'), @@ -44,17 +38,17 @@ urlpatterns = [ ), path( 'soustredeni//seznam_ucastniku', - staff_member_required(views.SoustredeniUcastniciView.as_view()), + org_required(views.SoustredeniUcastniciView.as_view()), name='soustredeni_ucastnici' ), path( 'soustredeni//maily_ucastniku', - staff_member_required(views.SoustredeniMailyUcastnikuView.as_view()), + org_required(views.SoustredeniMailyUcastnikuView.as_view()), name='maily_ucastniku' ), path( 'soustredeni//export_ucastniku', - staff_member_required(views.soustredeniUcastniciExportView), + org_required(views.soustredeniUcastniciExportView), name='soustredeni_ucastnici_export' ), path( @@ -64,7 +58,7 @@ urlpatterns = [ # Zadani path('zadani/aktualni/', views.AktualniZadaniView.as_view(), name='seminar_aktualni_zadani'), -# path('zadani/temata/', views.ZadaniTemataView, name='seminar_temata'), + path('zadani/temata/', views.ZadaniTemataView, name='seminar_temata'), #path('zadani/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'), path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'), @@ -73,61 +67,105 @@ urlpatterns = [ #path('clanky/org/', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'), # Aesop - path('aesop-export/mam-rocnik-.csv', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'), - path('aesop-export/mam-sous-.csv', export.ExportSousView.as_view(), name='seminar_export_sous'), - path('aesop-export/index.csv', export.ExportIndexView.as_view(), name='seminar_export_index'), + path( + 'aesop-export/mam-rocnik-.csv', + org_required(export.ExportRocnikView.as_view()), + name='seminar_export_rocnik' + ), + path( + 'aesop-export/mam-sous-.csv', + org_required(export.ExportSousView.as_view()), + name='seminar_export_sous' + ), + path( + 'aesop-export/index.csv', + org_required(export.ExportIndexView.as_view()), + name='seminar_export_index' + ), # Stranky viditelne pouze pro orgy: path( - 'rocnik//vysledkovka.tex', - staff_member_required(views.RocnikVysledkovkaView.as_view()), - name='seminar_rocnik_vysledkovka' - ), - path('cislo/./vysledkovka.tex', - staff_member_required(views.CisloVysledkovkaView.as_view()), - name='seminar_cislo_vysledkovka' - ), - path('cislo/./obalky.pdf', - staff_member_required(views.cisloObalkyView), name='seminar_cislo_obalky'), - - path('cislo/./tituly.tex', - staff_member_required(views.TitulyView), name='seminar_cislo_titul'), - path('stav', - staff_member_required(views.StavDatabazeView), name='stav_databaze'), - path('cislo/./obalkovani', - staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'), - path('soustredeni//obalky.pdf', - staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), - - path('org/vloz_body//', - staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'), - path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), - path('auth/login/', views.LoginView.as_view(), name='login'), - path('auth/logout/', views.LogoutView.as_view(), name='logout'), - path('auth/resitel/', views.ResitelView.as_view(), name='seminar_resitel'), - path('auth/reset_password/', views.PasswordResetView.as_view(), name='reset_password'), - path('auth/change_password/', views.PasswordChangeView.as_view(), name='change_password'), - path('auth/reset_password_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'), - path('auth/reset_password_confirm///', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), - path('auth/reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), - path('auth/resitel_edit', views.resitelEditView, name='seminar_resitel_edit'), + 'rocnik//vysledkovka.tex', + org_required(views.RocnikVysledkovkaView.as_view()), + name='seminar_rocnik_vysledkovka' + ), + path( + 'cislo/./vysledkovka.tex', + org_required(views.CisloVysledkovkaView.as_view()), + name='seminar_cislo_vysledkovka' + ), + path( + 'cislo/./obalky.pdf', + org_required(views.cisloObalkyView), + name='seminar_cislo_obalky' + ), + path( + 'cislo/./tituly.tex', + org_required(views.TitulyView), + name='seminar_cislo_titul' + ), + path( + 'stav', + org_required(views.StavDatabazeView), + name='stav_databaze' + ), + path( + 'cislo/./obalkovani', + org_required(views.ObalkovaniView.as_view()), + name='seminar_cislo_resitel_obalkovani' + ), + path( + 'soustredeni//obalky.pdf', + org_required(views.soustredeniObalkyView), + name='seminar_soustredeni_obalky' + ), + path( + 'org/vloz_body//', + org_required(views.VlozBodyView.as_view()), + name='seminar_org_vlozbody' + ), + # příprava na nestatický orgorozcestník + path( + 'org/rozcestnik/', + org_required(views.OrgoRozcestnikView.as_view()), + name='seminar_org_rozcestnik' + ), + + path('prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), + path('login/', views.LoginView.as_view(), name='login'), + path('logout/', views.LogoutView.as_view(), name='logout'), + path('resitel/', resitel_required(views.ResitelView.as_view()), name='seminar_resitel'), + path('reset_password/', views.PasswordResetView.as_view(), name='reset_password'), + path('change_password/', views.PasswordChangeView.as_view(), name='change_password'), + path('reset_password_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'), + path('reset_password_confirm///', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), + path('reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), + path( + 'resitel_edit', + login_required(views.resitelEditView, login_url='/login/'), + name='seminar_resitel_edit' + ), + + # Obecný view na profil -- orgům dá rozcestník, řešitelům jejich stránku + path('profil/', views.profilView, name='profil'), # Autocomplete path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), - path('autocomplete/resitel/',views.ResitelAutocomplete.as_view(), name='autocomplete_resitel'), + path('autocomplete/resitel/', org_required(views.ResitelAutocomplete.as_view()), name='autocomplete_resitel'), path('autocomplete/problem/odevzdatelny',views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'), - path('temp/add_solution', views.AddSolutionView.as_view(),name='seminar_vloz_reseni'), - path('temp/nahraj_reseni', views.NahrajReseniView.as_view(),name='seminar_nahraj_reseni'), + path('temp/add_solution', org_required(views.AddSolutionView.as_view()), name='seminar_vloz_reseni'), + path('temp/nahraj_reseni', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'), re_path(r'^temp/vue/.*$',views.VueTestView.as_view(),name='vue_test_view'), path('temp/image_upload/', views.NahrajObrazekKTreeNoduView.as_view()), path('', views.TitulniStranaView.as_view(), name='titulni_strana'), + path('jak-resit/', views.JakResitView.as_view(), name='jak-resit'), # Ceka na autocomplete v3 # path('autocomplete/organizatori/', - # staff_member_required(views.OrganizatorAutocomplete.as_view()), + # org_member_required(views.OrganizatorAutocomplete.as_view()), # name='seminar_autocomplete_organizator') diff --git a/seminar/utils.py b/seminar/utils.py index 19223b9b..ad9be95e 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -1,21 +1,37 @@ # -*- coding: utf-8 -*- import datetime -from django.contrib.auth.decorators import user_passes_test -from html.parser import HTMLParser + +from django.contrib.auth import get_user_model +from django.contrib.auth.decorators import permission_required +from html.parser import HTMLParser + +from django.contrib.auth.models import AnonymousUser +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ObjectDoesNotExist import seminar.models as m +import seminar.treelib as t + +org_required = permission_required('auth.org', raise_exception=True) +resitel_required = permission_required('auth.resitel', raise_exception=True) +User = get_user_model() +User.je_org = lambda self: self.has_perm('auth.org') +User.je_resitel = lambda self: self.has_perm('auth.resitel') +AnonymousUser.je_org = lambda self: False +AnonymousUser.je_resitel = lambda self: False -staff_member_required = user_passes_test(lambda u: u.is_staff) class FirstTagParser(HTMLParser): def __init__(self, *args, **kwargs): self.firstTag = None super().__init__(*args, **kwargs) + def handle_data(self, data): if self.firstTag == None: self.firstTag = data - + + def histogram(seznam): d = {} for i in seznam: @@ -24,9 +40,10 @@ def histogram(seznam): d[i] += 1 return d +# Pozor: zarovnáno velmi netradičně pro přehlednost +roman_numerals = zip((1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1), + ('M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I')) -roman_numerals = zip((1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1), - ('M', 'CM', 'D', 'CD','C', 'XC','L','XL','X','IX','V','IV','I')) def roman(num): res = "" @@ -35,6 +52,7 @@ def roman(num): num %= i return res + def from_roman(rom): if not rom: return 0 @@ -58,9 +76,9 @@ def seznam_problemu(): except: url = None if url: - s += '%s, ' % (url, o.pk, ) + s += '%s, ' % (url, o.pk,) else: - s += '%s, ' % (o.pk, ) + s += '%s, ' % (o.pk,) s = s[:-2] + ']' problemy.append(s) @@ -73,7 +91,7 @@ def seznam_problemu(): jmena[j].append(r) for j in jmena: if len(jmena[j]) > 1: - prb(m.Resitel, 'Duplicitní jméno "%s"' % (j, ), jmena[j]) + prb(m.Resitel, 'Duplicitní jméno "%s"' % (j,), jmena[j]) # Data maturity a narození for r in m.Resitel.objects.all(): @@ -81,11 +99,99 @@ def seznam_problemu(): prb(m.Resitel, 'Neznámý rok maturity', [r]) if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10): prb(m.Resitel, 'Podezřelé datum maturity', [r]) - if r.osoba.datum_narozeni and (r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12): + if r.osoba.datum_narozeni and ( + r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12): prb(m.Resitel, 'Podezřelé datum narození', [r]) -# if not r.email: -# prb(Resitel, u'Neznámý email', [r]) +# if not r.email: +# prb(Resitel, u'Neznámý email', [r]) + + ## Kontroly konzistence databáze a TreeNodů + + # Články + for clanek in m.Clanek.objects.all(): + # získáme řešení svázané se článkem a z něj node ve stromě + reseni = clanek.reseni_set + if (reseni.count() != 1): + raise ValueError("Článek k sobě má nejedno řešení!") + r = reseni.first() + clanek_node = r.text_cely # vazba na ReseniNode z Reseni + # content type je věc pomáhající rozeznávat různé typy objektů v django-polymorphic + # protože isinstance vrátí vždy jen TreeNode + # https://django-polymorphic.readthedocs.io/en/stable/migrating.html + cislonode_ct = ContentType.objects.get_for_model(m.CisloNode) + node = clanek_node + while node is not None: + node_ct = node.polymorphic_ctype + if node_ct == cislonode_ct: # dostali jsme se k CisloNode + # zkontrolujeme, že stromové číslo odpovídá atributu + # .cislonode je opačná vazba k treenode_ptr, abychom z TreeNode dostali + # CisloNode + if clanek.cislo != node.cislonode.cislo: + prb(m.Clanek, "Číslo otištění uložené u článku nesedí s " + "číslem otištění podle struktury treenodů.", [clanek]) + break + node = t.get_parent(node) return problemy +### Generovani obalek +def resi_v_rocniku(rocnik, cislo=None): + """ Vrátí seznam řešitelů, co vyřešili nějaký problém v daném ročníku, do daného čísla. + Parametry: + rocnik (typu Rocnik) ročník, ze kterého chci řešitele, co něco odevzdali + cislo (typu Cislo) číslo, do kterého včetně se počítá, že v daném + ročníku řešitel něco poslal. + Pokud není zadané, počítají se všechna řešení z daného ročníku. + Výstup: + QuerySet objektů typu Resitel """ + + if cislo is None: + # filtrujeme pouze podle ročníku + letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik) + else: # filtrujeme podle ročníku i čísla + letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik, + hodnoceni__cislo_body__poradi__lte=cislo.poradi) + + # vygenerujeme queryset řešitelů, co letos něco poslali + letosni_resitele = m.Resitel.objects.none() + for reseni in letosni_reseni: + letosni_resitele = letosni_resitele | reseni.resitele.filter(rok_maturity__gte=rocnik.druhy_rok()) + return letosni_resitele.distinct() + + +def aktivniResitele(cislo, pouze_letosni=False): + """ Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali + a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla). + Parametry: + cislo (typu Cislo) číslo, o které se jedná + pouze_letosni jen řešitelé, kteří tento rok něco poslali + + """ + letos = cislo.rocnik + + # detekujeme, zda jde o první tři čísla či nikoli (tj. zda spamovat řešitele z minulého roku) + zacatek_rocniku = True + try: + if int(cislo.poradi) > 3: + zacatek_rocniku = False + except ValueError: + if cislo.poradi != '7-8': + raise ValueError(f'{cislo} je neplatné číslo čísla (není int a není 7-8)') + zacatek_rocniku = False + + # nehledě na číslo chceme jen řešitele, kteří letos něco odevzdali + if pouze_letosni: + zacatek_rocniku = False + + try: + loni = m.Rocnik.objects.get(rocnik=letos.rocnik - 1) + except ObjectDoesNotExist: + # Pro první ročník neexistuje ročník předchozí + zacatek_rocniku = False + + if not zacatek_rocniku: + return resi_v_rocniku(letos, cislo) + else: + # spojíme querysety s řešiteli loni a letos do daného čísla + return (resi_v_rocniku(loni) | resi_v_rocniku(letos, cislo)).distinct() diff --git a/seminar/views/utils.py b/seminar/views/utils.py index 3869ffd4..1fa28827 100644 --- a/seminar/views/utils.py +++ b/seminar/views/utils.py @@ -6,8 +6,6 @@ from html.parser import HTMLParser import seminar.models as m -staff_member_required = user_passes_test(lambda u: u.is_staff) - class FirstTagParser(HTMLParser): def __init__(self, *args, **kwargs): self.firstTag = None diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index b0e64c2e..316211fd 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -10,9 +10,10 @@ from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect from django.db.models import Q, Sum, Count from django.views.decorators.csrf import ensure_csrf_cookie from django.views.generic.edit import FormView, CreateView +from django.views.generic.base import TemplateView from django.contrib.auth import authenticate, login, get_user_model, logout from django.contrib.auth import views as auth_views -from django.contrib.auth.models import User +from django.contrib.auth.models import User, Permission from django.contrib.auth.mixins import LoginRequiredMixin from django.db import transaction from django.core import serializers @@ -28,7 +29,7 @@ import seminar.forms as f import seminar.templatetags.treenodes as tnltt import seminar.views.views_rest as vr -from datetime import timedelta, date, datetime +from datetime import timedelta, date, datetime, MAXYEAR from django.utils import timezone from itertools import groupby from collections import OrderedDict @@ -46,17 +47,20 @@ import csv import logging import time +from seminar.utils import aktivniResitele, resi_v_rocniku -def verejna_temata(rocnik): - """Vrací queryset zveřejněných témat v daném ročníku. - """ - return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod') - -def temata_v_rocniku(rocnik): - return Problem.objects.filter(typ=Problem.TYP_TEMA, rocnik=rocnik) +# ze starého modelu +#def verejna_temata(rocnik): +# """ +# Vrací queryset zveřejněných témat v daném ročníku. +# """ +# return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod') +# +#def temata_v_rocniku(rocnik): +# return Problem.objects.filter(typ=Problem.TYP_TEMA, rocnik=rocnik) def get_problemy_k_tematu(tema): - return Problemy.objects.filter(nadproblem = tema) + return Problem.objects.filter(nadproblem = tema) class VlozBodyView(generic.ListView): @@ -379,7 +383,19 @@ class AktualniZadaniView(generic.TemplateView): # }, # ) # -#def ZadaniTemataView(request): +def ZadaniTemataView(request): + nastaveni = get_object_or_404(Nastaveni) + verejne = nastaveni.aktualni_cislo.verejne() + akt_rocnik = nastaveni.aktualni_cislo.rocnik + temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany') + return render(request, 'seminar/tematka/rozcestnik.html', + { + 'tematka': temata, + 'verejne': verejne, + }, + ) + + # nastaveni = get_object_or_404(Nastaveni) # temata = verejna_temata(nastaveni.aktualni_rocnik) # for t in temata: @@ -443,7 +459,7 @@ class AktualniZadaniView(generic.TemplateView): # "cisla" : cisla # }) # return render(request, 'seminar/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik}) -# +# #def ZadaniAktualniVysledkovkaView(request): # nastaveni = get_object_or_404(Nastaveni) @@ -472,49 +488,70 @@ class AktualniZadaniView(generic.TemplateView): ### Titulni strana +def spravne_novinky(request): + """ + Vrátí správný QuerySet novinek, tedy ten, který daný uživatel smí vidět. + Tj. Organizátorům všechny, ostatním jen veřejné + """ + user = request.user + # Využíváme líné vyhodnocování QuerySetů + qs = Novinky.objects.all() + if not user.je_org: + qs = qs.filter(zverejneno=True) + return qs.order_by('-datum') + +def aktualni_temata(rocnik): + """ + Vrací PolymorphicQuerySet témat v daném ročníku, ke kterým se aktuálně dá něco odevzdat. + """ + return Tema.objects.filter(rocnik=rocnik, stav='zadany').order_by('kod') + + class TitulniStranaView(generic.ListView): - model = Novinky template_name='seminar/titulnistrana.html' - queryset = Novinky.objects.order_by('-datum')[:5] + + def get_queryset(self): + return spravne_novinky(self.request)[:3] def get_context_data(self, **kwargs): context = super(TitulniStranaView, self).get_context_data(**kwargs) nastaveni = get_object_or_404(Nastaveni) + + deadline_soustredeni = (nastaveni.aktualni_cislo.datum_deadline_soustredeni, "soustredeni") + preddeadline = (nastaveni.aktualni_cislo.datum_preddeadline, "preddeadline") + deadline = (nastaveni.aktualni_cislo.datum_deadline, "deadline") - # zjisteni spravneho terminu - if nastaveni.aktualni_cislo.datum_deadline_soustredeni: - cas_deadline_soustredeni = nastaveni.aktualni_cislo.\ - datum_deadline_soustredeni - if (datetime.now().date() <= cas_deadline_soustredeni): - cas_deadline = cas_deadline_soustredeni - deadline_soustredeni = True - else: - cas_deadline = nastaveni.aktualni_cislo.datum_deadline - deadline_soustredeni = False - else: - cas_deadline = nastaveni.aktualni_cislo.datum_deadline - deadline_soustredeni = False - - # Pokud neni zverejnene cislo nezverejnuj odpocet - if nastaveni.aktualni_cislo.verejne(): - # pokus se zjistit termin odeslani a pokud neni zadany, - # nezverejnuj odpocet - context['deadline_soustredeni'] = deadline_soustredeni - try: - context['dead'] = datetime.combine(cas_deadline, - datetime.max.time()) - context['ted'] = datetime.now() - except: - context['dead'] = None + try: + nejblizsi_deadline = sorted(filter(lambda dl: dl[0] is not None and dl[0] >= date.today(), [deadline_soustredeni, preddeadline, deadline]))[0] + except IndexError: + nejblizsi_deadline = (None, None) # neni zadna aktualni deadline + + if nejblizsi_deadline[0] is not None: + context['nejblizsi_deadline'] = datetime.combine(nejblizsi_deadline[0], datetime.max.time()) else: - context['dead'] = None - context['deadline_soustredeni'] = deadline_soustredeni + context['nejblizsi_deadline'] = None + + context['typ_deadline'] = nejblizsi_deadline[1] + + # Aktuální témata + nazvy_a_odkazy_na_aktualni_temata = [] + akt_temata = aktualni_temata(nastaveni.aktualni_rocnik) + + for tema in akt_temata: + # FIXME: netuším, jestli funguje tema.verejne_url(), nemáme testdata na témátka - je to asi url vzhledem k ročníku + nazvy_a_odkazy_na_aktualni_temata.append({'nazev':tema.nazev,'url':tema.verejne_url()}) + + context['aktualni_temata'] = nazvy_a_odkazy_na_aktualni_temata + + print(context) + return context class StareNovinkyView(generic.ListView): - model = Novinky template_name = 'seminar/stare_novinky.html' - queryset = Novinky.objects.filter(zverejneno=True).order_by('-datum') + + def get_queryset(self): + return spravne_novinky(self.request) ### Co je M&M @@ -570,7 +607,8 @@ class ArchivView(generic.ListView): ### Výsledky def sloupec_s_poradim(setrizene_body): - """ Ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník + """ + Ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.), podle toho, jak jdou za sebou ve výsledkovce. Parametr: @@ -610,7 +648,8 @@ def sloupec_s_poradim(setrizene_body): return sloupec_s_poradim def cisla_rocniku(rocnik, jen_verejne=True): - """ Vrátí všechna čísla daného ročníku. + """ + Vrátí všechna čísla daného ročníku. Parametry: rocnik (Rocnik): ročník semináře jen_verejne (bool): zda se mají vrátit jen veřejná, nebo všechna čísla @@ -765,7 +804,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True): # získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele) - + # setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší setrizeni_resitele_id, setrizeni_resitele, setrizene_body = setrid_resitele_a_body(resitel_rocnikbody_sezn) poradi = sloupec_s_poradim(setrizene_body) @@ -830,6 +869,32 @@ class RocnikView(generic.DetailView): return context + +class ProblemView(generic.DetailView): + model = Problem + + # Používáme funkci, protože přímo template_name neumí mít v přiřazení dost logiky. Ledaže by se to udělalo polymorfně... + def get_template_names(self, **kwargs): + # FIXME: Switch podle typu není hezký, ale nechtělo se mi to přepisovat celé. Správně by se tohle mělo řešit polymorfismem. + spravne_templaty = { + s.Uloha: "uloha", + s.Tema: "tema", + s.Konfera: "konfera", + s.Clanek: "clanek", + } + context = super().get_context_data(**kwargs) + return ['seminar/archiv/problem_' + spravne_templaty[context['object'].__class__] + '.html'] + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + # Musí se používat context['object'], protože nevíme, jestli dostaneme úložku, téma, článek, .... a tyhle věci vyrábějí různé klíče. + if not context['object'].verejne() and not self.request.user.je_org: + raise PermissionDenied() + if isinstance(context['object'], Clanek): + context['reseni'] = Reseni.objects.filter(problem=context['object']).select_related('resitel').order_by('resitel__prijmeni') + return context + + class RadekVysledkovkyCisla(object): """Obsahuje věci, které se hodí vědět při konstruování výsledkovky. Umožňuje snazší práci v templatu (lepší, než seznam).""" @@ -926,7 +991,7 @@ def vysledkovka_cisla(cislo, context=None): ## TODO možná chytřeji vybírat aktivní řešitele # aktivní řešitelé - chceme letos něco poslal, TODO později vyfiltrujeme ty, kdo mají # u alespoň jedné hodnoty něco jiného než NULL - aktivni_resitele = list(aktivniResitele(cislo.rocnik.rocnik, cislo.poradi)) + aktivni_resitele = list(aktivniResitele(cislo)) # získáme body za číslo hlavni_problemy_slovnik, cislobody = secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy) @@ -974,10 +1039,11 @@ def vysledkovka_cisla(cislo, context=None): return context class CisloView(generic.DetailView): + # FIXME zobrazování témátek a vůbec, teď je tam jen odkaz na číslo v pdf model = Cislo template_name = 'seminar/archiv/cislo.html' - # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik) + # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik) def get_object(self, queryset=None): if queryset is None: queryset = self.get_queryset() @@ -1033,66 +1099,9 @@ class RocnikVysledkovkaView(RocnikView): content_type = 'text/plain; charset=UTF8' #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani -### Generovani obalek -def resi_v_rocniku(rocnik, cislo=None): - """ Vrátí seznam řešitelů, co vyřešili nějaký problém v daném ročníku, do daného čísla. - Parametry: - rocnik (typu Rocnik) ročník, ze kterého chci řešitele, co něco odevzdali - cislo (typu Cislo) číslo, do kterého včetně se počítá, že v daném - ročníku řešitel něco poslal. - Pokud není zadané, počítají se všechna řešení z daného ročníku. - Výstup: - QuerySet objektů typu Resitel """ - - if cislo is None: - # filtrujeme pouze podle ročníku - letosni_reseni = Reseni.objects.filter(hodnoceni__cislo_body__rocnik = rocnik) - else: # filtrujeme podle ročníku i čísla - letosni_reseni = Reseni.objects.filter(hodnoceni__cislo_body__rocnik = rocnik, - hodnoceni__cislo_body__poradi__lte=cislo.poradi) - - # vygenerujeme queryset řešitelů, co letos něco poslali - letosni_resitele = Resitel.objects.none() - for reseni in letosni_reseni: - letosni_resitele = letosni_resitele | reseni.resitele.filter(rok_maturity__gte=rocnik.druhy_rok()) - return letosni_resitele.distinct() - - -def aktivniResitele(rocnik, cislo, pouze_realni=False): - """ Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali - a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla). - Parametry: - rocnik (typu int) číslo ročníku, o který se jedná - cislo (typu int) pořadí čísla, o které se jedná - pouze_realni jen řešitelé, kteří tento rok něco poslali - - """ - letos = Rocnik.objects.get(rocnik = rocnik) - #TODO: co se stane, když zadané kombinace neexistují? ošetřit - aktualni_cislo = Cislo.objects.get(rocnik = rocnik, poradi = cislo) - loni = Rocnik.objects.get(rocnik = rocnik - 1) - - # detekujeme, zda jde o první tři čísla či nikoli - zacatek_rocniku = True - try: - if int(aktualni_cislo.poradi) > 3: - zacatek_rocniku = False - except ValueError: - # pravděpodobně se jedná o číslo 7-8 - zacatek_rocniku = False - - # nehledě na číslo chceme jen řešitele, kteří letos něco odevzdali - if pouze_realni: - zacatek_rocniku = False - - if not zacatek_rocniku: - return resi_v_rocniku(letos) - else: - # spojíme querysety s řešiteli loni a letos do daného čísla - return (resi_v_rocniku(loni) | resi_v_rocniku(letos, aktualni_cislo)).distinct() - def cisloObalkyView(request, rocnik, cislo): - return obalkyView(request, aktivniResitele(rocnik, cislo)) + realne_cislo = Cislo.objects.get(poradi=cislo, rocnik__rocnik=rocnik) + return obalkyView(request, aktivniResitele(realne_cislo)) def obalkyView(request, resitele): @@ -1131,6 +1140,43 @@ def oldObalkovaniView(request, rocnik, cislo): {'cislo': cislo, 'problemy': problemy, 'reseni': reseni} ) +### Orgostránky + +class OrgoRozcestnikView(TemplateView): + ''' Zobrazí organizátorský rozcestník.''' + + template_name = 'seminar/orgorozcestnik.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['posledni_soustredeni'] = Soustredeni.objects.order_by('-datum_konce').first() + nastaveni = Nastaveni.objects.first() + aktualni_rocnik = nastaveni.aktualni_rocnik + context['posledni_cislo_url'] = nastaveni.aktualni_cislo.verejne_url() + # TODO možná chceme odkazovat na právě rozpracované číslo, a ne to poslední vydané + # pokud nechceme haluzit kód (= poradi) dalšího čísla, bude asi potřeba jít + # přes treenody (a dát si přitom pozor na MezicisloNode) + + u = self.request.user + os = s.Osoba.objects.get(user=u) + organizator = s.Organizator.objects.get(osoba=os) + temata_garant = s.Tema.objects.filter(garant=organizator, + rocnik=aktualni_rocnik) + #FIXME: přidat opravovatel, stav='STAV_ZADANY' + ulohy_garant = s.Uloha.objects.filter(garant=organizator, + cislo_zadani__rocnik=aktualni_rocnik) + clanky_garant = s.Clanek.objects.filter(garant=organizator, + cislo__rocnik=aktualni_rocnik) + + context['temata'] = temata_garant + context['ulohy'] = ulohy_garant + context['clanky'] = clanky_garant + context['organizator'] = organizator + return context + + #content_type = 'text/plain; charset=UTF8' + #XXX + ### Tituly def TitulyView(request, rocnik, cislo): @@ -1209,12 +1255,44 @@ def soustredeniUcastniciExportView(request,soustredeni): ### Články +def group_by_rocnik(clanky): + ''' Vezme zadaný seznam článků a seskupí je podle ročníku. + Vrátí seznam seznamů článků ze stejného ročníku.''' + if len(clanky) == 0: + return clanky + clanky.order_by('cislo__rocnik__rocnik') + skupiny_clanku = [] + skupina = [] + + rocnik = clanky.first().cislo.rocnik.rocnik # první ročník + for clanek in clanky: + if clanek.cislo.rocnik.rocnik == rocnik: + skupina.append(clanek) + else: + skupiny_clanku.append(skupina) + skupina = [] + skupina.append(clanek) + rocnik = clanek.cislo.rocnik.rocnik + skupiny_clanku.append(skupina) + return skupiny_clanku + # FIXME: clanky jsou vsechny, pokud budou i neresitelske, tak se take zobrazi +# FIXME: Původně tu byl kód přímo v těle třídy, což rozbíjelo migrace. Opravil jsem, ale vůbec nevím, jestli to funguje. class ClankyResitelView(generic.ListView): model = Problem template_name = 'seminar/clanky/resitelske_clanky.html' - queryset = Clanek.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod') + + # FIXME: QuerySet není pole! + def get_queryset(self): + clanky = Clanek.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo__rocnik').order_by('-cislo__rocnik__rocnik') + queryset = [] + skupiny_clanku = group_by_rocnik(clanky) + for skupina in skupiny_clanku: + skupina.sort(key=lambda clanek: clanek.kod_v_rocniku()) + for clanek in skupina: + queryset.append(clanek) + return queryset # FIXME: pokud chceme orgoclanky, tak nejak zavest do modelu a podle toho odkomentovat a upravit #class ClankyOrganizatorView(generic.ListView): @@ -1245,7 +1323,7 @@ def StavDatabazeView(request): class ResitelView(LoginRequiredMixin,generic.DetailView): model = Resitel - template_name = 'seminar/resitel.html' + template_name = 'seminar/profil/resitel.html' def get_object(self, queryset=None): print(self.request.user) @@ -1260,7 +1338,7 @@ class AddSolutionView(LoginRequiredMixin, FormView): class NahrajReseniView(LoginRequiredMixin, CreateView): model = s.Reseni - template_name = 'seminar/nahraj_reseni.html' + template_name = 'seminar/profil/nahraj_reseni.html' form_class = f.NahrajReseniForm success_url = '/' @@ -1307,79 +1385,79 @@ def loginView(request): return HttpResponseRedirect('/') else: return render(request, - 'seminar/login.html', + 'seminar/profil/login.html', {'form': form, 'login_error': 'Neplatné jméno nebo heslo'}) else: form = LoginForm() - return render(request, 'seminar/login.html', {'form': form}) + return render(request, 'seminar/profil/login.html', {'form': form}) def logoutView(request): form = LoginForm() if request.user.is_authenticated: logout(request) - return render(request, 'seminar/login.html', {'form': form, 'login_error': 'Byli jste úspěšně odhlášeni'}) - return render(request, 'seminar/login.html', {'form': form}) + return render(request, 'seminar/profil/login.html', {'form': form, 'login_error': 'Byli jste úspěšně odhlášeni'}) + return render(request, 'seminar/profil/login.html', {'form': form}) def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data): - msg = "{}, form_hash:{}".format(msg,hash(form_data)) + msg = "{}, form_hash:{}".format(msg,hash(frozenset(form_data.items))) logger.warn(msg) gdpr_logger.warn(msg+", form:{}".format(form_data)) from django.forms.models import model_to_dict def resitelEditView(request): - err_logger = logging.getLogger('seminar.prihlaska.problem') - ## Načtení objektu Osoba a Resitel, patrici k aktuálně přihlášenému uživately - u = request.user - osoba_edit = Osoba.objects.get(user=u) - resitel_edit = osoba_edit.resitel - user_edit = osoba_edit.user - ## Vytvoření slovníku, kterým předvyplním formulář - prefill_1=model_to_dict(user_edit) - prefill_2=model_to_dict(resitel_edit) - prefill_3=model_to_dict(osoba_edit) - prefill_1.update(prefill_2) - prefill_1.update(prefill_3) - form = ProfileEditForm(initial=prefill_1) - ## Změna údajů a jejich uložení - if request.method == 'POST': - form = ProfileEditForm(request.POST) - if form.is_valid(): - ## Změny v osobě - fcd = form.cleaned_data - osoba_edit.jmeno = fcd['jmeno'] - osoba_edit.prijmeni = fcd['prijmeni'] - osoba_edit.pohlavi_muz = fcd['pohlavi_muz'] - osoba_edit.email = fcd['email'] - osoba_edit.telefon = fcd['telefon'] - osoba_edit.ulice = fcd['ulice'] - osoba_edit.mesto = fcd['mesto'] - osoba_edit.psc = fcd['psc'] - ## Změny v osobě s podmínkami - if fcd.get('spam',False): - osoba_edit.datum_souhlasu_zasilani = date.today() - if fcd.get('stat','') in ('CZ','SK'): - osoba_edit.stat = fcd['stat'] - else: - ## Neznámá země - msg = "Unknown country {}".format(fcd['stat_text']) - - ## Změny v řešiteli - resitel_edit.skola = fcd['skola'] - resitel_edit.rok_maturity = fcd['rok_maturity'] - resitel_edit.zasilat = fcd['zasilat'] - if fcd.get('skola'): - resitel_edit.skola = fcd['skola'] - else: - # Unknown school - log it - msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa']) - resitel_edit.save() - osoba_edit.save() - return HttpResponseRedirect('/thanks/') - else: - ## Stránka před odeslaním formuláře = předvyplněný formulář - return render(request, 'seminar/edit.html', {'form': form}) + err_logger = logging.getLogger('seminar.prihlaska.problem') + ## Načtení objektu Osoba a Resitel, patrici k aktuálně přihlášenému uživately + u = request.user + osoba_edit = Osoba.objects.get(user=u) + resitel_edit = osoba_edit.resitel + user_edit = osoba_edit.user + ## Vytvoření slovníku, kterým předvyplním formulář + prefill_1=model_to_dict(user_edit) + prefill_2=model_to_dict(resitel_edit) + prefill_3=model_to_dict(osoba_edit) + prefill_1.update(prefill_2) + prefill_1.update(prefill_3) + form = ProfileEditForm(initial=prefill_1) + ## Změna údajů a jejich uložení + if request.method == 'POST': + form = ProfileEditForm(request.POST) + if form.is_valid(): + ## Změny v osobě + fcd = form.cleaned_data + osoba_edit.jmeno = fcd['jmeno'] + osoba_edit.prijmeni = fcd['prijmeni'] + osoba_edit.pohlavi_muz = fcd['pohlavi_muz'] + osoba_edit.email = fcd['email'] + osoba_edit.telefon = fcd['telefon'] + osoba_edit.ulice = fcd['ulice'] + osoba_edit.mesto = fcd['mesto'] + osoba_edit.psc = fcd['psc'] + ## Změny v osobě s podmínkami + if fcd.get('spam',False): + osoba_edit.datum_souhlasu_zasilani = date.today() + if fcd.get('stat','') in ('CZ','SK'): + osoba_edit.stat = fcd['stat'] + else: + ## Neznámá země + msg = "Unknown country {}".format(fcd['stat_text']) + + ## Změny v řešiteli + resitel_edit.skola = fcd['skola'] + resitel_edit.rok_maturity = fcd['rok_maturity'] + resitel_edit.zasilat = fcd['zasilat'] + if fcd.get('skola'): + resitel_edit.skola = fcd['skola'] + else: + # Unknown school - log it + msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa']) + resitel_edit.save() + osoba_edit.save() + return formularOKView(request) + else: + ## Stránka před odeslaním formuláře = předvyplněný formulář + return render(request, 'seminar/profil/edit.html', {'form': form}) def prihlaskaView(request): generic_logger = logging.getLogger('seminar.prihlaska') @@ -1391,8 +1469,8 @@ def prihlaskaView(request): if form.is_valid(): generic_logger.info("Form valid") fcd = form.cleaned_data - form_hash = hash(fcd) - form_logger.info(fcd,form_hash=form_hash) + form_hash = hash(frozenset(fcd.items())) + form_logger.info(str(fcd) + str(form_hash)) # TODO možná logovat jinak with transaction.atomic(): u = User.objects.create_user( @@ -1400,6 +1478,8 @@ def prihlaskaView(request): password=fcd['password'], email = fcd['email']) u.save() + resitel_perm = Permission.objects.filter(codename__exact='resitel').first() + u.user_permissions.add(resitel_perm) o = Osoba( jmeno = fcd['jmeno'], @@ -1422,7 +1502,7 @@ def prihlaskaView(request): else: # Unknown country - log it msg = "Unknown country {}".format(fcd['stat_text']) - err_logger.warn(msg,form_hash=form_hash) + err_logger.warn(msg + str(form_hash)) o.save() o.user = u @@ -1440,22 +1520,22 @@ def prihlaskaView(request): else: # Unknown school - log it msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa']) - err_logger.warn(msg,form_hash=form_hash) + err_logger.warn(msg + str(form_hash)) r.save() - return HttpResponseRedirect('/thanks/') + return formularOKView(request) # if a GET (or any other method) we'll create a blank form else: form = PrihlaskaForm() - return render(request, 'seminar/prihlaska.html', {'form': form}) + return render(request, 'seminar/profil/prihlaska.html', {'form': form}) # FIXME: Tohle asi vlastně vůbec nepatří do aplikace 'seminar' class LoginView(auth_views.LoginView): # Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL - template_name = 'seminar/login.html' + template_name = 'seminar/profil/login.html' # Přesměrovací URL má být v kontextu: def get_context_data(self, **kwargs): @@ -1465,7 +1545,7 @@ class LoginView(auth_views.LoginView): class LogoutView(auth_views.LogoutView): # Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL - template_name = 'seminar/logout.html' + template_name = 'seminar/profil/logout.html' # Pavel: Vůbec nevím, proč to s _lazy funguje, ale bez toho to bylo rozbité. next_page = reverse_lazy('titulni_strana') @@ -1521,3 +1601,34 @@ class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView): return JsonResponse({"url":self.object.na_web.url}) + +# Jen hloupé rozhazovátko +def profilView(request): + user = request.user + if user.has_perm('auth.org'): + return OrgoRozcestnikView.as_view()(request) + if user.has_perm('auth.resitel'): + return ResitelView.as_view()(request) + else: + return LoginView.as_view()(request) + +# Interní, nemá se nikdy objevit v urls (jinak to účastníci vytrolí) +def formularOKView(request): + template_name = 'seminar/formular_ok.html' + odkazy = [ + # (Text, odkaz) + ('Vrátit se na titulní stránku', reverse('titulni_strana')), + ('Zobrazit aktuální zadání', reverse('seminar_aktualni_zadani')), + ] + context = { + 'odkazy': odkazy, + } + return render(request, template_name, context) + +#------------------ Jak řešit - možná má být udělané úplně jinak + +class JakResitView(generic.ListView): + template_name = 'seminar/jak-resit.html' + + def get_queryset(self): + return None diff --git a/sitetree_new.json b/sitetree_new.json deleted file mode 100644 index d1b7cfed..00000000 --- a/sitetree_new.json +++ /dev/null @@ -1 +0,0 @@ -[{"model": "sitetree.tree", "pk": 1, "fields": {"title": "Hlavn\u00ed menu", "alias": "main_menu"}}, {"model": "sitetree.treeitem", "pk": 1, "fields": {"title": "Co je M&M", "hint": "", "url": "/co-je-MaM/uvod/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 1, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 2, "fields": {"title": "Jak \u0159e\u0161it", "hint": "", "url": "/co-je-MaM/jak-resit/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 2, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 3, "fields": {"title": "Aktu\u00e1ln\u00ed
ro\u010dn\u00edk", "hint": "", "url": "/zadani/aktualni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 3, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 4, "fields": {"title": "Soust\u0159ed\u011bn\u00ed", "hint": "", "url": "/soustredeni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 4, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 5, "fields": {"title": "Archiv", "hint": "", "url": "/archiv/cisla/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 5, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 6, "fields": {"title": "P\u0159ihl\u00e1sit", "hint": "", "url": "/login/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": true, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 6, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 21, "fields": {"title": "Profil", "hint": "", "url": "/profil/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": true, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 21, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 7, "fields": {"title": "\u00davod", "hint": "", "url": "/co-je-MaM/uvod/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 7, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 8, "fields": {"title": "Organiz\u00e1to\u0159i", "hint": "", "url": "/co-je-MaM/organizatori/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 8, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 9, "fields": {"title": "FAQ", "hint": "", "url": "/co-je-MaM/FAQ/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 9, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 10, "fields": {"title": "Kontakt", "hint": "", "url": "/co-je-MaM/kontakt/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 10, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 11, "fields": {"title": "T\u00e9mata", "hint": "", "url": "/jak-resit/temata/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 11, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 12, "fields": {"title": "Jak ps\u00e1t p\u0159\u00edsp\u011bvek", "hint": "", "url": "/jak-resit/jak-psat-prispevek/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 12, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 13, "fields": {"title": "Odm\u011bny", "hint": "", "url": "/co-je-MaM/odmeny/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 13, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 14, "fields": {"title": "Jak poslat \u0159e\u0161en\u00ed", "hint": "", "url": "/jak-resit/jak-poslat-reseni", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 14, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 15, "fields": {"title": "Aktu\u00e1ln\u00ed t\u00e9mata", "hint": "", "url": "/zadani/temata/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 15, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 16, "fields": {"title": "V\u00fdsledkov\u00e1 listina", "hint": "", "url": "zadani/vysledkova-listina/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 16, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 17, "fields": {"title": "\u010cl\u00e1nky", "hint": "", "url": "/clanky/resitel/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 17, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 18, "fields": {"title": "\u00davod", "hint": "", "url": "/soustredeni/uvod/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 18, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 19, "fields": {"title": "P\u0159ipravujeme", "hint": "", "url": "/soustredeni/pripravujeme/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 19, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 20, "fields": {"title": "Prob\u011bhlo", "hint": "", "url": "/soustredeni/probehlo/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 20, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 22, "fields": {"title": "Osobn\u00ed \u00fadaje", "hint": "", "url": "/profil/osobni-udaje", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 21, "sort_order": 22, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 23, "fields": {"title": "Poslat \u0159e\u0161en\u00ed", "hint": "", "url": "/odeslat-reseni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 21, "sort_order": 23, "access_permissions": []}}]