Browse Source

Merge branch 'data_migrations' into email

export_seznamu_prednasek
Jonas Havelka 4 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. 28
      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. 2
      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. 326
      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. 23
      mamweb/templates/base.html
  52. 102
      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. 51
      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. 164
      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 kvůli přihlášení
.htpasswd .htpasswd
# reversion kvůli historii objektů v reversion
**/reversion
# pro lidi, co programují v nástrojích od JetBrains
.idea

187
MIGRATIONS

@ -0,0 +1,187 @@
Jak zvládnout migrace na nový model:
- V mojí verzi databáze mají úlohy-Problémy typ "b'uloha'"
Log migrace na nový model:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, django_comments, flatpages, fluent_comments, galerie, korektury, prednasky, reversion, seminar, sessions, sites, sitetree, taggit, threadedcomments
Running migrations:
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying galerie.0008_auto_20190430_2340... OK
Applying galerie.0009_auto_20190610_2358... OK
Applying galerie.0010_auto_20200819_0947... OK
Applying korektury.0016_auto_20190430_2340... OK
Applying korektury.0017_auto_20190610_2358... OK
Applying prednasky.0011_auto_20190430_2340... OK
Applying prednasky.0012_auto_20190610_2358... OK
Applying seminar.0049_auto_20190430_2354... OK
Applying seminar.0050_auto_20190510_2228... OK
Applying seminar.0051_resitel_to_osoba... OK
Applying seminar.0052_user_to_organizator... OK
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2004-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1998-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2017-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2017-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2014-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2011-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2013-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2004-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2013-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2012-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2007-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2011-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2009-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2009-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2008-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2005-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2015-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2001-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2010-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2008-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2006-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2002-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2005-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1999-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2003-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2000-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2002-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2001-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1996-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2000-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (1999-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (1996-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1994-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2012-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2016-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2018-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2014-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2019-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2006-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (1995-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_do received a naive datetime (2007-12-31 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2015-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2016-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2018-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2019-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
/aux/akce/mam/www/mamweb-test/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Organizator.organizuje_od received a naive datetime (2020-01-01 00:00:00) while time zone support is active.
RuntimeWarning)
Applying seminar.0053_organizator_organizuje_od_do... OK
Applying seminar.0055_smazat_nemigrovane_zastarale_veci... OK
Applying seminar.0056_vrcholy_pro_rocniky_a_cisla... OK
Applying seminar.0057_reseni_to_reseni_hodnoceni...!!!!!!!!!!!!!!!
31397 Reseni object (31397)
!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!
31396 Reseni object (31396)
!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!
31395 Reseni object (31395)
!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!
31394 Reseni object (31394)
!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!
31393 Reseni object (31393)
!!!!!!!!!!!!!!!
OK
Applying seminar.0058_problem_to_uloha_tema_clanek... OK
Applying seminar.fix_0058... OK
Applying seminar.0059_vytvorit_pohadkanode... OK
Applying seminar.0060_spoj_stromy... OK
Applying seminar.0061_kill_frankenstein... OK
Applying seminar.0062_redukce_modelu_pohadky... OK
Applying seminar.0063_procisteni_migraci... OK
Applying seminar.0064_auto_20190610_2358... OK
Applying seminar.0065_treenode_polymorphic_ctype... OK
Applying seminar.0066_problem_polymorphic_ctype... OK
Applying seminar.0067_auto_20190814_0805... OK
Applying seminar.0068_treenode_nazev... OK
Applying seminar.0069_auto_20191120_2115... OK
Applying seminar.0070_auto_20191120_2357... OK
Applying seminar.0071_remove_nastaveni_aktualni_rocnik... OK
Applying seminar.0072_auto_20191204_2257... OK
Applying seminar.0073_copy_osoba_email_to_user_email... OK
Applying seminar.0074_auto_20200228_1401... OK
Applying seminar.0075_auto_20200228_2010... OK
Applying seminar.0076_auto_20200228_2013... OK
Applying seminar.0077_auto_20200318_2146... OK
Applying seminar.0078_otistenereseninode... OK
Applying seminar.0079_clanek_resitelsky... OK
Applying seminar.0080_zruseni_claneknode_a_konferanode... OK
Applying seminar.0081_auto_20200408_2221... OK
Applying seminar.0082_auto_20200506_1951... OK
Applying seminar.0083_auto_20200506_1952... OK
WARNING 2020-08-20 00:49:07,941 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2215)
WARNING 2020-08-20 00:49:07,953 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2221)
WARNING 2020-08-20 00:49:07,959 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2212)
WARNING 2020-08-20 00:49:07,965 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1955)
WARNING 2020-08-20 00:49:07,968 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2027)
WARNING 2020-08-20 00:49:07,971 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1981)
WARNING 2020-08-20 00:49:07,974 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1970)
WARNING 2020-08-20 00:49:07,978 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2001)
WARNING 2020-08-20 00:49:07,981 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2004)
WARNING 2020-08-20 00:49:07,984 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1941)
WARNING 2020-08-20 00:49:07,990 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2024)
WARNING 2020-08-20 00:49:07,993 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2031)
WARNING 2020-08-20 00:49:07,997 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2211)
WARNING 2020-08-20 00:49:08,005 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2073)
WARNING 2020-08-20 00:49:08,017 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2018)
WARNING 2020-08-20 00:49:08,022 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2222)
WARNING 2020-08-20 00:49:08,028 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (1953)
WARNING 2020-08-20 00:49:08,034 0084_clanek_cislo: Více než jedno řešení pro článek Clanek object (2026)
Applying seminar.0084_clanek_cislo... OK
Applying seminar.0085_nepovinna_prezdivka... OK
Applying seminar.0086_auto_20200819_0959... OK
Applying sitetree.0001_initial... OK
Applying taggit.0003_taggeditem_add_unique_index... OK

16
Makefile

@ -34,6 +34,8 @@ install_web: venv_check
pip install --upgrade setuptools pip install --upgrade setuptools
# Instalace závislostí webu # Instalace závislostí webu
pip install -r requirements.txt --upgrade pip install -r requirements.txt --upgrade
# Po vygenerování testdat spusť ./manage.py loaddata data/*, ať máš menu a další modely
:x
install_venv: install_venv:
${VENV} ${VENV_PATH} ${VENV} ${VENV_PATH}
@ -65,7 +67,7 @@ schema_all.pdf: venv_check
# Deploy to current *mamweb-test* directory # Deploy to current *mamweb-test* directory
deploy_test: venv_check deploy_test: venv_check
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi @if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
@if [ `pwd` != "/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi @if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-test" ]; then echo "Only possible in directory mamweb-test"; exit 1; fi
@echo "Installing version from origin/test ..." @echo "Installing version from origin/test ..."
git pull origin test git pull origin test
git clean -f git clean -f
@ -81,9 +83,9 @@ deploy_test: venv_check
# Deploy to current *mamweb-prod* directory # Deploy to current *mamweb-prod* directory
deploy_prod: venv_check deploy_prod: venv_check
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi @if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
@if [ `pwd` != "/akce/mam/www/mamweb-prod" ]; then echo "Only possible in /akce/mam/www/mamweb-prod"; exit 1; fi @if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-prod" ]; then echo "Only possible in directory mamweb-prod"; exit 1; fi
@echo "Backing up production DB ..." @echo "Backing up production DB ..."
( cd .. && ./backup_prod_db.sh ) ( cd -P .. && ./backup_prod_db.sh )
@echo "Installing version from origin/master ..." @echo "Installing version from origin/master ..."
git pull origin master git pull origin master
git clean -f git clean -f
@ -109,7 +111,7 @@ sync_prod_flatpages: venv_check
# Sync test media directory with production # Sync test media directory with production
sync_test_media: sync_test_media:
@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi @if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
@if [ `pwd` != "/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi @if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi
rsync -av --delete /akce/mam/www/mamweb-prod/media/ ./media rsync -av --delete /akce/mam/www/mamweb-prod/media/ ./media
# Sync test database with production database # Sync test database with production database
@ -139,3 +141,9 @@ sync_local_db:
# Sync database and media. See above lines # Sync database and media. See above lines
sync_local: sync_local_media sync_local_db 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): class GalerieInline(admin.TabularInline):
model = Obrazek model = Obrazek
fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag'] fields = ['obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag', 'poradi']
readonly_fields = ['nazev', 'obrazek_maly_tag'] readonly_fields = ['nazev', 'obrazek_maly_tag']
formfield_overrides = { formfield_overrides = {
models.TextField: {'widget': forms.TextInput}, models.TextField: {'widget': forms.TextInput},
} }
class ObrazekAdmin(admin.ModelAdmin): class ObrazekAdmin(admin.ModelAdmin):
list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag') list_display = ('obrazek_velky', 'nazev', 'popis', 'obrazek_maly_tag', 'poradi')
search_fields = ['nazev','popis'] search_fields = ['nazev','popis']
class GalerieAdmin(admin.ModelAdmin): class GalerieAdmin(admin.ModelAdmin):

18
galerie/migrations/0010_auto_20200819_0947.py

@ -0,0 +1,18 @@
# Generated by Django 2.2.15 on 2020-08-19 07:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('galerie', '0009_auto_20190610_2358'),
]
operations = [
migrations.AlterField(
model_name='galerie',
name='poradi',
field=models.IntegerField(blank=True, default=0, verbose_name='Pořadí'),
),
]

2
galerie/models.py

@ -94,7 +94,7 @@ class Galerie(models.Model):
on_delete=models.SET_NULL) on_delete=models.SET_NULL)
soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True, soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True,
on_delete=models.PROTECT) on_delete=models.PROTECT)
poradi = models.IntegerField('Pořadí', blank = True, null = True) poradi = models.IntegerField('Pořadí', blank = True, null = False, default = 0)
def __str__(self): def __str__(self):
return self.nazev return self.nazev

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 %} {% block nadpis1a %}

6
galerie/templates/galerie/GalerieNahled.html

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

2
galerie/templates/galerie/GalerieNew.html

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

7
galerie/urls.py

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

28
galerie/views.py

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

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

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 %} {% load staticfiles %}
{% block title %} Nápověda ke korigovátku {% endblock title %} {% block title %} Nápověda ke korigovátku {% endblock title %}

4
korektury/templates/korektury/opraf.html

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

2
korektury/templates/korektury/seznam.html

@ -1,4 +1,4 @@
{% extends "korektury/base.html" %} {% extends "base.html" %}
{% load staticfiles %} {% load staticfiles %}
{% block script%} {% 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.urls import path
from django.contrib.auth.decorators import user_passes_test from seminar.utils import org_required
from . import views from . import views
staff_member_required = user_passes_test(lambda u: u.is_staff)
urlpatterns = [ urlpatterns = [
path('korektury/', staff_member_required(views.KorekturyListView.as_view()), name='korektury-list'), path('korektury/', org_required(views.KorekturyAktualniListView.as_view()), name='korektury_list'),
path('korektury/<int:pdf>/', staff_member_required(views.KorekturyView.as_view()), name='korektury'), path('korektury/zastarale/', org_required(views.KorekturyZastaraleListView.as_view()), name='korektury_stare_list'),
path('korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), path('korektury/<int:pdf>/', org_required(views.KorekturyView.as_view()), name='korektury'),
path('korektury/help/', org_required(views.KorekturyHelpView.as_view()), name='korektury-help'),
] ]

26
korektury/views.py

@ -29,6 +29,28 @@ class KorekturyListView(generic.ListView):
) )
template_name = 'korektury/seznam.html' template_name = 'korektury/seznam.html'
class KorekturyAktualniListView(KorekturyListView):
def get_queryset(self, *args, **kwargs):
queryset=super(KorekturyAktualniListView,self).get_queryset()
queryset=queryset.exclude(status="zastarale")
return queryset
def get_context_data(self, **kwargs):
context = super(KorekturyAktualniListView,self).get_context_data(**kwargs)
context['selected'] = 'aktualni'
return context
class KorekturyZastaraleListView(KorekturyListView):
def get_queryset(self, *args, **kwargs):
queryset=super(KorekturyZastaraleListView,self).get_queryset()
queryset=queryset.filter(status="zastarale")
return queryset
def get_context_data(self, **kwargs):
context = super(KorekturyZastaraleListView,self).get_context_data(**kwargs)
context['selected'] = 'zastarale'
return context
### Korektury ### Korektury
class KorekturyView(generic.TemplateView): class KorekturyView(generic.TemplateView):
model = Oprava model = Oprava
@ -130,7 +152,9 @@ class KorekturyView(generic.TemplateView):
''' '''
# parametry e-mailu # parametry e-mailu
odkaz = "https://mam.mff.cuni.cz/korektury/{}/".format(oprava.pdf.pk) #odkaz = "https://mam.mff.cuni.cz/korektury/{}/".format(oprava.pdf.pk)
from django.urls import reverse
odkaz = self.request.build_absolute_uri(reverse('korektury', kwargs={'pdf': oprava.pdf.pk}))
from_email = 'korekturovatko@mam.mff.cuni.cz' from_email = 'korekturovatko@mam.mff.cuni.cz'
subject = 'Nová korektura od {} v {}'.format(autor, subject = 'Nová korektura od {} v {}'.format(autor,
oprava.pdf.nazev) oprava.pdf.nazev)

2
mamweb/admin.py

@ -8,6 +8,7 @@ from django.contrib.flatpages.admin import FlatpageForm as FlatpageFormOld
from django import forms from django import forms
from ckeditor_uploader.widgets import CKEditorUploadingWidget from ckeditor_uploader.widgets import CKEditorUploadingWidget
class FlatpageForm(FlatpageFormOld): class FlatpageForm(FlatpageFormOld):
content = forms.CharField(widget=CKEditorUploadingWidget()) content = forms.CharField(widget=CKEditorUploadingWidget())
class Meta: class Meta:
@ -22,3 +23,4 @@ class FlatPageAdmin(FlatPageAdminOld):
# We have to unregister the normal admin, and then reregister ours # We have to unregister the normal admin, and then reregister ours
admin.site.unregister(FlatPage) admin.site.unregister(FlatPage)
admin.site.register(FlatPage, FlatPageAdmin) 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.template.context_processors.request',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'sekizai.context_processors.sekizai', 'sekizai.context_processors.sekizai',
'mamweb.context_processors.vzhled', 'header_fotky.context_processors.vzhled',
) )
}, },
}, },
@ -98,7 +98,7 @@ INSTALLED_APPS = (
# Utilities # Utilities
'sekizai', 'sekizai',
# 'reversion', 'reversion',
'django_countries', 'django_countries',
'solo', 'solo',
'ckeditor', 'ckeditor',
@ -121,12 +121,17 @@ INSTALLED_APPS = (
'polymorphic', 'polymorphic',
'webpack_loader',
'rest_framework',
'rest_framework.authtoken',
# MaMweb # MaMweb
'mamweb', 'mamweb',
'seminar', 'seminar',
'galerie', 'galerie',
'korektury', 'korektury',
'prednasky', 'prednasky',
'header_fotky',
# Admin upravy: # Admin upravy:
@ -136,7 +141,6 @@ INSTALLED_APPS = (
# 'admin_tools.theming', # 'admin_tools.theming',
# 'admin_tools.menu', # 'admin_tools.menu',
# 'admin_tools.dashboard', # 'admin_tools.dashboard',
'flat',
'django.contrib.admin', 'django.contrib.admin',
) )
@ -179,10 +183,32 @@ CKEDITOR_CONFIGS = {
# 'toolbar': 'full', # 'toolbar': 'full',
'height': '40em', 'height': '40em',
'width': '100%', '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 # Comments
@ -248,7 +274,7 @@ LOGGING = {
'class': 'django.utils.log.AdminEmailHandler', 'class': 'django.utils.log.AdminEmailHandler',
'formatter': 'verbose', 'formatter': 'verbose',
}, },
'mail_registraion': { 'mail_registration': {
'level': 'WARN', 'level': 'WARN',
'class': 'django.utils.log.AdminEmailHandler', 'class': 'django.utils.log.AdminEmailHandler',
'formatter': 'verbose', 'formatter': 'verbose',
@ -269,6 +295,9 @@ LOGGING = {
}, },
} }
# Permissions for uploads
FILE_UPLOAD_PERMISSIONS = 0o0644
# MaM specific # MaM specific
SEMINAR_RESENI_DIR = os.path.join('reseni') 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 TEMPLATES[0]['OPTIONS']['debug'] = True
ALLOWED_HOSTS = ['127.0.0.1'] ALLOWED_HOSTS = ['127.0.0.1', '192.168.43.34']
# Database # Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases # https://docs.djangoproject.com/en/1.7/ref/settings/#databases
@ -94,4 +94,6 @@ LOGGING = {
# set to 'DEBUG' for EXTRA verbose output # set to 'DEBUG' for EXTRA verbose output
# LOGGING['handlers']['console']['level'] = 'INFO' # LOGGING['handlers']['console']['level'] = 'INFO'
# E-maily posílat chceme, ale do terminálu :-)
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SEND_EMAIL_NOTIFICATIONS = True

4
mamweb/settings_test.py

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

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;
}

326
mamweb/static/css/mamweb.css

@ -101,6 +101,26 @@ h6 {
color: black; 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 { .org-logged-in .mam-text-plugin {
border: dashed 1px #6a0043; border: dashed 1px #6a0043;
@ -193,38 +213,6 @@ h1 {
top: 58px; 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 { #header img.logo {
position: absolute center; position: absolute center;
width: 100%; width: 100%;
@ -318,6 +306,14 @@ ul.submenu li>a:hover {
color: black; color: black;
} }
ul.menu li.active>a {
color: #f9d59e;
}
ul.submenu li.active>a {
color: black;
}
/* konec nového menu */ /* konec nového menu */
div.novinky_name { div.novinky_name {
@ -351,6 +347,10 @@ div.zadani_azad_termin {
bottom: 0px; bottom: 0px;
} }
#footer p.license a {
color: #333;
}
p.license-mobile { p.license-mobile {
display: none; display: none;
} }
@ -395,13 +395,82 @@ input[type="file"] {
} }
.field-with-comment:hover span.field-comment{ .field-with-comment:hover span.field-comment{
display:block; display: block;
} }
input { input {
margin: 5px; 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 * Zmenšování displeje
***********************/ ***********************/
@ -431,42 +500,22 @@ input {
width: 100%; width: 100%;
} }
div.novinky{ ul.menu {
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%; font-size: 90%;
margin-top: -7px; margin-top: -7px;
} }
ul.menu li { ul.menu li {
margin-top: 10px; /* posunutí textu hlavního menu níže */ margin-top: 10px; /* posunutí textu hlavního menu níže */
} }
ul.submenu li { ul.submenu li {
margin-top: 0px; /* aby se spolu s textem hlavního menu neposunoval níže i text submenu */ margin-top: 0px; /* aby se spolu s textem hlavního menu neposunoval níže i text submenu */
} }
ul.submenu { ul.submenu {
margin-top: 8px; /* mezera mezi hlavním menu a submenu */ margin-top: 8px; /* mezera mezi hlavním menu a submenu */
} }
} }
@ -498,11 +547,53 @@ ul.submenu {
display: inline-grid; display: inline-grid;
max-width: 300px; 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 */ /* malý tablet, mobil */
@media (max-width: 650px) { @media (max-width: 650px) {
.no-mobile{
display: none;
}
#hide-if-small.login-bar-flatpage { #hide-if-small.login-bar-flatpage {
display: none; display: none;
} }
@ -639,34 +730,59 @@ ul.submenu {
text-align: justify; text-align: justify;
} }
div.novinky { table.form td, table.form tr {
max-width: 100%; display: inherit;
float: none;
} }
div.graf { /* titulni stranka */
.titulnistrana {
display: block;
}
.graf {
padding-top: 40px;
}
.titulnistrana_obsah {
width: 100%; width: 100%;
} }
table.form td, table.form tr { .vitej_titulka, .temata_titulka {
display: inherit; width: 100%;
padding: 10px;
display: block;
}
.titulnistrana_novinky {
width: 100%;
padding: 10px;
} }
} }
/*stránka organizátorů*/ /*stránka organizátorů*/
div.seznam_orgu { div.seznam_orgu, div.rozcestnik_temat {
text-align: center; text-align: center;
padding-bottom: 10px;
} }
div.org_pole, div.rocnik_pole { div.org_pole, div.rocnik_pole, div.tema_pole {
display: inline-block; display: inline-block;
width: 30%; width: 30%;
min-width: 300px; min-width: 300px;
text-align: center; text-align: center;
} }
div.tema_pole {
display: inline-block;
width: 40%;
min-width: 350px;
padding-bottom: 20px;
text-align: center;
}
div.cislo_pole { div.cislo_pole {
display: inline-block; display: inline-block;
width: 15%; width: 15%;
@ -709,6 +825,11 @@ div.org_email {
height: 205px; height: 205px;
} }
#tema-rozcestnik.flip-card {
width: 300px;
height: 300px;
}
/* This container is needed to position the front and back side */ /* This container is needed to position the front and back side */
.flip-card-inner { .flip-card-inner {
position: relative; position: relative;
@ -732,12 +853,8 @@ div.org_email {
backface-visibility: hidden; 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%; width: 100%;
height: 100%; height: 100%;
@ -752,6 +869,10 @@ div.flip-card-foto img {
padding-top: 20px; padding-top: 20px;
} }
#archiv.flip-card-back {
background-color: white;
}
/* karty archiv */ /* karty archiv */
div.popis_rocniku { 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 { ul.form {
list-style-type: none; list-style-type: none;
padding-left: 0px; padding-left: 0px;
@ -1012,3 +1095,20 @@ p.gdpr {
div.gdpr { div.gdpr {
font-size: 6pt; 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

23
mamweb/templates/base.html

@ -6,13 +6,14 @@
<title>{% block title %}{% block nadpis1a %}{% endblock %} – Korespondenční seminář M&amp;M{% endblock title %}</title> <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"> <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"> <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-theme.css' %}" rel="stylesheet">
<link href="{% static 'css/bootstrap.css' %}" rel="stylesheet"> <link href="{% static 'css/bootstrap.css' %}" rel="stylesheet">
<link href="{% static 'css/mamweb.css' %}" rel="stylesheet"> <link href="{% static 'css/mamweb.css' %}" rel="stylesheet">
<link href="{% static 'css/prettyPhoto.css' %}" rel="stylesheet" type="text/css" media="screen" charset="utf-8" /> <link href="{% static 'css/prettyPhoto.css' %}" rel="stylesheet" type="text/css" media="screen" charset="utf-8" />
<script src="{% static 'js/jquery-1.11.1.js' %}"></script> <script src="{% static 'js/jquery-1.11.1.js' %}"></script>
<script src="{% static '/jquery-3.4.1.js' %}"></script> <script src="{% static 'js/jquery-3.4.1.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'fluent_comments/css/ajaxcomments.css' %}" /> <link rel="stylesheet" type="text/css" href="{% static 'fluent_comments/css/ajaxcomments.css' %}" />
<script type="text/javascript" src="{% static 'fluent_comments/js/ajaxcomments.js' %}"></script> <script type="text/javascript" src="{% static 'fluent_comments/js/ajaxcomments.js' %}"></script>
@ -56,13 +57,17 @@
<div class='col-md-12'> <div class='col-md-12'>
<a href='/'> <a href='/'>
<div id="title" >M&M - korespondenční seminář a časopis MFF&nbspUK</div> <div id="title" >M&M - korespondenční seminář a časopis MFF&nbspUK</div>
<div id="header" class="{% if noc %}NOC{% endif %}{% block header %}{% endblock %}"> <div id="header">
<img class="logo" src="{% static 'images/logo.svg' %}" /> <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' %}" /> <img class="logo-mobile" src="{% static 'images/logo-mobile.svg' %}" />
</div> </div>
</a> </a>
</div> </div>
</div> </div>
<div class='row'> <div class='row'>
<div class='col-md-12'> <div class='col-md-12'>
@ -72,6 +77,9 @@
{# ========= MENU MOBILE ========== #} {# ========= MENU MOBILE ========== #}
</div>
</div>
<!--Navbar--> <!--Navbar-->
<nav class="nav-button"> <nav class="nav-button">
@ -94,21 +102,24 @@
{# ========= END MENU ========== #} {# ========= END MENU ========== #}
<div class='row'>
<div class='row content'> <div class='row content'>
<div class='col-md-12'> <div class='col-md-12'>
{% block content %} {% block content %}
{% endblock content %} {% endblock content %}
</div> </div>
</div> </div>
</div>
<div class='row'> <div class='row'>
<div class='col-md-12'> <div class='col-md-12'>
<div id="footer"> <div id="footer">
<p class="license">S obsahem webu M&amp;M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p> <p class="license">S obsahem webu M&amp;M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p>
</div> </div>
<p class="license-mobile">Korespondenční seminář M&M organizují převážně studenti <a herf="https://www.mff.cuni.cz/">MFF UK</a>. Organizaci semináře a vydávání časopisu podporuje <a href="https://jcmf.cz/">Jednota českých matematiků a fyziků</a>. S obsahem webu M&amp;M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p> <p class="license-mobile">Korespondenční seminář M&M organizují převážně studenti <a href="https://www.mff.cuni.cz/">MFF UK</a>. Organizaci semináře a vydávání časopisu podporuje <a href="https://jcmf.cz/">Jednota českých matematiků a fyziků</a>. S obsahem webu M&amp;M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p>
</div> </div>
</div> </div>
</div> </div>
<script src="{% static 'js/bootstrap.js' %}"></script> <script src="{% static 'js/bootstrap.js' %}"></script>

102
mamweb/templates/flatpages/default.html

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

26
mamweb/templates/logo.html

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

4
mamweb/templates/menu.html

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

4
mamweb/templates/menu_mobile.html

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

5
mamweb/urls.py

@ -6,6 +6,8 @@ from django.views.generic.base import TemplateView
from django import views from django import views
from django.urls import path # As per docs. from django.urls import path # As per docs.
from .routers import router
urlpatterns = [ urlpatterns = [
# Admin a nastroje # Admin a nastroje
@ -25,6 +27,9 @@ urlpatterns = [
path('comments_dj/', include('django_comments.urls')), path('comments_dj/', include('django_comments.urls')),
path('comments_fl/', include('fluent_comments.urls')), path('comments_fl/', include('fluent_comments.urls')),
# REST API
path('api/', include(router.urls)),
] ]
# This is only needed when using runserver. # 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/ home = /akce/mam/www/mamweb-prod/
module = mamweb.wsgi module = mamweb.wsgi
plugin = python plugin = python3
virtualenv = env virtualenv = env
master = True master = True
vacuum = True vacuum = True

2
mamweb_test.ini

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

10
prednasky/templates/prednasky/base.html

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

6
prednasky/templates/prednasky/metaseznam_prednasek.html

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

6
prednasky/templates/prednasky/seznam_prednasek.html

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

14
prednasky/templates/prednasky/seznam_prednasek_export.txt

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

27
prednasky/urls.py

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

51
prednasky/views.py

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

3
requirements.txt

@ -28,6 +28,9 @@ django-imagekit
django-polymorphic django-polymorphic
django-sitetree django-sitetree
django_reverse_admin django_reverse_admin
django-rest-framework
django-webpack-loader
django-rest-polymorphic
# Comments # Comments
akismet==1.0.1 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 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 polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
from reversion.admin import VersionAdmin from reversion.admin import VersionAdmin
from django_reverse_admin import ReverseModelAdmin from django_reverse_admin import ReverseModelAdmin
from solo.admin import SingletonModelAdmin
# Todo: reversion # Todo: reversion
@ -12,12 +17,10 @@ admin.site.register(m.Skola)
admin.site.register(m.Prijemce) admin.site.register(m.Prijemce)
admin.site.register(m.Rocnik) admin.site.register(m.Rocnik)
admin.site.register(m.Cislo) admin.site.register(m.Cislo)
admin.site.register(m.Organizator)
admin.site.register(m.Soustredeni)
@admin.register(m.Osoba) @admin.register(m.Osoba)
class OsobaAdmin(admin.ModelAdmin): class OsobaAdmin(admin.ModelAdmin):
actions = ['synchronizuj_maily'] actions = ['synchronizuj_maily', 'udelej_orgem']
def synchronizuj_maily(self, request, queryset): def synchronizuj_maily(self, request, queryset):
for o in queryset: for o in queryset:
@ -28,6 +31,27 @@ class OsobaAdmin(admin.ModelAdmin):
self.message_user(request, "E-maily synchronizovány.") self.message_user(request, "E-maily synchronizovány.")
synchronizuj_maily.short_description = "Synchronizuj vybraným osobám e-maily do uživatelů" 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) @admin.register(m.Problem)
class ProblemAdmin(PolymorphicParentModelAdmin): class ProblemAdmin(PolymorphicParentModelAdmin):
base_model = m.Problem base_model = m.Problem
@ -58,15 +82,55 @@ class KonferaAdmin(PolymorphicChildModelAdmin):
base_model = m.Konfera base_model = m.Konfera
show_in_index = True show_in_index = True
class TextAdminInline(admin.TabularInline): class TextAdminInline(admin.TabularInline):
model = m.Text model = m.Text
formfield_overrides = {
models.TextField: {'widget': widgets.TextInput}
}
exclude = ['text_zkraceny_set','text_zkraceny'] exclude = ['text_zkraceny_set','text_zkraceny']
admin.site.register(m.Text) admin.site.register(m.Text)
class ResitelInline(admin.TabularInline): class ResitelInline(admin.TabularInline):
model = m.Resitel model = m.Resitel
extra = 1 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): class PrilohaReseniInline(admin.TabularInline):
model = m.PrilohaReseni model = m.PrilohaReseni
@ -76,6 +140,7 @@ admin.site.register(m.PrilohaReseni)
class Reseni_ResiteleInline(admin.TabularInline): class Reseni_ResiteleInline(admin.TabularInline):
model = m.Reseni_Resitele model = m.Reseni_Resitele
@admin.register(m.Reseni) @admin.register(m.Reseni)
class ReseniAdmin(ReverseModelAdmin): class ReseniAdmin(ReverseModelAdmin):
base_model = m.Reseni base_model = m.Reseni
@ -90,7 +155,6 @@ admin.site.register(m.Hodnoceni)
admin.site.register(m.Pohadka) admin.site.register(m.Pohadka)
admin.site.register(m.Obrazek) admin.site.register(m.Obrazek)
# Polymorfismus pro stromy # Polymorfismus pro stromy
# TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html # TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html
@ -106,6 +170,8 @@ class TreeNodeAdmin(PolymorphicParentModelAdmin):
m.PohadkaNode, m.PohadkaNode,
m.UlohaVzorakNode, m.UlohaVzorakNode,
m.TextNode, m.TextNode,
m.CastNode,
m.OrgTextNode,
] ]
actions = ['aktualizuj_nazvy'] actions = ['aktualizuj_nazvy']
@ -159,6 +225,17 @@ class TextNodeAdmin(PolymorphicChildModelAdmin):
base_model = m.TextNode base_model = m.TextNode
show_in_index = True 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) admin.site.register(m.Novinky)

34
seminar/forms.py

@ -10,6 +10,21 @@ import seminar.models as m
from datetime import date from datetime import date
import logging 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): class LoginForm(forms.Form):
username = forms.CharField(label='Přihlašovací jméno', username = forms.CharField(label='Přihlašovací jméno',
max_length=256, max_length=256,
@ -42,8 +57,8 @@ class PrihlaskaForm(forms.Form):
pohlavi_muz = forms.ChoiceField(label='Pohlaví', pohlavi_muz = forms.ChoiceField(label='Pohlaví',
choices = ((True,'muž'),(False,'žena')), required=True) choices = ((True,'muž'),(False,'žena')), required=True)
email = forms.EmailField(label='E-mail',max_length=256, required=True) email = forms.EmailField(label='E-mail',max_length=256, required=True)
telefon = forms.CharField(label='Telefon',max_length=256, required=False) telefon = forms.CharField(widget=TelInput(),label='Telefon',max_length=256, required=False)
datum_narozeni = forms.DateField(label='Datum narození', required=False) datum_narozeni = forms.DateField(widget=DateInput(),label='Datum narození', required=False)
ulice = forms.CharField(label='Ulice', max_length=256, required=False) ulice = forms.CharField(label='Ulice', max_length=256, required=False)
mesto = forms.CharField(label='Město', 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) psc = forms.CharField(label='PSČ', max_length=32, required=False)
@ -74,6 +89,8 @@ class PrihlaskaForm(forms.Form):
max_value=date.today().year+8, max_value=date.today().year+8,
required=True) required=True)
zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, 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) 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) 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í', pohlavi_muz = forms.ChoiceField(label='Pohlaví',
choices = ((True,'muž'),(False,'žena')), required=True) choices = ((True,'muž'),(False,'žena')), required=True)
email = forms.EmailField(label='E-mail',max_length=256, required=True) email = forms.EmailField(label='E-mail',max_length=256, required=True)
telefon = forms.CharField(label='Telefon',max_length=256, required=False) telefon = forms.CharField(widget=TelInput(),label='Telefon',max_length=256, required=False)
datum_narozeni = forms.DateField(label='Datum narození', required=False) datum_narozeni = forms.DateField(widget=DateInput(),label='Datum narození', required=False)
ulice = forms.CharField(label='Ulice', max_length=256, required=False) ulice = forms.CharField(label='Ulice', max_length=256, required=False)
mesto = forms.CharField(label='Město', 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) psc = forms.CharField(label='PSČ', max_length=32, required=False)
@ -167,6 +184,8 @@ class ProfileEditForm(forms.Form):
max_value=date.today().year+8, max_value=date.today().year+8,
required=True) required=True)
zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, 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) spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
# def clean_username(self): # def clean_username(self):
# err_logger = logging.getLogger('seminar.prihlaska.problem') # 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í', #resitele = models.ManyToManyField(Resitel, verbose_name='autoři řešení',
# help_text='Seznam autorů řešení', through='Reseni_Resitele') # 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) #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 -*- # -*- coding: utf-8 -*-
from django.core.management.base import NoArgsCommand from django.core.management.base import BaseCommand
from django.contrib.sessions.models import Session from django.contrib.sessions.models import Session
from django.contrib.auth.models import User from django.contrib.auth.models import User
class Command(NoArgsCommand): class Command(BaseCommand):
u"""Vypiš username přihlášeného orga s daným session_key. u"""Vypiš username přihlášeného orga s daným session_key.
Příkaz pro manage.py, který ze vstupu přečte session_key (tak, jak je Příkaz pro manage.py, který ze vstupu přečte session_key (tak, jak je
uložen v cookie sessionid) a pokud session existuje a příslušný přihlášený uložen v cookie sessionid) a pokud session existuje a příslušný přihlášený
uživatel právo přihlásit se do admina, vypíše jeho username. uživatel právo přihlásit se do admina, vypíše jeho username.
""" """
def handle_noargs(self, **options): def handle(self, *args, **options):
session_key = raw_input() session_key = raw_input()
s = Session.objects.get(pk=session_key).get_decoded() s = Session.objects.get(pk=session_key).get_decoded()
user_id = s['_auth_user_id'] user_id = s['_auth_user_id']

21
seminar/migrations/0001_squashed_0067_auto_20190814_0805.py

@ -511,7 +511,7 @@ def vyrob_problemum_ctypes(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
atomic = False atomic = False
replaces = [('seminar', '0001_initial'), ('seminar', '0002_add_body_views'), ('seminar', '0003_add_skola_zs_ss'), ('seminar', '0004_add_old_dakos_id'), ('seminar', '0005_alter_problem_autor'), ('seminar', '0006_problem_add_timestamp'), ('seminar', '0007_problem_zamereni'), ('seminar', '0008_reseni_forma'), ('seminar', '0009_rename_imported_IDs'), ('seminar', '0010_alter_rok_maturity'), ('seminar', '0011_alter_timestamp_def'), ('seminar', '0012_remove_soustredeni_ucastnici'), ('seminar', '0013_soustredeni_ucastnici_through_model'), ('seminar', '0014_uprava_poznamek'), ('seminar', '0015_soustredeni_text'), ('seminar', '0016_texty_problemu'), ('seminar', '0017_texty_problemu_minor'), ('seminar', '0018_problemnavrh_problemzadany'), ('seminar', '0019_rocnik_ciselne'), ('seminar', '0020_indexy_a_razeni'), ('seminar', '0021_cislo_verejna_vysledkovka'), ('seminar', '0022_decimal_body'), ('seminar', '0023_add_novinky'), ('seminar', '0024_add_organizator'), ('seminar', '0025_zmena_cesty_nahravani_obrazku'), ('seminar', '0026_soustredeni_typ'), ('seminar', '0027_export_flag_a_typ_akce'), ('seminar', '0028_add_body_celkem_views'), ('seminar', '0029_fix_body_celkem_views'), ('seminar', '0030_add_vysledky'), ('seminar', '0031_cislo_pdf'), ('seminar', '0032_cislo_pdf_blank_typos'), ('seminar', '0033_organizator_studuje_popisek'), ('seminar', '0034_reseni_forma_default_email'), ('seminar', '0035_django_imagekit'), ('seminar', '0036_add_org_to_soustredeni'), ('seminar', '0037_prispevek'), ('seminar', '0038_change_meta_prispevek'), ('seminar', '0039_pohadka'), ('seminar', '0040_pohadka_nepovinny_autor'), ('seminar', '0041_konfery'), ('seminar', '0042_cislo_faze'), ('seminar', '0043_uprava_faze'), ('seminar', '0044_uprava_faze'), ('seminar', '0045_cislo_pridani_faze_nahrano'), ('seminar', '0042_auto_20161005_0847'), ('seminar', '0046_merge'), ('seminar', '0047_auto_20170120_2118'), ('seminar', '0048_add_cislo_datum_deadline_soustredeni'), ('seminar', '0049_auto_20190430_2354'), ('seminar', '0050_auto_20190510_2228'), ('seminar', '0051_resitel_to_osoba'), ('seminar', '0052_user_to_organizator'), ('seminar', '0053_organizator_organizuje_od_do'), ('seminar', '0055_smazat_nemigrovane_zastarale_veci'), ('seminar', '0056_vrcholy_pro_rocniky_a_cisla'), ('seminar', '0057_reseni_to_reseni_hodnoceni'), ('seminar', '0058_problem_to_uloha_tema_clanek'), ('seminar', '0059_vytvorit_pohadkanode'), ('seminar', '0060_spoj_stromy'), ('seminar', '0061_kill_frankenstein'), ('seminar', '0062_redukce_modelu_pohadky'), ('seminar', '0063_procisteni_migraci'), ('seminar', '0064_auto_20190610_2358'), ('seminar', '0065_treenode_polymorphic_ctype'), ('seminar', '0066_problem_polymorphic_ctype'), ('seminar', '0067_auto_20190814_0805')] replaces = [('seminar', '0001_initial'), ('seminar', '0002_add_body_views'), ('seminar', '0003_add_skola_zs_ss'), ('seminar', '0004_add_old_dakos_id'), ('seminar', '0005_alter_problem_autor'), ('seminar', '0006_problem_add_timestamp'), ('seminar', '0007_problem_zamereni'), ('seminar', '0008_reseni_forma'), ('seminar', '0009_rename_imported_IDs'), ('seminar', '0010_alter_rok_maturity'), ('seminar', '0011_alter_timestamp_def'), ('seminar', '0012_remove_soustredeni_ucastnici'), ('seminar', '0013_soustredeni_ucastnici_through_model'), ('seminar', '0014_uprava_poznamek'), ('seminar', '0015_soustredeni_text'), ('seminar', '0016_texty_problemu'), ('seminar', '0017_texty_problemu_minor'), ('seminar', '0018_problemnavrh_problemzadany'), ('seminar', '0019_rocnik_ciselne'), ('seminar', '0020_indexy_a_razeni'), ('seminar', '0021_cislo_verejna_vysledkovka'), ('seminar', '0022_decimal_body'), ('seminar', '0023_add_novinky'), ('seminar', '0024_add_organizator'), ('seminar', '0025_zmena_cesty_nahravani_obrazku'), ('seminar', '0026_soustredeni_typ'), ('seminar', '0027_export_flag_a_typ_akce'), ('seminar', '0028_add_body_celkem_views'), ('seminar', '0029_fix_body_celkem_views'), ('seminar', '0030_add_vysledky'), ('seminar', '0031_cislo_pdf'), ('seminar', '0032_cislo_pdf_blank_typos'), ('seminar', '0033_organizator_studuje_popisek'), ('seminar', '0034_reseni_forma_default_email'), ('seminar', '0035_django_imagekit'), ('seminar', '0036_add_org_to_soustredeni'), ('seminar', '0037_prispevek'), ('seminar', '0038_change_meta_prispevek'), ('seminar', '0039_pohadka'), ('seminar', '0040_pohadka_nepovinny_autor'), ('seminar', '0041_konfery'), ('seminar', '0042_cislo_faze'), ('seminar', '0043_uprava_faze'), ('seminar', '0044_uprava_faze'), ('seminar', '0045_cislo_pridani_faze_nahrano'), ('seminar', '0042_auto_20161005_0847'), ('seminar', '0046_merge'), ('seminar', '0047_auto_20170120_2118'), ('seminar', '0048_add_cislo_datum_deadline_soustredeni'), ('seminar', '0049_auto_20190430_2354'), ('seminar', '0050_auto_20190510_2228'), ('seminar', '0051_resitel_to_osoba'), ('seminar', '0052_user_to_organizator'), ('seminar', '0053_organizator_organizuje_od_do'), ('seminar', '0055_smazat_nemigrovane_zastarale_veci'), ('seminar', '0056_vrcholy_pro_rocniky_a_cisla'), ('seminar', '0057_reseni_to_reseni_hodnoceni'), ('seminar', '0058_problem_to_uloha_tema_clanek'), ('seminar', 'fix_0058'), ('seminar', '0059_vytvorit_pohadkanode'), ('seminar', '0060_spoj_stromy'), ('seminar', '0061_kill_frankenstein'), ('seminar', '0062_redukce_modelu_pohadky'), ('seminar', '0063_procisteni_migraci'), ('seminar', '0064_auto_20190610_2358'), ('seminar', '0065_treenode_polymorphic_ctype'), ('seminar', '0066_problem_polymorphic_ctype'), ('seminar', '0067_auto_20190814_0805')]
initial = True initial = True
@ -877,6 +877,7 @@ class Migration(migrations.Migration):
), ),
migrations.RunSQL( migrations.RunSQL(
sql='update seminar_rocniky set rocnik_n = cast (rocnik as integer)', sql='update seminar_rocniky set rocnik_n = cast (rocnik as integer)',
reverse_sql='update seminar_rocniky set rocnik_n = cast (rocnik as nvarchar(16))',
), ),
migrations.RemoveField( migrations.RemoveField(
model_name='rocnik', model_name='rocnik',
@ -1733,15 +1734,19 @@ class Migration(migrations.Migration):
# migr 0052 # migr 0052
migrations.RunPython( migrations.RunPython(
spoj_k_organizatorum_osoby, spoj_k_organizatorum_osoby,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
fix_problem, fix_problem,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
fix_pohadka, fix_pohadka,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
fix_novinka, fix_novinka,
reverse_code=migrations.RunPython.noop,
), ),
# migr 0053 # migr 0053
@ -1795,35 +1800,49 @@ class Migration(migrations.Migration):
# migr 0056 # migr 0056
migrations.RunPython( migrations.RunPython(
generuj_RocnikNody_a_CisloNody, generuj_RocnikNody_a_CisloNody,
reverse_code=migrations.RunPython.noop,
), ),
# migr 0057 # migr 0057
migrations.RunPython( migrations.RunPython(
reseni_to_Reseni, reseni_to_Reseni,
reverse_code=migrations.RunPython.noop,
), ),
# migr 0058 # migr 0058
migrations.RunPython( migrations.RunPython(
uloha_to_Uloha, uloha_to_Uloha,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
tema_to_Tema, tema_to_Tema,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
clanek_to_Clanek, clanek_to_Clanek,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RunPython( migrations.RunPython(
konfery_rucne, konfery_rucne,
reverse_code=migrations.RunPython.noop,
),
# migr "fix 0058"
migrations.RunSQL(
"update seminar_problemy set typ = 'uloha' where typ like 'b_uloha_';",
"update seminar_problemy set typ = 'uloha' where typ like 'b_uloha_';"
), ),
# migr 0059 # migr 0059
migrations.RunPython( migrations.RunPython(
vytvor_pohadkanode, vytvor_pohadkanode,
reverse_code=migrations.RunPython.noop,
), ),
# migr 0060 # migr 0060
migrations.RunPython( migrations.RunPython(
pokacej_les, pokacej_les,
reverse_code=migrations.RunPython.noop,
), ),
migrations.RemoveField( migrations.RemoveField(

3
seminar/migrations/0019_rocnik_ciselne.py

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

8
seminar/migrations/0052_user_to_organizator.py

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

2
seminar/migrations/0056_vrcholy_pro_rocniky_a_cisla.py

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

2
seminar/migrations/0057_reseni_to_reseni_hodnoceni.py

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

8
seminar/migrations/0058_problem_to_uloha_tema_clanek.py

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

4
seminar/migrations/0059_vytvorit_pohadkanode.py

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

2
seminar/migrations/0060_spoj_stromy.py

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

4
seminar/migrations/0065_treenode_polymorphic_ctype.py

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

4
seminar/migrations/0066_problem_polymorphic_ctype.py

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

2
seminar/migrations/0068_treenode_nazev.py

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

6
seminar/migrations/0080_zruseni_claneknode_a_konferanode.py

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

8
seminar/migrations/0084_clanek_cislo.py

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

17
seminar/migrations/0086_auto_20200819_0959.py

@ -0,0 +1,17 @@
# Generated by Django 2.2.15 on 2020-08-19 07:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0085_nepovinna_prezdivka'),
]
operations = [
migrations.AlterModelOptions(
name='organizator',
options={'ordering': ['-organizuje_do', 'osoba__jmeno', 'osoba__prijmeni'], 'verbose_name': 'Organizátor', 'verbose_name_plural': 'Organizátoři'},
),
]

49
seminar/migrations/0087_fix_polymorphism.py

@ -0,0 +1,49 @@
# Generated by Django 2.2.16 on 2020-09-04 12:06
from django.db import migrations
from logging import getLogger
log = getLogger(__name__)
# Oprava migrací 0065 a 0066, kde jsem špatně pochopil django-polymorphic
# Pomocná funkce -- děláme to samé pro obě polymorfní hierarchie
def fix_ctypes(parent: str, children, apps, schema_editor):
Parent = apps.get_model('seminar', parent)
ContentType = apps.get_model('contenttypes', 'ContentType')
# Nejdřív všechno smažeme:
Parent.objects.update(polymorphic_ctype=None)
# Opravíme děti
for clsname in children:
Model = apps.get_model('seminar', clsname)
ct = ContentType.objects.get_for_model(Model)
Model.objects.update(polymorphic_ctype=ct)
# Ostatní instance mají mít explicitně content type pro rodiče
new_ct = ContentType.objects.get_for_model(Parent)
for obj in Parent.objects.filter(polymorphic_ctype__isnull=True):
log.warn(f"{parent} \"{obj}\" neměl content type -- nejspíš to je instance přímo {parent}!")
obj.polymorphic_ctype=new_ct
obj.save()
def fix_treenode(apps, schema_editor):
children = ['RocnikNode', 'CisloNode', 'MezicisloNode', 'TemaVCisleNode',
'OrgTextNode', 'UlohaZadaniNode', 'UlohaVzorakNode', 'PohadkaNode',
'TextNode', 'CastNode', 'ReseniNode']
fix_ctypes("TreeNode", children, apps, schema_editor)
def fix_problem(apps, schema_editor):
children = ['Tema', 'Clanek', 'Uloha'] # FIXME: Konfera z nějakého důvodu tenhle field vůbec nemá, asi je to špatně.
fix_ctypes("Problem", children, apps, schema_editor)
class Migration(migrations.Migration):
dependencies = [
('seminar', '0086_auto_20200819_0959'),
]
operations = [
migrations.RunPython(fix_treenode, migrations.RunPython.noop),
migrations.RunPython(fix_problem, migrations.RunPython.noop),
]

35
seminar/migrations/0088_perm_org_a_ucastnik.py

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

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

164
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 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 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 from polymorphic.models import PolymorphicModel
@ -263,8 +262,10 @@ class Resitel(SeminarModelBase):
(ZASILAT_DO_SKOLY, 'Do školy'), (ZASILAT_DO_SKOLY, 'Do školy'),
(ZASILAT_NIKAM, 'Nikam'), (ZASILAT_NIKAM, 'Nikam'),
] ]
zasilat = models.CharField('kam zasílat', max_length=32, choices=ZASILAT_CHOICES, blank=False, default=ZASILAT_DOMU) 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, poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k řešiteli (plain text)') 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)) return sum(h.body for h in list(vsechna_hodnoceni))
def get_titul(self, celkove_body=None): def get_titul(self, body=None):
"Vrati titul" "Vrati titul jako řetězec."
if celkove_body is None:
celkove_body = self.vsechny_body() # 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
if celkove_body < 10: def __str__(self):
return '' return self.value[1]
elif celkove_body < 20:
return 'Bc.' @classmethod
elif celkove_body < 50: def z_bodu(cls, body):
return 'Mgr.' aktualni = cls.nic
elif celkove_body < 100: # TODO: ověřit, že to funguje
return 'Dr.' for titul in cls: # Kdyžtak použít __members__.items()
elif celkove_body < 200: if titul.value[0] <= body:
return 'Doc.' aktualni = titul
elif celkove_body < 500:
return 'Prof.'
else: else:
return 'Akad.' 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:
# 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): def __str__(self):
return self.osoba.plne_jmeno() return self.osoba.plne_jmeno()
@ -445,6 +527,9 @@ class Cislo(SeminarModelBase):
datum_deadline = models.DateField('datum deadline', blank=True, null=True, datum_deadline = models.DateField('datum deadline', blank=True, null=True,
help_text='Datum pro příjem řešení úloh zadaných v tomto čísle') 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_soustredeni = models.DateField(
'datum deadline soustředění', 'datum deadline soustředění',
blank=True, null=True, blank=True, null=True,
@ -618,7 +703,7 @@ class Organizator(SeminarModelBase):
"školu, ale jen obor, možnost zobrazit zvlášť") "školu, ale jen obor, možnost zobrazit zvlášť")
def clean(self): def clean(self):
if self.organizuje_od > self.organizuje_do: if self.organizuje_od and self.organizuje_do and (self.organizuje_od > self.organizuje_do):
raise ValidationError("Organizátor nemůže skončit s organizováním dříve než začal!") raise ValidationError("Organizátor nemůže skončit s organizováním dříve než začal!")
super().clean() super().clean()
@ -633,6 +718,11 @@ class Organizator(SeminarModelBase):
class Meta: class Meta:
verbose_name = 'Organizátor' verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři' verbose_name_plural = 'Organizátoři'
# Řadí aktivní orgy na začátek, pod tím v pořadí od nejstarších neaktivní orgy.
# TODO: Chtěl bych spíš mít nejstarší orgy dole.
# TODO: Zohledňovat přezdívky?
# TODO: Sjednotit s tím, jak se řadí organizátoři v seznau orgů na webu
ordering = ['-organizuje_do', 'osoba__jmeno', 'osoba__prijmeni']
@reversion.register(ignore_duplicates=True) @reversion.register(ignore_duplicates=True)
class Soustredeni(SeminarModelBase): class Soustredeni(SeminarModelBase):
@ -734,6 +824,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
(STAV_SMAZANY, 'Smazaný'), (STAV_SMAZANY, 'Smazaný'),
] ]
stav = models.CharField('stav problému', max_length=32, choices=STAV_CHOICES, blank=False, default=STAV_NAVRH) 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í', zamereni = TaggableManager(verbose_name='zaměření',
help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True) 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ý>' return '<Není zadaný>'
def verejne(self): def verejne(self):
# FIXME: Tohle se liší podle typu problému, má se udělat polymorfně. # aktuálně podle stavu problému
# Zatím je tu jen dummy fail-safe default: nic není veřejné. # FIXME pro některé problémy možná chceme override
return False # FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.
# FIXME: Tohle je blbost # Je to tak správně?
return (self.cislo_zadani and self.cislo_zadani.verejne()) 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 verejne.boolean = True
def verejne_url(self): def verejne_url(self):
@ -871,9 +971,7 @@ class Text(SeminarModelBase):
tn.save() tn.save()
def __str__(self): def __str__(self):
parser = FirstTagParser() return str(self.na_web)[:20]
parser.feed(str(self.na_web))
return parser.firstTag
class Uloha(Problem): class Uloha(Problem):
class Meta: class Meta:
@ -1015,7 +1113,7 @@ def aux_generate_filename(self, filename):
unidecode(filename.replace('/', '-').replace('\0', '')) unidecode(filename.replace('/', '-').replace('\0', ''))
) )
datedir = timezone.now().strftime('%Y-%m') datedir = timezone.now().strftime('%Y-%m')
fname = "{}_{}".format( fname = "{}/{}".format(
timezone.now().strftime('%Y-%m-%d-%H:%M'), timezone.now().strftime('%Y-%m-%d-%H:%M'),
clean) clean)
return os.path.join(datedir, fname) return os.path.join(datedir, fname)
@ -1068,6 +1166,11 @@ class PrilohaReseni(SeminarModelBase):
def __str__(self): def __str__(self):
return str(self.soubor) 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): class Pohadka(SeminarModelBase):
"""Kus pohádky před/za úlohou v čísle""" """Kus pohádky před/za úlohou v čísle"""
@ -1389,6 +1492,7 @@ class MezicisloNode(TreeNode):
# TODO: Využít TreeLib # TODO: Využít TreeLib
def aktualizuj_nazev(self): def aktualizuj_nazev(self):
from seminar.treelib import safe_pred
if safe_pred(self) is not None: if safe_pred(self) is not None:
if (self.prev.get_real_instance_class() != CisloNode and if (self.prev.get_real_instance_class() != CisloNode and
self.prev.get_real_instance_class() != MezicisloNode): self.prev.get_real_instance_class() != MezicisloNode):
@ -1503,7 +1607,7 @@ class TextNode(TreeNode):
verbose_name = 'Text (Node)' verbose_name = 'Text (Node)'
verbose_name_plural = 'Text (Node)' verbose_name_plural = 'Text (Node)'
text = models.ForeignKey(Text, text = models.ForeignKey(Text,
on_delete=models.PROTECT, on_delete=models.CASCADE,
verbose_name = 'text') verbose_name = 'text')
def aktualizuj_nazev(self): def aktualizuj_nazev(self):
@ -1536,7 +1640,7 @@ class ReseniNode(TreeNode):
verbose_name = 'reseni') verbose_name = 'reseni')
def aktualizuj_nazev(self): def aktualizuj_nazev(self):
self.nazev = "OtisteneReseniNode: "+str(self.reseni) self.nazev = "ReseniNode: "+str(self.reseni)
def getOdkazStr(self): def getOdkazStr(self):
return str(self.reseni) 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 %} {% block content %}
<div> <div>
@ -8,10 +8,6 @@
{% endblock %}{% endblock %} {% endblock %}{% endblock %}
</h2> </h2>
<!-- <div class='nahledy_cisel'>
{% autoescape off %}{{ nahledy }}{% endautoescape %}
</div>-->
{% for rocnik, url_png in object_list.items %} {% for rocnik, url_png in object_list.items %}
<div class="rocnik_pole"> <div class="rocnik_pole">
@ -33,7 +29,7 @@
</div> </div>
</div> </div>
<div class="flip-card-back"> <div class="flip-card-back" id="archiv">
<div class="popis_rocniku"> <div class="popis_rocniku">
Jednotlivá čísla: Jednotlivá čísla:
<ul> <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 %} {% block content %}
<div> <div>
@ -18,9 +19,9 @@
<h2>Zadané problémy</h2> <h2>Zadané problémy</h2>
<ul> <ul>
{% for p in v_cisle_zadane %} {% for p in v_cisle_zadane %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}> <li{% if user.je_org and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff or cislo.verejne %} {% if user.je_org or cislo.verejne %}
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %} <a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.je_org or cislo.verejne %}</a>{% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
@ -29,14 +30,14 @@
<h2>Řešené problémy</h2> <h2>Řešené problémy</h2>
<ul> <ul>
{% for p in resene_problemy %} {% for p in resene_problemy %}
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}> <li{% if user.je_org and not cislo.verejne %} class='mam-org-only'{% endif %}>
{% if user.is_staff or cislo.verejne %} {% if user.je_org or cislo.verejne %}
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %} <a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.je_org or cislo.verejne %}</a>{% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
{% if user.is_staff %} {% if user.je_org %}
<div class="mam-org-only"> <div class="mam-org-only">
<h2> Orgovské odkazy </h2> <h2> Orgovské odkazy </h2>
<ul> <ul>
@ -44,21 +45,30 @@
<li><a href="tituly.tex">Tituly (TeX)</a></li> <li><a href="tituly.tex">Tituly (TeX)</a></li>
<li><a href="vysledkovka.tex">Výsledkovka (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="obalkovani">Obálkování</a></li>
<li><a href="odmeny/{{prevcislo.rocnik.rocnik}}.{{prevcislo.poradi}}/">Odměny</a></li>
</ul> </ul>
</div> </div>
{% endif %} {% 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 %} {% if cislo.verejna_vysledkovka %}
<h2>Výsledkovka</h2> <h2>Výsledkovka</h2>
{% else %} {% else %}
{% if user.is_staff %} {% if user.je_org %}
<div class='mam-org-only'> <div class='mam-org-only'>
<h2>Výsledkovka (neveřejná)</h2> <h2>Výsledkovka (neveřejná)</h2>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if cislo.verejna_vysledkovka or user.is_staff %} {% if cislo.verejna_vysledkovka or user.je_org %}
<table class='vysledkovka'> <table class='vysledkovka'>
<tr class='border-b'> <tr class='border-b'>
<th class='border-r'># <th class='border-r'>#
@ -66,7 +76,8 @@
{% for p in problemy %} {% for p in problemy %}
<th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a> <th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a>
{% endfor %} {% endfor %}
<th class='border-r'>Za číslo</sup> {% 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'>Za ročník
<th class='border-r'>Odjakživa <th class='border-r'>Odjakživa
{% for rv in radky_vysledkovky %} {% for rv in radky_vysledkovky %}
@ -88,7 +99,7 @@
</table> </table>
{% endif %} {% endif %}
{% if not cislo.verejna_vysledkovka and user.is_staff %} {% if not cislo.verejna_vysledkovka and user.je_org %}
</div> </div>
{% endif %} {% endif %}

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

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