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 1ace9e01..a9d2e082 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,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 @@ -81,9 +81,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 @@ -109,7 +109,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/flat.json index db13ba78..8adde103 100644 --- a/flat.json +++ b/flat.json @@ -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, 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/views.py b/galerie/views.py index 729ac3b8..d23e79f1 100644 --- a/galerie/views.py +++ b/galerie/views.py @@ -38,7 +38,7 @@ def nahled(request, pk, soustredeni): if not request.user.is_staff: 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 = [] @@ -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/korektury/models.py b/korektury/models.py index 6e5fed8a..88c1a5e6 100644 --- a/korektury/models.py +++ b/korektury/models.py @@ -79,16 +79,25 @@ 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 diff --git a/korektury/templates/korektury/base.html b/korektury/templates/korektury/base.html index b31d5d47..886a15e1 100644 --- a/korektury/templates/korektury/base.html +++ b/korektury/templates/korektury/base.html @@ -1,5 +1,9 @@ {% extends "base.html" %} +{% block submenu %} + {% include "korektury/submenu.html" %} +{% endblock %} + {% block content %} {# blok do kterého se nacita text, v pripade jinyhc templatu obalit vlastnim blokem #} {% endblock %} diff --git a/korektury/templates/korektury/help.html b/korektury/templates/korektury/help.html index 0024848e..f2ddafb9 100644 --- a/korektury/templates/korektury/help.html +++ b/korektury/templates/korektury/help.html @@ -1,4 +1,11 @@ {% extends "korektury/base.html" %} + +{% block submenu %} + {% with "help" as selected %} + {% include "korektury/submenu.html" %} + {% endwith %} +{% endblock %} + {% load staticfiles %} {% block title %} Nápověda ke korigovátku {% endblock title %} diff --git a/korektury/templates/korektury/seznam.html b/korektury/templates/korektury/seznam.html index f22ba673..61f6fff7 100644 --- a/korektury/templates/korektury/seznam.html +++ b/korektury/templates/korektury/seznam.html @@ -1,6 +1,10 @@ {% extends "korektury/base.html" %} {% load staticfiles %} +{% block submenu %} + {% include "korektury/submenu.html" %} +{% endblock %} + {% block script%} {% endblock %} diff --git a/korektury/templates/korektury/submenu.html b/korektury/templates/korektury/submenu.html new file mode 100644 index 00000000..0a5ed988 --- /dev/null +++ b/korektury/templates/korektury/submenu.html @@ -0,0 +1,13 @@ +{% with "/korektury" as cesta %} + + + +{% endwith %} + + diff --git a/korektury/urls.py b/korektury/urls.py index d6394820..77bc686d 100644 --- a/korektury/urls.py +++ b/korektury/urls.py @@ -5,7 +5,8 @@ from . import views staff_member_required = user_passes_test(lambda u: u.is_staff) urlpatterns = [ - path('korektury/', staff_member_required(views.KorekturyListView.as_view()), name='korektury-list'), + path('korektury/', staff_member_required(views.KorekturyAktualniListView.as_view()), name='korektury-list'), + path('korektury/zastarale/', staff_member_required(views.KorekturyZastaraleListView.as_view()), name='korektury-list'), path('korektury//', staff_member_required(views.KorekturyView.as_view()), name='korektury'), path('korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), ] diff --git a/korektury/views.py b/korektury/views.py index c3f22569..aea3813a 100644 --- a/korektury/views.py +++ b/korektury/views.py @@ -29,6 +29,28 @@ class KorekturyListView(generic.ListView): ) template_name = 'korektury/seznam.html' +class KorekturyAktualniListView(KorekturyListView): + def get_queryset(self, *args, **kwargs): + queryset=super(KorekturyAktualniListView,self).get_queryset() + queryset=queryset.exclude(status="zastarale") + return queryset + + def get_context_data(self, **kwargs): + context = super(KorekturyAktualniListView,self).get_context_data(**kwargs) + context['selected'] = 'aktualni' + return context + +class KorekturyZastaraleListView(KorekturyListView): + def get_queryset(self, *args, **kwargs): + queryset=super(KorekturyZastaraleListView,self).get_queryset() + queryset=queryset.filter(status="zastarale") + return queryset + + def get_context_data(self, **kwargs): + context = super(KorekturyZastaraleListView,self).get_context_data(**kwargs) + context['selected'] = 'zastarale' + return context + ### Korektury class KorekturyView(generic.TemplateView): model = Oprava @@ -130,7 +152,9 @@ class KorekturyView(generic.TemplateView): ''' # parametry e-mailu - odkaz = "https://mam.mff.cuni.cz/korektury/{}/".format(oprava.pdf.pk) + #odkaz = "https://mam.mff.cuni.cz/korektury/{}/".format(oprava.pdf.pk) + from django.urls import reverse + odkaz = self.request.build_absolute_uri(reverse('korektury', kwargs={'pdf': oprava.pdf.pk})) from_email = 'korekturovatko@mam.mff.cuni.cz' subject = 'Nová korektura od {} v {}'.format(autor, oprava.pdf.nazev) diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index 62cd7fe7..430fbe16 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -98,7 +98,7 @@ INSTALLED_APPS = ( # Utilities 'sekizai', -# 'reversion', + 'reversion', 'django_countries', 'solo', 'ckeditor', @@ -136,7 +136,6 @@ INSTALLED_APPS = ( # 'admin_tools.theming', # 'admin_tools.menu', # 'admin_tools.dashboard', - 'flat', 'django.contrib.admin', ) @@ -179,7 +178,8 @@ CKEDITOR_CONFIGS = { # 'toolbar': 'full', 'height': '40em', 'width': '100%', - 'toolbarStartupExpanded': False + 'toolbarStartupExpanded': False, + 'allowedContent' : True, }, } @@ -248,7 +248,7 @@ LOGGING = { 'class': 'django.utils.log.AdminEmailHandler', 'formatter': 'verbose', }, - 'mail_registraion': { + 'mail_registration': { 'level': 'WARN', 'class': 'django.utils.log.AdminEmailHandler', 'formatter': 'verbose', diff --git a/mamweb/settings_local.py b/mamweb/settings_local.py index 1e62009f..de1f0b9b 100644 --- a/mamweb/settings_local.py +++ b/mamweb/settings_local.py @@ -94,4 +94,6 @@ LOGGING = { # set to 'DEBUG' for EXTRA verbose output # LOGGING['handlers']['console']['level'] = 'INFO' +# E-maily posílat chceme, ale do terminálu :-) EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +SEND_EMAIL_NOTIFICATIONS = True diff --git a/mamweb/settings_test.py b/mamweb/settings_test.py index 2d85f2f5..e8af9a88 100644 --- a/mamweb/settings_test.py +++ b/mamweb/settings_test.py @@ -12,7 +12,7 @@ import os.path # Import common settings from .settings_common import * # zatim nutne, casem snad vyresime # noqa -MIDDLEWARE_CLASSES += ( +MIDDLEWARE += ( 'debug_toolbar.middleware.DebugToolbarMiddleware', ) @@ -32,7 +32,7 @@ DEBUG = True TEMPLATES[0]['OPTIONS']['debug'] = True -ALLOWED_HOSTS = ['*.mam.mff.cuni.cz', 'atrey.karlin.mff.cuni.cz', 'mam.mff.cuni.cz', 'mam-test.kam.mff.cuni.cz', 'gimli.ms.mff.cuni.cz'] +ALLOWED_HOSTS = ['*.mam.mff.cuni.cz', 'atrey.karlin.mff.cuni.cz', 'mam.mff.cuni.cz', 'mam-test.kam.mff.cuni.cz', 'gimli.ms.mff.cuni.cz', 'mam-test.ks.matfyz.cz'] # Database # https://docs.djangoproject.com/en/1.7/ref/settings/#databases diff --git a/mamweb_prod.ini b/mamweb_prod.ini index 218593e6..8816064f 100644 --- a/mamweb_prod.ini +++ b/mamweb_prod.ini @@ -5,7 +5,7 @@ chdir = /akce/mam/www/mamweb-prod/ home = /akce/mam/www/mamweb-prod/ module = mamweb.wsgi -plugin = python +plugin = python3 virtualenv = env master = True vacuum = True diff --git a/mamweb_test.ini b/mamweb_test.ini index a27f71f9..ddd6e55c 100644 --- a/mamweb_test.ini +++ b/mamweb_test.ini @@ -5,7 +5,7 @@ chdir = /akce/mam/www/mamweb-test/ home = /akce/mam/www/mamweb-test/ module = mamweb.wsgi -plugin = python +plugin = python3 virtualenv = env master = True vacuum = True diff --git a/prednasky/templates/prednasky/seznam_prednasek_export.txt b/prednasky/templates/prednasky/seznam_prednasek_export.txt index 2defc91e..21d88942 100644 --- a/prednasky/templates/prednasky/seznam_prednasek_export.txt +++ b/prednasky/templates/prednasky/seznam_prednasek_export.txt @@ -1,19 +1,7 @@ {% block content %} {% spaceless %} -{% for hlas in hlasovani %} -hlas({{hlas.ucastnik}},{{hlas.prednaska.id}},{{hlas.body}}) -{% endfor %} -{% for prednaska in prednasky %} -prednaska({{prednaska.id}},{{prednaska.org.id}},{{prednaska.obtiznost}},{{prednaska.obor}}) -{% endfor %} -{% for org in orgove %} -org({{org.id}},4,0,15) -{% endfor %} -{% for org in orgove %} -{{org.id}};{{org}} -{% endfor %} {% for prednaska in prednasky %} -{{prednaska.id}};{{prednaska.nazev}};{{prednaska.org.id}} +{{prednaska.id}};{{prednaska.nazev}};{{prednaska.org}} {{prednaska.body}} {% endfor %} {% endspaceless %} diff --git a/prednasky/views.py b/prednasky/views.py index a5dbbd76..93cccf1b 100644 --- a/prednasky/views.py +++ b/prednasky/views.py @@ -57,12 +57,26 @@ class SeznamListView(generic.ListView): self.seznam = get_object_or_404(Seznam, id=self.kwargs["seznam"]) prednasky = Prednaska.objects.filter(seznamy=self.seznam).order_by( 'org__user__first_name', 'org__user__last_name' - ).annotate(body=Sum('hlasovani__body')) + ) return prednasky + # FIXME nahradit anotaci s filtrem po prechodu na Django 2.2 + def get_context_data(self,**kwargs): + context = super(SeznamListView, self).get_context_data(**kwargs) + + # hlasovani se vztahuje k nejnovejsimu soustredeni + sous = Soustredeni.objects.first() + seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first() + + for obj in self.object_list: + hlasovani_set = obj.hlasovani_set.filter(seznam=seznam).only('body') + obj.body = sum(map(lambda x: x.body,hlasovani_set)) + + return context + def SeznamExportView(request, seznam): - u"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor""" + """Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor""" # TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro # lidi? hlasovani = Hlasovani.objects.filter(seznam=seznam) diff --git a/seminar/admin.py b/seminar/admin.py index edfbb595..c5d7e69b 100644 --- a/seminar/admin.py +++ b/seminar/admin.py @@ -3,6 +3,7 @@ from django.contrib import admin from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter from reversion.admin import VersionAdmin from django_reverse_admin import ReverseModelAdmin +from solo.admin import SingletonModelAdmin # Todo: reversion @@ -160,5 +161,5 @@ class TextNodeAdmin(PolymorphicChildModelAdmin): show_in_index = True -admin.site.register(m.Nastaveni) +admin.site.register(m.Nastaveni, SingletonModelAdmin) admin.site.register(m.Novinky) diff --git a/seminar/management/commands/auth.py b/seminar/management/commands/auth.py index 1aa504dd..71757418 100644 --- a/seminar/management/commands/auth.py +++ b/seminar/management/commands/auth.py @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- -from django.core.management.base import NoArgsCommand +from django.core.management.base import BaseCommand from django.contrib.sessions.models import Session from django.contrib.auth.models import User -class Command(NoArgsCommand): +class Command(BaseCommand): u"""Vypiš username přihlášeného orga s daným session_key. Příkaz pro manage.py, který ze vstupu přečte session_key (tak, jak je uložen v cookie sessionid) a pokud session existuje a příslušný přihlášený uživatel má právo přihlásit se do admina, vypíše jeho username. """ - def handle_noargs(self, **options): + def handle(self, *args, **options): session_key = raw_input() s = Session.objects.get(pk=session_key).get_decoded() user_id = s['_auth_user_id'] diff --git a/seminar/migrations/0001_squashed_0067_auto_20190814_0805.py b/seminar/migrations/0001_squashed_0067_auto_20190814_0805.py index 05d5f265..5eb3e452 100644 --- a/seminar/migrations/0001_squashed_0067_auto_20190814_0805.py +++ b/seminar/migrations/0001_squashed_0067_auto_20190814_0805.py @@ -511,7 +511,7 @@ def vyrob_problemum_ctypes(apps, schema_editor): class Migration(migrations.Migration): atomic = False - replaces = [('seminar', '0001_initial'), ('seminar', '0002_add_body_views'), ('seminar', '0003_add_skola_zs_ss'), ('seminar', '0004_add_old_dakos_id'), ('seminar', '0005_alter_problem_autor'), ('seminar', '0006_problem_add_timestamp'), ('seminar', '0007_problem_zamereni'), ('seminar', '0008_reseni_forma'), ('seminar', '0009_rename_imported_IDs'), ('seminar', '0010_alter_rok_maturity'), ('seminar', '0011_alter_timestamp_def'), ('seminar', '0012_remove_soustredeni_ucastnici'), ('seminar', '0013_soustredeni_ucastnici_through_model'), ('seminar', '0014_uprava_poznamek'), ('seminar', '0015_soustredeni_text'), ('seminar', '0016_texty_problemu'), ('seminar', '0017_texty_problemu_minor'), ('seminar', '0018_problemnavrh_problemzadany'), ('seminar', '0019_rocnik_ciselne'), ('seminar', '0020_indexy_a_razeni'), ('seminar', '0021_cislo_verejna_vysledkovka'), ('seminar', '0022_decimal_body'), ('seminar', '0023_add_novinky'), ('seminar', '0024_add_organizator'), ('seminar', '0025_zmena_cesty_nahravani_obrazku'), ('seminar', '0026_soustredeni_typ'), ('seminar', '0027_export_flag_a_typ_akce'), ('seminar', '0028_add_body_celkem_views'), ('seminar', '0029_fix_body_celkem_views'), ('seminar', '0030_add_vysledky'), ('seminar', '0031_cislo_pdf'), ('seminar', '0032_cislo_pdf_blank_typos'), ('seminar', '0033_organizator_studuje_popisek'), ('seminar', '0034_reseni_forma_default_email'), ('seminar', '0035_django_imagekit'), ('seminar', '0036_add_org_to_soustredeni'), ('seminar', '0037_prispevek'), ('seminar', '0038_change_meta_prispevek'), ('seminar', '0039_pohadka'), ('seminar', '0040_pohadka_nepovinny_autor'), ('seminar', '0041_konfery'), ('seminar', '0042_cislo_faze'), ('seminar', '0043_uprava_faze'), ('seminar', '0044_uprava_faze'), ('seminar', '0045_cislo_pridani_faze_nahrano'), ('seminar', '0042_auto_20161005_0847'), ('seminar', '0046_merge'), ('seminar', '0047_auto_20170120_2118'), ('seminar', '0048_add_cislo_datum_deadline_soustredeni'), ('seminar', '0049_auto_20190430_2354'), ('seminar', '0050_auto_20190510_2228'), ('seminar', '0051_resitel_to_osoba'), ('seminar', '0052_user_to_organizator'), ('seminar', '0053_organizator_organizuje_od_do'), ('seminar', '0055_smazat_nemigrovane_zastarale_veci'), ('seminar', '0056_vrcholy_pro_rocniky_a_cisla'), ('seminar', '0057_reseni_to_reseni_hodnoceni'), ('seminar', '0058_problem_to_uloha_tema_clanek'), ('seminar', '0059_vytvorit_pohadkanode'), ('seminar', '0060_spoj_stromy'), ('seminar', '0061_kill_frankenstein'), ('seminar', '0062_redukce_modelu_pohadky'), ('seminar', '0063_procisteni_migraci'), ('seminar', '0064_auto_20190610_2358'), ('seminar', '0065_treenode_polymorphic_ctype'), ('seminar', '0066_problem_polymorphic_ctype'), ('seminar', '0067_auto_20190814_0805')] + replaces = [('seminar', '0001_initial'), ('seminar', '0002_add_body_views'), ('seminar', '0003_add_skola_zs_ss'), ('seminar', '0004_add_old_dakos_id'), ('seminar', '0005_alter_problem_autor'), ('seminar', '0006_problem_add_timestamp'), ('seminar', '0007_problem_zamereni'), ('seminar', '0008_reseni_forma'), ('seminar', '0009_rename_imported_IDs'), ('seminar', '0010_alter_rok_maturity'), ('seminar', '0011_alter_timestamp_def'), ('seminar', '0012_remove_soustredeni_ucastnici'), ('seminar', '0013_soustredeni_ucastnici_through_model'), ('seminar', '0014_uprava_poznamek'), ('seminar', '0015_soustredeni_text'), ('seminar', '0016_texty_problemu'), ('seminar', '0017_texty_problemu_minor'), ('seminar', '0018_problemnavrh_problemzadany'), ('seminar', '0019_rocnik_ciselne'), ('seminar', '0020_indexy_a_razeni'), ('seminar', '0021_cislo_verejna_vysledkovka'), ('seminar', '0022_decimal_body'), ('seminar', '0023_add_novinky'), ('seminar', '0024_add_organizator'), ('seminar', '0025_zmena_cesty_nahravani_obrazku'), ('seminar', '0026_soustredeni_typ'), ('seminar', '0027_export_flag_a_typ_akce'), ('seminar', '0028_add_body_celkem_views'), ('seminar', '0029_fix_body_celkem_views'), ('seminar', '0030_add_vysledky'), ('seminar', '0031_cislo_pdf'), ('seminar', '0032_cislo_pdf_blank_typos'), ('seminar', '0033_organizator_studuje_popisek'), ('seminar', '0034_reseni_forma_default_email'), ('seminar', '0035_django_imagekit'), ('seminar', '0036_add_org_to_soustredeni'), ('seminar', '0037_prispevek'), ('seminar', '0038_change_meta_prispevek'), ('seminar', '0039_pohadka'), ('seminar', '0040_pohadka_nepovinny_autor'), ('seminar', '0041_konfery'), ('seminar', '0042_cislo_faze'), ('seminar', '0043_uprava_faze'), ('seminar', '0044_uprava_faze'), ('seminar', '0045_cislo_pridani_faze_nahrano'), ('seminar', '0042_auto_20161005_0847'), ('seminar', '0046_merge'), ('seminar', '0047_auto_20170120_2118'), ('seminar', '0048_add_cislo_datum_deadline_soustredeni'), ('seminar', '0049_auto_20190430_2354'), ('seminar', '0050_auto_20190510_2228'), ('seminar', '0051_resitel_to_osoba'), ('seminar', '0052_user_to_organizator'), ('seminar', '0053_organizator_organizuje_od_do'), ('seminar', '0055_smazat_nemigrovane_zastarale_veci'), ('seminar', '0056_vrcholy_pro_rocniky_a_cisla'), ('seminar', '0057_reseni_to_reseni_hodnoceni'), ('seminar', '0058_problem_to_uloha_tema_clanek'), ('seminar', 'fix_0058'), ('seminar', '0059_vytvorit_pohadkanode'), ('seminar', '0060_spoj_stromy'), ('seminar', '0061_kill_frankenstein'), ('seminar', '0062_redukce_modelu_pohadky'), ('seminar', '0063_procisteni_migraci'), ('seminar', '0064_auto_20190610_2358'), ('seminar', '0065_treenode_polymorphic_ctype'), ('seminar', '0066_problem_polymorphic_ctype'), ('seminar', '0067_auto_20190814_0805')] initial = True @@ -1816,6 +1816,12 @@ class Migration(migrations.Migration): konfery_rucne, ), + # migr "fix 0058" + migrations.RunSQL( + "update seminar_problemy set typ = 'uloha' where typ like 'b_uloha_';", + "update seminar_problemy set typ = 'uloha' where typ like 'b_uloha_';" + ), + # migr 0059 migrations.RunPython( vytvor_pohadkanode, diff --git a/seminar/migrations/0059_vytvorit_pohadkanode.py b/seminar/migrations/0059_vytvorit_pohadkanode.py index 7ff7c655..d0edd677 100644 --- a/seminar/migrations/0059_vytvorit_pohadkanode.py +++ b/seminar/migrations/0059_vytvorit_pohadkanode.py @@ -21,7 +21,7 @@ def vytvor_pohadkanode(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('seminar', '0058_problem_to_uloha_tema_clanek'), + ('seminar', 'fix_0058'), ] operations = [ diff --git a/seminar/migrations/0065_treenode_polymorphic_ctype.py b/seminar/migrations/0065_treenode_polymorphic_ctype.py index 71eef262..cb65d8f1 100644 --- a/seminar/migrations/0065_treenode_polymorphic_ctype.py +++ b/seminar/migrations/0065_treenode_polymorphic_ctype.py @@ -5,7 +5,7 @@ import django.db.models.deletion def vyrob_treenodum_ctypes(apps, schema_editor): # Kód zkopírovaný z dokumentace: https://django-polymorphic.readthedocs.io/en/stable/migrating.html - # XXX: Nevím, jestli se tohle náhodou nemělo spustit na všech childech (jen/i) + # NOTE: Tahle migrace je špatně, 0087 ji opravuje. Možno squashnout pryč. TreeNode = apps.get_model('seminar', 'TreeNode') ContentType = apps.get_model('contenttypes', 'ContentType') @@ -27,5 +27,5 @@ class Migration(migrations.Migration): name='polymorphic_ctype', field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_seminar.treenode_set+', to='contenttypes.ContentType'), ), - migrations.RunPython(vyrob_treenodum_ctypes, migrations.RunPython.noop), + migrations.RunPython(vyrob_treenodum_ctypes, migrations.RunPython.noop, elidable=True), ] diff --git a/seminar/migrations/0066_problem_polymorphic_ctype.py b/seminar/migrations/0066_problem_polymorphic_ctype.py index f956217e..3aab4605 100644 --- a/seminar/migrations/0066_problem_polymorphic_ctype.py +++ b/seminar/migrations/0066_problem_polymorphic_ctype.py @@ -5,7 +5,7 @@ import django.db.models.deletion def vyrob_problemum_ctypes(apps, schema_editor): # Kód zkopírovaný z dokumentace: https://django-polymorphic.readthedocs.io/en/stable/migrating.html - # XXX: Nevím, jestli se tohle náhodou nemělo spustit na všech childech (jen/i) + # NOTE: Tahle migrace je špatně, 0087 ji opravuje. Možno squashnout pryč. Problem = apps.get_model('seminar', 'Problem') ContentType = apps.get_model('contenttypes', 'ContentType') @@ -25,5 +25,5 @@ class Migration(migrations.Migration): name='polymorphic_ctype', field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_seminar.problem_set+', to='contenttypes.ContentType'), ), - migrations.RunPython(vyrob_problemum_ctypes, migrations.RunPython.noop), + migrations.RunPython(vyrob_problemum_ctypes, migrations.RunPython.noop, elidable=True), ] diff --git a/seminar/migrations/0084_clanek_cislo.py b/seminar/migrations/0084_clanek_cislo.py index 5de1fefa..7a211fa6 100644 --- a/seminar/migrations/0084_clanek_cislo.py +++ b/seminar/migrations/0084_clanek_cislo.py @@ -4,6 +4,9 @@ from django.db import migrations, models import django.db.models.deletion from seminar.treelib import get_parent +import logging +logger = logging.getLogger(__name__) + def najdi_cislo(apps, schema_editor): Clanek = apps.get_model('seminar', 'Clanek') Hodnoceni = apps.get_model('seminar', 'Hodnoceni') @@ -15,7 +18,10 @@ def najdi_cislo(apps, schema_editor): for c in Clanek.objects.all(): reseni = c.reseni_set if (reseni.count() != 1): # Pozor, reseni_set je Manager, takže se na něj musí trošku jinak - raise ValueError("Článek k sobě má nejedno řešení!") + logger.warn(f"Více než jedno řešení pro článek {c}") + c.cislo = None + c.save() + continue r = reseni.first() aktualniNode = r.text_cely # Hlavní ReseniNode pro řešení while aktualniNode is not None: diff --git a/seminar/migrations/0086_auto_20200819_0959.py b/seminar/migrations/0086_auto_20200819_0959.py new file mode 100644 index 00000000..a5847e71 --- /dev/null +++ b/seminar/migrations/0086_auto_20200819_0959.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.15 on 2020-08-19 07:59 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('seminar', '0085_nepovinna_prezdivka'), + ] + + operations = [ + migrations.AlterModelOptions( + name='organizator', + options={'ordering': ['-organizuje_do', 'osoba__jmeno', 'osoba__prijmeni'], 'verbose_name': 'Organizátor', 'verbose_name_plural': 'Organizátoři'}, + ), + ] diff --git a/seminar/migrations/0087_fix_polymorphism.py b/seminar/migrations/0087_fix_polymorphism.py new file mode 100644 index 00000000..40ce9adf --- /dev/null +++ b/seminar/migrations/0087_fix_polymorphism.py @@ -0,0 +1,49 @@ +# Generated by Django 2.2.16 on 2020-09-04 12:06 + +from django.db import migrations +from logging import getLogger + +log = getLogger(__name__) + +# Oprava migrací 0065 a 0066, kde jsem špatně pochopil django-polymorphic + +# Pomocná funkce -- děláme to samé pro obě polymorfní hierarchie +def fix_ctypes(parent: str, children, apps, schema_editor): + Parent = apps.get_model('seminar', parent) + ContentType = apps.get_model('contenttypes', 'ContentType') + + # Nejdřív všechno smažeme: + Parent.objects.update(polymorphic_ctype=None) + + # Opravíme děti + for clsname in children: + Model = apps.get_model('seminar', clsname) + ct = ContentType.objects.get_for_model(Model) + Model.objects.update(polymorphic_ctype=ct) + + + # Ostatní instance mají mít explicitně content type pro rodiče + new_ct = ContentType.objects.get_for_model(Parent) + for obj in Parent.objects.filter(polymorphic_ctype__isnull=True): + log.warn(f"{parent} \"{obj}\" neměl content type -- nejspíš to je instance přímo {parent}!") + obj.polymorphic_ctype=new_ct + obj.save() + +def fix_treenode(apps, schema_editor): + children = ['RocnikNode', 'CisloNode', 'MezicisloNode', 'TemaVCisleNode', + 'OrgTextNode', 'UlohaZadaniNode', 'UlohaVzorakNode', 'PohadkaNode', + 'TextNode', 'CastNode', 'ReseniNode'] + fix_ctypes("TreeNode", children, apps, schema_editor) + +def fix_problem(apps, schema_editor): + children = ['Tema', 'Clanek', 'Uloha'] # FIXME: Konfera z nějakého důvodu tenhle field vůbec nemá, asi je to špatně. + fix_ctypes("Problem", children, apps, schema_editor) + +class Migration(migrations.Migration): + dependencies = [ + ('seminar', '0086_auto_20200819_0959'), + ] + operations = [ + migrations.RunPython(fix_treenode, migrations.RunPython.noop), + migrations.RunPython(fix_problem, migrations.RunPython.noop), + ] diff --git a/seminar/migrations/fix_0058.py b/seminar/migrations/fix_0058.py new file mode 100644 index 00000000..ac36d0a0 --- /dev/null +++ b/seminar/migrations/fix_0058.py @@ -0,0 +1,14 @@ +from django.db import migrations + +sql = "update seminar_problemy set typ = 'uloha' where typ like 'b_uloha_';" + +class Migration(migrations.Migration): + + dependencies = [ + ('seminar', '0058_problem_to_uloha_tema_clanek'), + ] + + operations = [ + migrations.RunSQL(sql, sql), + ] + diff --git a/seminar/models.py b/seminar/models.py index deb0c9b9..d706db0d 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -582,7 +582,7 @@ class Organizator(SeminarModelBase): "školu, ale jen obor, možnost zobrazit zvlášť") def clean(self): - if self.organizuje_od > self.organizuje_do: + if self.organizuje_od and self.organizuje_do and (self.organizuje_od > self.organizuje_do): raise ValidationError("Organizátor nemůže skončit s organizováním dříve než začal!") super().clean() @@ -597,6 +597,11 @@ class Organizator(SeminarModelBase): class Meta: verbose_name = 'Organizátor' verbose_name_plural = 'Organizátoři' + # Řadí aktivní orgy na začátek, pod tím v pořadí od nejstarších neaktivní orgy. + # TODO: Chtěl bych spíš mít nejstarší orgy dole. + # TODO: Zohledňovat přezdívky? + # TODO: Sjednotit s tím, jak se řadí organizátoři v seznau orgů na webu + ordering = ['-organizuje_do', 'osoba__jmeno', 'osoba__prijmeni'] @reversion.register(ignore_duplicates=True) class Soustredeni(SeminarModelBase): diff --git a/seminar/templates/seminar/clanky/resitelske_clanky.html b/seminar/templates/seminar/clanky/resitelske_clanky.html index 1e15fcbc..84089753 100644 --- a/seminar/templates/seminar/clanky/resitelske_clanky.html +++ b/seminar/templates/seminar/clanky/resitelske_clanky.html @@ -17,7 +17,7 @@ {% for clanek in object_list %} -{% with clanek.cislo_zadani.rocnik.rocnik as rocnik %} +{% with clanek.cislo.rocnik.rocnik as rocnik %} {% ifchanged rocnik %} {% if not forloop.first %}{% endif %}

{{ rocnik }}. ročník

diff --git a/seminar/templates/seminar/formular_ok.html b/seminar/templates/seminar/formular_ok.html new file mode 100644 index 00000000..6388f60c --- /dev/null +++ b/seminar/templates/seminar/formular_ok.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block nadpis1a %}Formulář byl odeslán{% endblock %} + +{% block content %} +

Formulář byl úspěšně odeslán

+{% for odkaz in odkazy %} +

{{odkaz.0}}

+{% endfor %} +{% endblock %} diff --git a/seminar/templates/seminar/orgorozcestnik.html b/seminar/templates/seminar/orgorozcestnik.html new file mode 100644 index 00000000..73268812 --- /dev/null +++ b/seminar/templates/seminar/orgorozcestnik.html @@ -0,0 +1,87 @@ +{% extends "base.html" %} +{# FIXME: Použít ideálně reverse() ke zjišťování URL #} + +{% block content %} +

Informace, komunikace

+ + + +
+

Tvorba čísla

+ + +
+ +

Moje problémy

+ +

Témata

+ + +

Úlohy

+ + +

Články

+ + +
+

Soustředění

+ + + +
+

Můj profil

+ + + +
+

Nemůžeš najít, co hledáš? Může to být v administračním rozhraní webu.

+{% endblock content %} + diff --git a/seminar/templates/seminar/titulnistrana.html b/seminar/templates/seminar/titulnistrana.html index bf9a884a..8f6057bf 100644 --- a/seminar/templates/seminar/titulnistrana.html +++ b/seminar/templates/seminar/titulnistrana.html @@ -20,7 +20,7 @@ M&M je korespondenční seminář. Několikrát do roka zdarma vydáváme č
{% if dead %}
-

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

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

{% endif %} diff --git a/seminar/templates/seminar/treenode.html b/seminar/templates/seminar/treenode.html index 0fd734ef..ca4df002 100644 --- a/seminar/templates/seminar/treenode.html +++ b/seminar/templates/seminar/treenode.html @@ -1,4 +1,4 @@ -{% extends "seminar/archiv/base_ulohy.html" %} +{% extends "seminar/archiv/base.html" %} {% load comments %} diff --git a/seminar/templates/seminar/zadani/AktualniZadani.html b/seminar/templates/seminar/zadani/AktualniZadani.html index b611eee9..93fac9a4 100644 --- a/seminar/templates/seminar/zadani/AktualniZadani.html +++ b/seminar/templates/seminar/zadani/AktualniZadani.html @@ -35,27 +35,30 @@ {% 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 %} {% else %} @@ -63,6 +66,7 @@ {% 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..9b4e0156 100644 --- a/seminar/templates/seminar/zadani/Temata.html +++ b/seminar/templates/seminar/zadani/Temata.html @@ -16,15 +16,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/urls.py b/seminar/urls.py index df2e1435..e5fed60e 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -90,6 +90,9 @@ urlpatterns = [ path('org/vloz_body//', staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'), + # příprava na nestatický orgorozcestník + path('org/rozcestnik/', + staff_member_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'), @@ -101,6 +104,9 @@ urlpatterns = [ path('reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), path('resitel_edit', views.resitelEditView, 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'), diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 87c7dbe5..cae17b77 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -10,6 +10,7 @@ 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 @@ -200,7 +201,7 @@ class AktualniZadaniView(TreeNodeView): # "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) @@ -873,6 +874,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): @@ -951,12 +989,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): @@ -1065,63 +1135,63 @@ def logoutView(request): 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/profil/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') @@ -1133,8 +1203,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( @@ -1164,7 +1234,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 @@ -1182,11 +1252,11 @@ 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: @@ -1236,3 +1306,29 @@ class PasswordResetCompleteView(auth_views.PasswordResetCompleteView): class PasswordChangeView(auth_views.PasswordChangeView): #template_name = 'seminar/password_change.html' success_url = reverse_lazy('titulni_strana') + + +# Jen hloupé rozhazovátko +def profilView(request): + user = request.user + # FIXME: správná oprávnění + if user.has_perm('org'): + return OrgoRozcestnikView.as_view()(request) + if user.has_perm('ucastnik'): + 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) +