Browse Source

Merge branch 'data_migrations' into email

export_seznamu_prednasek
Jonas Havelka 3 years ago
parent
commit
01648bb846
  1. 6
      .gitignore
  2. 187
      MIGRATIONS
  3. 16
      Makefile
  4. 8
      data/flat.json
  5. 207
      data/fotka_header.json
  6. 782
      data/sitetree_new.json
  7. 4
      galerie/admin.py
  8. 18
      galerie/migrations/0010_auto_20200819_0947.py
  9. 2
      galerie/models.py
  10. 6
      galerie/templates/galerie/Base.html
  11. 2
      galerie/templates/galerie/Galerie.html
  12. 6
      galerie/templates/galerie/GalerieNahled.html
  13. 2
      galerie/templates/galerie/GalerieNew.html
  14. 7
      galerie/urls.py
  15. 62
      galerie/views.py
  16. 0
      header_fotky/__init__.py
  17. 10
      header_fotky/admin.py
  18. 5
      header_fotky/apps.py
  19. 45
      header_fotky/context_processors.py
  20. 63
      header_fotky/migrations/0001_initial.py
  21. 0
      header_fotky/migrations/__init__.py
  22. 65
      header_fotky/models.py
  23. 29
      korektury/models.py
  24. 9
      korektury/templates/korektury/base.html
  25. 3
      korektury/templates/korektury/help.html
  26. 4
      korektury/templates/korektury/opraf.html
  27. 2
      korektury/templates/korektury/seznam.html
  28. BIN
      korektury/testpdfs/A.pdf
  29. 5125
      korektury/testpdfs/B.pdf
  30. 69
      korektury/testutils.py
  31. 11
      korektury/urls.py
  32. 26
      korektury/views.py
  33. 4
      mamweb/admin.py
  34. 12
      mamweb/context_processors.py
  35. 15
      mamweb/routers.py
  36. 39
      mamweb/settings_common.py
  37. 4
      mamweb/settings_local.py
  38. 4
      mamweb/settings_test.py
  39. 38
      mamweb/static/css/mamweb-dev.css
  40. 338
      mamweb/static/css/mamweb.css
  41. BIN
      mamweb/static/images/header/beh.jpg
  42. 26847
      mamweb/static/images/jakresit_1.svg
  43. 26847
      mamweb/static/images/jakresit_2.svg
  44. 26847
      mamweb/static/images/jakresit_3.svg
  45. 0
      mamweb/static/images/logo_1.svg
  46. 0
      mamweb/static/images/logo_2.svg
  47. 0
      mamweb/static/images/logo_3.svg
  48. 0
      mamweb/static/images/logo_4.svg
  49. 0
      mamweb/static/images/logo_5.svg
  50. 0
      mamweb/static/images/logo_6.svg
  51. 25
      mamweb/templates/base.html
  52. 104
      mamweb/templates/flatpages/default.html
  53. 26
      mamweb/templates/logo.html
  54. 4
      mamweb/templates/menu.html
  55. 4
      mamweb/templates/menu_mobile.html
  56. 5
      mamweb/urls.py
  57. 2
      mamweb_prod.ini
  58. 2
      mamweb_test.ini
  59. 10
      prednasky/templates/prednasky/base.html
  60. 6
      prednasky/templates/prednasky/metaseznam_prednasek.html
  61. 6
      prednasky/templates/prednasky/seznam_prednasek.html
  62. 14
      prednasky/templates/prednasky/seznam_prednasek_export.txt
  63. 27
      prednasky/urls.py
  64. 55
      prednasky/views.py
  65. 3
      requirements.txt
  66. 1
      seminar/.~lock.profile_vysledkovka.txt#
  67. 89
      seminar/admin.py
  68. 34
      seminar/forms.py
  69. 6
      seminar/management/commands/auth.py
  70. 21
      seminar/migrations/0001_squashed_0067_auto_20190814_0805.py
  71. 3
      seminar/migrations/0019_rocnik_ciselne.py
  72. 8
      seminar/migrations/0052_user_to_organizator.py
  73. 2
      seminar/migrations/0056_vrcholy_pro_rocniky_a_cisla.py
  74. 2
      seminar/migrations/0057_reseni_to_reseni_hodnoceni.py
  75. 8
      seminar/migrations/0058_problem_to_uloha_tema_clanek.py
  76. 4
      seminar/migrations/0059_vytvorit_pohadkanode.py
  77. 2
      seminar/migrations/0060_spoj_stromy.py
  78. 4
      seminar/migrations/0065_treenode_polymorphic_ctype.py
  79. 4
      seminar/migrations/0066_problem_polymorphic_ctype.py
  80. 2
      seminar/migrations/0068_treenode_nazev.py
  81. 6
      seminar/migrations/0080_zruseni_claneknode_a_konferanode.py
  82. 8
      seminar/migrations/0084_clanek_cislo.py
  83. 17
      seminar/migrations/0086_auto_20200819_0959.py
  84. 49
      seminar/migrations/0087_fix_polymorphism.py
  85. 35
      seminar/migrations/0088_perm_org_a_ucastnik.py
  86. 18
      seminar/migrations/0089_cislo_datum_preddeadline.py
  87. 19
      seminar/migrations/0090_auto_20201110_1958.py
  88. 18
      seminar/migrations/0091_resitel_zasilat_cislo_emailem.py
  89. 14
      seminar/migrations/fix_0058.py
  90. 166
      seminar/models.py
  91. 7
      seminar/permissions.py
  92. BIN
      seminar/static/images/no-picture.png
  93. BIN
      seminar/static/images/tema-bez-obrazku.png
  94. 18
      seminar/static/seminar/treenode_editor.js
  95. 6
      seminar/templates/seminar/archiv/base.html
  96. 8
      seminar/templates/seminar/archiv/cisla.html
  97. 97
      seminar/templates/seminar/archiv/cislo-normal.html
  98. 35
      seminar/templates/seminar/archiv/cislo.html
  99. 2
      seminar/templates/seminar/archiv/cislo_obalkovani.html
  100. 15
      seminar/templates/seminar/archiv/odmeny.html

6
.gitignore

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

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

16
Makefile

@ -34,6 +34,8 @@ install_web: venv_check
pip install --upgrade setuptools
# Instalace závislostí webu
pip install -r requirements.txt --upgrade
# Po vygenerování testdat spusť ./manage.py loaddata data/*, ať máš menu a další modely
:x
install_venv:
${VENV} ${VENV_PATH}
@ -65,7 +67,7 @@ schema_all.pdf: venv_check
# Deploy to current *mamweb-test* directory
deploy_test: venv_check
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
@if [ `pwd` != "/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi
@if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-test" ]; then echo "Only possible in directory mamweb-test"; exit 1; fi
@echo "Installing version from origin/test ..."
git pull origin test
git clean -f
@ -81,9 +83,9 @@ deploy_test: venv_check
# Deploy to current *mamweb-prod* directory
deploy_prod: venv_check
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
@if [ `pwd` != "/akce/mam/www/mamweb-prod" ]; then echo "Only possible in /akce/mam/www/mamweb-prod"; exit 1; fi
@if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-prod" ]; then echo "Only possible in directory mamweb-prod"; exit 1; fi
@echo "Backing up production DB ..."
( cd .. && ./backup_prod_db.sh )
( cd -P .. && ./backup_prod_db.sh )
@echo "Installing version from origin/master ..."
git pull origin master
git clean -f
@ -109,7 +111,7 @@ sync_prod_flatpages: venv_check
# Sync test media directory with production
sync_test_media:
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
@if [ `pwd` != "/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi
@if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi
rsync -av --delete /akce/mam/www/mamweb-prod/media/ ./media
# Sync test database with production database
@ -139,3 +141,9 @@ sync_local_db:
# Sync database and media. See above lines
sync_local: sync_local_media sync_local_db
# Push local compiled Vue to gimli test site
push_compiled_vue_to_test:
scp vue_frontend/webpack-stats.json mam-web@gimli:/akce/mam/www/mamweb-test/vue_frontend/
rsync -ave ssh seminar/static/seminar/vue mam-web@gimli:/akce/mam/www/mamweb-test/seminar/static/seminar/
ssh mam-web@gimli.ms.mff.cuni.cz 'cd /akce/mam/www/mamweb-test/ && . env/bin/activate && ./manage.py collectstatic --noinput'

8
flat.json → data/flat.json

File diff suppressed because one or more lines are too long

207
data/fotka_header.json

@ -0,0 +1,207 @@
[
{
"model": "header_fotky.fotkaheader",
"pk": "baliky.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/baliky.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "beh.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/beh.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "kryptografie.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/kryptografie.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "mam_cernobile.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/mam_cernobile.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "noc.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/noc.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "ohen.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/ohen.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "snih.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/snih.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "spolecna.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/spolecna.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "stiny.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/stiny.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "vikendovka.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/vikendovka.jpg"
}
},
{
"model": "header_fotky.fotkaheader",
"pk": "vylet.jpg",
"fields": {
"cas": "2020-09-20T09:18:34.562Z",
"fotka": "header/vylet.jpg"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 1,
"fields": {
"url": "/archiv/",
"fotka": "stiny.jpg",
"denni_doba": "oboji"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 2,
"fields": {
"url": "/clanky/",
"fotka": "kryptografie.jpg",
"denni_doba": "den"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 3,
"fields": {
"url": "/clanky/",
"fotka": "ohen.jpg",
"denni_doba": "noc"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 4,
"fields": {
"url": "/zadani/",
"fotka": "baliky.jpg",
"denni_doba": "den"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 5,
"fields": {
"url": "/zadani/",
"fotka": "stiny.jpg",
"denni_doba": "noc"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 6,
"fields": {
"url": "/co-je-MaM/",
"fotka": "vikendovka.jpg",
"denni_doba": "den"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 7,
"fields": {
"url": "/co-je-MaM/",
"fotka": "noc.jpg",
"denni_doba": "noc"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 8,
"fields": {
"url": "/soustredeni/",
"fotka": "beh.jpg",
"denni_doba": "den"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 9,
"fields": {
"url": "/soustredeni/",
"fotka": "vylet.jpg",
"denni_doba": "noc"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 10,
"fields": {
"url": "/login/",
"fotka": "baliky.jpg",
"denni_doba": "den"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 11,
"fields": {
"url": "/login/",
"fotka": "stiny.jpg",
"denni_doba": "noc"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 12,
"fields": {
"url": "/profil/",
"fotka": "baliky.jpg",
"denni_doba": "den"
}
},
{
"model": "header_fotky.fotkaurlvazba",
"pk": 13,
"fields": {
"url": "/profil/",
"fotka": "stiny.jpg",
"denni_doba": "noc"
}
}
]

782
data/sitetree_new.json

@ -0,0 +1,782 @@
[
{
"model":"sitetree.tree",
"fields":{
"title":"Hlavní menu",
"alias":"main_menu"
},
"pk":1
},
{
"pk":1,
"fields":{
"parent":null,
"insitetree":true,
"tree":1,
"description":"",
"urlaspattern":false,
"title":"Co je M&M",
"access_guest":false,
"alias":null,
"url":"/co-je-MaM/uvod/",
"inmenu":true,
"access_perm_type":1,
"access_permissions":[],
"hint":"",
"sort_order":1,
"access_loggedin":false,
"inbreadcrumbs":true,
"access_restricted":false,
"hidden":false
},
"model":"sitetree.treeitem"
},
{
"pk":2,
"fields":{
"access_permissions":[],
"access_perm_type":1,
"url":"/jak-resit/",
"inmenu":true,
"alias":null,
"hint":"",
"access_loggedin":false,
"sort_order":2,
"hidden":false,
"access_restricted":false,
"inbreadcrumbs":true,
"parent":null,
"tree":1,
"insitetree":true,
"access_guest":false,
"title":"Jak řešit",
"urlaspattern":false,
"description":""
},
"model":"sitetree.treeitem"
},
{
"pk":3,
"fields":{
"access_loggedin":false,
"sort_order":3,
"access_restricted":false,
"hidden":false,
"inbreadcrumbs":true,
"inmenu":true,
"url":"/zadani/aktualni/",
"access_permissions":[],
"access_perm_type":1,
"alias":null,
"hint":"",
"insitetree":true,
"tree":1,
"urlaspattern":false,
"title":"Aktuální<br/> ročník",
"access_guest":false,
"description":"",
"parent":null
},
"model":"sitetree.treeitem"
},
{
"fields":{
"hint":"",
"alias":null,
"access_perm_type":1,
"access_permissions":[],
"inmenu":true,
"url":"/soustredeni/",
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false,
"access_loggedin":false,
"sort_order":4,
"parent":null,
"description":"",
"access_guest":false,
"title":"Soustředění",
"urlaspattern":false,
"tree":1,
"insitetree":true
},
"model":"sitetree.treeitem",
"pk":4
},
{
"model":"sitetree.treeitem",
"fields":{
"parent":null,
"insitetree":true,
"tree":1,
"description":"",
"urlaspattern":false,
"title":"Archiv",
"access_guest":false,
"alias":null,
"inmenu":true,
"url":"/archiv/rocniky/",
"access_permissions":[],
"access_perm_type":1,
"hint":"",
"sort_order":5,
"access_loggedin":false,
"inbreadcrumbs":true,
"access_restricted":false,
"hidden":false
},
"pk":5
},
{
"model":"sitetree.treeitem",
"fields":{
"insitetree":true,
"tree":1,
"urlaspattern":false,
"access_guest":true,
"title":"Přihlásit",
"description":"",
"parent":null,
"sort_order":6,
"access_loggedin":false,
"access_restricted":false,
"hidden":false,
"inbreadcrumbs":true,
"inmenu":true,
"url":"/login/",
"access_perm_type":1,
"access_permissions":[],
"alias":null,
"hint":""
},
"pk":6
},
{
"model":"sitetree.treeitem",
"fields":{
"insitetree":true,
"tree":1,
"description":"",
"urlaspattern":false,
"access_guest":false,
"title":"Úvod",
"parent":1,
"access_loggedin":false,
"sort_order":7,
"inbreadcrumbs":true,
"access_restricted":false,
"hidden":false,
"alias":null,
"inmenu":true,
"url":"/co-je-MaM/uvod/",
"access_permissions":[],
"access_perm_type":1,
"hint":""
},
"pk":7
},
{
"model":"sitetree.treeitem",
"fields":{
"parent":1,
"description":"",
"urlaspattern":false,
"title":"Organizátoři",
"access_guest":false,
"insitetree":true,
"tree":1,
"hint":"",
"alias":null,
"url":"/co-je-MaM/organizatori/",
"inmenu":true,
"access_permissions":[],
"access_perm_type":1,
"inbreadcrumbs":true,
"access_restricted":false,
"hidden":false,
"access_loggedin":false,
"sort_order":8
},
"pk":8
},
{
"model":"sitetree.treeitem",
"fields":{
"parent":1,
"tree":1,
"insitetree":true,
"description":"",
"title":"FAQ",
"access_guest":false,
"urlaspattern":false,
"alias":null,
"access_perm_type":1,
"access_permissions":[],
"url":"/co-je-MaM/FAQ/",
"inmenu":true,
"hint":"",
"access_loggedin":false,
"sort_order":9,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false
},
"pk":9
},
{
"pk":10,
"fields":{
"urlaspattern":false,
"title":"Kontakt",
"access_guest":false,
"description":"",
"insitetree":true,
"tree":1,
"parent":1,
"access_restricted":false,
"hidden":false,
"inbreadcrumbs":true,
"access_loggedin":false,
"sort_order":10,
"hint":"",
"inmenu":true,
"url":"/co-je-MaM/kontakt/",
"access_perm_type":1,
"access_permissions":[],
"alias":null
},
"model":"sitetree.treeitem"
},
{
"model":"sitetree.treeitem",
"fields":{
"urlaspattern":false,
"access_guest":false,
"title":"Témata",
"description":"",
"insitetree":true,
"tree":1,
"parent":2,
"access_restricted":false,
"hidden":false,
"inbreadcrumbs":true,
"sort_order":11,
"access_loggedin":false,
"hint":"",
"inmenu":true,
"url":"/jak-resit/",
"access_permissions":[],
"access_perm_type":1,
"alias":null
},
"pk":11
},
{
"pk":12,
"model":"sitetree.treeitem",
"fields":{
"hidden":false,
"access_restricted":false,
"inbreadcrumbs":true,
"sort_order":12,
"access_loggedin":false,
"hint":"",
"access_permissions":[],
"access_perm_type":1,
"inmenu":true,
"url":"/jak-resit/jak-psat-prispevek/",
"alias":null,
"access_guest":false,
"title":"Jak psát příspěvek",
"urlaspattern":false,
"description":"",
"tree":1,
"insitetree":true,
"parent":2
}
},
{
"model":"sitetree.treeitem",
"fields":{
"hint":"",
"access_permissions":[],
"access_perm_type":1,
"inmenu":true,
"url":"/co-je-MaM/odmeny/",
"alias":null,
"hidden":false,
"access_restricted":false,
"inbreadcrumbs":true,
"access_loggedin":false,
"sort_order":13,
"parent":2,
"access_guest":false,
"title":"Odměny",
"urlaspattern":false,
"description":"",
"tree":1,
"insitetree":true
},
"pk":13
},
{
"pk":16,
"fields":{
"tree":1,
"insitetree":true,
"access_guest":false,
"title":"Výsledková listina",
"urlaspattern":false,
"description":"",
"parent":3,
"access_loggedin":false,
"sort_order":33,
"hidden":false,
"access_restricted":false,
"inbreadcrumbs":true,
"access_perm_type":1,
"access_permissions":[],
"url":"zadani/vysledkova-listina/",
"inmenu":true,
"alias":null,
"hint":""
},
"model":"sitetree.treeitem"
},
{
"fields":{
"title":"Články",
"access_guest":false,
"urlaspattern":false,
"description":"",
"tree":1,
"insitetree":true,
"parent":3,
"hidden":false,
"access_restricted":false,
"inbreadcrumbs":true,
"sort_order":34,
"access_loggedin":false,
"hint":"",
"access_perm_type":1,
"access_permissions":[],
"inmenu":true,
"url":"/clanky/resitel/",
"alias":null
},
"model":"sitetree.treeitem",
"pk":17
},
{
"pk":18,
"model":"sitetree.treeitem",
"fields":{
"tree":1,
"insitetree":true,
"description":"",
"access_guest":false,
"title":"Úvod",
"urlaspattern":false,
"parent":4,
"access_loggedin":false,
"sort_order":18,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false,
"alias":null,
"access_permissions":[],
"access_perm_type":1,
"url":"/soustredeni/",
"inmenu":true,
"hint":""
}
},
{
"fields":{
"sort_order":19,
"access_loggedin":false,
"inbreadcrumbs":true,
"access_restricted":false,
"hidden":false,
"alias":null,
"inmenu":true,
"url":"/soustredeni/pripravujeme/",
"access_perm_type":1,
"access_permissions":[],
"hint":"",
"insitetree":true,
"tree":1,
"description":"",
"urlaspattern":false,
"access_guest":false,
"title":"Připravujeme",
"parent":4
},
"model":"sitetree.treeitem",
"pk":19
},
{
"pk":20,
"fields":{
"parent":4,
"tree":1,
"insitetree":true,
"description":"",
"access_guest":false,
"title":"Proběhlo",
"urlaspattern":false,
"alias":null,
"access_permissions":[],
"access_perm_type":1,
"url":"/soustredeni/probehlo/",
"inmenu":true,
"hint":"",
"sort_order":20,
"access_loggedin":false,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false
},
"model":"sitetree.treeitem"
},
{
"pk":21,
"model":"sitetree.treeitem",
"fields":{
"urlaspattern":false,
"access_guest":false,
"title":"Profil",
"description":"",
"insitetree":true,
"tree":1,
"parent":null,
"access_restricted":false,
"hidden":false,
"inbreadcrumbs":true,
"sort_order":21,
"access_loggedin":true,
"hint":"",
"url":"/profil/",
"inmenu":true,
"access_permissions":[],
"access_perm_type":1,
"alias":null
}
},
{
"pk":22,
"fields":{
"parent":21,
"tree":1,
"insitetree":true,
"description":"",
"access_guest":false,
"title":"Osobní údaje",
"urlaspattern":false,
"alias":null,
"access_permissions":[],
"access_perm_type":1,
"inmenu":true,
"url":"/profil/osobni-udaje",
"hint":"",
"access_loggedin":false,
"sort_order":23,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false
},
"model":"sitetree.treeitem"
},
{
"model":"sitetree.treeitem",
"fields":{
"access_loggedin":false,
"sort_order":36,
"access_restricted":false,
"hidden":false,
"inbreadcrumbs":true,
"inmenu":true,
"url":"/odeslat-reseni/",
"access_perm_type":1,
"access_permissions":[],
"alias":null,
"hint":"",
"insitetree":true,
"tree":1,
"urlaspattern":false,
"title":"Poslat řešení",
"access_guest":false,
"description":"",
"parent":21
},
"pk":23
},
{
"pk":24,
"fields":{
"tree":1,
"insitetree":true,
"description":"",
"title":"Témata",
"access_guest":false,
"urlaspattern":false,
"parent":5,
"access_loggedin":false,
"sort_order":35,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false,
"alias":null,
"access_perm_type":1,
"access_permissions":[],
"url":"/archiv/temata/",
"inmenu":true,
"hint":""
},
"model":"sitetree.treeitem"
},
{
"model":"sitetree.treeitem",
"fields":{
"hint":"",
"alias":null,
"access_perm_type":1,
"access_permissions":[
1
],
"url":"/korektury/",
"inmenu":true,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":true,
"sort_order":28,
"access_loggedin":false,
"parent":null,
"description":"",
"title":"HIDDEN",
"access_guest":false,
"urlaspattern":false,
"tree":1,
"insitetree":true
},
"pk":28
},
{
"pk":30,
"fields":{
"description":"",
"title":"Aktuální",
"access_guest":false,
"urlaspattern":false,
"tree":1,
"insitetree":true,
"parent":28,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false,
"sort_order":30,
"access_loggedin":false,
"hint":"",
"alias":null,
"access_perm_type":1,
"access_permissions":[],
"inmenu":true,
"url":"/korektury/"
},
"model":"sitetree.treeitem"
},
{
"pk":31,
"model":"sitetree.treeitem",
"fields":{
"alias":null,
"access_permissions":[],
"access_perm_type":1,
"url":"/korektury/zastarale/",
"inmenu":true,
"hint":"",
"access_loggedin":false,
"sort_order":31,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false,
"parent":28,
"tree":1,
"insitetree":true,
"description":"",
"title":"Zastaralé",
"access_guest":false,
"urlaspattern":false
}
},
{
"fields":{
"alias":null,
"inmenu":true,
"url":"/korektury/help/",
"access_permissions":[],
"access_perm_type":1,
"hint":"",
"access_loggedin":false,
"sort_order":32,
"inbreadcrumbs":true,
"access_restricted":false,
"hidden":false,
"parent":28,
"insitetree":true,
"tree":1,
"description":"",
"urlaspattern":false,
"access_guest":false,
"title":"Nápověda"
},
"model":"sitetree.treeitem",
"pk":32
},
{
"model":"sitetree.treeitem",
"fields":{
"tree":1,
"insitetree":true,
"access_guest":false,
"title":"Aktuální číslo",
"urlaspattern":false,
"description":"",
"parent":3,
"access_loggedin":false,
"sort_order":15,
"hidden":false,
"access_restricted":false,
"inbreadcrumbs":true,
"access_perm_type":1,
"access_permissions":[],
"url":"/zadani/aktualni/",
"inmenu":true,
"alias":null,
"hint":""
},
"pk":33
},
{
"fields":{
"hint":"",
"alias":null,
"access_permissions":[],
"access_perm_type":1,
"url":"/zadani/temata/",
"inmenu":true,
"inbreadcrumbs":true,
"hidden":false,
"access_restricted":false,
"access_loggedin":false,
"sort_order":17,
"parent":3,
"description":"",
"title":"Témata",
"access_guest":false,
"urlaspattern":false,
"tree":1,
"insitetree":true
},
"model":"sitetree.treeitem",
"pk":34
},
{
"pk":35,
"model":"sitetree.treeitem",
"fields":{
"hint":"",
"access_permissions":[],
"access_perm_type":1,
"inmenu":true,
"url":"/archiv/rocniky/",
"alias":null,
"hidden":false,
"access_restricted":false,
"inbreadcrumbs":true,
"sort_order":24,
"access_loggedin":false,
"parent":5,
"access_guest":false,
"title":"Čísla",
"urlaspattern":false,
"description":"",
"tree":1,
"insitetree":true
}
},
{
"pk":36,
"fields":{
"inbreadcrumbs":true,
"access_restricted":false,
"hidden":false,
"sort_order":22,
"access_loggedin":false,
"hint":"",
"alias":null,
"inmenu":true,
"url":"/profil/",
"access_perm_type":1,
"access_permissions":[],
"description":"",
"urlaspattern":false,
"title":"Úvod",
"access_guest":false,
"insitetree":true,
"tree":1,
"parent":21
},
"model":"sitetree.treeitem"
},
{
"fields":{
"parent":21,
"description":"",
"urlaspattern":true,
"title":"Odevzdaná řešení",
"access_guest":false,
"insitetree":true,
"tree":1,
"hint":"",
"alias":null,
"inmenu":true,
"url":"odevzdavatko_tabulka",
"access_perm_type":1,
"access_permissions":[
1
],
"inbreadcrumbs":true,
"access_restricted":true,
"hidden":false,
"access_loggedin":false,
"sort_order":37
},
"model":"sitetree.treeitem",
"pk":37
},
{
"model":"sitetree.treeitem",
"fields":{
"inmenu":true,
"url":"/logout/",
"access_perm_type":1,
"access_permissions":[],
"alias":null,
"hint":"",
"access_loggedin":true,
"sort_order":38,
"access_restricted":false,
"hidden":false,
"inbreadcrumbs":true,
"parent":21,
"insitetree":true,
"tree":1,
"urlaspattern":false,
"title":"Odhlásit se",
"access_guest":false,
"description":""
},
"pk":38
}
]

4
galerie/admin.py

@ -30,14 +30,14 @@ def prepnout_fotogalerii_do_org_rezimu(modeladmin, request, queryset):
class GalerieInline(admin.TabularInline):
model = Obrazek
fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag']
fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag', 'poradi']
readonly_fields = ['nazev', 'obrazek_maly_tag']
formfield_overrides = {
models.TextField: {'widget': forms.TextInput},
}
class ObrazekAdmin(admin.ModelAdmin):
list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag')
list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag', 'poradi')
search_fields = ['nazev','popis']
class GalerieAdmin(admin.ModelAdmin):

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)
soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True,
on_delete=models.PROTECT)
poradi = models.IntegerField('Pořadí', blank = True, null = True)
poradi = models.IntegerField('Pořadí', blank = True, null = False, default = 0)
def __str__(self):
return self.nazev

6
galerie/templates/galerie/Base.html

@ -1,6 +0,0 @@
{% extends "base.html" %}
{# TODO predelat pres context processor #}
{% block header %}soustredeni{% endblock %}
{% block menu_soustredeni %}selected{% endblock %}
{% block submenu %}{% include 'seminar/soustredeni/submenu.html' %}{% endblock %}

2
galerie/templates/galerie/Galerie.html

@ -1,4 +1,4 @@
{% extends "galerie/Base.html" %}
{% extends "base.html" %}
{% block nadpis1a %}

6
galerie/templates/galerie/GalerieNahled.html

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

2
galerie/templates/galerie/GalerieNew.html

@ -1,4 +1,4 @@
{% extends "galerie/Base.html" %}
{% extends "base.html" %}
{% block title %}{% block nadpis1a %}
Vytvářím novou galerii

7
galerie/urls.py

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

62
galerie/views.py

@ -14,7 +14,7 @@ from galerie.forms import KomentarForm, NewGalerieForm
def zobrazit(galerie, request):
preview = False
if galerie.zobrazit >= 1:
if request.user.is_staff:
if request.user.je_org:
preview = True;
else:
raise Http404
@ -35,16 +35,16 @@ def nahled(request, pk, soustredeni):
galerie = get_object_or_404(Galerie, pk=pk)
podgalerie = Galerie.objects.filter(galerie_up = galerie).order_by('poradi')
if not request.user.is_staff:
if not request.user.je_org:
podgalerie = podgalerie.filter(zobrazit__lt=1)
obrazky = Obrazek.objects.filter(galerie = galerie)
obrazky = Obrazek.objects.filter(galerie = galerie).order_by('poradi', 'nazev')
preview = zobrazit(galerie, request)
sourozenci = []
if galerie.galerie_up:
sourozenci = galerie.galerie_up.galerie_set.all().order_by('poradi')
if not request.user.is_staff:
if not request.user.je_org:
sourozenci = sourozenci.filter(zobrazit__lt=1)
predchozi = None
@ -82,7 +82,7 @@ def detail(request, pk, fotka, soustredeni):
galerie = get_object_or_404(Galerie, pk=pk)
preview = zobrazit(galerie, request)
obrazek = get_object_or_404(Obrazek, pk=fotka)
obrazky = galerie.obrazek_set.all()
obrazky = galerie.obrazek_set.all().order_by('poradi', 'nazev')
# vytvoreni a obslouzeni formulare
if request.method == 'POST':
@ -96,22 +96,23 @@ def detail(request, pk, fotka, soustredeni):
# Poradi aktualniho obrazku v galerii/stitku.
for i in range(len(obrazky)):
if obrazky[i] == obrazek:
znacka = i
poradi = i
break
else:
# Obrazek neni v galerii/stitku.
raise Http404
# Nacteni okolnich obrazku a galerii
# TODO vyjmout zjisteni predchozich a nasledujicich galerii
# a udelat z toho funkci, ktera se pouzije u nahledu
predchozi_galerie = None
nasledujici_galerie = None
obrazky_dalsi = obrazky[znacka+1:znacka+NAHLEDU+1]
if (znacka+1) > NAHLEDU:
obrazky_predchozi = obrazky[znacka-NAHLEDU:znacka]
obrazky_dalsi = obrazky[poradi+1:poradi+NAHLEDU+1]
if (poradi+1) > NAHLEDU:
obrazky_predchozi = obrazky[poradi-NAHLEDU:poradi]
else:
obrazky_predchozi = obrazky[0:znacka]
obrazky_predchozi = obrazky[0:poradi]
if galerie.poradi > 1:
predchozi_galerie = Galerie.objects.\
filter(galerie_up=galerie.galerie_up).\
@ -120,41 +121,44 @@ def detail(request, pk, fotka, soustredeni):
predchozi_galerie = predchozi_galerie[0]
else:
predchozi_galerie = None
if (znacka+1) == len(obrazky):
nasledujici_galerie = Galerie.objects.\
filter(galerie_up=galerie.galerie_up).\
filter(poradi=(galerie.poradi+1))
if (poradi+1) == len(obrazky): # Tohle je poslední obrázek
if (galerie.poradi is not None
and galerie.galerie_up is not None):
nasledujici_galerie = Galerie.objects.\
filter(galerie_up=galerie.galerie_up).\
filter(poradi=(galerie.poradi+1))
else:
nasledujici_galerie = None
if nasledujici_galerie:
nasledujici_galerie = nasledujici_galerie[0]
else:
nasledujici_galerie = None
# Preskalovani obrazku do vybraneho prostoru.
vyska = obrazek.obrazek_stredni.height
sirka = obrazek.obrazek_stredni.width
if vyska > MAX_VYSKA:
sirka = sirka * MAX_VYSKA / vyska
sirka = sirka * MAX_VYSKA / vyska
vyska = MAX_VYSKA
if sirka > MAX_SIRKA:
vyska = vyska * MAX_SIRKA / sirka
sirka = MAX_SIRKA
return render(request, 'galerie/Galerie.html',
{'galerie' : galerie,
'predchozi_galerie' : predchozi_galerie,
'nasledujici_galerie' : nasledujici_galerie,
'obrazek' : obrazek,
'vyska' : vyska,
'sirka' : sirka,
'obrazky_predchozi' : obrazky_predchozi,
'obrazky_dalsi' : obrazky_dalsi,
'preview' : preview,
'form' : form,
'cesta': cesta_od_korene(galerie),
})
{'galerie' : galerie,
'predchozi_galerie' : predchozi_galerie,
'nasledujici_galerie' : nasledujici_galerie,
'obrazek' : obrazek,
'vyska' : vyska,
'sirka' : sirka,
'obrazky_predchozi' : obrazky_predchozi,
'obrazky_dalsi' : obrazky_dalsi,
'preview' : preview,
'form' : form,
'cesta': cesta_od_korene(galerie),
})
def new_galerie(request, galerie, soustredeni):

0
header_fotky/__init__.py

10
header_fotky/admin.py

@ -0,0 +1,10 @@
from django.contrib import admin
from django.contrib.admin import ModelAdmin
import header_fotky.models as m
class FotkaPozadiAdmin(ModelAdmin):
readonly_fields = ['cas']
admin.site.register(m.FotkaHeader, FotkaPozadiAdmin)
admin.site.register(m.FotkaUrlVazba)

5
header_fotky/apps.py

@ -0,0 +1,5 @@
from django.apps import AppConfig
class HeaderFotkyConfig(AppConfig):
name = 'header_fotky'

45
header_fotky/context_processors.py

@ -0,0 +1,45 @@
from datetime import datetime, date
import random
from django.conf import settings
from header_fotky.models import FotkaUrlVazba
def vzhled(request):
''' Podle casu prida do templatu, zdali je nebo neni noc '''
hodin = datetime.now().hour
if (hodin <= 6) or (hodin >= 20):
noc = True
nedoba = 'den'
doba = 'noc'
else:
noc = False
nedoba = 'noc'
doba = 'den'
url = request.path
fotky = FotkaUrlVazba.objects.exclude(denni_doba=nedoba)
fotka = None
# TODO rychlejší patternmatch?
while (fotka is None) and (url != ''):
presne = fotky.filter(url__exact=url)
if presne.count() > 0:
presne_doba = presne.filter(denni_doba=doba)
if presne_doba.count() > 0:
fotka = random.choice(presne_doba).url_fotky()
else:
fotka = random.choice(presne).url_fotky()
url = url[:-1]
index = url.rfind('/')
if index != -1:
url = url[:index+1]
if fotka is None:
fotka = settings.STATIC_URL + "images/header/vikendovka.jpg"
return {'noc': noc, 'fotka': fotka}

63
header_fotky/migrations/0001_initial.py

@ -0,0 +1,63 @@
# Generated by Django 2.2.15 on 2020-09-20 09:14
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
from shutil import copytree
def zkopiruj_fotky(apps, schema_editor):
try:
copytree("mamweb/static/images/header/", "media/header/") # FIXME: bylo tu dirs_exists_ok=True, nekompatibilní s Py 3.7
except FileExistsError:
pass
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='FotkaHeader',
fields=[
('cas', models.DateTimeField(default=django.utils.timezone.now, help_text='Čas vložení fotky',
verbose_name='čas vložení fotky')),
('nazev',
models.CharField(help_text='Název např. archiv_noc', max_length=50, primary_key=True, serialize=False,
unique=True, verbose_name='název fotky')),
('fotka', models.ImageField(upload_to='header')),
],
options={
'verbose_name': 'fotka do pozadí menu',
'verbose_name_plural': 'fotky do pozadí menu',
'db_table': 'fotky_header',
'ordering': ['-cas'],
},
),
migrations.CreateModel(
name='FotkaUrlVazba',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('url',
models.CharField(blank=True, help_text='url prefix stránek např: /archiv/ nebo /', max_length=100,
verbose_name='URL')),
('denni_doba', models.CharField(choices=[('den', 'Zobrazit jen ve dne'), ('noc', 'Zobrazit jen v noci'),
('oboji', 'Zobrazovat pořád')], default='oboji', max_length=16,
verbose_name='denní doba')),
('fotka', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='header_fotky.FotkaHeader',
verbose_name='fotka')),
],
options={
'verbose_name': 'vazba url a fotky do pozadí menu',
'verbose_name_plural': 'vazby url a fotek do pozadí menu',
'db_table': 'fotky_url_vazby',
'ordering': ['url'],
},
),
migrations.RunPython(zkopiruj_fotky, migrations.RunPython.noop),
]

0
header_fotky/migrations/__init__.py

65
header_fotky/models.py

@ -0,0 +1,65 @@
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
class FotkaHeader(models.Model):
class Meta:
ordering = ['-cas']
db_table = 'fotky_header'
verbose_name = u'fotka do pozadí menu'
verbose_name_plural = u'fotky do pozadí menu'
cas = models.DateTimeField(u'čas vložení fotky', default=timezone.now, help_text='Čas vložení fotky')
nazev = models.CharField(
u'název fotky', null=False, blank=False, unique=True, primary_key=True,
max_length=50, help_text='Název např. archiv_noc'
)
fotka = models.ImageField(upload_to='header', null=False, blank=False)
def __str__(self):
return self.nazev
def clean(self):
if not self.fotka:
raise ValidationError("Chybí obrázek")
""" Kontroluje, zda sedí poměr stran """
if abs(self.fotka.width - (self.fotka.height * 970 / 350)) > 2:
raise ValidationError("Obrázek by měl mít rozměry 970w na 350h, nebo alespoň podobný poměr stran.")
super().clean()
class FotkaUrlVazba(models.Model):
class Meta:
ordering = ['url']
db_table = 'fotky_url_vazby'
verbose_name = u'vazba url a fotky do pozadí menu'
verbose_name_plural = u'vazby url a fotek do pozadí menu'
url = models.CharField(
u'URL', blank=True, null=False, max_length=100,
help_text='url prefix stránek např: /archiv/ nebo /'
)
fotka = models.ForeignKey(
FotkaHeader, blank=False, null=False, verbose_name='fotka',
on_delete=models.CASCADE
)
DOBA_DEN = 'den'
DOBA_NOC = 'noc'
DOBA_OBOJI = 'oboji'
DOBA_CHOICES = [
(DOBA_DEN, 'Zobrazit jen ve dne'),
(DOBA_NOC, 'Zobrazit jen v noci'),
(DOBA_OBOJI, 'Zobrazovat pořád')]
denni_doba = models.CharField('denní doba', max_length=16, choices=DOBA_CHOICES, blank=False, default=DOBA_OBOJI)
def __str__(self):
return self.url
def url_fotky(self):
return self.fotka.fotka.url

29
korektury/models.py

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

9
korektury/templates/korektury/base.html

@ -1,9 +0,0 @@
{% extends "base.html" %}
{% block content %}
{# blok do kterého se nacita text, v pripade jinyhc templatu obalit vlastnim blokem #}
{% endblock %}
{% block title %}
{# blok pro titulek stranky #}
{% endblock %}

3
korektury/templates/korektury/help.html

@ -1,4 +1,5 @@
{% extends "korektury/base.html" %}
{% extends "base.html" %}
{% load staticfiles %}
{% block title %} Nápověda ke korigovátku {% endblock title %}

4
korektury/templates/korektury/opraf.html

@ -36,12 +36,12 @@
id="neni_chyba_checkbox"
name="neni_chyba_checkbox"
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"
id="k_zaneseni_checkbox"
name="k_zaneseni_checkbox"
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/>

2
korektury/templates/korektury/seznam.html

@ -1,4 +1,4 @@
{% extends "korektury/base.html" %}
{% extends "base.html" %}
{% load staticfiles %}
{% block script%}

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.contrib.auth.decorators import user_passes_test
from seminar.utils import org_required
from . import views
staff_member_required = user_passes_test(lambda u: u.is_staff)
urlpatterns = [
path('korektury/', staff_member_required(views.KorekturyListView.as_view()), name='korektury-list'),
path('korektury/<int:pdf>/', staff_member_required(views.KorekturyView.as_view()), name='korektury'),
path('korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'),
path('korektury/', org_required(views.KorekturyAktualniListView.as_view()), name='korektury_list'),
path('korektury/zastarale/', org_required(views.KorekturyZastaraleListView.as_view()), name='korektury_stare_list'),
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'
class KorekturyAktualniListView(KorekturyListView):
def get_queryset(self, *args, **kwargs):
queryset=super(KorekturyAktualniListView,self).get_queryset()
queryset=queryset.exclude(status="zastarale")
return queryset
def get_context_data(self, **kwargs):
context = super(KorekturyAktualniListView,self).get_context_data(**kwargs)
context['selected'] = 'aktualni'
return context
class KorekturyZastaraleListView(KorekturyListView):
def get_queryset(self, *args, **kwargs):
queryset=super(KorekturyZastaraleListView,self).get_queryset()
queryset=queryset.filter(status="zastarale")
return queryset
def get_context_data(self, **kwargs):
context = super(KorekturyZastaraleListView,self).get_context_data(**kwargs)
context['selected'] = 'zastarale'
return context
### Korektury
class KorekturyView(generic.TemplateView):
model = Oprava
@ -130,7 +152,9 @@ class KorekturyView(generic.TemplateView):
'''
# parametry e-mailu
odkaz = "https://mam.mff.cuni.cz/korektury/{}/".format(oprava.pdf.pk)
#odkaz = "https://mam.mff.cuni.cz/korektury/{}/".format(oprava.pdf.pk)
from django.urls import reverse
odkaz = self.request.build_absolute_uri(reverse('korektury', kwargs={'pdf': oprava.pdf.pk}))
from_email = 'korekturovatko@mam.mff.cuni.cz'
subject = 'Nová korektura od {} v {}'.format(autor,
oprava.pdf.nazev)

4
mamweb/admin.py

@ -7,7 +7,8 @@ from django.contrib.flatpages.admin import FlatpageForm as FlatpageFormOld
from django import forms
from ckeditor_uploader.widgets import CKEditorUploadingWidget
class FlatpageForm(FlatpageFormOld):
content = forms.CharField(widget=CKEditorUploadingWidget())
class Meta:
@ -22,3 +23,4 @@ class FlatPageAdmin(FlatPageAdminOld):
# We have to unregister the normal admin, and then reregister ours
admin.site.unregister(FlatPage)
admin.site.register(FlatPage, FlatPageAdmin)

12
mamweb/context_processors.py

@ -1,12 +0,0 @@
from datetime import datetime, date
def vzhled(request):
''' Podle casu prida do templatu, zdali je nebo neni noc '''
hodin = datetime.now().hour
if (hodin <= 6) or (hodin >= 20):
noc = True
else:
noc = False
return {'noc' : noc}

15
mamweb/routers.py

@ -0,0 +1,15 @@
from rest_framework import routers
from seminar import viewsets as vs
router = routers.DefaultRouter()
router.register(r'ulohavzoraknode', vs.UlohaVzorakNodeViewSet,basename='ulohavzoraknode')
router.register(r'reseninode', vs.ReseniNodeViewSet,basename='reseninode')
router.register(r'text', vs.TextViewSet)
router.register(r'textnode', vs.TextNodeViewSet)
router.register(r'castnode', vs.CastNodeViewSet)
router.register(r'problem', vs.ProblemViewSet, basename='problem')
router.register(r'uloha', vs.UlohaViewSet, basename='uloha')
router.register(r'reseni', vs.ReseniViewSet, basename='reseni')
router.register(r'ulohazadaninode', vs.UlohaZadaniNodeViewSet)

39
mamweb/settings_common.py

@ -77,7 +77,7 @@ TEMPLATES = [
'django.template.context_processors.request',
'django.contrib.messages.context_processors.messages',
'sekizai.context_processors.sekizai',
'mamweb.context_processors.vzhled',
'header_fotky.context_processors.vzhled',
)
},
},
@ -98,7 +98,7 @@ INSTALLED_APPS = (
# Utilities
'sekizai',
# 'reversion',
'reversion',
'django_countries',
'solo',
'ckeditor',
@ -120,6 +120,10 @@ INSTALLED_APPS = (
'imagekit',
'polymorphic',
'webpack_loader',
'rest_framework',
'rest_framework.authtoken',
# MaMweb
'mamweb',
@ -127,6 +131,7 @@ INSTALLED_APPS = (
'galerie',
'korektury',
'prednasky',
'header_fotky',
# Admin upravy:
@ -136,7 +141,6 @@ INSTALLED_APPS = (
# 'admin_tools.theming',
# 'admin_tools.menu',
# 'admin_tools.dashboard',
'flat',
'django.contrib.admin',
)
@ -179,10 +183,32 @@ CKEDITOR_CONFIGS = {
# 'toolbar': 'full',
'height': '40em',
'width': '100%',
'toolbarStartupExpanded': False
'toolbarStartupExpanded': False,
'allowedContent' : True,
},
}
# Webpack loader
VUE_FRONTEND_DIR = os.path.join(BASE_DIR, 'vue_frontend')
WEBPACK_LOADER = {
'DEFAULT': {
'CACHE': False,
'BUNDLE_DIR_NAME': 'vue/', # must end with slash
'STATS_FILE': os.path.join(VUE_FRONTEND_DIR, 'webpack-stats.json'),
'POLL_INTERVAL': 0.1,
'TIMEOUT': None,
'IGNORE': [r'.+\.hot-update.js', r'.+\.map']
}
}
# Dajngo REST Framework
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 100
}
# Comments
@ -248,7 +274,7 @@ LOGGING = {
'class': 'django.utils.log.AdminEmailHandler',
'formatter': 'verbose',
},
'mail_registraion': {
'mail_registration': {
'level': 'WARN',
'class': 'django.utils.log.AdminEmailHandler',
'formatter': 'verbose',
@ -269,6 +295,9 @@ LOGGING = {
},
}
# Permissions for uploads
FILE_UPLOAD_PERMISSIONS = 0o0644
# MaM specific
SEMINAR_RESENI_DIR = os.path.join('reseni')

4
mamweb/settings_local.py

@ -28,7 +28,7 @@ INTERNAL_IPS = ['127.0.0.1']
TEMPLATES[0]['OPTIONS']['debug'] = True
ALLOWED_HOSTS = ['127.0.0.1']
ALLOWED_HOSTS = ['127.0.0.1', '192.168.43.34']
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
@ -94,4 +94,6 @@ LOGGING = {
# set to 'DEBUG' for EXTRA verbose output
# LOGGING['handlers']['console']['level'] = 'INFO'
# E-maily posílat chceme, ale do terminálu :-)
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SEND_EMAIL_NOTIFICATIONS = True

4
mamweb/settings_test.py

@ -12,7 +12,7 @@ import os.path
# Import common settings
from .settings_common import * # zatim nutne, casem snad vyresime # noqa
MIDDLEWARE_CLASSES += (
MIDDLEWARE += (
'debug_toolbar.middleware.DebugToolbarMiddleware',
)
@ -32,7 +32,7 @@ DEBUG = True
TEMPLATES[0]['OPTIONS']['debug'] = True
ALLOWED_HOSTS = ['*.mam.mff.cuni.cz', 'atrey.karlin.mff.cuni.cz', 'mam.mff.cuni.cz', 'mam-test.kam.mff.cuni.cz', 'gimli.ms.mff.cuni.cz']
ALLOWED_HOSTS = ['*.mam.mff.cuni.cz', 'atrey.karlin.mff.cuni.cz', 'mam.mff.cuni.cz', 'mam-test.kam.mff.cuni.cz', 'gimli.ms.mff.cuni.cz', 'mam-test.ks.matfyz.cz']
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases

38
mamweb/static/css/mamweb-dev.css

@ -0,0 +1,38 @@
/*
.pink {
background-color: #ffc0cb;
}
div.borderized {
border-style: solid;
border-radius: 5px;
padding: 5px;
padding-right: 20px;
}
div.tnmenu {
float: right;
margin-right: 0px;
}
div.parent {
border-width: 2px;
}
div.children {
border-width: 1px;
}
div.node_type {
background-color: #d4d4d4;
}
.hidden-tn {
display: none;
}
/*test*/
h1 {
color: chartreuse;
}

338
mamweb/static/css/mamweb.css

@ -101,6 +101,26 @@ h6 {
color: black;
}
.button {
margin: 10px 0px 10px 0px;
padding: 4px 0; /*vertikální centování textu*/
text-align: center;
background-color: #e84e10;
color: #fffbf6;
font-size: 150%;
font-weight: bold;
font-variant: small-caps;
filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
}
.button:hover {
position: relative;
top: 2px;
left:2px;
background-color: #df490e;
;
}
.org-logged-in .mam-text-plugin {
border: dashed 1px #6a0043;
@ -193,38 +213,6 @@ h1 {
top: 58px;
}
/*
fotky:
todo url
kryptografie
baliky
beh
mam_cernobile -pro archiv? asi ne
vylet
spolecna -spíš ne, moc lidí
snih
ohen
noc
stiny
vikendovka
*/
#header.cojemam { background-image: url("../images/header/vikendovka.jpg");}
#header.soustredeni { background-image: url("../images/header/beh.jpg");}
#header.zadani { background-image: url("../images/header/baliky.jpg");}
#header.clanky { background-image: url("../images/header/kryptografie.jpg");}
#header.archiv { background-image: url("../images/header/stiny.jpg");}
#header.NOC {background-image: url("../images/header/noc.jpg");}
#header.NOCcojemam { background-image: url("../images/header/noc.jpg");}
#header.NOCsoustredeni { background-image: url("../images/header/vylet.jpg");}
#header.NOCzadani { background-image: url("../images/header/stiny.jpg");}
#header.NOCclanky { background-image: url("../images/header/ohen.jpg");}
#header.NOCarchiv { background-image: url("../images/header/stiny.jpg");}
#header img.logo {
position: absolute center;
width: 100%;
@ -318,6 +306,14 @@ ul.submenu li>a:hover {
color: black;
}
ul.menu li.active>a {
color: #f9d59e;
}
ul.submenu li.active>a {
color: black;
}
/* konec nového menu */
div.novinky_name {
@ -351,6 +347,10 @@ div.zadani_azad_termin {
bottom: 0px;
}
#footer p.license a {
color: #333;
}
p.license-mobile {
display: none;
}
@ -395,13 +395,82 @@ input[type="file"] {
}
.field-with-comment:hover span.field-comment{
display:block;
display: block;
}
input {
margin: 5px;
}
/* titulni stranka */
.titulnistrana {
display: flex;
text-align: justify;
}
.titulnistrana h1 {
text-align: center;
}
.zjistit_vic{
text-align: center;
margin-bottom: 30px;
}
.zjistit_vic hr {
display: none;
}
.graf-svg {
display: flex;
}
#svg-graf {
width: 100%;
height: auto;
margin: 30px;
}
.titulnistrana_obsah {
width: 66%;
}
.vitej_titulka, .temata_titulka {
width: 49%;
padding: 10px;
display: table-cell;
}
.titulnistrana_novinky {
width: 33%;
padding: 10px;
}
.novinka_obrazek {
margin: 10px 0px 10px 0px;
width: 100%;
}
.novinka_datum {
font-weight: bold;
}
.novinka_autor {
text-align: right;
font-style: italic;
}
div.org-text {
font-style: italic;
}
div.odpocet {
margin: 20px;
text-align: center;
}
/**********************
* Zmenšování displeje
***********************/
@ -431,42 +500,22 @@ input {
width: 100%;
}
div.novinky{
max-width: 100%;
margin-left: auto;
margin-right: auto;
float: none;
}
div.graf{
width: 70%;
float: none;
margin-left: auto;
margin-right: auto;
margin-top: 10px;
}
#svg-graf{
width: 100%;
height: auto;;
ul.menu {
font-size: 90%;
margin-top: -7px;
}
ul.menu {
font-size: 90%;
margin-top: -7px;
}
ul.menu li {
margin-top: 10px; /* posunutí textu hlavního menu níže */
}
ul.submenu li {
margin-top: 0px; /* aby se spolu s textem hlavního menu neposunoval níže i text submenu */
}
ul.menu li {
margin-top: 10px; /* posunutí textu hlavního menu níže */
}
ul.submenu {
margin-top: 8px; /* mezera mezi hlavním menu a submenu */
}
ul.submenu li {
margin-top: 0px; /* aby se spolu s textem hlavního menu neposunoval níže i text submenu */
}
ul.submenu {
margin-top: 8px; /* mezera mezi hlavním menu a submenu */
}
}
@ -498,11 +547,53 @@ ul.submenu {
display: inline-grid;
max-width: 300px;
}
/* titulni stranka */
.titulnistrana {
display: block;
}
.graf {
padding-top: 40px;
}
.titulnistrana_obsah {
width: 100%;
}
.vitej_titulka, .temata_titulka {
width: 49%;
padding: 10px;
display: table-cell;
}
.titulnistrana_novinky {
width: 100%;
max-width: 500px;
padding: 10px;
margin: auto;
}
#svg-graf {
width: 100%;
max-width: 500px;
padding: 10px;
margin: auto;
}
.zjistit_vic hr {
display: flex;
}
}
/* malý tablet, mobil */
@media (max-width: 650px) {
.no-mobile{
display: none;
}
#hide-if-small.login-bar-flatpage {
display: none;
}
@ -639,34 +730,59 @@ ul.submenu {
text-align: justify;
}
div.novinky {
max-width: 100%;
float: none;
}
table.form td, table.form tr {
display: inherit;
}
/* titulni stranka */
.titulnistrana {
display: block;
}
.graf {
padding-top: 40px;
}
div.graf {
.titulnistrana_obsah {
width: 100%;
}
table.form td, table.form tr {
display: inherit;
}
.vitej_titulka, .temata_titulka {
width: 100%;
padding: 10px;
display: block;
}
.titulnistrana_novinky {
width: 100%;
padding: 10px;
}
}
/*stránka organizátorů*/
div.seznam_orgu {
div.seznam_orgu, div.rozcestnik_temat {
text-align: center;
padding-bottom: 10px;
}
div.org_pole, div.rocnik_pole {
div.org_pole, div.rocnik_pole, div.tema_pole {
display: inline-block;
width: 30%;
min-width: 300px;
text-align: center;
}
div.tema_pole {
display: inline-block;
width: 40%;
min-width: 350px;
padding-bottom: 20px;
text-align: center;
}
div.cislo_pole {
display: inline-block;
width: 15%;
@ -709,6 +825,11 @@ div.org_email {
height: 205px;
}
#tema-rozcestnik.flip-card {
width: 300px;
height: 300px;
}
/* This container is needed to position the front and back side */
.flip-card-inner {
position: relative;
@ -732,12 +853,8 @@ div.org_email {
backface-visibility: hidden;
}
/* Style the front side (fallback if image is missing) */
.flip-card-front {
background-color: #bbb;
}
div.flip-card-foto img {
div.flip-card-foto, div.flip-card-foto img {
width: 100%;
height: 100%;
@ -752,6 +869,10 @@ div.flip-card-foto img {
padding-top: 20px;
}
#archiv.flip-card-back {
background-color: white;
}
/* karty archiv */
div.popis_rocniku {
@ -948,46 +1069,8 @@ div.cislo_odkazy ul {
}
/* titulni stranka */
.zjistit_vic{
text-align: center;
}
.graf{
float: left;
}
.novinky{
float: right;
max-width: 42%;
}
.novinka_obrazek img {
margin-bottom: 15px;
}
div.novinka_obrazek {
width: 100%;
max-width: 400px; /*FIXME*/
}
div.org-text {
font-style: italic;
}
div.nahledy_cisel {
float: right;
height: 297px;
width: 420px;
position: relative;
margin-right: 10%;
margin-bottom: 50px;
}
/**/
div.nahledy_cisel div, div.nahledy_cisel img {
position: absolute;
}
ul.form {
list-style-type: none;
padding-left: 0px;
@ -1012,3 +1095,20 @@ p.gdpr {
div.gdpr {
font-size: 6pt;
}
/* Jak řešit */
.jakresit img {
width: 33%;
padding: 10px;
filter: none;
}
@media(max-width: 860px) {
.jakresit img {
margin: auto;
display: grid;
width: 100%;
max-width: 360px;
}
}

BIN
mamweb/static/images/header/beh.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 476 KiB

26847
mamweb/static/images/jakresit_1.svg

File diff suppressed because it is too large

After

Width:  |  Height:  |  Size: 1.8 MiB

26847
mamweb/static/images/jakresit_2.svg

File diff suppressed because it is too large

After

Width:  |  Height:  |  Size: 1.8 MiB

26847
mamweb/static/images/jakresit_3.svg

File diff suppressed because it is too large

After

Width:  |  Height:  |  Size: 1.8 MiB

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

25
mamweb/templates/base.html

@ -6,13 +6,14 @@
<title>{% block title %}{% block nadpis1a %}{% endblock %} – Korespondenční seminář M&amp;M{% endblock title %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{% static 'images/MATFYZ_MM_barevne.svg' %}" type="image/x-icon">
{% render_block "css" %}
{% render_block css %}
{% block custom_css %}{% endblock %}
<link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
<link href="{% static 'css/bootstrap.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" />
<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' %}" />
<script type="text/javascript" src="{% static 'fluent_comments/js/ajaxcomments.js' %}"></script>
@ -56,13 +57,17 @@
<div class='col-md-12'>
<a href='/'>
<div id="title" >M&M - korespondenční seminář a časopis MFF&nbspUK</div>
<div id="header" class="{% if noc %}NOC{% endif %}{% block header %}{% endblock %}">
<img class="logo" src="{% static 'images/logo.svg' %}" />
<div id="header">
<div class="no-mobile" style="background-image: url('{{ fotka }}')">
{# TODO style=… není fancy řešení, ale u <img> se bojím, že mi to rozbije vzhled #}
{% sitetree_menu from "main_menu" include "trunk" template "logo.html" %}
</div>
<img class="logo-mobile" src="{% static 'images/logo-mobile.svg' %}" />
</div>
</a>
</div>
</div>
<div class='row'>
<div class='col-md-12'>
@ -72,6 +77,9 @@
{# ========= MENU MOBILE ========== #}
</div>
</div>
<!--Navbar-->
<nav class="nav-button">
@ -94,21 +102,24 @@
{# ========= END MENU ========== #}
<div class='row'>
<div class='row content'>
<div class='col-md-12'>
{% block content %}
{% endblock content %}
</div>
</div>
</div>
</div>
<div class='row'>
<div class='col-md-12'>
<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>
</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>
<script src="{% static 'js/bootstrap.js' %}"></script>

104
mamweb/templates/flatpages/default.html

@ -8,106 +8,4 @@
<div>
{{ flatpage.content }}
</div>
{% endblock content %}
{# nahraj spravne submenu #}
{% block submenu %}
{# co-je-MaM #}
{% if "/co-je-MaM/" in flatpage.url %}
{% if "/uvod/" in flatpage.url %}
{% with "uvod" as selected %}
{% include "seminar/cojemam/submenu.html" %}
{% endwith %}
{% elif "jak-resit" in flatpage.url %}
{% with "jak-resit" as selected %}
{% include "seminar/cojemam/submenu.html" %}
{% endwith %}
{% elif "odmeny" in flatpage.url %}
{% with "odmeny" as selected %}
{% include "seminar/cojemam/submenu.html" %}
{% endwith %}
{% elif "FAQ" in flatpage.url %}
{% with "FAQ" as selected %}
{% include "seminar/cojemam/submenu.html" %}
{% endwith %}
{% elif "kontakt" in flatpage.url %}
{% else %}
{% include "seminar/cojemam/submenu.html" %}
{% endif %}
{% endif %}
{# soustredeni #}
{% if "/soustredeni/" in flatpage.url %}
{% if "/pripravujeme/" in flatpage.url %}
{% with "pripravujeme" as selected %}
{% include "seminar/soustredeni/submenu.html" %}
{% endwith %}
{% else %}
{% with "uvod" as selected %}
{% include "seminar/soustredeni/submenu.html" %}
{% endwith %}
{% endif %}
{% endif %}
{# zadani #}
{% if "/zadani/" in flatpage.url %}
{% if "/aktualni-cislo/" in flatpage.url %}
{% with "aktualni-cislo" as selected %}
{% include "seminar/zadani/submenu.html" %}
{% endwith %}
{% elif "/vysledkova-listina/" in flatpage.url %}
{% with "vysledkova-listina" as selected %}
{% include "seminar/zadani/submenu.html" %}
{% endwith %}
{% else %}
{% include "seminar/zadani/submenu.html" %}
{% endif %}
{% endif %}
{# clanky #}
{% if "/clanky/" in flatpage.url %}
{% if "/uvod/" in flatpage.url %}
{% with "uvod" as selected %}
{% include "seminar/clanky/submenu.html" %}
{% endwith %}
{% elif "/org/" in flatpage.url %}
{% with "org" as selected %}
{% include "seminar/clanky/submenu.html" %}
{% endwith %}
{% elif "/resitel/" in flatpage.url %}
{% with "resitel" as selected %}
{% include "seminar/clanky/submenu.html" %}
{% endwith %}
{% elif "/jak-psat-vedecky-clanek/" in flatpage.url %}
{% with "jak-psat-vedecky-clanek" as selected %}
{% include "seminar/clanky/submenu.html" %}
{% endwith %}
{% else %}
{% include "seminar/clanky/submenu.html" %}
{% endif %}
{% endif %}
{# archiv #}
{% if "/archiv/" in flatpage.url %}
{% if "/ulohy/" in flatpage.url %}
{% with "ulohy" as selected %}
{% include "seminar/archiv/submenu.html" %}
{% endwith %}
{% elif "/vysledky/" in flatpage.url %}
{% with "vysledky" as selected %}
{% include "seminar/archiv/submenu.html" %}
{% endwith %}
{% else %}
{% include "seminar/archiv/submenu.html" %}
{% endif %}
{% endif %}
{% endblock %}
{# zvirazneni menu #}
{% block menu_uvod %}{% if not "/kontakt/" in flatpage.url %}{% if "/co-je-MaM/" in flatpage.url %}selected{% endif %}{% endif %}{% endblock %}
{% block menu_soustredeni %}{% if "/soustredeni/" in flatpage.url %}selected{% endif %}{% endblock %}
{% block menu_zadani %}{% if "/zadani/" in flatpage.url %}selected{% endif %}{% endblock %}
{% block menu_clanky %}{% if "/clanky/" in flatpage.url %}selected{% endif %}{% endblock %}
{% block menu_archiv %}{% if "/archiv/" in flatpage.url %}selected{% endif %}{% endblock %}
{% block menu_odevzdat %}{% if "/kontakt/" in flatpage.url %}selected{% endif %}{% endblock %}
{# zmena titulniho obrazku #}
{% block header %}{% if "/co-je-MaM/" in flatpage.url %}cojemam{% elif "/soustredeni/" in flatpage.url %}soustredeni{% elif "/zadani/" in flatpage.url %}zadani{% elif "/clanky/" in flatpage.url %}clanky{% elif "/archiv/" in flatpage.url %}archiv{% else %}odeslat{% endif %}{% endblock header %}
{# TODO zvirazneni submenu #}
{% endblock content %}

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 %}
<ul class="menu">
{% 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 %}" >
{{ item.title_resolved }}
</a>

4
mamweb/templates/menu_mobile.html

@ -3,7 +3,9 @@
{% autoescape off %}
<ul class="menu_mobile">
{% 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 %}>
{{ item.title_resolved }}
</a>

5
mamweb/urls.py

@ -6,6 +6,8 @@ from django.views.generic.base import TemplateView
from django import views
from django.urls import path # As per docs.
from .routers import router
urlpatterns = [
# Admin a nastroje
@ -25,6 +27,9 @@ urlpatterns = [
path('comments_dj/', include('django_comments.urls')),
path('comments_fl/', include('fluent_comments.urls')),
# REST API
path('api/', include(router.urls)),
]
# This is only needed when using runserver.

2
mamweb_prod.ini

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

2
mamweb_test.ini

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

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">
{% csrf_token %}
<table>{{form.as_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><p><i>{{p.anotace}}</i></p></td></tr>
<tr><td><label>Obor: </label> {{p.obor}}</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%}
<tr><td>Hodnocení:
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="-1"> rozhodně nechci
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="0" checked> 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ě nechci
<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" {% if h == 1 %} CHECKED="checked" {% endif %}> rozhodně chci
</td></tr>
<tr><td>&nbsp;</td></tr>
{% endfor %}

6
prednasky/templates/prednasky/metaseznam_prednasek.html

@ -1,9 +1,5 @@
{% extends "prednasky/base.html" %}
{% block header %}hlasovani{% endblock %}
{% block content %}
<h1>{% block nadpis1a %}{% block nadpis1b %}Hlasování o přednáškách{% endblock %}{% endblock %}</h1>
{# Projdi vsechny seznamy #}
@ -19,6 +15,8 @@
<a href="/prednasky/seznam_prednasek/{{seznam.id}}/export">Export</a>
</li>
{% endfor %}
</ul>
</div>
{% endblock %}

6
prednasky/templates/prednasky/seznam_prednasek.html

@ -1,9 +1,5 @@
{% extends "prednasky/base.html" %}
{% block header %}seznam_prednasek{% endblock %}
{% block content %}
<h1>{% block nadpis1a %}Průběžné výsledky hlasování{% endblock %}</h1>
<div class="mam-org-only">
@ -15,5 +11,7 @@
{{ prednaska.body }} b</i>) &ndash; {{ prednaska.org }}
</li>
{% endfor %}
</ul>
</div>
{% endblock %}

14
prednasky/templates/prednasky/seznam_prednasek_export.txt

@ -1,19 +1,7 @@
{% block content %}
{% spaceless %}
{% for hlas in hlasovani %}
hlas({{hlas.ucastnik}},{{hlas.prednaska.id}},{{hlas.body}})
{% endfor %}
{% for prednaska in prednasky %}
prednaska({{prednaska.id}},{{prednaska.org.id}},{{prednaska.obtiznost}},{{prednaska.obor}})
{% endfor %}
{% for org in orgove %}
org({{org.id}},4,0,15)
{% endfor %}
{% for org in orgove %}
{{org.id}};{{org}}
{% endfor %}
{% for prednaska in prednasky %}
{{prednaska.id}};{{prednaska.nazev}};{{prednaska.org.id}}
{{prednaska.id}};{{prednaska.nazev}};{{prednaska.org}}
{{prednaska.body}}
{% endfor %}
{% endspaceless %}

27
prednasky/urls.py

@ -1,14 +1,25 @@
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
staff_member_required = user_passes_test(lambda u: u.is_staff)
urlpatterns = [
path('prednasky/', views.newPrednaska),
path(
'prednasky/',
resitel_required(views.newPrednaska)
),
path('prednasky/hotovo', views.Prednaska_hotovo),
path('prednasky/metaseznam_prednasek', staff_member_required(views.MetaSeznamListView.as_view()), name='metaseznam-list'),
path('prednasky/seznam_prednasek/<int:seznam>/export', staff_member_required(views.SeznamExportView), name='seznam-export'),
path('prednasky/seznam_prednasek/<int:seznam>/', staff_member_required(views.SeznamListView.as_view()), name='seznam-list'),
# path('korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'),
path(
'prednasky/metaseznam_prednasek',
org_required(views.MetaSeznamListView.as_view()),
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'
),
]

55
prednasky/views.py

@ -4,41 +4,52 @@ from django.views import generic
from django.shortcuts import HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Sum
from django.forms import Form
from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH
from seminar.models import Soustredeni
from prednasky.forms import NewPrednaskyForm
from seminar.models import Soustredeni, Osoba
def newPrednaska(request):
# hlasovani se vztahuje k nejnovejsimu soustredeni
sous = Soustredeni.objects.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
if request.method == 'POST':
form = NewPrednaskyForm(request.POST, request.FILES)
form = Form(request.POST, request.FILES)
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:
if i[0] == 'q':
hlasovani = Hlasovani()
print("q:"+i[1:])
hlasovani.prednaska = Prednaska.objects.filter(pk = int(i[1:]))[0]
prednaska = Prednaska.objects.filter(pk=int(i[1:]))[0]
hlasovani = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first()
if not hlasovani:
hlasovani = Hlasovani()
hlasovani.prednaska = prednaska
hlasovani.ucastnik = ucastnik
hlasovani.seznam = seznam
hlasovani.body = int(request.POST[i])
hlasovani.ucastnik = jmeno
hlasovani.seznam = seznam
hlasovani.save()
# presmerovani na prave vzniklou galerii
return HttpResponseRedirect('./hotovo')
else:
form = NewPrednaskyForm()
def prednaska_hodnoceni(prednaska):
h = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first()
if h:
return prednaska, h.body
else:
return prednaska, 0
return render(
request,
'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"])
prednasky = Prednaska.objects.filter(seznamy=self.seznam).order_by(
'org__user__first_name', 'org__user__last_name'
).annotate(body=Sum('hlasovani__body'))
)
return prednasky
# FIXME nahradit anotaci s filtrem po prechodu na Django 2.2
def get_context_data(self,**kwargs):
context = super(SeznamListView, self).get_context_data(**kwargs)
# hlasovani se vztahuje k nejnovejsimu soustredeni
sous = Soustredeni.objects.first()
seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first()
for obj in self.object_list:
hlasovani_set = obj.hlasovani_set.filter(seznam=seznam).only('body')
obj.body = sum(map(lambda x: x.body,hlasovani_set))
return context
def SeznamExportView(request, seznam):
u"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor"""
"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor"""
# TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro
# lidi?
hlasovani = Hlasovani.objects.filter(seznam=seznam)

3
requirements.txt

@ -28,6 +28,9 @@ django-imagekit
django-polymorphic
django-sitetree
django_reverse_admin
django-rest-framework
django-webpack-loader
django-rest-polymorphic
# Comments
akismet==1.0.1

1
seminar/.~lock.profile_vysledkovka.txt#

@ -0,0 +1 @@
,anet,erebus,25.03.2020 22:21,file:///home/anet/.config/libreoffice/4;

89
seminar/admin.py

@ -1,8 +1,13 @@
from django.contrib import admin
from django.contrib.auth.models import Permission
from django.db import models
from django.forms import widgets
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
from reversion.admin import VersionAdmin
from django_reverse_admin import ReverseModelAdmin
from solo.admin import SingletonModelAdmin
# Todo: reversion
@ -12,12 +17,10 @@ admin.site.register(m.Skola)
admin.site.register(m.Prijemce)
admin.site.register(m.Rocnik)
admin.site.register(m.Cislo)
admin.site.register(m.Organizator)
admin.site.register(m.Soustredeni)
@admin.register(m.Osoba)
class OsobaAdmin(admin.ModelAdmin):
actions = ['synchronizuj_maily']
actions = ['synchronizuj_maily', 'udelej_orgem']
def synchronizuj_maily(self, request, queryset):
for o in queryset:
@ -28,6 +31,27 @@ class OsobaAdmin(admin.ModelAdmin):
self.message_user(request, "E-maily synchronizovány.")
synchronizuj_maily.short_description = "Synchronizuj vybraným osobám e-maily do uživatelů"
def udelej_orgem(self,request,queryset):
org_perm = Permission.objects.filter(codename__exact='org').first()
print(queryset)
for o in queryset:
user = o.user
user.user_permissions.add(org_perm)
user.is_staff = True
user.save()
org = m.Organizator.objects.create(osoba=o)
org.save()
udelej_orgem.short_description = "Udělej vybraných osob organizátory"
@admin.register(m.Organizator)
class OrganizatorAdmin(admin.ModelAdmin):
search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'prezdivka']
@admin.register(m.Resitel)
class ResitelAdmin(admin.ModelAdmin):
search_fields = ['jmeno', 'prijmeni', 'prezdivka']
ordering = ('osoba__jmeno','osoba__prijmeni')
@admin.register(m.Problem)
class ProblemAdmin(PolymorphicParentModelAdmin):
base_model = m.Problem
@ -58,15 +82,55 @@ class KonferaAdmin(PolymorphicChildModelAdmin):
base_model = m.Konfera
show_in_index = True
class TextAdminInline(admin.TabularInline):
model = m.Text
formfield_overrides = {
models.TextField: {'widget': widgets.TextInput}
}
exclude = ['text_zkraceny_set','text_zkraceny']
admin.site.register(m.Text)
class ResitelInline(admin.TabularInline):
model = m.Resitel
extra = 1
admin.site.register(m.Resitel)
class SoustredeniUcastniciInline(admin.TabularInline):
model = m.Soustredeni_Ucastnici
extra = 1
fields = ['resitel','poznamka']
autocomplete_fields = ['resitel']
ordering = ['resitel__osoba__jmeno', 'resitel__osoba__prijmeni']
formfield_overrides = {
models.TextField: {'widget': widgets.TextInput}
}
def get_queryset(self,request):
qs = super().get_queryset(request)
return qs.select_related('resitel','soustredeni')
class SoustredeniOrganizatoriInline(admin.TabularInline):
model = m.Soustredeni.organizatori.through
extra = 1
fields = ['organizator','poznamka']
autocomplete_fields = ['organizator']
ordering = ['organizator__osoba__jmeno','organizator__prijmeni']
formfield_overrides = {
models.TextField: {'widget': widgets.TextInput}
}
def get_queryset(self,request):
qs = super().get_queryset(request)
return qs.select_related('organizator', 'soustredeni')
@admin.register(m.Soustredeni)
class SoustredeniAdmin(admin.ModelAdmin):
model = m.Soustredeni
inline_type = 'tabular'
inlines = [SoustredeniUcastniciInline, SoustredeniOrganizatoriInline]
class PrilohaReseniInline(admin.TabularInline):
model = m.PrilohaReseni
@ -76,6 +140,7 @@ admin.site.register(m.PrilohaReseni)
class Reseni_ResiteleInline(admin.TabularInline):
model = m.Reseni_Resitele
@admin.register(m.Reseni)
class ReseniAdmin(ReverseModelAdmin):
base_model = m.Reseni
@ -90,7 +155,6 @@ admin.site.register(m.Hodnoceni)
admin.site.register(m.Pohadka)
admin.site.register(m.Obrazek)
# Polymorfismus pro stromy
# TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html
@ -106,6 +170,8 @@ class TreeNodeAdmin(PolymorphicParentModelAdmin):
m.PohadkaNode,
m.UlohaVzorakNode,
m.TextNode,
m.CastNode,
m.OrgTextNode,
]
actions = ['aktualizuj_nazvy']
@ -159,6 +225,17 @@ class TextNodeAdmin(PolymorphicChildModelAdmin):
base_model = m.TextNode
show_in_index = True
@admin.register(m.CastNode)
class TextNodeAdmin(PolymorphicChildModelAdmin):
base_model = m.CastNode
show_in_index = True
fields = ('nadpis',)
@admin.register(m.OrgTextNode)
class TextNodeAdmin(PolymorphicChildModelAdmin):
base_model = m.OrgTextNode
show_in_index = True
admin.site.register(m.Nastaveni)
admin.site.register(m.Nastaveni, SingletonModelAdmin)
admin.site.register(m.Novinky)

34
seminar/forms.py

@ -10,6 +10,21 @@ import seminar.models as m
from datetime import date
import logging
# pro přidání políčka do formuláře je potřeba
# - mít v modelu tu položku, kterou chci upravovat
# - přidat do views (prihlaskaView, resitelEditView)
# - přidat do forms
# - includovat do html
class DateInput(forms.DateInput):
# aby se datum dalo vybírat z kalendáře
input_type = 'date'
class TelInput(forms.TextInput):
# tohle je možná k niřemu, ale alepsoň to mění input type a nic to nekazí
input_type = 'tel'
input_pattern="^[+]?[()/0-9. -]{9,}$"
class LoginForm(forms.Form):
username = forms.CharField(label='Přihlašovací jméno',
max_length=256,
@ -42,8 +57,8 @@ class PrihlaskaForm(forms.Form):
pohlavi_muz = forms.ChoiceField(label='Pohlaví',
choices = ((True,'muž'),(False,'žena')), required=True)
email = forms.EmailField(label='E-mail',max_length=256, required=True)
telefon = forms.CharField(label='Telefon',max_length=256, required=False)
datum_narozeni = forms.DateField(label='Datum narození', required=False)
telefon = forms.CharField(widget=TelInput(),label='Telefon',max_length=256, required=False)
datum_narozeni = forms.DateField(widget=DateInput(),label='Datum narození', required=False)
ulice = forms.CharField(label='Ulice', max_length=256, required=False)
mesto = forms.CharField(label='Město', max_length=256, required=False)
psc = forms.CharField(label='PSČ', max_length=32, required=False)
@ -74,6 +89,8 @@ class PrihlaskaForm(forms.Form):
max_value=date.today().year+8,
required=True)
zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True)
zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat emailem upozornění na vydání nového čísla', required=True)
gdpr = forms.BooleanField(label='Souhlasím se zpracováním osobních údajů', required=True)
spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
@ -135,8 +152,8 @@ class ProfileEditForm(forms.Form):
pohlavi_muz = forms.ChoiceField(label='Pohlaví',
choices = ((True,'muž'),(False,'žena')), required=True)
email = forms.EmailField(label='E-mail',max_length=256, required=True)
telefon = forms.CharField(label='Telefon',max_length=256, required=False)
datum_narozeni = forms.DateField(label='Datum narození', required=False)
telefon = forms.CharField(widget=TelInput(),label='Telefon',max_length=256, required=False)
datum_narozeni = forms.DateField(widget=DateInput(),label='Datum narození', required=False)
ulice = forms.CharField(label='Ulice', max_length=256, required=False)
mesto = forms.CharField(label='Město', max_length=256, required=False)
psc = forms.CharField(label='PSČ', max_length=32, required=False)
@ -167,6 +184,8 @@ class ProfileEditForm(forms.Form):
max_value=date.today().year+8,
required=True)
zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True)
zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat email s upozorněním na vydání nového čísla', required=True)
spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
# def clean_username(self):
# err_logger = logging.getLogger('seminar.prihlaska.problem')
@ -234,7 +253,7 @@ class VlozReseniForm(forms.Form):
#resitele = models.ManyToManyField(Resitel, verbose_name='autoři řešení',
# help_text='Seznam autorů řešení', through='Reseni_Resitele')
cas_doruceni = forms.DateField(label="Čas doručení")
cas_doruceni = forms.DateField(widget=DateInput(),label="Čas doručení")
#cas_doruceni = models.DateTimeField('čas_doručení', default=timezone.now, blank=True)
@ -277,3 +296,8 @@ ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni,
)
class NahrajObrazekKTreeNoduForm(forms.ModelForm):
class Meta:
model = m.Obrazek
fields = ('na_web',)

6
seminar/management/commands/auth.py

@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
from django.core.management.base import NoArgsCommand
from django.core.management.base import BaseCommand
from django.contrib.sessions.models import Session
from django.contrib.auth.models import User
class Command(NoArgsCommand):
class Command(BaseCommand):
u"""Vypiš username přihlášeného orga s daným session_key.
Příkaz pro manage.py, který ze vstupu přečte session_key (tak, jak je
uložen v cookie sessionid) a pokud session existuje a příslušný přihlášený
uživatel právo přihlásit se do admina, vypíše jeho username.
"""
def handle_noargs(self, **options):
def handle(self, *args, **options):
session_key = raw_input()
s = Session.objects.get(pk=session_key).get_decoded()
user_id = s['_auth_user_id']

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):
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
@ -877,6 +877,7 @@ class Migration(migrations.Migration):
),
migrations.RunSQL(
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(
model_name='rocnik',
@ -1733,15 +1734,19 @@ class Migration(migrations.Migration):
# migr 0052
migrations.RunPython(
spoj_k_organizatorum_osoby,
reverse_code=migrations.RunPython.noop,
),
migrations.RunPython(
fix_problem,
reverse_code=migrations.RunPython.noop,
),
migrations.RunPython(
fix_pohadka,
reverse_code=migrations.RunPython.noop,
),
migrations.RunPython(
fix_novinka,
reverse_code=migrations.RunPython.noop,
),
# migr 0053
@ -1795,35 +1800,49 @@ class Migration(migrations.Migration):
# migr 0056
migrations.RunPython(
generuj_RocnikNody_a_CisloNody,
reverse_code=migrations.RunPython.noop,
),
# migr 0057
migrations.RunPython(
reseni_to_Reseni,
reverse_code=migrations.RunPython.noop,
),
# migr 0058
migrations.RunPython(
uloha_to_Uloha,
reverse_code=migrations.RunPython.noop,
),
migrations.RunPython(
tema_to_Tema,
reverse_code=migrations.RunPython.noop,
),
migrations.RunPython(
clanek_to_Clanek,
reverse_code=migrations.RunPython.noop,
),
migrations.RunPython(
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
migrations.RunPython(
vytvor_pohadkanode,
reverse_code=migrations.RunPython.noop,
),
# migr 0060
migrations.RunPython(
pokacej_les,
reverse_code=migrations.RunPython.noop,
),
migrations.RemoveField(

3
seminar/migrations/0019_rocnik_ciselne.py

@ -18,7 +18,8 @@ class Migration(migrations.Migration):
preserve_default=False,
),
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(
model_name='rocnik',

8
seminar/migrations/0052_user_to_organizator.py

@ -75,8 +75,8 @@ class Migration(migrations.Migration):
]
operations = [
migrations.RunPython(spoj_k_organizatorum_osoby),
migrations.RunPython(fix_problem),
migrations.RunPython(fix_pohadka),
migrations.RunPython(fix_novinka),
migrations.RunPython(spoj_k_organizatorum_osoby, migrations.RunPython.noop),
migrations.RunPython(fix_problem, migrations.RunPython.noop),
migrations.RunPython(fix_pohadka, migrations.RunPython.noop),
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 = [
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 = [
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 = [
# ashes to Ashes, dust to Dust....
migrations.RunPython(uloha_to_Uloha),
migrations.RunPython(tema_to_Tema),
migrations.RunPython(clanek_to_Clanek),
migrations.RunPython(konfery_rucne),
migrations.RunPython(uloha_to_Uloha, migrations.RunPython.noop),
migrations.RunPython(tema_to_Tema, migrations.RunPython.noop),
migrations.RunPython(clanek_to_Clanek, migrations.RunPython.noop),
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):
dependencies = [
('seminar', '0058_problem_to_uloha_tema_clanek'),
('seminar', 'fix_0058'),
]
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 = [
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):
# Kód zkopírovaný z dokumentace: https://django-polymorphic.readthedocs.io/en/stable/migrating.html
# XXX: Nevím, jestli se tohle náhodou nemělo spustit na všech childech (jen/i)
# NOTE: Tahle migrace je špatně, 0087 ji opravuje. Možno squashnout pryč.
TreeNode = apps.get_model('seminar', 'TreeNode')
ContentType = apps.get_model('contenttypes', 'ContentType')
@ -27,5 +27,5 @@ class Migration(migrations.Migration):
name='polymorphic_ctype',
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_seminar.treenode_set+', to='contenttypes.ContentType'),
),
migrations.RunPython(vyrob_treenodum_ctypes, migrations.RunPython.noop),
migrations.RunPython(vyrob_treenodum_ctypes, migrations.RunPython.noop, elidable=True),
]

4
seminar/migrations/0066_problem_polymorphic_ctype.py

@ -5,7 +5,7 @@ import django.db.models.deletion
def vyrob_problemum_ctypes(apps, schema_editor):
# Kód zkopírovaný z dokumentace: https://django-polymorphic.readthedocs.io/en/stable/migrating.html
# XXX: Nevím, jestli se tohle náhodou nemělo spustit na všech childech (jen/i)
# NOTE: Tahle migrace je špatně, 0087 ji opravuje. Možno squashnout pryč.
Problem = apps.get_model('seminar', 'Problem')
ContentType = apps.get_model('contenttypes', 'ContentType')
@ -25,5 +25,5 @@ class Migration(migrations.Migration):
name='polymorphic_ctype',
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_seminar.problem_set+', to='contenttypes.ContentType'),
),
migrations.RunPython(vyrob_problemum_ctypes, migrations.RunPython.noop),
migrations.RunPython(vyrob_problemum_ctypes, migrations.RunPython.noop, elidable=True),
]

2
seminar/migrations/0068_treenode_nazev.py

@ -103,5 +103,5 @@ class Migration(migrations.Migration):
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'),
),
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',
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(
model_name='konfera',
name='problem_ptr',
@ -95,9 +98,6 @@ class Migration(migrations.Migration):
migrations.DeleteModel(
name='ClanekNode',
),
migrations.DeleteModel(
name='KonferaNode',
),
migrations.CreateModel(
name='Konfery_Ucastnici',
fields=[

8
seminar/migrations/0084_clanek_cislo.py

@ -4,6 +4,9 @@ from django.db import migrations, models
import django.db.models.deletion
from seminar.treelib import get_parent
import logging
logger = logging.getLogger(__name__)
def najdi_cislo(apps, schema_editor):
Clanek = apps.get_model('seminar', 'Clanek')
Hodnoceni = apps.get_model('seminar', 'Hodnoceni')
@ -15,7 +18,10 @@ def najdi_cislo(apps, schema_editor):
for c in Clanek.objects.all():
reseni = c.reseni_set
if (reseni.count() != 1): # Pozor, reseni_set je Manager, takže se na něj musí trošku jinak
raise ValueError("Článek k sobě má nejedno řešení!")
logger.warn(f"Více než jedno řešení pro článek {c}")
c.cislo = None
c.save()
continue
r = reseni.first()
aktualniNode = r.text_cely # Hlavní ReseniNode pro řešení
while aktualniNode is not None:

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

18
seminar/migrations/0089_cislo_datum_preddeadline.py

@ -0,0 +1,18 @@
# Generated by Django 2.2.16 on 2020-10-13 19:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('seminar', '0088_perm_org_a_ucastnik'),
]
operations = [
migrations.AddField(
model_name='cislo',
name='datum_preddeadline',
field=models.DateField(blank=True, help_text='Datum pro příjem řešení, která se otisknou v dalším čísle', null=True, verbose_name='datum předdeadline'),
),
]

19
seminar/migrations/0090_auto_20201110_1958.py

@ -0,0 +1,19 @@
# Generated by Django 2.2.12 on 2020-11-10 18:58
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('seminar', '0089_cislo_datum_preddeadline'),
]
operations = [
migrations.AlterField(
model_name='textnode',
name='text',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='seminar.Text', verbose_name='text'),
),
]

18
seminar/migrations/0091_resitel_zasilat_cislo_emailem.py

@ -0,0 +1,18 @@
# Generated by Django 2.2.17 on 2020-12-01 19:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('seminar', '0090_auto_20201110_1958'),
]
operations = [
migrations.AddField(
model_name='resitel',
name='zasilat_cislo_emailem',
field=models.BooleanField(default=False, help_text='True pokud chce řešitel dostávat číslo emailem', verbose_name='zasílat číslo emailem'),
),
]

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

166
seminar/models.py

@ -28,7 +28,6 @@ from reversion import revisions as reversion
from seminar.utils import roman, FirstTagParser # Pro získání úryvku z TextNode
from unidecode import unidecode # Používám pro získání ID odkazu (ještě je to někde po někom zakomentované)
from seminar.treelib import safe_pred
from polymorphic.models import PolymorphicModel
@ -263,8 +262,10 @@ class Resitel(SeminarModelBase):
(ZASILAT_DO_SKOLY, 'Do školy'),
(ZASILAT_NIKAM, 'Nikam'),
]
zasilat = models.CharField('kam zasílat', max_length=32, choices=ZASILAT_CHOICES, blank=False, default=ZASILAT_DOMU)
zasilat_cislo_emailem = models.BooleanField('zasílat číslo emailem', help_text='True pokud chce řešitel dostávat číslo emailem', default=False)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k řešiteli (plain text)')
@ -312,25 +313,106 @@ class Resitel(SeminarModelBase):
return sum(h.body for h in list(vsechna_hodnoceni))
def get_titul(self, celkove_body=None):
"Vrati titul"
if celkove_body is None:
celkove_body = self.vsechny_body()
if celkove_body < 10:
return ''
elif celkove_body < 20:
return 'Bc.'
elif celkove_body < 50:
return 'Mgr.'
elif celkove_body < 100:
return 'Dr.'
elif celkove_body < 200:
return 'Doc.'
elif celkove_body < 500:
return 'Prof.'
def get_titul(self, body=None):
"Vrati titul jako řetězec."
# Nejprve si zadefinujeme titul
from enum import Enum
from functools import total_ordering
@total_ordering
class Titul(Enum):
""" Třída reprezentující možné tituly. Hodnoty jsou dvojice (dolní hranice, stringifikace). """
nic = (0, '')
bc = (20, 'Bc.')
mgr = (50, 'Mgr.')
dr = (100, 'Dr.')
doc = (200, 'Doc.')
prof = (500, 'Prof.')
akad = (1000, 'Akad.')
def __lt__(self, other):
return True if self.value[0] < other.value[0] else False
def __eq__(self, other): # Měla by být implicitní, ale klidně explicitně.
return True if self.value[0] == other.value[0] else False
def __str__(self):
return self.value[1]
@classmethod
def z_bodu(cls, body):
aktualni = cls.nic
# TODO: ověřit, že to funguje
for titul in cls: # Kdyžtak použít __members__.items()
if titul.value[0] <= body:
aktualni = titul
else:
break
return aktualni
# Hledáme body v databázi
# V listopadu 2020 jsme se na filosofické schůzce shodli o změně hranic titulů:
# - body z 25. ročníku a dříve byly shledány dvakrát hodnotnějšími
# - proto se započítávají dvojnásobně a byly posunuté hranice titulů
# - staré tituly se ale nemají odebrat, pokud řešitel v t.č. minulém (26.) ročníku měl titul, má ho mít pořád.
hodnoceni_do_25_rocniku = Hodnoceni.objects.filter(cislo_body__rocnik__rocnik__lte=25,reseni__in=self.reseni_set.all())
novejsi_hodnoceni = Hodnoceni.objects.filter(reseni__in=self.reseni_set.all()).difference(hodnoceni_do_25_rocniku)
def body_z_hodnoceni(hh : list):
return sum(h.body for h in hh)
stare_body = body_z_hodnoceni(hodnoceni_do_25_rocniku)
if body is None:
nove_body = body_z_hodnoceni(novejsi_hodnoceni)
else:
return 'Akad.'
# Zjistíme, kolik bodů jsou staré, tedy hodnotnější
nove_body = max(0, body - stare_body) # Všechny body nad počet původních hodnotnějších
stare_body = min(stare_body, body) # Skutečný počet hodnotnějších bodů
logicke_body = 2*stare_body + nove_body
# Titul se určí následovně:
# - Pokud se řeší body, které jsou starší, než do 26 ročníku (včetně), dáváme tituly postaru.
# - Jinak dáváme tituly po novu...
# - ... ale titul se nesmí odebrat, pokud se zmenšil.
def titul_do_26_rocniku(body):
""" Původní hranice bodů za tituly """
if body < 10:
return Titul.nic
elif body < 20:
return Titul.bc
elif body < 50:
return Titul.mgr
elif body < 100:
return Titul.dr
elif body < 200:
return Titul.doc
elif body < 500:
return Titul.prof
else:
return Titul.akad
hodnoceni_do_26_rocniku = Hodnoceni.objects.filter(cislo_body__rocnik__rocnik__lte=26,reseni__in=self.reseni_set.all())
novejsi_body = body_z_hodnoceni(
Hodnoceni.objects.filter(reseni__in=self.reseni_set.all())
.difference(hodnoceni_do_26_rocniku)
)
starsi_body = body_z_hodnoceni(hodnoceni_do_26_rocniku)
if body is not None:
# Ještě z toho vybereme ty správně staré body
novejsi_body = max(0, body - starsi_body)
starsi_body = min(starsi_body, body)
# Titul pro 26. ročník
stary_titul = titul_do_26_rocniku(starsi_body)
# Titul podle aktuálních pravidel
novy_titul = Titul.z_bodu(logicke_body)
if novejsi_body == 0:
# Žádné nové body -- titul podle starých pravidel
return str(stary_titul)
return str(max(novy_titul, stary_titul))
def __str__(self):
return self.osoba.plne_jmeno()
@ -445,6 +527,9 @@ class Cislo(SeminarModelBase):
datum_deadline = models.DateField('datum deadline', blank=True, null=True,
help_text='Datum pro příjem řešení úloh zadaných v tomto čísle')
datum_preddeadline = models.DateField('datum předdeadline', blank=True, null=True,
help_text='Datum pro příjem řešení, která se otisknou v dalším čísle')
datum_deadline_soustredeni = models.DateField(
'datum deadline soustředění',
blank=True, null=True,
@ -618,7 +703,7 @@ class Organizator(SeminarModelBase):
"školu, ale jen obor, možnost zobrazit zvlášť")
def clean(self):
if self.organizuje_od > self.organizuje_do:
if self.organizuje_od and self.organizuje_do and (self.organizuje_od > self.organizuje_do):
raise ValidationError("Organizátor nemůže skončit s organizováním dříve než začal!")
super().clean()
@ -633,6 +718,11 @@ class Organizator(SeminarModelBase):
class Meta:
verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři'
# Řadí aktivní orgy na začátek, pod tím v pořadí od nejstarších neaktivní orgy.
# TODO: Chtěl bych spíš mít nejstarší orgy dole.
# TODO: Zohledňovat přezdívky?
# TODO: Sjednotit s tím, jak se řadí organizátoři v seznau orgů na webu
ordering = ['-organizuje_do', 'osoba__jmeno', 'osoba__prijmeni']
@reversion.register(ignore_duplicates=True)
class Soustredeni(SeminarModelBase):
@ -734,6 +824,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
(STAV_SMAZANY, 'Smazaný'),
]
stav = models.CharField('stav problému', max_length=32, choices=STAV_CHOICES, blank=False, default=STAV_NAVRH)
# Téma je taky Problém, takže má stavy, "zadané" témátko je aktuálně otevřené a dá se k němu něco poslat (řešení nebo článek)
zamereni = TaggableManager(verbose_name='zaměření',
help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True)
@ -771,11 +862,20 @@ class Problem(SeminarModelBase,PolymorphicModel):
return '<Není zadaný>'
def verejne(self):
# FIXME: Tohle se liší podle typu problému, má se udělat polymorfně.
# Zatím je tu jen dummy fail-safe default: nic není veřejné.
return False
# FIXME: Tohle je blbost
return (self.cislo_zadani and self.cislo_zadani.verejne())
# aktuálně podle stavu problému
# FIXME pro některé problémy možná chceme override
# FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.
# Je to tak správně?
stav_verejny = False
if self.stav == 'zadany' or self.stav == 'vyreseny':
stav_verejny = True
return stav_verejny
#cislo_verejne = False
#if (self.cislo_zadani and self.cislo_zadani.verejne()):
# cislo_verejne = True
#return (stav_verejny and cislo_verejne)
verejne.boolean = True
def verejne_url(self):
@ -871,9 +971,7 @@ class Text(SeminarModelBase):
tn.save()
def __str__(self):
parser = FirstTagParser()
parser.feed(str(self.na_web))
return parser.firstTag
return str(self.na_web)[:20]
class Uloha(Problem):
class Meta:
@ -1015,7 +1113,7 @@ def aux_generate_filename(self, filename):
unidecode(filename.replace('/', '-').replace('\0', ''))
)
datedir = timezone.now().strftime('%Y-%m')
fname = "{}_{}".format(
fname = "{}/{}".format(
timezone.now().strftime('%Y-%m-%d-%H:%M'),
clean)
return os.path.join(datedir, fname)
@ -1068,6 +1166,11 @@ class PrilohaReseni(SeminarModelBase):
def __str__(self):
return str(self.soubor)
def split(self):
"Vrátí cestu rozsekanou po složkách. To se hodí v templatech"
# Věřím, že tohle funguje, případně použít os.path nebo pathlib.
return self.soubor.url.split('/')
class Pohadka(SeminarModelBase):
"""Kus pohádky před/za úlohou v čísle"""
@ -1389,6 +1492,7 @@ class MezicisloNode(TreeNode):
# TODO: Využít TreeLib
def aktualizuj_nazev(self):
from seminar.treelib import safe_pred
if safe_pred(self) is not None:
if (self.prev.get_real_instance_class() != CisloNode and
self.prev.get_real_instance_class() != MezicisloNode):
@ -1503,7 +1607,7 @@ class TextNode(TreeNode):
verbose_name = 'Text (Node)'
verbose_name_plural = 'Text (Node)'
text = models.ForeignKey(Text,
on_delete=models.PROTECT,
on_delete=models.CASCADE,
verbose_name = 'text')
def aktualizuj_nazev(self):
@ -1536,7 +1640,7 @@ class ReseniNode(TreeNode):
verbose_name = 'reseni')
def aktualizuj_nazev(self):
self.nazev = "OtisteneReseniNode: "+str(self.reseni)
self.nazev = "ReseniNode: "+str(self.reseni)
def getOdkazStr(self):
return str(self.reseni)

7
seminar/permissions.py

@ -0,0 +1,7 @@
from rest_framework.permissions import BasePermission
class AllowWrite(BasePermission):
def has_permission(self, request, view):
return request.user.has_perm('auth.org')

BIN
seminar/static/images/no-picture.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
seminar/static/images/tema-bez-obrazku.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

18
seminar/static/seminar/treenode_editor.js

@ -0,0 +1,18 @@
function showSelectedItemForm(sel,id){
var option;
var name;
var div;
Array.from(sel.options).forEach(function(option){
console.log(option);
name = 'pridat-'+option.value+'-'+id;
div = document.getElementById(name);
console.log(div);
div.style.display = 'none';
});
name = sel.options[sel.selectedIndex].value;
name = 'pridat-'+name+'-'+id;
div = document.getElementById(name);
console.log(div);
div.style.display = 'block';
}

6
seminar/templates/seminar/archiv/base.html

@ -1,6 +0,0 @@
{% extends "base.html" %}
{% block menu_archiv %}selected{% endblock %}
{# zmena fotky #}{% block header %}archiv{% endblock %}

8
seminar/templates/seminar/archiv/cisla.html

@ -1,4 +1,4 @@
{% extends "seminar/archiv/base.html" %}
{% extends "base.html" %}
{% block content %}
<div>
@ -8,10 +8,6 @@
{% endblock %}{% endblock %}
</h2>
<!-- <div class='nahledy_cisel'>
{% autoescape off %}{{ nahledy }}{% endautoescape %}
</div>-->
{% for rocnik, url_png in object_list.items %}
<div class="rocnik_pole">
@ -33,7 +29,7 @@
</div>
</div>
<div class="flip-card-back">
<div class="flip-card-back" id="archiv">
<div class="popis_rocniku">
Jednotlivá čísla:
<ul>

97
seminar/templates/seminar/archiv/cislo-normal.html

@ -0,0 +1,97 @@
{% extends "seminar/archiv/base_cisla.html" %}
{# {% block content %}
<div>
<h1>
{% block nadpis1a %}{% block nadpis1b %}
Číslo {{ cislo }}
{% endblock %}{% endblock %}
</h1>
{% if cislo.pdf %}
<p><a href='{{ cislo.pdf.url }}'>Číslo v pdf</a>
{% endif %}
<p><a href='{{ cislo.rocnik.verejne_url }}'>Ročník {{ cislo.rocnik }}</a>
{% if v_cisle_zadane %}
<h2>Zadané problémy</h2>
<ul>
{% for p in v_cisle_zadane %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff 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 %}
{% endfor %}
</ul>
{% endif %}
{% if resene_problemy %}
<h2>Řešené problémy</h2>
<ul>
{% for p in resene_problemy %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff 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 %}
{% endfor %}
</ul>
{% endif %}
{% if user.is_staff %}
<div class="mam-org-only">
<h2> Orgovské odkazy </h2>
<ul>
<li><a href="obalky.pdf">Obálky (PDF)</a></li>
<li><a href="tituly.tex">Tituly (TeX)</a></li>
<li><a href="vysledkovka.tex">Výsledkovka (TeX)</a></li>
<li><a href="obalkovani">Obálkování</a></li>
</ul>
</div>
{% endif %}
{% if cislo.verejna_vysledkovka %}
<h2>Výsledkovka</h2>
{% else %}
{% if user.is_staff %}
<div class='mam-org-only'>
<h2>Výsledkovka (neveřejná)</h2>
{% endif %}
{% endif %}
{% if cislo.verejna_vysledkovka or user.is_staff %}
<table class='vysledkovka'>
<tr class='border-b'>
<th class='border-r'>#
<th class='border-r'>Jméno #}
{# problémy by měly být veřejné, když je veřejná výsledkovka #}
{# {% for p in problemy %}
<th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a>
{% endfor %}
<th class='border-r'>Za číslo</sup>
<th class='border-r'>Za ročník
<th class='border-r'>Odjakživa
{% for rv in radky_vysledkovky %}
<tr>
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}
<th class='border-r'>
{% if rv.resitel.titul != "" %}
{{ rv.resitel.titul }}<sup>MM</sup>
{% endif %}
{{ rv.resitel.osoba.plne_jmeno }}
{% for b in rv.hlavni_problemy_body %}
<td class='border-r'>{{ b }}
{% endfor %}
<td class='border-r'>{{ rv.body_cislo }}
<td class='border-r'><b>{{ rv.body_rocnik }}</b>
<td class='border-r'>{{ rv.body_celkem_odjakziva }}
</tr>
{% endfor %}
</table>
{% endif %}
{% if not cislo.verejna_vysledkovka and user.is_staff %}
</div>
{% endif %}
</div>
{% endblock content %} #}

35
seminar/templates/seminar/archiv/cislo.html

@ -1,4 +1,5 @@
{% extends "seminar/archiv/base.html" %}
{% extends "base.html" %}
{% load render_bundle from webpack_loader %}
{% block content %}
<div>
@ -18,9 +19,9 @@
<h2>Zadané problémy</h2>
<ul>
{% for p in v_cisle_zadane %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff 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 %}
<li{% if user.je_org and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% 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.je_org or cislo.verejne %}</a>{% endif %}
{% endfor %}
</ul>
{% endif %}
@ -29,14 +30,14 @@
<h2>Řešené problémy</h2>
<ul>
{% for p in resene_problemy %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff 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 %}
<li{% if user.je_org and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% 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.je_org or cislo.verejne %}</a>{% endif %}
{% endfor %}
</ul>
{% endif %}
{% if user.is_staff %}
{% if user.je_org %}
<div class="mam-org-only">
<h2> Orgovské odkazy </h2>
<ul>
@ -44,21 +45,30 @@
<li><a href="tituly.tex">Tituly (TeX)</a></li>
<li><a href="vysledkovka.tex">Výsledkovka (TeX)</a></li>
<li><a href="obalkovani">Obálkování</a></li>
<li><a href="odmeny/{{prevcislo.rocnik.rocnik}}.{{prevcislo.poradi}}/">Odměny</a></li>
</ul>
</div>
{% endif %}
<script id="vuedata" type="application/json">{"treenode":{{cislo.cislonode.id}}}</script>
<div id="app">
<app></app>
</div>
{% render_bundle 'chunk-vendors' %}
{% render_bundle 'vue_app_01' %}
{% if cislo.verejna_vysledkovka %}
<h2>Výsledkovka</h2>
{% else %}
{% if user.is_staff %}
{% if user.je_org %}
<div class='mam-org-only'>
<h2>Výsledkovka (neveřejná)</h2>
{% endif %}
{% endif %}
{% if cislo.verejna_vysledkovka or user.is_staff %}
{% if cislo.verejna_vysledkovka or user.je_org %}
<table class='vysledkovka'>
<tr class='border-b'>
<th class='border-r'>#
@ -66,7 +76,8 @@
{% for p in problemy %}
<th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a>
{% endfor %}
<th class='border-r'>Za číslo</sup>
{% if ostatni %}<th class='border-r'>Ostatní {% endif %}
<th class='border-r'>Za číslo
<th class='border-r'>Za ročník
<th class='border-r'>Odjakživa
{% for rv in radky_vysledkovky %}
@ -88,7 +99,7 @@
</table>
{% endif %}
{% if not cislo.verejna_vysledkovka and user.is_staff %}
{% if not cislo.verejna_vysledkovka and user.je_org %}
</div>
{% endif %}

2
seminar/templates/seminar/archiv/cislo_obalkovani.html

@ -1,4 +1,4 @@
{% extends "seminar/archiv/base.html" %}
{% extends "base.html" %}
{% block content %}
<h1>

15
seminar/templates/seminar/archiv/odmeny.html

@ -0,0 +1,15 @@
{% extends "base.html" %}
{% block content %}
<h1>
{% block nadpis1a %}{% block nadpis1b %}
Odměny {{ cislo }}
{% endblock %}{% endblock %}
</h1>
<ul>
{% for z in zmeny %}
<li> {{z.jmeno}}: {{z.ftitul}} &rarr; {{z.ttitul}}</li>
{% endfor %}
</ul>
{% endblock content %}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save