Browse Source

merge

export_seznamu_prednasek
Kateřina Č 4 years ago
parent
commit
d873544f8a
  1. 6
      .gitignore
  2. 187
      MIGRATIONS
  3. 8
      Makefile
  4. 2
      flat.json
  5. 4
      galerie/admin.py
  6. 18
      galerie/migrations/0010_auto_20200819_0947.py
  7. 2
      galerie/models.py
  8. 4
      galerie/templates/galerie/GalerieNahled.html
  9. 7
      galerie/urls.py
  10. 28
      galerie/views.py
  11. 29
      korektury/models.py
  12. 4
      korektury/templates/korektury/base.html
  13. 7
      korektury/templates/korektury/help.html
  14. 4
      korektury/templates/korektury/opraf.html
  15. 4
      korektury/templates/korektury/seznam.html
  16. 13
      korektury/templates/korektury/submenu.html
  17. BIN
      korektury/testpdfs/A.pdf
  18. 5125
      korektury/testpdfs/B.pdf
  19. 69
      korektury/testutils.py
  20. 11
      korektury/urls.py
  21. 26
      korektury/views.py
  22. 8
      mamweb/settings_common.py
  23. 2
      mamweb/settings_local.py
  24. 4
      mamweb/settings_test.py
  25. 4
      mamweb/static/css/mamweb.css
  26. 0
      mamweb/static/images/logo_1.svg
  27. 0
      mamweb/static/images/logo_2.svg
  28. 0
      mamweb/static/images/logo_3.svg
  29. 0
      mamweb/static/images/logo_4.svg
  30. 0
      mamweb/static/images/logo_5.svg
  31. 0
      mamweb/static/images/logo_6.svg
  32. 6
      mamweb/templates/base.html
  33. 26
      mamweb/templates/logo.html
  34. 4
      mamweb/templates/menu.html
  35. 4
      mamweb/templates/menu_mobile.html
  36. 2
      mamweb_prod.ini
  37. 2
      mamweb_test.ini
  38. 10
      prednasky/templates/prednasky/base.html
  39. 2
      prednasky/templates/prednasky/metaseznam_prednasek.html
  40. 2
      prednasky/templates/prednasky/seznam_prednasek.html
  41. 14
      prednasky/templates/prednasky/seznam_prednasek_export.txt
  42. 27
      prednasky/urls.py
  43. 51
      prednasky/views.py
  44. 3
      seminar/admin.py
  45. 6
      seminar/management/commands/auth.py
  46. 21
      seminar/migrations/0001_squashed_0067_auto_20190814_0805.py
  47. 3
      seminar/migrations/0019_rocnik_ciselne.py
  48. 8
      seminar/migrations/0052_user_to_organizator.py
  49. 2
      seminar/migrations/0056_vrcholy_pro_rocniky_a_cisla.py
  50. 2
      seminar/migrations/0057_reseni_to_reseni_hodnoceni.py
  51. 8
      seminar/migrations/0058_problem_to_uloha_tema_clanek.py
  52. 4
      seminar/migrations/0059_vytvorit_pohadkanode.py
  53. 2
      seminar/migrations/0060_spoj_stromy.py
  54. 4
      seminar/migrations/0065_treenode_polymorphic_ctype.py
  55. 4
      seminar/migrations/0066_problem_polymorphic_ctype.py
  56. 2
      seminar/migrations/0068_treenode_nazev.py
  57. 6
      seminar/migrations/0080_zruseni_claneknode_a_konferanode.py
  58. 8
      seminar/migrations/0084_clanek_cislo.py
  59. 17
      seminar/migrations/0086_auto_20200819_0959.py
  60. 49
      seminar/migrations/0087_fix_polymorphism.py
  61. 35
      seminar/migrations/0088_perm_org_a_ucastnik.py
  62. 14
      seminar/migrations/fix_0058.py
  63. 7
      seminar/models.py
  64. 22
      seminar/templates/seminar/archiv/cislo.html
  65. 4
      seminar/templates/seminar/archiv/problem.html
  66. 4
      seminar/templates/seminar/archiv/rocnik.html
  67. 2
      seminar/templates/seminar/clanky/resitelske_clanky.html
  68. 10
      seminar/templates/seminar/formular_ok.html
  69. 8
      seminar/templates/seminar/novinky.html
  70. 87
      seminar/templates/seminar/orgorozcestnik.html
  71. 3
      seminar/templates/seminar/profil/gdpr.html
  72. 6
      seminar/templates/seminar/profil/nahraj_reseni.html
  73. 2
      seminar/templates/seminar/profil/prihlaska_field.html
  74. 14
      seminar/templates/seminar/soustredeni/seznam_soustredeni.html
  75. 1
      seminar/templates/seminar/soustredeni/seznam_ucastniku.html
  76. 2
      seminar/templates/seminar/titulnistrana.html
  77. 2
      seminar/templates/seminar/treenode.html
  78. 2
      seminar/templates/seminar/zadani/AktualniVysledkovka.html
  79. 19
      seminar/templates/seminar/zadani/AktualniZadani.html
  80. 14
      seminar/templates/seminar/zadani/Temata.html
  81. 55
      seminar/testutils.py
  82. 106
      seminar/urls.py
  83. 14
      seminar/utils.py
  84. 2
      seminar/views/utils.py
  85. 122
      seminar/views/views_all.py
  86. 661
      sitetree_new.json

6
.gitignore

@ -24,3 +24,9 @@ TODO
# .htpasswd kvůli přihlášení # .htpasswd kvůli přihlášení
.htpasswd .htpasswd
# reversion kvůli historii objektů v reversion
**/reversion
# pro lidi, co programují v nástrojích od JetBrains
.idea

187
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

8
Makefile

@ -65,7 +65,7 @@ schema_all.pdf: venv_check
# Deploy to current *mamweb-test* directory # Deploy to current *mamweb-test* directory
deploy_test: venv_check deploy_test: venv_check
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi @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 ..." @echo "Installing version from origin/test ..."
git pull origin test git pull origin test
git clean -f git clean -f
@ -81,9 +81,9 @@ deploy_test: venv_check
# Deploy to current *mamweb-prod* directory # Deploy to current *mamweb-prod* directory
deploy_prod: venv_check deploy_prod: venv_check
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi @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 ..." @echo "Backing up production DB ..."
( cd .. && ./backup_prod_db.sh ) ( cd -P .. && ./backup_prod_db.sh )
@echo "Installing version from origin/master ..." @echo "Installing version from origin/master ..."
git pull origin master git pull origin master
git clean -f git clean -f
@ -109,7 +109,7 @@ sync_prod_flatpages: venv_check
# Sync test media directory with production # Sync test media directory with production
sync_test_media: sync_test_media:
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi @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 rsync -av --delete /akce/mam/www/mamweb-prod/media/ ./media
# Sync test database with production database # Sync test database with production database

2
flat.json

File diff suppressed because one or more lines are too long

4
galerie/admin.py

@ -30,14 +30,14 @@ def prepnout_fotogalerii_do_org_rezimu(modeladmin, request, queryset):
class GalerieInline(admin.TabularInline): class GalerieInline(admin.TabularInline):
model = Obrazek 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'] readonly_fields = ['nazev', 'obrazek_maly_tag']
formfield_overrides = { formfield_overrides = {
models.TextField: {'widget': forms.TextInput}, models.TextField: {'widget': forms.TextInput},
} }
class ObrazekAdmin(admin.ModelAdmin): 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'] search_fields = ['nazev','popis']
class GalerieAdmin(admin.ModelAdmin): class GalerieAdmin(admin.ModelAdmin):

18
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í'),
),
]

2
galerie/models.py

@ -94,7 +94,7 @@ class Galerie(models.Model):
on_delete=models.SET_NULL) on_delete=models.SET_NULL)
soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True, soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True,
on_delete=models.PROTECT) 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): def __str__(self):
return self.nazev return self.nazev

4
galerie/templates/galerie/GalerieNahled.html

@ -61,7 +61,7 @@ Galerie {{galerie.nazev}}
{{ galerie|truncatechars:max_delka_nazvu }} {{ galerie|truncatechars:max_delka_nazvu }}
</div> </div>
</a> </a>
{% if user.is_staff and galerie.zobrazit > 0 %} {% if user.je_org and galerie.zobrazit > 0 %}
<div class="mam-org-only-galerie"> <div class="mam-org-only-galerie">
({{galerie.poradi}}) ({{galerie.poradi}})
<span class="plus"><a href="plus/{{galerie.pk}}/">+</a></span> <span class="plus"><a href="plus/{{galerie.pk}}/">+</a></span>
@ -73,7 +73,7 @@ Galerie {{galerie.nazev}}
{% endwith %} {% endwith %}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if user.is_staff and galerie.zobrazit > 0 %} {% if user.je_org and galerie.zobrazit > 0 %}
<div class="mam-org-only"> <div class="mam-org-only">
<a href="./new">Vytvořit novou podgalerii </a> <a href="./new">Vytvořit novou podgalerii </a>
</div> </div>

7
galerie/urls.py

@ -1,13 +1,14 @@
# coding: utf-8 # coding: utf-8
from django.urls import path from django.urls import path
from seminar.utils import org_required
from . import views from . import views
urlpatterns = [ urlpatterns = [
path('<int:pk>/', views.nahled), path('<int:pk>/', views.nahled),
path('<int:pk>/<int:fotka>/', views.detail), path('<int:pk>/<int:fotka>/', views.detail),
path('<int:galerie>/new/', views.new_galerie), path('<int:galerie>/new/', org_required(views.new_galerie)),
path('<int:galerie>/plus/<int:subgalerie>/', views.plus_galerie), path('<int:galerie>/plus/<int:subgalerie>/', org_required(views.plus_galerie)),
path('<int:galerie>/minus/<int:subgalerie>/', views.minus_galerie), path('<int:galerie>/minus/<int:subgalerie>/', org_required(views.minus_galerie)),
] ]

28
galerie/views.py

@ -14,7 +14,7 @@ from galerie.forms import KomentarForm, NewGalerieForm
def zobrazit(galerie, request): def zobrazit(galerie, request):
preview = False preview = False
if galerie.zobrazit >= 1: if galerie.zobrazit >= 1:
if request.user.is_staff: if request.user.je_org:
preview = True; preview = True;
else: else:
raise Http404 raise Http404
@ -35,16 +35,16 @@ def nahled(request, pk, soustredeni):
galerie = get_object_or_404(Galerie, pk=pk) galerie = get_object_or_404(Galerie, pk=pk)
podgalerie = Galerie.objects.filter(galerie_up = galerie).order_by('poradi') 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) 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) preview = zobrazit(galerie, request)
sourozenci = [] sourozenci = []
if galerie.galerie_up: if galerie.galerie_up:
sourozenci = galerie.galerie_up.galerie_set.all().order_by('poradi') 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) sourozenci = sourozenci.filter(zobrazit__lt=1)
predchozi = None predchozi = None
@ -82,7 +82,7 @@ def detail(request, pk, fotka, soustredeni):
galerie = get_object_or_404(Galerie, pk=pk) galerie = get_object_or_404(Galerie, pk=pk)
preview = zobrazit(galerie, request) preview = zobrazit(galerie, request)
obrazek = get_object_or_404(Obrazek, pk=fotka) 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 # vytvoreni a obslouzeni formulare
if request.method == 'POST': if request.method == 'POST':
@ -96,22 +96,23 @@ def detail(request, pk, fotka, soustredeni):
# Poradi aktualniho obrazku v galerii/stitku. # Poradi aktualniho obrazku v galerii/stitku.
for i in range(len(obrazky)): for i in range(len(obrazky)):
if obrazky[i] == obrazek: if obrazky[i] == obrazek:
znacka = i poradi = i
break break
else: else:
# Obrazek neni v galerii/stitku. # Obrazek neni v galerii/stitku.
raise Http404 raise Http404
# Nacteni okolnich obrazku a galerii # Nacteni okolnich obrazku a galerii
# TODO vyjmout zjisteni predchozich a nasledujicich galerii # TODO vyjmout zjisteni predchozich a nasledujicich galerii
# a udelat z toho funkci, ktera se pouzije u nahledu # a udelat z toho funkci, ktera se pouzije u nahledu
predchozi_galerie = None predchozi_galerie = None
nasledujici_galerie = None nasledujici_galerie = None
obrazky_dalsi = obrazky[znacka+1:znacka+NAHLEDU+1] obrazky_dalsi = obrazky[poradi+1:poradi+NAHLEDU+1]
if (znacka+1) > NAHLEDU: if (poradi+1) > NAHLEDU:
obrazky_predchozi = obrazky[znacka-NAHLEDU:znacka] obrazky_predchozi = obrazky[poradi-NAHLEDU:poradi]
else: else:
obrazky_predchozi = obrazky[0:znacka] obrazky_predchozi = obrazky[0:poradi]
if galerie.poradi > 1: if galerie.poradi > 1:
predchozi_galerie = Galerie.objects.\ predchozi_galerie = Galerie.objects.\
filter(galerie_up=galerie.galerie_up).\ filter(galerie_up=galerie.galerie_up).\
@ -120,10 +121,14 @@ def detail(request, pk, fotka, soustredeni):
predchozi_galerie = predchozi_galerie[0] predchozi_galerie = predchozi_galerie[0]
else: else:
predchozi_galerie = None predchozi_galerie = None
if (znacka+1) == len(obrazky): 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.\ nasledujici_galerie = Galerie.objects.\
filter(galerie_up=galerie.galerie_up).\ filter(galerie_up=galerie.galerie_up).\
filter(poradi=(galerie.poradi+1)) filter(poradi=(galerie.poradi+1))
else:
nasledujici_galerie = None
if nasledujici_galerie: if nasledujici_galerie:
nasledujici_galerie = nasledujici_galerie[0] nasledujici_galerie = nasledujici_galerie[0]
else: else:
@ -155,7 +160,6 @@ def detail(request, pk, fotka, soustredeni):
'cesta': cesta_od_korene(galerie), 'cesta': cesta_od_korene(galerie),
}) })
def new_galerie(request, galerie, soustredeni): def new_galerie(request, galerie, soustredeni):
# zjistime k jakemu soustredeni se vaze nove vytvarena galerie # zjistime k jakemu soustredeni se vaze nove vytvarena galerie

29
korektury/models.py

@ -79,22 +79,31 @@ class KorekturovanePDF(models.Model):
self.stran = 0 self.stran = 0
while True: while True:
res = subprocess.call([ res = subprocess.call([
"convert", #Parametry inspirovány chybovou hláškou imagemagicku
"-density", "180x180", "gs",
"-geometry", " 1024x1448", "-sstdout=%stderr",
"%s[%d]" % (self.pdf.path, self.stran), "-dSAFER",
os.path.join( "-dNOPAUSE",
"-dBATCH",
"-dNOPROMPT",
"-sDEVICE=pngalpha",
"-r180x180",
"-dFirstPage=%d" % (self.stran+1),
"-dLastPage=%d" % (self.stran+1),
"-sOutputFile="+os.path.join(
dirname, 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 break
self.stran += 1 self.stran += 1
# Změnil se počet stran, ukládáme # Změnil se počet stran, ukládáme
super(KorekturovanePDF, self).save() super(KorekturovanePDF, self).save()
def save(self): def save(self, **kwargs):
# Pokud se nezmenilo PDF, tak nepregenerovavej nahledy # Pokud se nezmenilo PDF, tak nepregenerovavej nahledy
try: try:
original = KorekturovanePDF.objects.get(pk=self.pk) original = KorekturovanePDF.objects.get(pk=self.pk)
@ -104,7 +113,7 @@ class KorekturovanePDF(models.Model):
except ObjectDoesNotExist: except ObjectDoesNotExist:
pass pass
# uložíme nahrávané pdf # uložíme nahrávané pdf
super(KorekturovanePDF, self).save() super(KorekturovanePDF, self).save(kwargs)
# uložíme png a změněný počet stran # uložíme png a změněný počet stran
self.convert() self.convert()

4
korektury/templates/korektury/base.html

@ -1,5 +1,9 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block submenu %}
{% include "korektury/submenu.html" %}
{% endblock %}
{% block content %} {% block content %}
{# blok do kterého se nacita text, v pripade jinyhc templatu obalit vlastnim blokem #} {# blok do kterého se nacita text, v pripade jinyhc templatu obalit vlastnim blokem #}
{% endblock %} {% endblock %}

7
korektury/templates/korektury/help.html

@ -1,4 +1,11 @@
{% extends "korektury/base.html" %} {% extends "korektury/base.html" %}
{% block submenu %}
{% with "help" as selected %}
{% include "korektury/submenu.html" %}
{% endwith %}
{% endblock %}
{% load staticfiles %} {% load staticfiles %}
{% block title %} Nápověda ke korigovátku {% endblock title %} {% block title %} Nápověda ke korigovátku {% endblock title %}

4
korektury/templates/korektury/opraf.html

@ -36,12 +36,12 @@
id="neni_chyba_checkbox" id="neni_chyba_checkbox"
name="neni_chyba_checkbox" name="neni_chyba_checkbox"
onchange="toggle_corrections('neni_chyba')" checked> onchange="toggle_corrections('neni_chyba')" checked>
<label for="neni_chyba_checkbox">Není chyba ({{neni_chyba_cnt}})</labe> <label for="neni_chyba_checkbox">Není chyba ({{neni_chyba_cnt}})</label>
<input type="checkbox" <input type="checkbox"
id="k_zaneseni_checkbox" id="k_zaneseni_checkbox"
name="k_zaneseni_checkbox" name="k_zaneseni_checkbox"
onchange="toggle_corrections('k_zaneseni')" checked> onchange="toggle_corrections('k_zaneseni')" checked>
<label for="k_zaneseni_checkbox">K zanesení ({{k_zaneseni_cnt}})</labe> <label for="k_zaneseni_checkbox">K zanesení ({{k_zaneseni_cnt}})</label>
<hr/> <hr/>

4
korektury/templates/korektury/seznam.html

@ -1,6 +1,10 @@
{% extends "korektury/base.html" %} {% extends "korektury/base.html" %}
{% load staticfiles %} {% load staticfiles %}
{% block submenu %}
{% include "korektury/submenu.html" %}
{% endblock %}
{% block script%} {% block script%}
<link rel="stylesheet" type="text/css" media="screen, projection" href="{% static "korektury/opraf-list.css" %}" /> <link rel="stylesheet" type="text/css" media="screen, projection" href="{% static "korektury/opraf-list.css" %}" />
{% endblock %} {% endblock %}

13
korektury/templates/korektury/submenu.html

@ -0,0 +1,13 @@
{% with "/korektury" as cesta %}
<div id='submenu'>
<ul>
<li class="{% if selected == "aktualni" %}selected{% endif %}"><a href="{{cesta}}/">Aktuální</a>
<li class="{% if selected == "zastarale" %}selected{% endif %}"><a href="{{cesta}}/zastarale/">Zastaralé</a>
<li class="{% if selected == "help" %}selected{% endif %}"><a href="{{cesta}}/help/">Nápověda</a>
</ul>
</div>
{% endwith %}

BIN
korektury/testpdfs/A.pdf

Binary file not shown.

5125
korektury/testpdfs/B.pdf

File diff suppressed because one or more lines are too long

69
korektury/testutils.py

@ -0,0 +1,69 @@
import logging
import os
from shutil import copyfile, rmtree
from django.db import transaction
from django.conf import settings
from korektury.models import KorekturovanePDF, generate_filename
logger = logging.getLogger(__name__)
@transaction.atomic
def create_test_pdf(rnd, organizatori):
logger.info('Vyrábím testovací pdf ke korekturovani')
try:
testpdfs = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'testpdfs')
# smaže minulé pdfka a obrázky k nim a vytvoří (znovu) jejich složky
pdf_dir = os.path.join(settings.BASE_DIR, os.path.join('media', settings.KOREKTURY_PDF_DIR))
img_dir = os.path.join(settings.BASE_DIR, os.path.join('media', settings.KOREKTURY_IMG_DIR))
rmtree(pdf_dir, ignore_errors=True)
os.makedirs(pdf_dir)
rmtree(img_dir, ignore_errors=True)
os.makedirs(img_dir)
def gen_filename(filename):
name = generate_filename(None, filename)
print(name)
copyfile(os.path.join(testpdfs, filename), os.path.join(settings.BASE_DIR, os.path.join('media', name)))
return name
# TODO silent ghostscript (vypisuje odstavec za každou stránku…)
KorekturovanePDF.objects.create(
nazev='B', komentar='Neuronové sítě', org=rnd.choice(organizatori), pdf=gen_filename(filename='B.pdf')
)
KorekturovanePDF.objects.create(
nazev='A', komentar='M&M: Jak řešit?', org=rnd.choice(organizatori), pdf=gen_filename(filename='A.pdf')
)
korekturovane_pdf = KorekturovanePDF.objects.create(
nazev='A', komentar='M&M: Jak řešit?', org=rnd.choice(organizatori), pdf=gen_filename(filename='A.pdf'),
status='zanaseni'
)
KorekturovanePDF.objects.create(
nazev='A', komentar='M&M: Jak řešit?', org=rnd.choice(organizatori), pdf=gen_filename(filename='A.pdf'),
status='zastarale'
)
except (FileNotFoundError, Exception) as e:
# TODO najít správné chyby, které vyhazují různé systémy při neexistenci ImageMagick, nebo knihoven
logger.error(str(e))
logger.error(
'Chyba vytváření testovacích korektur, pravděpodobně není nainstalován ImageMagick nebo některá z knihoven'
'pro práci se soubory pdf (ghostscript) nebo png (libpng?).\n'
'''
Instalaci na linux provedete např. příkazy:
sudo apt-get build-dep imagemagick
git clone https://github.com/ImageMagick/ImageMagick.git
cd ImageMagick/
./configure
make
sudo make install
sudo ldconfig /usr/local/lib
cd ..
rm -r ImageMagick/
'''
)

11
korektury/urls.py

@ -1,11 +1,10 @@
from django.urls import path from django.urls import path
from django.contrib.auth.decorators import user_passes_test from seminar.utils import org_required
from . import views from . import views
staff_member_required = user_passes_test(lambda u: u.is_staff)
urlpatterns = [ urlpatterns = [
path('korektury/', staff_member_required(views.KorekturyListView.as_view()), name='korektury-list'), path('korektury/', org_required(views.KorekturyAktualniListView.as_view()), name='korektury-list'),
path('korektury/<int:pdf>/', staff_member_required(views.KorekturyView.as_view()), name='korektury'), path('korektury/zastarale/', org_required(views.KorekturyZastaraleListView.as_view()), name='korektury-list'),
path('korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), path('korektury/<int:pdf>/', org_required(views.KorekturyView.as_view()), name='korektury'),
path('korektury/help/', org_required(views.KorekturyHelpView.as_view()), name='korektury-help'),
] ]

26
korektury/views.py

@ -29,6 +29,28 @@ class KorekturyListView(generic.ListView):
) )
template_name = 'korektury/seznam.html' 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 ### Korektury
class KorekturyView(generic.TemplateView): class KorekturyView(generic.TemplateView):
model = Oprava model = Oprava
@ -130,7 +152,9 @@ class KorekturyView(generic.TemplateView):
''' '''
# parametry e-mailu # 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' from_email = 'korekturovatko@mam.mff.cuni.cz'
subject = 'Nová korektura od {} v {}'.format(autor, subject = 'Nová korektura od {} v {}'.format(autor,
oprava.pdf.nazev) oprava.pdf.nazev)

8
mamweb/settings_common.py

@ -98,7 +98,7 @@ INSTALLED_APPS = (
# Utilities # Utilities
'sekizai', 'sekizai',
# 'reversion', 'reversion',
'django_countries', 'django_countries',
'solo', 'solo',
'ckeditor', 'ckeditor',
@ -136,7 +136,6 @@ INSTALLED_APPS = (
# 'admin_tools.theming', # 'admin_tools.theming',
# 'admin_tools.menu', # 'admin_tools.menu',
# 'admin_tools.dashboard', # 'admin_tools.dashboard',
'flat',
'django.contrib.admin', 'django.contrib.admin',
) )
@ -179,7 +178,8 @@ CKEDITOR_CONFIGS = {
# 'toolbar': 'full', # 'toolbar': 'full',
'height': '40em', 'height': '40em',
'width': '100%', 'width': '100%',
'toolbarStartupExpanded': False 'toolbarStartupExpanded': False,
'allowedContent' : True,
}, },
} }
@ -248,7 +248,7 @@ LOGGING = {
'class': 'django.utils.log.AdminEmailHandler', 'class': 'django.utils.log.AdminEmailHandler',
'formatter': 'verbose', 'formatter': 'verbose',
}, },
'mail_registraion': { 'mail_registration': {
'level': 'WARN', 'level': 'WARN',
'class': 'django.utils.log.AdminEmailHandler', 'class': 'django.utils.log.AdminEmailHandler',
'formatter': 'verbose', 'formatter': 'verbose',

2
mamweb/settings_local.py

@ -94,4 +94,6 @@ LOGGING = {
# set to 'DEBUG' for EXTRA verbose output # set to 'DEBUG' for EXTRA verbose output
# LOGGING['handlers']['console']['level'] = 'INFO' # LOGGING['handlers']['console']['level'] = 'INFO'
# E-maily posílat chceme, ale do terminálu :-)
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SEND_EMAIL_NOTIFICATIONS = True

4
mamweb/settings_test.py

@ -12,7 +12,7 @@ import os.path
# Import common settings # Import common settings
from .settings_common import * # zatim nutne, casem snad vyresime # noqa from .settings_common import * # zatim nutne, casem snad vyresime # noqa
MIDDLEWARE_CLASSES += ( MIDDLEWARE += (
'debug_toolbar.middleware.DebugToolbarMiddleware', 'debug_toolbar.middleware.DebugToolbarMiddleware',
) )
@ -32,7 +32,7 @@ DEBUG = True
TEMPLATES[0]['OPTIONS']['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 # Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases # https://docs.djangoproject.com/en/1.7/ref/settings/#databases

4
mamweb/static/css/mamweb.css

@ -338,6 +338,10 @@ ul.submenu li>a:hover {
color: black; color: black;
} }
ul.menu li.active>a, ul.submenu li.active>a {
color: black;
}
/* konec nového menu */ /* konec nového menu */
div.novinky_name { div.novinky_name {

0
mamweb/static/images/logo_co-je-mam.svg → mamweb/static/images/logo_1.svg

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
mamweb/static/images/logo_jak-resit.svg → mamweb/static/images/logo_2.svg

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
mamweb/static/images/logo_aktualni.svg → mamweb/static/images/logo_3.svg

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
mamweb/static/images/logo_soustredeni.svg → mamweb/static/images/logo_4.svg

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
mamweb/static/images/logo_archiv.svg → mamweb/static/images/logo_5.svg

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
mamweb/static/images/logo_profil.svg → mamweb/static/images/logo_6.svg

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

6
mamweb/templates/base.html

@ -12,7 +12,7 @@
<link href="{% static 'css/mamweb.css' %}" rel="stylesheet"> <link href="{% static 'css/mamweb.css' %}" rel="stylesheet">
<link href="{% static 'css/prettyPhoto.css' %}" rel="stylesheet" type="text/css" media="screen" charset="utf-8" /> <link href="{% static 'css/prettyPhoto.css' %}" rel="stylesheet" type="text/css" media="screen" charset="utf-8" />
<script src="{% static 'js/jquery-1.11.1.js' %}"></script> <script src="{% static 'js/jquery-1.11.1.js' %}"></script>
<script src="{% static '/jquery-3.4.1.js' %}"></script> <script src="{% static 'js/jquery-3.4.1.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'fluent_comments/css/ajaxcomments.css' %}" /> <link rel="stylesheet" type="text/css" href="{% static 'fluent_comments/css/ajaxcomments.css' %}" />
<script type="text/javascript" src="{% static 'fluent_comments/js/ajaxcomments.js' %}"></script> <script type="text/javascript" src="{% static 'fluent_comments/js/ajaxcomments.js' %}"></script>
@ -57,7 +57,7 @@
<a href='/'> <a href='/'>
<div id="title" >M&M - korespondenční seminář a časopis MFF&nbspUK</div> <div id="title" >M&M - korespondenční seminář a časopis MFF&nbspUK</div>
<div id="header" class="{% if noc %}NOC{% endif %}{% block header %}{% endblock %}"> <div id="header" class="{% if noc %}NOC{% endif %}{% block header %}{% endblock %}">
<img class="logo" src="{% static 'images/logo.svg' %}" /> {% sitetree_menu from "main_menu" include "trunk" template "logo.html" %}
<img class="logo-mobile" src="{% static 'images/logo-mobile.svg' %}" /> <img class="logo-mobile" src="{% static 'images/logo-mobile.svg' %}" />
</div> </div>
</a> </a>
@ -106,7 +106,7 @@
<div id="footer"> <div id="footer">
<p class="license">S obsahem webu M&amp;M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p> <p class="license">S obsahem webu M&amp;M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p>
</div> </div>
<p class="license-mobile">Korespondenční seminář M&M organizují převážně studenti <a herf="https://www.mff.cuni.cz/">MFF UK</a>. Organizaci semináře a vydávání časopisu podporuje <a href="https://jcmf.cz/">Jednota českých matematiků a fyziků</a>. S obsahem webu M&amp;M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p> <p class="license-mobile">Korespondenční seminář M&M organizují převážně studenti <a href="https://www.mff.cuni.cz/">MFF UK</a>. Organizaci semináře a vydávání časopisu podporuje <a href="https://jcmf.cz/">Jednota českých matematiků a fyziků</a>. S obsahem webu M&amp;M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p>
</div> </div>
</div> </div>
</div> </div>

26
mamweb/templates/logo.html

@ -0,0 +1,26 @@
{% load staticfiles %}
<img class="logo"
{% for item in sitetree_items %}
{% if item.is_active or item.in_current_branch %}
{% if forloop.counter == 1 %}
src="{% static 'images/logo_1.svg' %}"
{% endif %}
{% if forloop.counter == 2 %}
src="{% static 'images/logo_2.svg' %}"
{% endif %}
{% if forloop.counter == 3 %}
src="{% static 'images/logo_3.svg' %}"
{% endif %}
{% if forloop.counter == 4 %}
src="{% static 'images/logo_4.svg' %}"
{% endif %}
{% if forloop.counter == 5 %}
src="{% static 'images/logo_5.svg' %}"
{% endif %}
{% if forloop.counter == 6 %}
src="{% static 'images/logo_6.svg' %}"
{% endif %}
{% endif %}
{% endfor %}
src="{% static 'images/logo.svg' %}"
/>

4
mamweb/templates/menu.html

@ -3,7 +3,9 @@
{% autoescape off %} {% autoescape off %}
<ul class="menu"> <ul class="menu">
{% for item in sitetree_items %} {% for item in sitetree_items %}
<li class="{% if item.has_children %}dropdown{% endif %} {% if item.is_current or item.in_current_branch %}active{% endif %}" > <li class="{% if item.has_children %}dropdown{% endif %} {% if item.is_current or item.in_current_branch %}active{% endif %}"
style="{% if item.title == "HIDDEN" %}display:none{% endif %}"
>
<a href="{% sitetree_url for item %}" > <a href="{% sitetree_url for item %}" >
{{ item.title_resolved }} {{ item.title_resolved }}
</a> </a>

4
mamweb/templates/menu_mobile.html

@ -3,7 +3,9 @@
{% autoescape off %} {% autoescape off %}
<ul class="menu_mobile"> <ul class="menu_mobile">
{% for item in sitetree_items %} {% for item in sitetree_items %}
<li class="{% if item.has_children %}dropdown{% endif %} {% if item.is_current or item.in_current_branch %}active{% endif %}"> <li class="{% if item.has_children %}dropdown{% endif %} {% if item.is_current or item.in_current_branch %}active{% endif %}"
style="{% if item.title == "HIDDEN" %}display:none{% endif %}"
>
<a href="{% if item.has_children %}#{% else %}{% sitetree_url for item %}{% endif %}" {% if item.has_children %}class="dropdown-toggle" data-toggle="dropdown"{% endif %}> <a href="{% if item.has_children %}#{% else %}{% sitetree_url for item %}{% endif %}" {% if item.has_children %}class="dropdown-toggle" data-toggle="dropdown"{% endif %}>
{{ item.title_resolved }} {{ item.title_resolved }}
</a> </a>

2
mamweb_prod.ini

@ -5,7 +5,7 @@ chdir = /akce/mam/www/mamweb-prod/
home = /akce/mam/www/mamweb-prod/ home = /akce/mam/www/mamweb-prod/
module = mamweb.wsgi module = mamweb.wsgi
plugin = python plugin = python3
virtualenv = env virtualenv = env
master = True master = True
vacuum = True vacuum = True

2
mamweb_test.ini

@ -5,7 +5,7 @@ chdir = /akce/mam/www/mamweb-test/
home = /akce/mam/www/mamweb-test/ home = /akce/mam/www/mamweb-test/
module = mamweb.wsgi module = mamweb.wsgi
plugin = python plugin = python3
virtualenv = env virtualenv = env
master = True master = True
vacuum = True vacuum = True

10
prednasky/templates/prednasky/base.html

@ -17,19 +17,17 @@ Jak moc by ses chtěl(a) zúčastnit následujících přednášek?
<form enctype="multipart/form-data" action="." method="post"> <form enctype="multipart/form-data" action="." method="post">
{% csrf_token %} {% csrf_token %}
<table>{{form.as_table}}
</table>
<table> <table>
{% for p in prednasky.prednaska_set.all %} {% for p, h in prednasky %}
<tr><td><label>{{p.org}}: <span style="font-size: 175%">{{p.nazev}}</span></label></td></tr> <tr><td><label>{{p.org}}: <span style="font-size: 175%">{{p.nazev}}</span></label></td></tr>
<tr><td><p><i>{{p.anotace}}</i></p></td></tr> <tr><td><p><i>{{p.anotace}}</i></p></td></tr>
<tr><td><label>Obor: </label> {{p.obor}}</td></tr> <tr><td><label>Obor: </label> {{p.obor}}</td></tr>
<tr><td><label>Obtížnost: </label> {{p.obtiznost}}</td> </tr> <tr><td><label>Obtížnost: </label> {{p.obtiznost}}</td> </tr>
{% if p.klicova %}<tr><td><label>Klíčová slova: </label> {{p.klicova}}</td></tr>{% endif%} {% if p.klicova %}<tr><td><label>Klíčová slova: </label> {{p.klicova}}</td></tr>{% endif%}
<tr><td>Hodnocení: <tr><td>Hodnocení:
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="-1"> rozhodně nechci <INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="-1" {% if h == -1 %} CHECKED="checked" {% endif %} > rozhodně nechci
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="0" checked> je mi to jedno <INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="0" {% if h == 0 %} CHECKED="checked" {% endif %}> je mi to jedno
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="1"> rozhodně chci <INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="1" {% if h == 1 %} CHECKED="checked" {% endif %}> rozhodně chci
</td></tr> </td></tr>
<tr><td>&nbsp;</td></tr> <tr><td>&nbsp;</td></tr>
{% endfor %} {% endfor %}

2
prednasky/templates/prednasky/metaseznam_prednasek.html

@ -19,6 +19,8 @@
<a href="/prednasky/seznam_prednasek/{{seznam.id}}/export">Export</a> <a href="/prednasky/seznam_prednasek/{{seznam.id}}/export">Export</a>
</li> </li>
{% endfor %} {% endfor %}
</ul>
</div>
{% endblock %} {% endblock %}

2
prednasky/templates/prednasky/seznam_prednasek.html

@ -15,5 +15,7 @@
{{ prednaska.body }} b</i>) &ndash; {{ prednaska.org }} {{ prednaska.body }} b</i>) &ndash; {{ prednaska.org }}
</li> </li>
{% endfor %} {% endfor %}
</ul>
</div>
{% endblock %} {% endblock %}

14
prednasky/templates/prednasky/seznam_prednasek_export.txt

@ -1,19 +1,7 @@
{% block content %} {% block content %}
{% spaceless %} {% 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 %} {% for prednaska in prednasky %}
{{prednaska.id}};{{prednaska.nazev}};{{prednaska.org.id}} {{prednaska.id}};{{prednaska.nazev}};{{prednaska.org}}
{{prednaska.body}} {{prednaska.body}}
{% endfor %} {% endfor %}
{% endspaceless %} {% endspaceless %}

27
prednasky/urls.py

@ -1,14 +1,25 @@
from django.urls import path from django.urls import path
from django.contrib.auth.decorators import user_passes_test from seminar.utils import org_required, resitel_required
from . import views from . import views
staff_member_required = user_passes_test(lambda u: u.is_staff)
urlpatterns = [ urlpatterns = [
path('prednasky/', views.newPrednaska), path(
'prednasky/',
resitel_required(views.newPrednaska)
),
path('prednasky/hotovo', views.Prednaska_hotovo), path('prednasky/hotovo', views.Prednaska_hotovo),
path('prednasky/metaseznam_prednasek', staff_member_required(views.MetaSeznamListView.as_view()), name='metaseznam-list'), path(
path('prednasky/seznam_prednasek/<int:seznam>/export', staff_member_required(views.SeznamExportView), name='seznam-export'), 'prednasky/metaseznam_prednasek',
path('prednasky/seznam_prednasek/<int:seznam>/', staff_member_required(views.SeznamListView.as_view()), name='seznam-list'), org_required(views.MetaSeznamListView.as_view()),
# path('korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), name='metaseznam-list'),
path(
'prednasky/seznam_prednasek/<int:seznam>/export',
org_required(views.SeznamExportView),
name='seznam-export'
),
path(
'prednasky/seznam_prednasek/<int:seznam>/',
org_required(views.SeznamListView.as_view()),
name='seznam-list'
),
] ]

51
prednasky/views.py

@ -4,41 +4,52 @@ from django.views import generic
from django.shortcuts import HttpResponseRedirect from django.shortcuts import HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Sum from django.db.models import Sum
from django.forms import Form
from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH
from seminar.models import Soustredeni from seminar.models import Soustredeni, Osoba
from prednasky.forms import NewPrednaskyForm
def newPrednaska(request): def newPrednaska(request):
# hlasovani se vztahuje k nejnovejsimu soustredeni # hlasovani se vztahuje k nejnovejsimu soustredeni
sous = Soustredeni.objects.first() sous = Soustredeni.objects.first()
seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first() seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first()
print(seznam) osoba = Osoba.objects.filter(user=request.user).first()
ucastnik = osoba.plne_jmeno() + ' ' + str(osoba.id)
# obsluha formulare # obsluha formulare
if request.method == 'POST': if request.method == 'POST':
form = NewPrednaskyForm(request.POST, request.FILES) form = Form(request.POST, request.FILES)
if form.is_valid(): if form.is_valid():
jmeno = form.cleaned_data['ucastnik'] # id z důvodu duplicitních jmen (přechod z jména na objekt Osoby nějak kape na tom,
# že všechna předchozí hlasování zde mají náhodný string…)
# TODO Změnit to na Osobu
# TODO v následujících řádcích je zbytečně mnoho dotazů na QuerySet (pokud účastník hlasoval, hlasoval u všech)
for i in request.POST: for i in request.POST:
if i[0] == 'q': if i[0] == 'q':
prednaska = Prednaska.objects.filter(pk=int(i[1:]))[0]
hlasovani = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first()
if not hlasovani:
hlasovani = Hlasovani() hlasovani = Hlasovani()
print("q:"+i[1:]) hlasovani.prednaska = prednaska
hlasovani.prednaska = Prednaska.objects.filter(pk = int(i[1:]))[0] hlasovani.ucastnik = ucastnik
hlasovani.body = int(request.POST[i])
hlasovani.ucastnik = jmeno
hlasovani.seznam = seznam hlasovani.seznam = seznam
hlasovani.body = int(request.POST[i])
hlasovani.save() hlasovani.save()
# presmerovani na prave vzniklou galerii # presmerovani na prave vzniklou galerii
return HttpResponseRedirect('./hotovo') return HttpResponseRedirect('./hotovo')
def prednaska_hodnoceni(prednaska):
h = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first()
if h:
return prednaska, h.body
else: else:
form = NewPrednaskyForm() return prednaska, 0
return render( return render(
request, request,
'prednasky/base.html', 'prednasky/base.html',
{'form': form, 'prednasky': seznam} {'prednasky': map(prednaska_hodnoceni, seznam.prednaska_set.all())}
) )
@ -57,12 +68,26 @@ class SeznamListView(generic.ListView):
self.seznam = get_object_or_404(Seznam, id=self.kwargs["seznam"]) self.seznam = get_object_or_404(Seznam, id=self.kwargs["seznam"])
prednasky = Prednaska.objects.filter(seznamy=self.seznam).order_by( prednasky = Prednaska.objects.filter(seznamy=self.seznam).order_by(
'org__user__first_name', 'org__user__last_name' 'org__user__first_name', 'org__user__last_name'
).annotate(body=Sum('hlasovani__body')) )
return prednasky 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): 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 # TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro
# lidi? # lidi?
hlasovani = Hlasovani.objects.filter(seznam=seznam) hlasovani = Hlasovani.objects.filter(seznam=seznam)

3
seminar/admin.py

@ -3,6 +3,7 @@ from django.contrib import admin
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
from reversion.admin import VersionAdmin from reversion.admin import VersionAdmin
from django_reverse_admin import ReverseModelAdmin from django_reverse_admin import ReverseModelAdmin
from solo.admin import SingletonModelAdmin
# Todo: reversion # Todo: reversion
@ -160,5 +161,5 @@ class TextNodeAdmin(PolymorphicChildModelAdmin):
show_in_index = True show_in_index = True
admin.site.register(m.Nastaveni) admin.site.register(m.Nastaveni, SingletonModelAdmin)
admin.site.register(m.Novinky) admin.site.register(m.Novinky)

6
seminar/management/commands/auth.py

@ -1,17 +1,17 @@
# -*- coding: utf-8 -*- # -*- 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.sessions.models import Session
from django.contrib.auth.models import User 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. 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 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ý uložen v cookie sessionid) a pokud session existuje a příslušný přihlášený
uživatel právo přihlásit se do admina, vypíše jeho username. uživatel 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() session_key = raw_input()
s = Session.objects.get(pk=session_key).get_decoded() s = Session.objects.get(pk=session_key).get_decoded()
user_id = s['_auth_user_id'] user_id = s['_auth_user_id']

21
seminar/migrations/0001_squashed_0067_auto_20190814_0805.py

@ -511,7 +511,7 @@ def vyrob_problemum_ctypes(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
atomic = False 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 initial = True
@ -877,6 +877,7 @@ class Migration(migrations.Migration):
), ),
migrations.RunSQL( migrations.RunSQL(
sql='update seminar_rocniky set rocnik_n = cast (rocnik as integer)', sql='update seminar_rocniky set rocnik_n = cast (rocnik as integer)',
reverse_sql='update seminar_rocniky set rocnik_n = cast (rocnik as nvarchar(16))',
), ),
migrations.RemoveField( migrations.RemoveField(
model_name='rocnik', model_name='rocnik',
@ -1733,15 +1734,19 @@ class Migration(migrations.Migration):
# migr 0052 # migr 0052
migrations.RunPython( migrations.RunPython(
spoj_k_organizatorum_osoby, spoj_k_organizatorum_osoby,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
fix_problem, fix_problem,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
fix_pohadka, fix_pohadka,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
fix_novinka, fix_novinka,
reverse_code=migrations.RunPython.noop,
), ),
# migr 0053 # migr 0053
@ -1795,35 +1800,49 @@ class Migration(migrations.Migration):
# migr 0056 # migr 0056
migrations.RunPython( migrations.RunPython(
generuj_RocnikNody_a_CisloNody, generuj_RocnikNody_a_CisloNody,
reverse_code=migrations.RunPython.noop,
), ),
# migr 0057 # migr 0057
migrations.RunPython( migrations.RunPython(
reseni_to_Reseni, reseni_to_Reseni,
reverse_code=migrations.RunPython.noop,
), ),
# migr 0058 # migr 0058
migrations.RunPython( migrations.RunPython(
uloha_to_Uloha, uloha_to_Uloha,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
tema_to_Tema, tema_to_Tema,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
clanek_to_Clanek, clanek_to_Clanek,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
konfery_rucne, konfery_rucne,
reverse_code=migrations.RunPython.noop,
),
# 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 # migr 0059
migrations.RunPython( migrations.RunPython(
vytvor_pohadkanode, vytvor_pohadkanode,
reverse_code=migrations.RunPython.noop,
), ),
# migr 0060 # migr 0060
migrations.RunPython( migrations.RunPython(
pokacej_les, pokacej_les,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RemoveField( migrations.RemoveField(

3
seminar/migrations/0019_rocnik_ciselne.py

@ -18,7 +18,8 @@ class Migration(migrations.Migration):
preserve_default=False, preserve_default=False,
), ),
migrations.RunSQL( migrations.RunSQL(
sql="update seminar_rocniky set rocnik_n = cast (rocnik as integer)" sql="update seminar_rocniky set rocnik_n = cast (rocnik as integer)",
reverse_sql='update seminar_rocniky set rocnik_n = cast (rocnik as nvarchar(16))',
), ),
migrations.RemoveField( migrations.RemoveField(
model_name='rocnik', model_name='rocnik',

8
seminar/migrations/0052_user_to_organizator.py

@ -75,8 +75,8 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RunPython(spoj_k_organizatorum_osoby), migrations.RunPython(spoj_k_organizatorum_osoby, migrations.RunPython.noop),
migrations.RunPython(fix_problem), migrations.RunPython(fix_problem, migrations.RunPython.noop),
migrations.RunPython(fix_pohadka), migrations.RunPython(fix_pohadka, migrations.RunPython.noop),
migrations.RunPython(fix_novinka), migrations.RunPython(fix_novinka, migrations.RunPython.noop),
] ]

2
seminar/migrations/0056_vrcholy_pro_rocniky_a_cisla.py

@ -43,5 +43,5 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RunPython(generuj_RocnikNody_a_CisloNody), migrations.RunPython(generuj_RocnikNody_a_CisloNody, migrations.RunPython.noop),
] ]

2
seminar/migrations/0057_reseni_to_reseni_hodnoceni.py

@ -30,5 +30,5 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RunPython(reseni_to_Reseni) migrations.RunPython(reseni_to_Reseni, migrations.RunPython.noop)
] ]

8
seminar/migrations/0058_problem_to_uloha_tema_clanek.py

@ -154,8 +154,8 @@ class Migration(migrations.Migration):
operations = [ operations = [
# ashes to Ashes, dust to Dust.... # ashes to Ashes, dust to Dust....
migrations.RunPython(uloha_to_Uloha), migrations.RunPython(uloha_to_Uloha, migrations.RunPython.noop),
migrations.RunPython(tema_to_Tema), migrations.RunPython(tema_to_Tema, migrations.RunPython.noop),
migrations.RunPython(clanek_to_Clanek), migrations.RunPython(clanek_to_Clanek, migrations.RunPython.noop),
migrations.RunPython(konfery_rucne), migrations.RunPython(konfery_rucne, migrations.RunPython.noop),
] ]

4
seminar/migrations/0059_vytvorit_pohadkanode.py

@ -21,9 +21,9 @@ def vytvor_pohadkanode(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('seminar', '0058_problem_to_uloha_tema_clanek'), ('seminar', 'fix_0058'),
] ]
operations = [ operations = [
migrations.RunPython(vytvor_pohadkanode), migrations.RunPython(vytvor_pohadkanode, migrations.RunPython.noop),
] ]

2
seminar/migrations/0060_spoj_stromy.py

@ -108,5 +108,5 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RunPython(pokacej_les), migrations.RunPython(pokacej_les, migrations.RunPython.noop),
] ]

4
seminar/migrations/0065_treenode_polymorphic_ctype.py

@ -5,7 +5,7 @@ import django.db.models.deletion
def vyrob_treenodum_ctypes(apps, schema_editor): def vyrob_treenodum_ctypes(apps, schema_editor):
# Kód zkopírovaný z dokumentace: https://django-polymorphic.readthedocs.io/en/stable/migrating.html # 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') TreeNode = apps.get_model('seminar', 'TreeNode')
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
@ -27,5 +27,5 @@ class Migration(migrations.Migration):
name='polymorphic_ctype', 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'), 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),
] ]

4
seminar/migrations/0066_problem_polymorphic_ctype.py

@ -5,7 +5,7 @@ import django.db.models.deletion
def vyrob_problemum_ctypes(apps, schema_editor): def vyrob_problemum_ctypes(apps, schema_editor):
# Kód zkopírovaný z dokumentace: https://django-polymorphic.readthedocs.io/en/stable/migrating.html # 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') Problem = apps.get_model('seminar', 'Problem')
ContentType = apps.get_model('contenttypes', 'ContentType') ContentType = apps.get_model('contenttypes', 'ContentType')
@ -25,5 +25,5 @@ class Migration(migrations.Migration):
name='polymorphic_ctype', 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'), 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),
] ]

2
seminar/migrations/0068_treenode_nazev.py

@ -103,5 +103,5 @@ class Migration(migrations.Migration):
name='nazev', name='nazev',
field=models.TextField(help_text='Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode', null=True, verbose_name='název tohoto node'), field=models.TextField(help_text='Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode', null=True, verbose_name='název tohoto node'),
), ),
migrations.RunPython(fix_all_names), migrations.RunPython(fix_all_names, migrations.RunPython.noop),
] ]

6
seminar/migrations/0080_zruseni_claneknode_a_konferanode.py

@ -65,6 +65,9 @@ class Migration(migrations.Migration):
model_name='reseni', model_name='reseni',
name='text_zkraceny', name='text_zkraceny',
), ),
migrations.DeleteModel( # nejdříve musím smazat objekt ukazující na konferu,
name='KonferaNode', # pak až změnit klíč konferám (viz další operace)
),
migrations.AddField( migrations.AddField(
model_name='konfera', model_name='konfera',
name='problem_ptr', name='problem_ptr',
@ -95,9 +98,6 @@ class Migration(migrations.Migration):
migrations.DeleteModel( migrations.DeleteModel(
name='ClanekNode', name='ClanekNode',
), ),
migrations.DeleteModel(
name='KonferaNode',
),
migrations.CreateModel( migrations.CreateModel(
name='Konfery_Ucastnici', name='Konfery_Ucastnici',
fields=[ fields=[

8
seminar/migrations/0084_clanek_cislo.py

@ -4,6 +4,9 @@ from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from seminar.treelib import get_parent from seminar.treelib import get_parent
import logging
logger = logging.getLogger(__name__)
def najdi_cislo(apps, schema_editor): def najdi_cislo(apps, schema_editor):
Clanek = apps.get_model('seminar', 'Clanek') Clanek = apps.get_model('seminar', 'Clanek')
Hodnoceni = apps.get_model('seminar', 'Hodnoceni') Hodnoceni = apps.get_model('seminar', 'Hodnoceni')
@ -15,7 +18,10 @@ def najdi_cislo(apps, schema_editor):
for c in Clanek.objects.all(): for c in Clanek.objects.all():
reseni = c.reseni_set reseni = c.reseni_set
if (reseni.count() != 1): # Pozor, reseni_set je Manager, takže se na něj musí trošku jinak 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() r = reseni.first()
aktualniNode = r.text_cely # Hlavní ReseniNode pro řešení aktualniNode = r.text_cely # Hlavní ReseniNode pro řešení
while aktualniNode is not None: while aktualniNode is not None:

17
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'},
),
]

49
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),
]

35
seminar/migrations/0088_perm_org_a_ucastnik.py

@ -0,0 +1,35 @@
# Generated by Django 2.2.15 on 2020-09-05 10:10
from django.db import migrations
def add_perms(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType')
User = apps.get_model('auth', 'User')
Permission = apps.get_model('auth', 'Permission')
Resitel = apps.get_model('seminar', 'Resitel')
c = ContentType.objects.get_for_model(User)
org_perm = Permission.objects.filter(codename__exact='org').first()
if not org_perm:
org_perm = Permission.objects.create(codename='org', name='org', content_type=c)
resitel_perm = Permission.objects.filter(codename__exact='resitel').first()
if not resitel_perm:
resitel_perm = Permission.objects.create(codename='resitel', name='resitel', content_type=c)
for r in Resitel.objects.all():
u = r.osoba.user
if u:
u.user_permissions.add(resitel_perm)
for org in User.objects.all():
if org and org.is_staff:
org.user_permissions.add(org_perm)
class Migration(migrations.Migration):
dependencies = [
('seminar', '0087_fix_polymorphism'),
]
operations = [
migrations.RunPython(add_perms, migrations.RunPython.noop),
]

14
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),
]

7
seminar/models.py

@ -582,7 +582,7 @@ class Organizator(SeminarModelBase):
"školu, ale jen obor, možnost zobrazit zvlášť") "školu, ale jen obor, možnost zobrazit zvlášť")
def clean(self): 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!") raise ValidationError("Organizátor nemůže skončit s organizováním dříve než začal!")
super().clean() super().clean()
@ -597,6 +597,11 @@ class Organizator(SeminarModelBase):
class Meta: class Meta:
verbose_name = 'Organizátor' verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři' 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) @reversion.register(ignore_duplicates=True)
class Soustredeni(SeminarModelBase): class Soustredeni(SeminarModelBase):

22
seminar/templates/seminar/archiv/cislo.html

@ -18,9 +18,9 @@
<h2>Zadané problémy</h2> <h2>Zadané problémy</h2>
<ul> <ul>
{% for p in v_cisle_zadane %} {% for p in v_cisle_zadane %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}> <li{% if user.je_org and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff or cislo.verejne %} {% if user.je_org or cislo.verejne %}
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %} <a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.je_org or cislo.verejne %}</a>{% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
@ -29,14 +29,14 @@
<h2>Řešené problémy</h2> <h2>Řešené problémy</h2>
<ul> <ul>
{% for p in resene_problemy %} {% for p in resene_problemy %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}> <li{% if user.je_org and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff or cislo.verejne %} {% if user.je_org or cislo.verejne %}
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %} <a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.je_org or cislo.verejne %}</a>{% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
{% if user.is_staff %} {% if user.je_org %}
<div class="mam-org-only"> <div class="mam-org-only">
<h2> Orgovské odkazy </h2> <h2> Orgovské odkazy </h2>
<ul> <ul>
@ -52,13 +52,13 @@
<h2>Výsledkovka</h2> <h2>Výsledkovka</h2>
{% else %} {% else %}
{% if user.is_staff %} {% if user.je_org %}
<div class='mam-org-only'> <div class='mam-org-only'>
<h2>Výsledkovka (neveřejná)</h2> <h2>Výsledkovka (neveřejná)</h2>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if cislo.verejna_vysledkovka or user.is_staff %} {% if cislo.verejna_vysledkovka or user.je_org %}
<table class='vysledkovka'> <table class='vysledkovka'>
<tr class='border-b'> <tr class='border-b'>
<th class='border-r'># <th class='border-r'>#
@ -66,7 +66,7 @@
{% for p in problemy %} {% for p in problemy %}
<th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a> <th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a>
{% endfor %} {% endfor %}
<th class='border-r'>Za číslo</sup> <th class='border-r'>Za číslo
<th class='border-r'>Za ročník <th class='border-r'>Za ročník
<th class='border-r'>Odjakživa <th class='border-r'>Odjakživa
{% for rv in radky_vysledkovky %} {% for rv in radky_vysledkovky %}
@ -88,7 +88,7 @@
</table> </table>
{% endif %} {% endif %}
{% if not cislo.verejna_vysledkovka and user.is_staff %} {% if not cislo.verejna_vysledkovka and user.je_org %}
</div> </div>
{% endif %} {% endif %}

4
seminar/templates/seminar/archiv/problem.html

@ -3,11 +3,11 @@
{% load comments %} {% load comments %}
{% block content %} {% block content %}
<div {% if not problem.verejne and user.is_staff %}class="mam-org-only"{% endif %}> <div {% if not problem.verejne and user.je_org %}class="mam-org-only"{% endif %}>
{% block problem %} {% block problem %}
{% endblock %} {% endblock %}
{% if user.is_staff %} {% if user.je_org %}
<div class='mam-org-only'> <div class='mam-org-only'>
<h2>Text - org</h2> <h2>Text - org</h2>

4
seminar/templates/seminar/archiv/rocnik.html

@ -62,7 +62,7 @@
</div> </div>
{% if vysledkovka %} {% if vysledkovka %}
{% if user.is_staff %} {% if user.je_org %}
<div class='mam-org-only'> <div class='mam-org-only'>
<a href='vysledkovka.tex'>Výsledkovka ročníku (LaTeX)</a> <a href='vysledkovka.tex'>Výsledkovka ročníku (LaTeX)</a>
</div> </div>
@ -72,7 +72,7 @@
{% include "seminar/vysledkovka_rocnik.html" %} {% include "seminar/vysledkovka_rocnik.html" %}
{% endif %} {% endif %}
{% if user.is_staff and vysledkovka_s_neverejnymi %} {% if user.je_org and vysledkovka_s_neverejnymi %}
<div class='mam-org-only'> <div class='mam-org-only'>
<h2>Výsledková listina včetně neveřejných bodů</h2> <h2>Výsledková listina včetně neveřejných bodů</h2>
{% with radky_vyledkovky_s_neverejnymi as radky_vysledkovky %} {% with radky_vyledkovky_s_neverejnymi as radky_vysledkovky %}

2
seminar/templates/seminar/clanky/resitelske_clanky.html

@ -17,7 +17,7 @@
</h1> </h1>
{% for clanek in object_list %} {% for clanek in object_list %}
{% with clanek.cislo_zadani.rocnik.rocnik as rocnik %} {% with clanek.cislo.rocnik.rocnik as rocnik %}
{% ifchanged rocnik %} {% ifchanged rocnik %}
{% if not forloop.first %}</ul>{% endif %} {% if not forloop.first %}</ul>{% endif %}
<h2>{{ rocnik }}. ročník</h2> <h2>{{ rocnik }}. ročník</h2>

10
seminar/templates/seminar/formular_ok.html

@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block nadpis1a %}Formulář byl odeslán{% endblock %}
{% block content %}
<h1> Formulář byl úspěšně odeslán </h1>
{% for odkaz in odkazy %}
<p><a href="{{odkaz.1}}">{{odkaz.0}}</a></p>
{% endfor %}
{% endblock %}

8
seminar/templates/seminar/novinky.html

@ -1,11 +1,13 @@
{% for novinka in object_list %} {% for novinka in object_list %}
{% if not novinka.zverejneno and user.is_staff %} {# pripravene div-y na stylovani#}
<div>
{% if not novinka.zverejneno and user.je_org %}
<div class="mam-org-only"> <div class="mam-org-only">
<ul> <ul>
<li><a href="/admin/seminar/novinky/{{novinka.pk}}">Upravit novinku</a> <li><a href="/admin/seminar/novinky/{{novinka.pk}}">Upravit novinku</a>
</ul> </ul>
{% endif %} {% endif %}
{% if novinka.zverejneno or user.is_staff %} {% if novinka.zverejneno or user.je_org %}
{# datum #} {# datum #}
<div class=novinka_datum>{{novinka.datum}}</div> <div class=novinka_datum>{{novinka.datum}}</div>
{# text #} {# text #}
@ -31,7 +33,7 @@
{{novinka.autor.osoba.prijmeni}} {{novinka.autor.osoba.prijmeni}}
</div> </div>
{% endif %} {% endif %}
{% if not novinka.zverejneno and user.is_staff %} {% if not novinka.zverejneno and user.je_org %}
</div> </div>
{% endif %} {% endif %}
{% endfor%} {% endfor%}

87
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 %}
<h2><strong>Informace, komunikace</strong></h2>
<ul>
<li><strong><a href="https://wiki.mam.bezva.org/">wiki</a> </strong>obsahuje různé návody a know-how</li>
<li><strong><a href="https://riot.im/app/#/room/#orgovna:dolujeme.eu">Riot</a> </strong>chatování s dalšími orgy</li>
<li><strong>Kanboard </strong>správa TODO
<ul>
<li><a href="https://kanboard.ledoian.cz/?controller=BoardViewController&amp;action=show&amp;project_id=10">webařský</a></li>
<li>soustředění</li>
</ul>
</li>
<li><a href="/admin/seminar/novinky/add/"><strong>přidat novinku</strong></a> na web</li>
</ul>
<hr />
<h2><strong>Tvorba čísla</strong></h2>
<ul>
<li><a href="/admin/seminar/problemnavrh/add/"><strong>přidat téma</strong></a></li>
<li><strong>korektury</strong>
<ul>
<li><a href="/korektury/">korekturování</a></li>
<li><a href="/admin/korektury/korekturovanepdf/add/">přidat pdf k opravám</a></li>
</ul>
</li>
<li><a href='{{ posledni_cislo_url }}'><strong>poslední vydané číslo </strong></a></li>
</ul>
<hr />
<h2><strong>Moje problémy</strong></h2>
<h3> Témata </h3>
<ul>
{% for t in temata %}
<li> {{ t }} </li>
{% endfor %}
</ul>
<h3> Úlohy </h3>
<ul>
{% for u in ulohy %}
<li> {{ u }} </li>
{% endfor %}
</ul>
<h3> Články </h3>
<ul>
{% for c in clanky %}
<li> {{ c }} </li>
{% endfor %}
</ul>
<hr />
<h2><strong>Soustředění</strong></h2>
<ul>
<li><strong>přednášky</strong>
<ul>
<li><a href="/admin/prednasky/prednaska/">vypisování přednášek</a></li>
<li>hlasování o přednáškách</li>
</ul>
</li>
<li><a href="/soustredeni/probehlo/">proběhlá soustředění</a>
<ul>
<li>vytvoření galerie</li>
<li>stažení seznamu účastníků</li>
<li>obálky</li>
</ul>
</li>
</ul>
<hr />
<h2><strong>Můj profil</strong></h2>
<ul>
<li><a href="http://127.0.0.1:8000/admin/seminar/organizator/{{ organizator.id }}/change/"><strong>upravit </strong></a></li>
</ul>
<hr />
<p>Nemůžeš najít, co hledáš? Může to být v <a href="/admin/">administračním rozhraní webu</a>.</p>
{% endblock content %}

3
seminar/templates/seminar/profil/gdpr.html

@ -36,13 +36,14 @@ Tento souhlas uděluji ze své vlastní a svobodné vůle a beru na vědomí, ž
</p> </p>
<p class="gdpr"> <p class="gdpr">
Dále máte právo: Dále máte právo:
</p>
<ul> <ul>
<li>požádat o informaci, jaké osobní údaje jsou o vás zpracovávány, <li>požádat o informaci, jaké osobní údaje jsou o vás zpracovávány,
<li>požadovat opravu osobních údajů, pokud jsou neplatné nebo zastaralé, <li>požadovat opravu osobních údajů, pokud jsou neplatné nebo zastaralé,
<li>požadovat, aby nebyly vaše osobní údaje zpracovávány do doby, než bude vyřešena oprávněnost výše uvedených požadavků, <li>požadovat, aby nebyly vaše osobní údaje zpracovávány do doby, než bude vyřešena oprávněnost výše uvedených požadavků,
<li>požadovat, aby byly vaše osobní údaje předány jinému správci, <li>požadovat, aby byly vaše osobní údaje předány jinému správci,
<li>podat stížnost u dozorového úřadu. <li>podat stížnost u dozorového úřadu.
</p> </ul>
<p class="gdpr"> <p class="gdpr">
V případě jakéhokoliv dotazu nebo uplatnění svých práv můžete kontaktovat pověřence pro ochranu osobních údajů na e-mailové adrese gdpr@cuni.cz. V případě jakéhokoliv dotazu nebo uplatnění svých práv můžete kontaktovat pověřence pro ochranu osobních údajů na e-mailové adrese gdpr@cuni.cz.
</p> </p>

6
seminar/templates/seminar/profil/nahraj_reseni.html

@ -53,7 +53,7 @@
</td> </td>
<td {% if field.help_text %} class="field-with-comment"{% endif %}> <td {% if field.help_text %} class="field-with-comment"{% endif %}>
{{ field }} {{ field }}
<span class="field-comment">{{ field.help_text|safe }} <span class="field-comment">{{ field.help_text|safe }}</span>>
</td> </td>
<td><span class="field-error">{{ field.errors }}</span></td> <td><span class="field-error">{{ field.errors }}</span></td>
@ -74,7 +74,7 @@
<div id="empty_form" style="display:none"> <div id="empty_form" style="display:none">
<div class="attachment"> <div class="attachment">
<table class='form' id="reseni" class='no_error'> <table class='form no_error' id="reseni">
<tr> <tr>
{% for field in prilohy.empty_form.visible_fields %} {% for field in prilohy.empty_form.visible_fields %}
@ -86,7 +86,7 @@
</td> </td>
<td {% if field.help_text %} class="field-with-comment"{% endif %}> <td {% if field.help_text %} class="field-with-comment"{% endif %}>
{{ field }} {{ field }}
<span class="field-comment">{{ field.help_text|safe }} <span class="field-comment">{{ field.help_text|safe }}</span>
</td> </td>
<td><span class="field-error">{{ field.errors }}</span></td> <td><span class="field-error">{{ field.errors }}</span></td>

2
seminar/templates/seminar/profil/prihlaska_field.html

@ -8,7 +8,7 @@
</td> </td>
<td {% if field.help_text %} class="field-with-comment"{% endif %}> <td {% if field.help_text %} class="field-with-comment"{% endif %}>
{{ field }} {{ field }}
<span class="field-comment">{{ field.help_text|safe }} <span class="field-comment">{{ field.help_text|safe }}</span>
</td> </td>
</tr> </tr>

14
seminar/templates/seminar/soustredeni/seznam_soustredeni.html

@ -12,8 +12,8 @@
{# Projdi vsechna soustredeni #} {# Projdi vsechna soustredeni #}
{% for soustredeni in object_list %} {% for soustredeni in object_list %}
{# Kdyz je verejne -> zobraz #} {# Kdyz je verejne -> zobraz #}
{% if soustredeni.verejne_db or user.is_staff %} {% if soustredeni.verejne_db or user.je_org %}
{% if not soustredeni.verejne_db and user.is_staff %} {% if not soustredeni.verejne_db and user.je_org %}
<div class="mam-org-only"> <div class="mam-org-only">
<!--Groups of user: {{user.groups.all}} <br>--> <!--Groups of user: {{user.groups.all}} <br>-->
{% endif %} {% endif %}
@ -29,8 +29,8 @@
{# Zobrazeni odkazu na galerie #} {# Zobrazeni odkazu na galerie #}
{% if soustredeni.galerie_set.all %} {% if soustredeni.galerie_set.all %}
{% for galerie in soustredeni.galerie_set.all %} {% for galerie in soustredeni.galerie_set.all %}
{% if galerie.zobrazit == 0 or user.is_staff %} {% if galerie.zobrazit == 0 or user.je_org %}
<li {% if galerie.zobrazit > 0 and user.is_staff %}class="mam-org-only"{% endif %}> <li {% if galerie.zobrazit > 0 and user.je_org %}class="mam-org-only"{% endif %}>
<a href="../{{soustredeni.pk}}/fotogalerie/{{galerie.pk}}">Fotogalerie</a> <a href="../{{soustredeni.pk}}/fotogalerie/{{galerie.pk}}">Fotogalerie</a>
{# TODO kdyz je titulni obrazek, tak asi i titulni obrazek #} {# TODO kdyz je titulni obrazek, tak asi i titulni obrazek #}
</li> </li>
@ -38,7 +38,7 @@
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</ul> </ul>
{% if user.is_staff %} {% if user.je_org %}
<div class="mam-org-only"> <div class="mam-org-only">
<a href="../{{soustredeni.pk}}/fotogalerie/0/new/">Vytvořit novou fotogalerii</a><br> <a href="../{{soustredeni.pk}}/fotogalerie/0/new/">Vytvořit novou fotogalerii</a><br>
<a href="../{{soustredeni.pk}}/obalky.pdf">Vygenerovat obálky pro účastníky</a><br> <a href="../{{soustredeni.pk}}/obalky.pdf">Vygenerovat obálky pro účastníky</a><br>
@ -55,7 +55,7 @@
{% if soustredeni.text %} {% if soustredeni.text %}
{% autoescape off %}{{soustredeni.text}}{% endautoescape %} {% autoescape off %}{{soustredeni.text}}{% endautoescape %}
{% endif %} {% endif %}
{% if user.is_staff %} {% if user.je_org %}
<div class="mam-org-only"> <div class="mam-org-only">
{# Účastníci #} {# Účastníci #}
<h2>Soustředění se zúčastnili tito účastníci:</h2> <h2>Soustředění se zúčastnili tito účastníci:</h2>
@ -77,7 +77,7 @@
</div> </div>
{% endif %} {% endif %}
{% if not soustredeni.verejne_db and user.is_staff %} {% if not soustredeni.verejne_db and user.je_org %}
</div> {# class="mam-org-only" #} </div> {# class="mam-org-only" #}
{% endif %} {% endif %}
{% endif %} {% endif %}

1
seminar/templates/seminar/soustredeni/seznam_ucastniku.html

@ -35,7 +35,6 @@
Žádní účastníci nebyli... Žádní účastníci nebyli...
{% endfor %} {% endfor %}
</table> </table>
</ul>
</body> </body>
</html> </html>

2
seminar/templates/seminar/titulnistrana.html

@ -10,7 +10,7 @@
{% if dead %} {% if dead %}
<div class="odpocet"> <div class="odpocet">
<p><b>Do konce <a href="https://mam.mff.cuni.cz/zadani/aktualni/">odeslání řešení</a> {% if deadline_soustredeni %}(pro účast na soustředění) {% endif %}zbývá:<br> <p><b>Do konce <a href="/zadani/aktualni/">odeslání řešení</a> {% if deadline_soustredeni %}(pro účast na soustředění) {% endif %}zbývá:<br>
<big>{{ted|timesince:dead}}</big></b></p> <big>{{ted|timesince:dead}}</big></b></p>
</div> </div>
{% endif %} {% endif %}

2
seminar/templates/seminar/treenode.html

@ -1,4 +1,4 @@
{% extends "seminar/archiv/base_ulohy.html" %} {% extends "seminar/archiv/base.html" %}
{% load comments %} {% load comments %}

2
seminar/templates/seminar/zadani/AktualniVysledkovka.html

@ -27,7 +27,7 @@
v&nbsp;<a href="/archiv/cisla/">archivu</a>. v&nbsp;<a href="/archiv/cisla/">archivu</a>.
</p> </p>
{% if user.is_staff and vysledkovka_s_neverejnymi %} {% if user.je_org and vysledkovka_s_neverejnymi %}
<div class='mam-org-only'> <div class='mam-org-only'>
<h1>Výsledky včetně neveřejných</h1> <h1>Výsledky včetně neveřejných</h1>
{% with vysledkovka_s_neverejnymi as vysledkovka %} {% with vysledkovka_s_neverejnymi as vysledkovka %}

19
seminar/templates/seminar/zadani/AktualniZadani.html

@ -16,8 +16,8 @@
{% with nastaveni.aktualni_cislo as ac %} {% with nastaveni.aktualni_cislo as ac %}
{# Zobrazovani neverejnych zadani jen organizatorum #} {# Zobrazovani neverejnych zadani jen organizatorum #}
{% if user.is_staff or verejne %} {% if user.je_org or verejne %}
{% if user.is_staff and not verejne %}<div class="mam-org-only">{% endif %} {% if user.je_org and not verejne %}<div class="mam-org-only">{% endif %}
{% if ac.zadane_problemy.all %} {% if ac.zadane_problemy.all %}
{% if ac.datum_deadline_soustredeni %} {% if ac.datum_deadline_soustredeni %}
@ -35,8 +35,10 @@
{% if ac.pdf %} {% if ac.pdf %}
<p><a href="{{ac.pdf.url}}">Aktuální číslo v PDF</a></p> <h3>Aktuální témata najdete v <a href="{{ac.pdf.url}}">aktuálním čísle v PDF</a>.</h3>
{% endif %} {% endif %}
<!--Toto jsem zakomentoval, aby se tam nezobrazovala temata, ale text, že vše najdou pouze v PDF-->
{% if False %}
{% for sada in jednorazove_problemy %} {% for sada in jednorazove_problemy %}
{# podnadpisy, kdyz neni zakomentuje se nadpis #} {# podnadpisy, kdyz neni zakomentuje se nadpis #}
{% if not sada %}<!--{% endif %} {% if not sada %}<!--{% endif %}
@ -56,13 +58,15 @@
{% empty %} {% empty %}
Aktuálně nejsou zadané žádné úlohy k řešení. Aktuálně nejsou zadané žádné úlohy k řešení.
{% endfor %} {% endfor %}
{% endif %}
{% if user.is_staff and not verejne%}</div>{% endif %} {% if user.je_org and not verejne%}</div>{% endif %}
{% else %} {% else %}
<h2>Aktuálně nejsou zveřejněny žádné úlohy</h2> <h2>Aktuálně nejsou zveřejněny žádné úlohy</h2>
{% endif %} {% endif %}
{% if False %}
<h2>Témata</h2> <h2>Témata</h2>
<ul> <ul>
{% for problem in temata %} {% for problem in temata %}
@ -71,9 +75,14 @@
<a href="{{problem.verejne_url}}">Téma {{problem.kod}}: {{problem.nazev}}</a> <a href="{{problem.verejne_url}}">Téma {{problem.kod}}: {{problem.nazev}}</a>
</li> </li>
{% empty %} {% empty %}
Aktuálně nejsou zadána žádná témata k řešení. {% if ac.pdf %}
<p>Aktuální témata najdete v <a href="{{ac.pdf.url}}">aktuálním čísle v PDF</a>.</p>
{% else %}
<p>Aktuálně nemáme žádná témata.</p>
{% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %}
{% endwith %} {% endwith %}

14
seminar/templates/seminar/zadani/Temata.html

@ -16,15 +16,20 @@
{% endblock %}{% endblock %} {% endblock %}{% endblock %}
</h1> </h1>
<h3>
<b> Pozor, tato stránka není aktuální!</b> Aktualizovaný seznam všech čísel v PDF najdete <a href="/rocnik/26/">zde</a>. Za problémy se omlouváme.
</h3>
<p> <p>
Témata jsou hlavním obsahem časopisu M&amp;M. Obvykle představují Témata jsou texty nejen z oblasti matematiky, fyziky a informatiky, které
složitější a obecnější problémy než samostatné úlohy. Navíc je v&nbsp;jejich popisují nějaký problém a jsou doprovázeny návodnými úlohami. Vaším úkolem
zadání vždy prostor pro tvůrčí rozšíření. Za pěkný článek k&nbsp;tématu lze je zamyslet se nad daným problémem a sepsat vaše úvahy ve formě krátkého
získat třeba i 20 bodů, určitě se tedy vyplatí se tématy zabývat. textu.
</p> </p>
<p> <p>
<a href="/co-je-MaM/jak-resit/">Jak řešit téma?</a> <a href="/co-je-MaM/jak-resit/">Jak řešit téma?</a>
</p> </p>
<!--
{% if temata %} {% if temata %}
<p> <p>
Letos jsme pro tebe připravili tato témata: Letos jsme pro tebe připravili tato témata:
@ -72,6 +77,7 @@
{% empty %} {% empty %}
Aktuálně nejsou zadána žádná témata k řešení. Aktuálně nejsou zadána žádná témata k řešení.
{% endfor %} {% endfor %}
-->
</div> </div>
{% endwith %} {% endwith %}

55
seminar/testutils.py

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import datetime import datetime
from django.contrib.auth.models import Permission
from pytz import timezone from pytz import timezone
import random import random
import lorem import lorem
@ -9,6 +11,7 @@ from django.db import transaction
import unidecode import unidecode
import logging 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 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 import seminar.models as m
@ -70,7 +73,7 @@ def gen_osoby(rnd, size):
if pokusy >= max_pokusy: if pokusy >= max_pokusy:
print("Chyba, na danou velikost testovacích dat příliš málo možných" print("Chyba, na danou velikost testovacích dat příliš málo možných"
" jmen a příjmení") " jmen a příjmení")
exit exit()
prezdivka = rnd.choice(prezdivky) prezdivka = rnd.choice(prezdivky)
email = "@".join([unidecode.unidecode(jmeno), rnd.choice(domain)]) email = "@".join([unidecode.unidecode(jmeno), rnd.choice(domain)])
telefon = "".join([str(rnd.choice([k for k in range(10)])) for i in range(9)]) 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...') logger.info('Generuji řešitele...')
resitele = [] resitele = []
x = 0
resitel_perm = Permission.objects.filter(codename__exact='resitel').first()
for os in osoby: for os in osoby:
rand = rnd.randint(0, 8) rand = rnd.randint(0, 8)
if not (rand % 8 == 0): 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), resitele.append(Resitel.objects.create(osoba=os, skola=rnd.choice(skoly),
rok_maturity=rnd.randint(2019, 2029), rok_maturity=rnd.randint(2019, 2029),
zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)[0])) 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)) prijemci.append(Prijemce.objects.create(osoba=i))
return prijemci return prijemci
def gen_organizatori(rnd, osoby, last_rocnik, users): def gen_organizatori(rnd, osoby, last_rocnik):
logger.info('Generuji organizátory...') logger.info('Generuji organizátory...')
organizatori = [] organizatori = []
@ -149,6 +163,8 @@ def gen_organizatori(rnd, osoby, last_rocnik, users):
seznam_oboru = ["matematiku", "matematiku", "matematiku", "fyziku", "literaturu", seznam_oboru = ["matematiku", "matematiku", "matematiku", "fyziku", "literaturu",
"informatiku", "informatiku", "běhání dokolečka"] "informatiku", "informatiku", "běhání dokolečka"]
x = 0
org_perm = Permission.objects.filter(codename__exact='org').first()
for os in osoby: for os in osoby:
rand = rnd.randint(0, 8) rand = rnd.randint(0, 8)
if (rand % 8 == 0): if (rand % 8 == 0):
@ -175,6 +191,15 @@ def gen_organizatori(rnd, osoby, last_rocnik, users):
if do.year > datetime.datetime.now().year: if do.year > datetime.datetime.now().year:
do = None 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, organizatori.append(Organizator.objects.create(osoba=os,
organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga)) organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga))
return organizatori return organizatori
@ -681,14 +706,14 @@ def otec_syn(otec, syn):
syn.save() syn.save()
otec.save() otec.save()
def gen_clanek(rnd): def gen_clanek(rnd, organizatori, resitele):
logger.info("Generuji článek do čísla 22.2") logger.info("Generuji článek do čísla 22.2")
clanek = m.Clanek.objects.create( clanek = m.Clanek.objects.create(
nazev="Článek o Lorem ipsum", nazev="Článek o Lorem ipsum",
nadproblem=None, nadproblem=None,
stav='vyreseny', stav='vyreseny',
zamereni=['I'], zamereni=['I'],
garant=rnd.choice(m.Organizator.objects.all()), garant=rnd.choice(organizatori),
kod='cl', kod='cl',
) )
clanek.save() clanek.save()
@ -696,7 +721,7 @@ def gen_clanek(rnd):
reseni = m.Reseni.objects.create( reseni = m.Reseni.objects.create(
zverejneno=True, zverejneno=True,
) )
reseni.resitele.add(rnd.choice(m.Resitel.objects.all())) reseni.resitele.add(rnd.choice(resitele))
reseni.save() reseni.save()
cislo = m.Cislo.objects.get(rocnik__rocnik=22, poradi=2) cislo = m.Cislo.objects.get(rocnik__rocnik=22, poradi=2)
@ -771,11 +796,22 @@ def create_test_data(size = 6, rnd = None):
# users # users
admin = User.objects.create_superuser(username='admin', email='', password='admin') 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'] usernames = ['anet', 'bara', 'cyril', 'david', 'eva', 'filip']
users = [] users = []
for usr in usernames[:size]: 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.first_name = usr.capitalize()
u.save() u.save()
users.append(u) users.append(u)
@ -789,8 +825,8 @@ def create_test_data(size = 6, rnd = None):
# resitele a organizatori # resitele a organizatori
last_rocnik = 25 last_rocnik = 25
organizatori = gen_organizatori(rnd, osoby, last_rocnik)
resitele = gen_resitele(rnd, osoby, skoly) resitele = gen_resitele(rnd, osoby, skoly)
organizatori = gen_organizatori(rnd, osoby, last_rocnik, users)
#generování novinek #generování novinek
novinky = gen_novinky(rnd, organizatori) novinky = gen_novinky(rnd, organizatori)
@ -830,6 +866,9 @@ def create_test_data(size = 6, rnd = None):
#generování konfer #generování konfer
konfery = gen_konfery(size, rnd, organizatori, resitele, soustredeni) 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 # 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) # 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 # TODO: vytvorit temata s ruznymi vlakny
@ -840,7 +879,7 @@ def create_test_data(size = 6, rnd = None):
# TODO: přidat ke konferám řešení a dát je do čísel # TODO: přidat ke konferám řešení a dát je do čísel
# Dohackované vytvoření jednoho článku # Dohackované vytvoření jednoho článku
gen_clanek(rnd) gen_clanek(rnd, organizatori, resitele)
# obecné nastavení semináře, musí být už přidané ročníky a čísla, jinak se nastaví divně # obecné nastavení semináře, musí být už přidané ročníky a čísla, jinak se nastaví divně

106
seminar/urls.py

@ -1,11 +1,8 @@
from django.urls import path, include from django.urls import path, include
from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.decorators import login_required
from . import views, export 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.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 = [ urlpatterns = [
# path('aktualni/temata/', views.TemataRozcestnikView), # path('aktualni/temata/', views.TemataRozcestnikView),
@ -33,17 +30,17 @@ urlpatterns = [
), ),
path( path(
'soustredeni/<int:soustredeni>/seznam_ucastniku', 'soustredeni/<int:soustredeni>/seznam_ucastniku',
staff_member_required(views.SoustredeniUcastniciView.as_view()), org_required(views.SoustredeniUcastniciView.as_view()),
name='soustredeni_ucastnici' name='soustredeni_ucastnici'
), ),
path( path(
'soustredeni/<int:soustredeni>/maily_ucastniku', 'soustredeni/<int:soustredeni>/maily_ucastniku',
staff_member_required(views.SoustredeniMailyUcastnikuView.as_view()), org_required(views.SoustredeniMailyUcastnikuView.as_view()),
name='maily_ucastniku' name='maily_ucastniku'
), ),
path( path(
'soustredeni/<int:soustredeni>/export_ucastniku', 'soustredeni/<int:soustredeni>/export_ucastniku',
staff_member_required(views.soustredeniUcastniciExportView), org_required(views.soustredeniUcastniciExportView),
name='soustredeni_ucastnici_export' name='soustredeni_ucastnici_export'
), ),
path( path(
@ -62,58 +59,101 @@ urlpatterns = [
#path('clanky/org/', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'), #path('clanky/org/', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'),
# Aesop # Aesop
path('aesop-export/mam-rocnik-<int:prvni_rok>.csv', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'), path(
path('aesop-export/mam-sous-<str:datum_zacatku>.csv', export.ExportSousView.as_view(), name='seminar_export_sous'), 'aesop-export/mam-rocnik-<int:prvni_rok>.csv',
path('aesop-export/index.csv', export.ExportIndexView.as_view(), name='seminar_export_index'), org_required(export.ExportRocnikView.as_view()),
name='seminar_export_rocnik'
),
path(
'aesop-export/mam-sous-<str:datum_zacatku>.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: # Stranky viditelne pouze pro orgy:
path( path(
'rocnik/<int:rocnik>/vysledkovka.tex', 'rocnik/<int:rocnik>/vysledkovka.tex',
staff_member_required(views.RocnikVysledkovkaView.as_view()), org_required(views.RocnikVysledkovkaView.as_view()),
name='seminar_rocnik_vysledkovka' name='seminar_rocnik_vysledkovka'
), ),
path('cislo/<int:rocnik>.<int:cislo>/vysledkovka.tex', path(
staff_member_required(views.CisloVysledkovkaView.as_view()), 'cislo/<int:rocnik>.<int:cislo>/vysledkovka.tex',
org_required(views.CisloVysledkovkaView.as_view()),
name='seminar_cislo_vysledkovka' name='seminar_cislo_vysledkovka'
), ),
path('cislo/<int:rocnik>.<int:cislo>/obalky.pdf', path(
staff_member_required(views.cisloObalkyView), name='seminar_cislo_obalky'), 'cislo/<int:rocnik>.<int:cislo>/obalky.pdf',
org_required(views.cisloObalkyView),
path('cislo/<int:rocnik>.<int:cislo>/tituly.tex', name='seminar_cislo_obalky'
staff_member_required(views.TitulyView), name='seminar_cislo_titul'), ),
path('stav', path(
staff_member_required(views.StavDatabazeView), name='stav_databaze'), 'cislo/<int:rocnik>.<int:cislo>/tituly.tex',
path('cislo/<int:rocnik>.<int:cislo>/obalkovani', org_required(views.TitulyView),
staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'), name='seminar_cislo_titul'
path('soustredeni/<int:soustredeni>/obalky.pdf', ),
staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), path(
'stav',
org_required(views.StavDatabazeView),
name='stav_databaze'
),
path(
'cislo/<int:rocnik>.<int:cislo>/obalkovani',
org_required(views.ObalkovaniView.as_view()),
name='seminar_cislo_resitel_obalkovani'
),
path(
'soustredeni/<int:soustredeni>/obalky.pdf',
org_required(views.soustredeniObalkyView),
name='seminar_soustredeni_obalky'
),
path(
'org/vloz_body/<int:tema>/',
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('org/vloz_body/<int:tema>/',
staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'),
path('prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), path('prihlaska/',views.prihlaskaView, name='seminar_prihlaska'),
path('login/', views.LoginView.as_view(), name='login'), path('login/', views.LoginView.as_view(), name='login'),
path('logout/', views.LogoutView.as_view(), name='logout'), path('logout/', views.LogoutView.as_view(), name='logout'),
path('resitel/', views.ResitelView.as_view(), name='seminar_resitel'), path('resitel/', resitel_required(views.ResitelView.as_view()), name='seminar_resitel'),
path('reset_password/', views.PasswordResetView.as_view(), name='reset_password'), path('reset_password/', views.PasswordResetView.as_view(), name='reset_password'),
path('change_password/', views.PasswordChangeView.as_view(), name='change_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_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'),
path('reset_password_confirm/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), path('reset_password_confirm/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
path('reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), path('reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'),
path('resitel_edit', views.resitelEditView, name='seminar_resitel_edit'), 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 # Autocomplete
path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), 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('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/add_solution', org_required(views.AddSolutionView.as_view()), name='seminar_vloz_reseni'),
path('temp/nahraj_reseni', views.NahrajReseniView.as_view(),name='seminar_nahraj_reseni'), path('temp/nahraj_reseni', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'),
path('', views.TitulniStranaView.as_view(), name='titulni_strana'), path('', views.TitulniStranaView.as_view(), name='titulni_strana'),
# Ceka na autocomplete v3 # Ceka na autocomplete v3
# path('autocomplete/organizatori/', # path('autocomplete/organizatori/',
# staff_member_required(views.OrganizatorAutocomplete.as_view()), # org_member_required(views.OrganizatorAutocomplete.as_view()),
# name='seminar_autocomplete_organizator') # name='seminar_autocomplete_organizator')

14
seminar/utils.py

@ -1,15 +1,25 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import datetime import datetime
from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import permission_required
from html.parser import HTMLParser from html.parser import HTMLParser
from django.contrib.auth.models import AnonymousUser
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
import seminar.models as m import seminar.models as m
import seminar.treelib as t import seminar.treelib as t
staff_member_required = user_passes_test(lambda u: u.is_staff) 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
class FirstTagParser(HTMLParser): class FirstTagParser(HTMLParser):

2
seminar/views/utils.py

@ -6,8 +6,6 @@ from html.parser import HTMLParser
import seminar.models as m import seminar.models as m
staff_member_required = user_passes_test(lambda u: u.is_staff)
class FirstTagParser(HTMLParser): class FirstTagParser(HTMLParser):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.firstTag = None self.firstTag = None

122
seminar/views/views_all.py

@ -1,6 +1,6 @@
# coding:utf-8 # coding:utf-8
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render, redirect
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
from django.urls import reverse,reverse_lazy from django.urls import reverse,reverse_lazy
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
@ -10,9 +10,10 @@ from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect
from django.db.models import Q, Sum, Count from django.db.models import Q, Sum, Count
from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.generic.edit import FormView, CreateView 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 authenticate, login, get_user_model, logout
from django.contrib.auth import views as auth_views 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.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction from django.db import transaction
@ -238,8 +239,7 @@ def spravne_novinky(request):
user = request.user user = request.user
# Využíváme líné vyhodnocování QuerySetů # Využíváme líné vyhodnocování QuerySetů
qs = Novinky.objects.all() qs = Novinky.objects.all()
# TODO: Tohle by mělo spíš kontrolovat, že je/není někdo org, než že může do Adminu. if not user.je_org:
if not user.is_staff:
qs = qs.filter(zverejneno=True) qs = qs.filter(zverejneno=True)
return qs.order_by('-datum') return qs.order_by('-datum')
@ -644,7 +644,7 @@ class ProblemView(generic.DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**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. # 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.is_staff: if not context['object'].verejne() and not self.request.user.je_org:
raise PermissionDenied() raise PermissionDenied()
if isinstance(context['object'], Clanek): if isinstance(context['object'], Clanek):
context['reseni'] = Reseni.objects.filter(problem=context['object']).select_related('resitel').order_by('resitel__prijmeni') context['reseni'] = Reseni.objects.filter(problem=context['object']).select_related('resitel').order_by('resitel__prijmeni')
@ -896,6 +896,43 @@ def oldObalkovaniView(request, rocnik, cislo):
{'cislo': cislo, 'problemy': problemy, 'reseni': reseni} {'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 ### Tituly
def TitulyView(request, rocnik, cislo): def TitulyView(request, rocnik, cislo):
@ -974,12 +1011,44 @@ def soustredeniUcastniciExportView(request,soustredeni):
### Články ### Č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: 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): class ClankyResitelView(generic.ListView):
model = Problem model = Problem
template_name = 'seminar/clanky/resitelske_clanky.html' 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 # FIXME: pokud chceme orgoclanky, tak nejak zavest do modelu a podle toho odkomentovat a upravit
#class ClankyOrganizatorView(generic.ListView)<F12>: #class ClankyOrganizatorView(generic.ListView)<F12>:
@ -1088,7 +1157,7 @@ def logoutView(request):
def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data): 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) logger.warn(msg)
gdpr_logger.warn(msg+", form:{}".format(form_data)) gdpr_logger.warn(msg+", form:{}".format(form_data))
@ -1141,7 +1210,7 @@ def resitelEditView(request):
msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa']) msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa'])
resitel_edit.save() resitel_edit.save()
osoba_edit.save() osoba_edit.save()
return HttpResponseRedirect('/thanks/') return formularOKView(request)
else: else:
## Stránka před odeslaním formuláře = předvyplněný formulář ## Stránka před odeslaním formuláře = předvyplněný formulář
return render(request, 'seminar/profil/edit.html', {'form': form}) return render(request, 'seminar/profil/edit.html', {'form': form})
@ -1156,8 +1225,8 @@ def prihlaskaView(request):
if form.is_valid(): if form.is_valid():
generic_logger.info("Form valid") generic_logger.info("Form valid")
fcd = form.cleaned_data fcd = form.cleaned_data
form_hash = hash(fcd) form_hash = hash(frozenset(fcd.items()))
form_logger.info(fcd,form_hash=form_hash) form_logger.info(str(fcd) + str(form_hash)) # TODO možná logovat jinak
with transaction.atomic(): with transaction.atomic():
u = User.objects.create_user( u = User.objects.create_user(
@ -1165,6 +1234,8 @@ def prihlaskaView(request):
password=fcd['password'], password=fcd['password'],
email = fcd['email']) email = fcd['email'])
u.save() u.save()
resitel_perm = Permission.objects.filter(codename__exact='resitel').first()
u.user_permissions.add(resitel_perm)
o = Osoba( o = Osoba(
jmeno = fcd['jmeno'], jmeno = fcd['jmeno'],
@ -1187,7 +1258,7 @@ def prihlaskaView(request):
else: else:
# Unknown country - log it # Unknown country - log it
msg = "Unknown country {}".format(fcd['stat_text']) 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.save()
o.user = u o.user = u
@ -1205,11 +1276,11 @@ def prihlaskaView(request):
else: else:
# Unknown school - log it # Unknown school - log it
msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa']) 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() r.save()
return HttpResponseRedirect('/thanks/') return formularOKView(request)
# if a GET (or any other method) we'll create a blank form # if a GET (or any other method) we'll create a blank form
else: else:
@ -1259,3 +1330,28 @@ class PasswordResetCompleteView(auth_views.PasswordResetCompleteView):
class PasswordChangeView(auth_views.PasswordChangeView): class PasswordChangeView(auth_views.PasswordChangeView):
#template_name = 'seminar/password_change.html' #template_name = 'seminar/password_change.html'
success_url = reverse_lazy('titulni_strana') success_url = reverse_lazy('titulni_strana')
# 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)

661
sitetree_new.json

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save