Compare commits

..

2 commits

Author SHA1 Message Date
9c1007073d try except fix 2024-12-01 15:44:56 +01:00
1f77e2a6aa hack for utf-á 2024-11-27 11:36:50 +01:00
46 changed files with 775 additions and 1078 deletions

View file

@ -1,645 +0,0 @@
[
{
"fields": {
"name": "org",
"permissions": [
[
"org",
"auth",
"user"
],
[
"add_flatpage",
"flatpages",
"flatpage"
],
[
"delete_flatpage",
"flatpages",
"flatpage"
],
[
"change_flatpage",
"flatpages",
"flatpage"
],
[
"view_flatpage",
"flatpages",
"flatpage"
],
[
"add_galerie",
"galerie",
"galerie"
],
[
"delete_galerie",
"galerie",
"galerie"
],
[
"change_galerie",
"galerie",
"galerie"
],
[
"view_galerie",
"galerie",
"galerie"
],
[
"add_obrazek",
"galerie",
"obrazek"
],
[
"delete_obrazek",
"galerie",
"obrazek"
],
[
"change_obrazek",
"galerie",
"obrazek"
],
[
"view_obrazek",
"galerie",
"obrazek"
],
[
"add_fotkaheader",
"header_fotky",
"fotkaheader"
],
[
"change_fotkaheader",
"header_fotky",
"fotkaheader"
],
[
"view_fotkaheader",
"header_fotky",
"fotkaheader"
],
[
"add_fotkaurlvazba",
"header_fotky",
"fotkaurlvazba"
],
[
"change_fotkaurlvazba",
"header_fotky",
"fotkaurlvazba"
],
[
"view_fotkaurlvazba",
"header_fotky",
"fotkaurlvazba"
],
[
"add_komentar",
"korektury",
"komentar"
],
[
"delete_komentar",
"korektury",
"komentar"
],
[
"change_komentar",
"korektury",
"komentar"
],
[
"view_komentar",
"korektury",
"komentar"
],
[
"add_korekturovanepdf",
"korektury",
"korekturovanepdf"
],
[
"delete_korekturovanepdf",
"korektury",
"korekturovanepdf"
],
[
"change_korekturovanepdf",
"korektury",
"korekturovanepdf"
],
[
"view_korekturovanepdf",
"korektury",
"korekturovanepdf"
],
[
"add_oprava",
"korektury",
"oprava"
],
[
"delete_oprava",
"korektury",
"oprava"
],
[
"change_oprava",
"korektury",
"oprava"
],
[
"view_oprava",
"korektury",
"oprava"
],
[
"add_novinky",
"novinky",
"novinky"
],
[
"delete_novinky",
"novinky",
"novinky"
],
[
"change_novinky",
"novinky",
"novinky"
],
[
"view_novinky",
"novinky",
"novinky"
],
[
"change_organizator",
"personalni",
"organizator"
],
[
"view_organizator",
"personalni",
"organizator"
],
[
"change_osoba",
"personalni",
"osoba"
],
[
"view_osoba",
"personalni",
"osoba"
],
[
"add_prijemce",
"personalni",
"prijemce"
],
[
"delete_prijemce",
"personalni",
"prijemce"
],
[
"change_prijemce",
"personalni",
"prijemce"
],
[
"view_prijemce",
"personalni",
"prijemce"
],
[
"change_resitel",
"personalni",
"resitel"
],
[
"view_resitel",
"personalni",
"resitel"
],
[
"add_skola",
"personalni",
"skola"
],
[
"delete_skola",
"personalni",
"skola"
],
[
"change_skola",
"personalni",
"skola"
],
[
"view_skola",
"personalni",
"skola"
],
[
"add_hlasovani",
"prednasky",
"hlasovani"
],
[
"delete_hlasovani",
"prednasky",
"hlasovani"
],
[
"change_hlasovani",
"prednasky",
"hlasovani"
],
[
"view_hlasovani",
"prednasky",
"hlasovani"
],
[
"add_prednaska",
"prednasky",
"prednaska"
],
[
"delete_prednaska",
"prednasky",
"prednaska"
],
[
"change_prednaska",
"prednasky",
"prednaska"
],
[
"view_prednaska",
"prednasky",
"prednaska"
],
[
"add_seznam",
"prednasky",
"seznam"
],
[
"delete_seznam",
"prednasky",
"seznam"
],
[
"change_seznam",
"prednasky",
"seznam"
],
[
"view_seznam",
"prednasky",
"seznam"
],
[
"add_konfera",
"soustredeni",
"konfera"
],
[
"delete_konfera",
"soustredeni",
"konfera"
],
[
"change_konfera",
"soustredeni",
"konfera"
],
[
"view_konfera",
"soustredeni",
"konfera"
],
[
"add_konfery_ucastnici",
"soustredeni",
"konfery_ucastnici"
],
[
"delete_konfery_ucastnici",
"soustredeni",
"konfery_ucastnici"
],
[
"change_konfery_ucastnici",
"soustredeni",
"konfery_ucastnici"
],
[
"view_konfery_ucastnici",
"soustredeni",
"konfery_ucastnici"
],
[
"add_soustredeni",
"soustredeni",
"soustredeni"
],
[
"delete_soustredeni",
"soustredeni",
"soustredeni"
],
[
"change_soustredeni",
"soustredeni",
"soustredeni"
],
[
"view_soustredeni",
"soustredeni",
"soustredeni"
],
[
"add_soustredeni_organizatori",
"soustredeni",
"soustredeni_organizatori"
],
[
"delete_soustredeni_organizatori",
"soustredeni",
"soustredeni_organizatori"
],
[
"change_soustredeni_organizatori",
"soustredeni",
"soustredeni_organizatori"
],
[
"view_soustredeni_organizatori",
"soustredeni",
"soustredeni_organizatori"
],
[
"add_soustredeni_ucastnici",
"soustredeni",
"soustredeni_ucastnici"
],
[
"delete_soustredeni_ucastnici",
"soustredeni",
"soustredeni_ucastnici"
],
[
"change_soustredeni_ucastnici",
"soustredeni",
"soustredeni_ucastnici"
],
[
"view_soustredeni_ucastnici",
"soustredeni",
"soustredeni_ucastnici"
],
[
"add_tag",
"taggit",
"tag"
],
[
"delete_tag",
"taggit",
"tag"
],
[
"change_tag",
"taggit",
"tag"
],
[
"view_tag",
"taggit",
"tag"
],
[
"add_taggeditem",
"taggit",
"taggeditem"
],
[
"delete_taggeditem",
"taggit",
"taggeditem"
],
[
"change_taggeditem",
"taggit",
"taggeditem"
],
[
"view_taggeditem",
"taggit",
"taggeditem"
],
[
"add_cislo",
"tvorba",
"cislo"
],
[
"delete_cislo",
"tvorba",
"cislo"
],
[
"change_cislo",
"tvorba",
"cislo"
],
[
"view_cislo",
"tvorba",
"cislo"
],
[
"add_clanek",
"tvorba",
"clanek"
],
[
"delete_clanek",
"tvorba",
"clanek"
],
[
"change_clanek",
"tvorba",
"clanek"
],
[
"view_clanek",
"tvorba",
"clanek"
],
[
"add_deadline",
"tvorba",
"deadline"
],
[
"change_deadline",
"tvorba",
"deadline"
],
[
"view_deadline",
"tvorba",
"deadline"
],
[
"add_pohadka",
"tvorba",
"pohadka"
],
[
"delete_pohadka",
"tvorba",
"pohadka"
],
[
"change_pohadka",
"tvorba",
"pohadka"
],
[
"view_pohadka",
"tvorba",
"pohadka"
],
[
"add_problem",
"tvorba",
"problem"
],
[
"delete_problem",
"tvorba",
"problem"
],
[
"change_problem",
"tvorba",
"problem"
],
[
"view_problem",
"tvorba",
"problem"
],
[
"add_rocnik",
"tvorba",
"rocnik"
],
[
"delete_rocnik",
"tvorba",
"rocnik"
],
[
"change_rocnik",
"tvorba",
"rocnik"
],
[
"view_rocnik",
"tvorba",
"rocnik"
],
[
"add_tema",
"tvorba",
"tema"
],
[
"delete_tema",
"tvorba",
"tema"
],
[
"change_tema",
"tvorba",
"tema"
],
[
"view_tema",
"tvorba",
"tema"
],
[
"add_uloha",
"tvorba",
"uloha"
],
[
"delete_uloha",
"tvorba",
"uloha"
],
[
"change_uloha",
"tvorba",
"uloha"
],
[
"view_uloha",
"tvorba",
"uloha"
],
[
"add_nastaveni",
"various",
"nastaveni"
],
[
"delete_nastaveni",
"various",
"nastaveni"
],
[
"change_nastaveni",
"various",
"nastaveni"
],
[
"view_nastaveni",
"various",
"nastaveni"
]
]
},
"model": "auth.group",
"pk": 1
},
{
"fields": {
"name": "resitel",
"permissions": [
[
"resitel",
"auth",
"user"
]
]
},
"model": "auth.group",
"pk": 2
}
]

View file

@ -0,0 +1,622 @@
[
{
"codename": "org",
"ct_app_label": "auth",
"ct_model": "user"
},
{
"codename": "add_flatpage",
"ct_app_label": "flatpages",
"ct_model": "flatpage"
},
{
"codename": "change_flatpage",
"ct_app_label": "flatpages",
"ct_model": "flatpage"
},
{
"codename": "delete_flatpage",
"ct_app_label": "flatpages",
"ct_model": "flatpage"
},
{
"codename": "view_flatpage",
"ct_app_label": "flatpages",
"ct_model": "flatpage"
},
{
"codename": "add_galerie",
"ct_app_label": "galerie",
"ct_model": "galerie"
},
{
"codename": "change_galerie",
"ct_app_label": "galerie",
"ct_model": "galerie"
},
{
"codename": "delete_galerie",
"ct_app_label": "galerie",
"ct_model": "galerie"
},
{
"codename": "view_galerie",
"ct_app_label": "galerie",
"ct_model": "galerie"
},
{
"codename": "add_obrazek",
"ct_app_label": "galerie",
"ct_model": "obrazek"
},
{
"codename": "change_obrazek",
"ct_app_label": "galerie",
"ct_model": "obrazek"
},
{
"codename": "delete_obrazek",
"ct_app_label": "galerie",
"ct_model": "obrazek"
},
{
"codename": "view_obrazek",
"ct_app_label": "galerie",
"ct_model": "obrazek"
},
{
"codename": "add_fotkaheader",
"ct_app_label": "header_fotky",
"ct_model": "fotkaheader"
},
{
"codename": "change_fotkaheader",
"ct_app_label": "header_fotky",
"ct_model": "fotkaheader"
},
{
"codename": "view_fotkaheader",
"ct_app_label": "header_fotky",
"ct_model": "fotkaheader"
},
{
"codename": "add_fotkaurlvazba",
"ct_app_label": "header_fotky",
"ct_model": "fotkaurlvazba"
},
{
"codename": "change_fotkaurlvazba",
"ct_app_label": "header_fotky",
"ct_model": "fotkaurlvazba"
},
{
"codename": "view_fotkaurlvazba",
"ct_app_label": "header_fotky",
"ct_model": "fotkaurlvazba"
},
{
"codename": "add_komentar",
"ct_app_label": "korektury",
"ct_model": "komentar"
},
{
"codename": "change_komentar",
"ct_app_label": "korektury",
"ct_model": "komentar"
},
{
"codename": "delete_komentar",
"ct_app_label": "korektury",
"ct_model": "komentar"
},
{
"codename": "view_komentar",
"ct_app_label": "korektury",
"ct_model": "komentar"
},
{
"codename": "add_korekturovanepdf",
"ct_app_label": "korektury",
"ct_model": "korekturovanepdf"
},
{
"codename": "change_korekturovanepdf",
"ct_app_label": "korektury",
"ct_model": "korekturovanepdf"
},
{
"codename": "delete_korekturovanepdf",
"ct_app_label": "korektury",
"ct_model": "korekturovanepdf"
},
{
"codename": "view_korekturovanepdf",
"ct_app_label": "korektury",
"ct_model": "korekturovanepdf"
},
{
"codename": "add_oprava",
"ct_app_label": "korektury",
"ct_model": "oprava"
},
{
"codename": "change_oprava",
"ct_app_label": "korektury",
"ct_model": "oprava"
},
{
"codename": "delete_oprava",
"ct_app_label": "korektury",
"ct_model": "oprava"
},
{
"codename": "view_oprava",
"ct_app_label": "korektury",
"ct_model": "oprava"
},
{
"codename": "add_hlasovani",
"ct_app_label": "prednasky",
"ct_model": "hlasovani"
},
{
"codename": "change_hlasovani",
"ct_app_label": "prednasky",
"ct_model": "hlasovani"
},
{
"codename": "delete_hlasovani",
"ct_app_label": "prednasky",
"ct_model": "hlasovani"
},
{
"codename": "view_hlasovani",
"ct_app_label": "prednasky",
"ct_model": "hlasovani"
},
{
"codename": "add_prednaska",
"ct_app_label": "prednasky",
"ct_model": "prednaska"
},
{
"codename": "change_prednaska",
"ct_app_label": "prednasky",
"ct_model": "prednaska"
},
{
"codename": "delete_prednaska",
"ct_app_label": "prednasky",
"ct_model": "prednaska"
},
{
"codename": "view_prednaska",
"ct_app_label": "prednasky",
"ct_model": "prednaska"
},
{
"codename": "add_seznam",
"ct_app_label": "prednasky",
"ct_model": "seznam"
},
{
"codename": "change_seznam",
"ct_app_label": "prednasky",
"ct_model": "seznam"
},
{
"codename": "delete_seznam",
"ct_app_label": "prednasky",
"ct_model": "seznam"
},
{
"codename": "view_seznam",
"ct_app_label": "prednasky",
"ct_model": "seznam"
},
{
"codename": "add_cislo",
"ct_app_label": "tvorba",
"ct_model": "cislo"
},
{
"codename": "change_cislo",
"ct_app_label": "tvorba",
"ct_model": "cislo"
},
{
"codename": "delete_cislo",
"ct_app_label": "tvorba",
"ct_model": "cislo"
},
{
"codename": "view_cislo",
"ct_app_label": "tvorba",
"ct_model": "cislo"
},
{
"codename": "add_clanek",
"ct_app_label": "tvorba",
"ct_model": "clanek"
},
{
"codename": "change_clanek",
"ct_app_label": "tvorba",
"ct_model": "clanek"
},
{
"codename": "delete_clanek",
"ct_app_label": "tvorba",
"ct_model": "clanek"
},
{
"codename": "view_clanek",
"ct_app_label": "tvorba",
"ct_model": "clanek"
},
{
"codename": "add_deadline",
"ct_app_label": "tvorba",
"ct_model": "deadline"
},
{
"codename": "change_deadline",
"ct_app_label": "tvorba",
"ct_model": "deadline"
},
{
"codename": "view_deadline",
"ct_app_label": "tvorba",
"ct_model": "deadline"
},
{
"codename": "add_konfera",
"ct_app_label": "soustredeni",
"ct_model": "konfera"
},
{
"codename": "change_konfera",
"ct_app_label": "soustredeni",
"ct_model": "konfera"
},
{
"codename": "delete_konfera",
"ct_app_label": "soustredeni",
"ct_model": "konfera"
},
{
"codename": "view_konfera",
"ct_app_label": "soustredeni",
"ct_model": "konfera"
},
{
"codename": "add_konfery_ucastnici",
"ct_app_label": "soustredeni",
"ct_model": "konfery_ucastnici"
},
{
"codename": "change_konfery_ucastnici",
"ct_app_label": "soustredeni",
"ct_model": "konfery_ucastnici"
},
{
"codename": "delete_konfery_ucastnici",
"ct_app_label": "soustredeni",
"ct_model": "konfery_ucastnici"
},
{
"codename": "view_konfery_ucastnici",
"ct_app_label": "soustredeni",
"ct_model": "konfery_ucastnici"
},
{
"codename": "add_nastaveni",
"ct_app_label": "various",
"ct_model": "nastaveni"
},
{
"codename": "change_nastaveni",
"ct_app_label": "various",
"ct_model": "nastaveni"
},
{
"codename": "delete_nastaveni",
"ct_app_label": "various",
"ct_model": "nastaveni"
},
{
"codename": "view_nastaveni",
"ct_app_label": "various",
"ct_model": "nastaveni"
},
{
"codename": "add_novinky",
"ct_app_label": "novinky",
"ct_model": "novinky"
},
{
"codename": "change_novinky",
"ct_app_label": "novinky",
"ct_model": "novinky"
},
{
"codename": "delete_novinky",
"ct_app_label": "novinky",
"ct_model": "novinky"
},
{
"codename": "view_novinky",
"ct_app_label": "novinky",
"ct_model": "novinky"
},
{
"codename": "change_organizator",
"ct_app_label": "personalni",
"ct_model": "organizator"
},
{
"codename": "view_organizator",
"ct_app_label": "personalni",
"ct_model": "organizator"
},
{
"codename": "change_osoba",
"ct_app_label": "personalni",
"ct_model": "osoba"
},
{
"codename": "view_osoba",
"ct_app_label": "personalni",
"ct_model": "osoba"
},
{
"codename": "add_pohadka",
"ct_app_label": "tvorba",
"ct_model": "pohadka"
},
{
"codename": "change_pohadka",
"ct_app_label": "tvorba",
"ct_model": "pohadka"
},
{
"codename": "delete_pohadka",
"ct_app_label": "tvorba",
"ct_model": "pohadka"
},
{
"codename": "view_pohadka",
"ct_app_label": "tvorba",
"ct_model": "pohadka"
},
{
"codename": "add_prijemce",
"ct_app_label": "personalni",
"ct_model": "prijemce"
},
{
"codename": "change_prijemce",
"ct_app_label": "personalni",
"ct_model": "prijemce"
},
{
"codename": "delete_prijemce",
"ct_app_label": "personalni",
"ct_model": "prijemce"
},
{
"codename": "view_prijemce",
"ct_app_label": "personalni",
"ct_model": "prijemce"
},
{
"codename": "add_problem",
"ct_app_label": "tvorba",
"ct_model": "problem"
},
{
"codename": "change_problem",
"ct_app_label": "tvorba",
"ct_model": "problem"
},
{
"codename": "delete_problem",
"ct_app_label": "tvorba",
"ct_model": "problem"
},
{
"codename": "view_problem",
"ct_app_label": "tvorba",
"ct_model": "problem"
},
{
"codename": "change_resitel",
"ct_app_label": "personalni",
"ct_model": "resitel"
},
{
"codename": "view_resitel",
"ct_app_label": "personalni",
"ct_model": "resitel"
},
{
"codename": "add_rocnik",
"ct_app_label": "tvorba",
"ct_model": "rocnik"
},
{
"codename": "change_rocnik",
"ct_app_label": "tvorba",
"ct_model": "rocnik"
},
{
"codename": "delete_rocnik",
"ct_app_label": "tvorba",
"ct_model": "rocnik"
},
{
"codename": "view_rocnik",
"ct_app_label": "tvorba",
"ct_model": "rocnik"
},
{
"codename": "add_skola",
"ct_app_label": "personalni",
"ct_model": "skola"
},
{
"codename": "change_skola",
"ct_app_label": "personalni",
"ct_model": "skola"
},
{
"codename": "delete_skola",
"ct_app_label": "personalni",
"ct_model": "skola"
},
{
"codename": "view_skola",
"ct_app_label": "personalni",
"ct_model": "skola"
},
{
"codename": "add_soustredeni",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni"
},
{
"codename": "change_soustredeni",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni"
},
{
"codename": "delete_soustredeni",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni"
},
{
"codename": "view_soustredeni",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni"
},
{
"codename": "add_soustredeni_organizatori",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni_organizatori"
},
{
"codename": "change_soustredeni_organizatori",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni_organizatori"
},
{
"codename": "delete_soustredeni_organizatori",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni_organizatori"
},
{
"codename": "view_soustredeni_organizatori",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni_organizatori"
},
{
"codename": "add_soustredeni_ucastnici",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni_ucastnici"
},
{
"codename": "change_soustredeni_ucastnici",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni_ucastnici"
},
{
"codename": "delete_soustredeni_ucastnici",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni_ucastnici"
},
{
"codename": "view_soustredeni_ucastnici",
"ct_app_label": "soustredeni",
"ct_model": "soustredeni_ucastnici"
},
{
"codename": "add_tema",
"ct_app_label": "tvorba",
"ct_model": "tema"
},
{
"codename": "change_tema",
"ct_app_label": "tvorba",
"ct_model": "tema"
},
{
"codename": "delete_tema",
"ct_app_label": "tvorba",
"ct_model": "tema"
},
{
"codename": "view_tema",
"ct_app_label": "tvorba",
"ct_model": "tema"
},
{
"codename": "add_uloha",
"ct_app_label": "tvorba",
"ct_model": "uloha"
},
{
"codename": "change_uloha",
"ct_app_label": "tvorba",
"ct_model": "uloha"
},
{
"codename": "delete_uloha",
"ct_app_label": "tvorba",
"ct_model": "uloha"
},
{
"codename": "view_uloha",
"ct_app_label": "tvorba",
"ct_model": "uloha"
},
{
"codename": "add_tag",
"ct_app_label": "taggit",
"ct_model": "tag"
},
{
"codename": "change_tag",
"ct_app_label": "taggit",
"ct_model": "tag"
},
{
"codename": "delete_tag",
"ct_app_label": "taggit",
"ct_model": "tag"
},
{
"codename": "view_tag",
"ct_app_label": "taggit",
"ct_model": "tag"
},
{
"codename": "add_taggeditem",
"ct_app_label": "taggit",
"ct_model": "taggeditem"
},
{
"codename": "change_taggeditem",
"ct_app_label": "taggit",
"ct_model": "taggeditem"
},
{
"codename": "delete_taggeditem",
"ct_app_label": "taggit",
"ct_model": "taggeditem"
},
{
"codename": "view_taggeditem",
"ct_app_label": "taggit",
"ct_model": "taggeditem"
}
]

View file

@ -13,6 +13,7 @@ make install_venv
make install
deploy_v2/pre_migration.py
make deploy_test
./manage.py load_org_permissions admin_org_prava.json
./manage.py loaddata data/*
systemctl --user start mamweb-test.service
./manage.py generate_thumbnails

View file

@ -30,7 +30,6 @@ Dokumentace (jak v ``docs/``, tak přímo v kódu) je psaná ve
zavislosti
sphinx
skripty
zkratky
modules/modules
dalsi_soubory
zapisy/zapisy

View file

@ -1,15 +1,13 @@
Sphinx na našem webu
====================
Dokumentace se zkompiluje příkazem ``make html`` ve složce ``docs``. (Musíte mít zapnutý virtualenv)
Dokumentace se zkompiluje příkazem ``make html`` ve složce ``doc``.
Složka ``modules`` je automaticiky generována a přegenerovávána. (**Nic v ní neupravovat!**)
Jinak všechny rst, co jsou ve složce ``docs`` a jejích podsložkách nezačínajících podtržítkem, budou v dokumentaci a to je přesně to, co editovat pro změnu dokumentace (kromě dokumentace přímo v Pythonu).
Jinak všechny rst, co jsou ve složce ``doc`` a jejích podsložkách nezačínajících podtržítkem, budou v dokumentaci a to je přesně to, co editovat pro změnu dokumentace (kromě dokumentace přímo v Pythonu).
Sphinx se píše v rst: `Návod na syntaxi rst`_ `Cheat sheet`_
Pokud něco chcete protlačit do bočního meníčka, je potřeba to připsat do souboru ``docs/index.rst`` (Zatím není úplně konsensus nad tím, co tam má a nemá být, takže pokud si nejste jistí, cpěte tam *všechno* ☺)
To je snad vše, co je potřeba vědět k dokumentaci mamwebu. Následující sekce jsou o tom, co jsem provedl Sphinxu, aby to fungovalo:
.. _Návod na syntaxi rst: https://sphinx-tutorial.readthedocs.io/step-1/#sections

View file

@ -1,86 +0,0 @@
Zkratky aplikací ve zdrojácích
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Ve zdrojácích (zejména různé ``models.py``, ``views.py`` ap.) používáme spoustu
modelů. Někdy je praktičtější / někdo preferuje importovat celou aplikaci jako
jedno jméno a používat modely bez explicitních importů, tj::
# „hromadné“ importy:
import personalni.models as p
...
p.Organizator.objects.all()
# „explicitní“ importy:
from personalni.models import Organizator
...
Organizator.objects.all()
Na webschůzce 2024-11-05 jsme na toto téma otevřeli diskusi, tady je její závěr.
.. admonition:: Historické okénko
:class: note
Kdysi jsme měli (prakticky) všechny modely v jedné aplikaci, ``seminar``. Na
různých místech se pak ``seminar.models`` importovalo typicky jako ``s``
nebo jako ``m``.
Přirozeně, toto už nejde tak snadno, protože už neexistuje jedno místo, ze
kterého chceme tahat modely v kódu.
Konvence
========
Shodli jsme se, že nám rozhodně nevadí explicitní importy a z pohledu
čitelnosti je preferujeme. Nicméně při psaní kódu to některým webařům přijde
nepohodlné, takže očekáváme, že bude existovat spousta kódu, která bude chtít
importovat hromadně. Usnesli jsme se proto na následujících kanonických
zkratkách, aby se aplikace alespoň zkracovaly konzistentně.
V závorkách je uvedené případné jméno, ale nepředpokládáme, že někdo bude danou
aplikaci chtít importovat hromadně. Některé aplikace zkratku nemají, ty se
importují vždy pod plným jménem nebo explicitně.
.. list-table::
:header-rows: 1
* - Model
- Zkratka
* - ``aesop``
- ---
* - ``api``
- --- (``api``)
* - ``galerie``
- ``g``
* - ``header_fotky``
- --- (``hdr``)
* - ``korektury``
- ``kor``
* - ``novinky``
- ``nov``
* - ``odevzdavatko``
- ``odev``
* - ``personální``
- ``pers``/``p``
* - ``sifrovacka``
- (``sifr``)
* - ``soustredeni``
- ``sou``
* - ``treenode``
- ``tn``
* - ``tvorba``
- ``tv``
* - ``various``
- ``v``/``var``
* - ``vyroci``
- ---
* - ``vysledkovky``
- ``vysl``
.. admonition:: O všech modelech pod jedním jménem
:class: warning
Historické okénko výš zatajuje jeden detail: Při práci v shellu se hodí mít
modely k dispozici a nemuset přemýšlet nad dělením do aplikací, takže ve
skutečnosti existuje ``mamweb.vsechno``, jenž všechny modely obsahuje.
Z čitelnostních důvodů je ale *zakázáno* tento modul používat v kódu.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 617 B

View file

@ -35,27 +35,24 @@ def create_test_pdf(rnd, organizatori):
# TODO silent ghostscript (vypisuje odstavec za každou stránku…)
korekturovane_pdf = KorekturovanePDF.objects.create(
nazev='B', komentar='Neuronové sítě', pdf=gen_filename(filename='B.pdf')
KorekturovanePDF.objects.create(
nazev='B', komentar='Neuronové sítě', org=rnd.choice(organizatori), pdf=gen_filename(filename='B.pdf')
)
korekturovane_pdf.orgove.set((rnd.choice(organizatori),))
korekturovane_pdf = KorekturovanePDF.objects.create(
nazev='A', komentar='M&M: Jak řešit?', pdf=gen_filename(filename='A.pdf')
)
korekturovane_pdf.orgove.set(rnd.sample(organizatori, 2))
KorekturovanePDF.objects.create(
nazev='A', komentar='M&M: Jak řešit?', pdf=gen_filename(filename='A.pdf'),
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'
)
korekturovane_pdf = KorekturovanePDF.objects.create(
nazev='A', komentar='M&M: Jak řešit?', pdf=gen_filename(filename='A.pdf'),
KorekturovanePDF.objects.create(
nazev='A', komentar='M&M: Jak řešit?', org=rnd.choice(organizatori), pdf=gen_filename(filename='A.pdf'),
status='zastarale'
)
korekturovane_pdf.orgove.set((rnd.choice(organizatori),))
except OSError as e:
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(

View file

@ -8,3 +8,4 @@ ensure_venv
./manage.py testdata
./manage.py loaddata data/*
#make/sync_prod_flatpages
./manage.py load_org_permissions deploy_v2/admin_org_prava.json

View file

@ -95,7 +95,7 @@ function safe_checkout_branch {
echo >&2 "Změna v $SCRIPT, prosím pullni manuálně"
exit 1
fi
git checkout "$BRANCH" --
git checkout "$BRANCH"
git pull
git clean -f
}

View file

@ -7,7 +7,6 @@ import locale
from django.contrib import admin
from django.contrib.admin import AdminSite
from django.contrib.flatpages.models import FlatPage
import logging
# Note: we are renaming the original Admin and Form as we import them!
from django.contrib.flatpages.admin import FlatPageAdmin as FlatPageAdminOld
@ -55,16 +54,11 @@ def get_app_list(self, request, app_label=None):
# Odhlášený admin má prázdný app_dict :-/
app_list = [app_dict[label] for label in aplikace_nahore if label in app_dict] + [app_dict[label] for label in app_dict if label not in aplikace_nahore]
# Sort the models alphabetically within each app.
try: # na macu nefunguje locale.strxfrm :-/ proto je tu try except block
try:
for app in app_list:
app['models'].sort(key=lambda x: locale.strxfrm(x['name'].lower()))
except OSError as e:
# locale.strxfrm nefunguje na macu... :-/ -> neprovede se řazení
logger = logging.getLogger(__name__)
logger.error(e)
except OSError:
pass # locale.strxfrm nefunguje na macu... :-/ -> neprovede se řazení
return app_list
AdminSite.get_app_list = get_app_list

View file

@ -10,8 +10,6 @@
--orgovska-fialova: #6a0043;
--orgovska-svetla-fialova: #eee4ec;
--resitelska-fialova: #f296b3;
--resitelska-svetla-fialova: #f2E5EF;
--barva-pozadi: #fffbf6;
}

View file

@ -17,27 +17,7 @@
border: var(--orgovska-fialova) 2px dashed;
& .mam-org-only {
/* Vnitřní rámečky mají být taky vidět */
border-width: 1px;
background-color: rgba(0, 0, 0, 0.06);
}
& li {
padding: 3px 0;
margin: -2px 0;
}
}
.mam-resitel-only {
background: var(--resitelska-svetla-fialova);
padding: 10px;
margin: 10px -10px;
border: var(--resitelska-fialova) 2px dashed;
& .mam-resitel-only {
/* Vnitřní rámečky mají být taky vidět */
border-width: 1px;
background-color: rgba(0, 0, 0, 0.06);
border: 0;
}
& li {

View file

@ -1,6 +1,6 @@
# Tento soubor slouží pouze pro shell a podobné. Nikde neimportovat v kódu!
print("Naimportoval jsi `mamweb.vsechno`. Pevně věřím, že to nebylo nikde v kódu. Díky.")
print("Naimportoval jsi `seminar.models`. Pevně věřím, že to nebylo nikde v kódu. Díky.")
from galerie.models import *
from header_fotky.models import *

View file

@ -65,9 +65,6 @@ class Reseni(SeminarModelBase):
def absolute_url(self):
return "https://" + str(get_current_site(None)) + self.verejne_url()
def resitel_url(self):
return f'https://{get_current_site(None)}{reverse_lazy("odevzdavatko_resitel_reseni", args=[self.id])}'
# má OneToOneField s:
# Konfera

View file

@ -191,7 +191,7 @@ Sloupce:
</ul>
</li>
<li>Pokud nemáš důvod, deadline neměň. Sloupeček s deadlinem znamená, do kterého deadlinu se započítají body (nemusí se shodovat s deadlinem řešení).</li>
<li>Poslední sloupec je na zpětnou vazbu řešiteli, tedy (na rozdíl od Neveřejné poznámky, která je určena pro synchronizaci orgů) ji uvidí řešitelé. Změníte-li u nějakého hodnocení toto políčko, řešitel bude upozorněn emailem, pokud si tuto možnost nevypl ve svém profilu. Pohled řešitele si můžete prohlédnout <a href="{% url 'odevzdavatko_resitel_reseni' reseni.id %}">zde</a>. Pokud chcete z nějakého důvodu napsat řešitelům e-mail, klikněte na „Poslat mail všem řešitelům“.</li>
<li>Poslední sloupec je na zpětnou vazbu řešiteli, tedy (na rozdíl od Neveřejné poznámky, která je určena pro synchronizaci orgů) ji uvidí řešitelé. Zatím jen pasivně (nechodí e-mail). Pohled řešitele si můžete prohlédnout <a href="{% url 'odevzdavatko_resitel_reseni' reseni.id %}">zde</a>. Pokud chcete z nějakého důvodu napsat řešitelům e-mail, klikněte na „Poslat mail všem řešitelům“.</li>
</ol>
Další poznámky

View file

@ -222,17 +222,6 @@ class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixi
ctx["problem_id"] = self.kwargs['problem']
return ctx
HODNOCENI_INITIAL_DATA = [
"problem",
"body",
"body_celkem",
"body_neprepocitane",
"body_neprepocitane_celkem",
"body_max",
"body_neprepocitane_max",
"deadline_body",
"feedback",
]
## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex
class DetailReseniView(DetailView):
""" Náhled na řešení. Editace je v :py:class:`EditReseniView`. """
@ -243,7 +232,18 @@ class DetailReseniView(DetailView):
self.reseni = get_object_or_404(Reseni, id=self.kwargs['pk'])
result = [] # Slovníky s klíči problem, body, deadline_body -- initial data pro f.OhodnoceniReseniFormSet
for hodn in Hodnoceni.objects.filter(reseni=self.reseni):
result.append({attr: getattr(hodn, attr) for attr in HODNOCENI_INITIAL_DATA})
seznam_atributu = [
"problem",
"body",
"body_celkem",
"body_neprepocitane",
"body_neprepocitane_celkem",
"body_max",
"body_neprepocitane_max",
"deadline_body",
"feedback",
]
result.append({attr: getattr(hodn, attr) for attr in seznam_atributu})
return result
def get_context_data(self, **kw):
@ -291,9 +291,9 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
reseni = get_object_or_404(Reseni, pk=pk)
success_url = reverse('odevzdavatko_detail_reseni', kwargs={'pk': pk})
formset = f.OhodnoceniReseniFormSet(request.POST, initial=[
{k: getattr(h, k) for k in HODNOCENI_INITIAL_DATA} for h in Hodnoceni.objects.filter(reseni=reseni)
])
# FIXME: Použit initial i tady a nebastlit hodnocení tak nízkoúrovňově
# Also: https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#django.forms.ModelForm
formset = f.OhodnoceniReseniFormSet(request.POST)
poznamka_form = f.PoznamkaReseniForm(request.POST, instance=reseni)
# TODO: Napsat validaci formuláře a formsetu
if not (formset.is_valid() and poznamka_form.is_valid()):
@ -309,9 +309,7 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
qs.delete()
# Vyrobíme nová podle formsetu
notifikace = False
for form in formset:
notifikace |= 'feedback' in form.changed_data
data_for_hodnoceni = form.cleaned_data
data_for_body = data_for_hodnoceni.copy()
del(data_for_hodnoceni["body_celkem"])
@ -322,44 +320,16 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
**form.cleaned_data,
)
logger.info(f"Creating Hodnoceni: {hodnoceni}")
# FIXME následující kód má velmi vysokou šanci se rozbít, vymyslet, jak to udělat jinak
zmeny_bodu = [it for it in form.changed_data if it.startswith("body")]
if len(zmeny_bodu) != 0:
body_nastaveny: None | tuple[str, object] = None
def nastav_body(jake, na_kolik):
nonlocal body_nastaveny
if body_nastaveny is not None:
logger.warning(f"Hodnocení {hodnoceni} s id {hodnoceni.id} k řešení {reseni.id} mělo mít nastavené kromě {body_nastaveny[0]} na {body_nastaveny[1]} ještě další body: {jake} na {na_kolik}. Nastavuji -0.1.")
hodnoceni.body = -0.1
else:
body_nastaveny = (jake, na_kolik)
hodnoceni.__setattr__(jake, na_kolik)
for key, value in data_for_body.items():
if key.startswith("body") and value is not None:
nastav_body(key, value)
# Něco se změnilo, ale nic není nastavené = něco bylo smazáno
if body_nastaveny is None:
hodnoceni.body = None
if len(zmeny_bodu) == 1:
hodnoceni.__setattr__(zmeny_bodu[0], data_for_body[zmeny_bodu[0]])
# > jedna změna je špatně, ale 4 "změny" znamenají že nebylo nic zadáno
if len(zmeny_bodu) > 1 and len(zmeny_bodu) != 4 and len(zmeny_bodu) != 2:
# 4 znamená vše už vyplněno a nic nezměněno, 2 znamená předvyplnili se součty a nic se nezměnilo
logger.warning(f"Hodnocení {hodnoceni} mělo mít nastavené víc různých bodů: {zmeny_bodu}. Nastavuji -0.1.")
hodnoceni.body = -0.1
hodnoceni.save()
adresati = reseni.resitele.filter(upozornovat_na_opravy_reseni=True).values_list('osoba__email', flat=True)
if notifikace and adresati:
email = EmailMessage(
subject='Změna hodnocení odevzdaného řešení',
body=f"""Milá řešitelko, milý řešiteli,
došlo ke změně zpětné vazby k Tebou odevzdanému řešení. Zobrazit si ji můžeš na {reseni.resitel_url()}.
Tvoji organizátoři M&M
---
Nechceš-li tato upozornění dostávat, můžeš si to nastavit ve svém profilu.""",
from_email='odevzdavatko@mam.mff.cuni.cz',
bcc=adresati,
)
email.send()
return redirect(success_url)

View file

@ -71,8 +71,6 @@ class UdajeForm(forms.Form):
zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat e-mailem upozornění na vydání nového čísla', required=False, initial=True)
spam = forms.BooleanField(label='Souhlasím se zasíláním propagačních materiálů od MFF UK', required=False)
upozornovat_na_opravy_reseni = forms.BooleanField(label='Chci dostávat emailová upozornění na změnu zpětné vazby k mým řešením', required=False, initial=True)
def clean_prezdivka_resitele(self):
prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele')
if prezdivka_resitele == '':

View file

@ -1,22 +0,0 @@
# Generated by Django 4.2.16 on 2024-12-03 19:08
from django.db import migrations, models
def vypnuti_upozorneni_na_opravy_reseni(apps, schema_editor):
Resitel = apps.get_model('personalni', 'Resitel')
Resitel.objects.update(upozorneni=False)
class Migration(migrations.Migration):
dependencies = [
('personalni', '0017_odstrel_treenode_post'),
]
operations = [
migrations.AddField(
model_name='resitel',
name='upozorneni',
field=models.BooleanField(default=True, verbose_name='zasílat upozornění na změnu zpětné vazby k řešení emailem'),
),
migrations.RunPython(vypnuti_upozorneni_na_opravy_reseni),
]

View file

@ -1,18 +0,0 @@
# Generated by Django 4.2.18 on 2025-01-14 19:48
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('personalni', '0018_resitel_upozorneni'),
]
operations = [
migrations.RenameField(
model_name='resitel',
old_name='upozorneni',
new_name='upozornovat_na_opravy_reseni',
),
]

View file

@ -250,8 +250,6 @@ class Resitel(SeminarModelBase):
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k řešiteli (plain text)')
upozornovat_na_opravy_reseni = models.BooleanField('zasílat upozornění na změnu zpětné vazby k řešení emailem', default=True)
def export_row(self):
"Slovnik pro pouziti v AESOP exportu"

View file

@ -1,34 +0,0 @@
.seznam {
display: flex;
flex-direction: column;
gap: 0.3em;
}
.hint {
border: 1px solid #ccc;
padding: 0.3em 1em;
border-radius: 5px;
margin-bottom: 1em;
}
.osoba {
display: flex;
justify-content: space-between;
gap: 0.5em;
.uno {
flex: 2;
}
.dos {
flex: 2;
}
.tres {
flex: 1;
}
.grey {
opacity: 0.5;
}
}

View file

@ -1,28 +0,0 @@
{% extends "base.html" %}
{% block custom_css %}
{% load static %}
<link href="{% static 'personalni/jak_se_dozvedeli.css' %}" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="seznam">
<div class="osoba hint">
<div class="uno">Jméno</div>
<div class="dos">Jak se dozvěděli</div>
<div class="tres">Datum registrace</div>
</div>
{% for osoba in object_list %}
<div class="osoba">
<div class="uno">{{ osoba.jmeno }} {{ osoba.prijmeni }}</div>
<div class="dos {% if not osoba.jak_se_dozvedeli %}grey{% endif %}">{% if osoba.jak_se_dozvedeli %} {{osoba.jak_se_dozvedeli}} {% else %} NEZADÁNO {% endif %}</div>
<div class="tres">{{ osoba.datum_registrace }}</div>
</div>
{% endfor %}
</div>
{% endblock%}

View file

@ -51,7 +51,6 @@
</h4>
<table class="form">
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_emailem %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.upozornovat_na_opravy_reseni %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_papirove %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.spam %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat %}

View file

@ -33,11 +33,4 @@ urlpatterns = [
name='stari_organizatori'
),
# Zpřístupnění dat z "jak jste se o nás dozvěděli" pro orgy propagace
path(
'org/propagace/jak-se-dozvedeli/',
org_required(views.JakSeDozvedeliView.as_view()),
name='jak_se_dozvedeli'
)
]

View file

@ -34,7 +34,7 @@ from various.autentizace.utils import posli_reset_hesla
from django.forms.models import model_to_dict
from .models import Organizator, Osoba
from .models import Organizator
def aktivniOrganizatori(datum=timezone.now()):
@ -62,11 +62,6 @@ class CojemamOrganizatoriStariView(generic.ListView):
id__in=aktivniOrganizatori()
).order_by('-organizuje_do')
class JakSeDozvedeliView(generic.ListView):
model = Osoba
template_name = 'personalni/jak_se_dozvedeli.html'
queryset = Osoba.objects.order_by('-datum_registrace')
def obalkyView(request, resitele):
if len(resitele) == 0:
@ -235,7 +230,6 @@ def resitelEditView(request):
resitel_edit.zasilat = fcd['zasilat']
resitel_edit.zasilat_cislo_emailem = fcd['zasilat_cislo_emailem']
resitel_edit.zasilat_cislo_papirove = fcd['zasilat_cislo_papirove']
resitel_edit.upozornovat_na_opravy_reseni = fcd['upozornovat_na_opravy_reseni']
if fcd.get('skola'):
resitel_edit.skola = fcd['skola']
else:

View file

@ -30,8 +30,6 @@ Jak moc by ses chtěl(a) zúčastnit následujících přednášek?
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="1" {% if h == 1 %} CHECKED="checked" {% endif %}> rozhodně chci
</td></tr>
<tr><td>&nbsp;</td></tr>
{% empty %}
Nejsou žádné přednášky o kterých by šlo hlasovat.
{% endfor %}
<tr><td><input name="odeslat" type="submit" value="Odeslat"></td><tr>
</table>

View file

@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% load humanize %}
{% load static %}
{% block content %}
<h1> Děkujeme. </h1>
{% endblock %}

View file

@ -1,5 +1,3 @@
import http
from django.shortcuts import render, get_object_or_404
from django.views import generic
from django.shortcuts import HttpResponseRedirect
@ -7,22 +5,14 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Sum
from django.forms import Form
from various.views.pomocne import formularOKView
from various.models import Nastaveni
from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH
from soustredeni.models import Soustredeni
from personalni.models import Osoba
def newPrednaska(request):
# hlasovani se vztahuje k nejnovejsimu soustredeni
sous = Nastaveni.get_solo().aktualni_sous
sous = Soustredeni.objects.first()
seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first()
if sous is None or seznam is None:
return render(request, 'universal.html', {
'title': "Nelze hlasovat",
'text': "Není žádný seznam přednášek, o kterém by se dalo hlasovat.",
}, status=http.HTTPStatus.NOT_FOUND)
osoba = Osoba.objects.filter(user=request.user).first()
ucastnik = osoba.plne_jmeno() + ' ' + str(osoba.id)
# obsluha formulare
@ -64,7 +54,7 @@ def newPrednaska(request):
def Prednaska_hotovo(request):
return formularOKView(request, "Děkujeme za vyplnění hlasování o přednáškách a těšíme se na soustředění.")
return render(request, 'prednasky/hotovo.html')
class MetaSeznamListView(generic.ListView):
model = Seznam
@ -77,7 +67,7 @@ class SeznamListView(generic.ListView):
def get_queryset(self):
self.seznam = get_object_or_404(Seznam, id=self.kwargs["seznam"])
prednasky = Prednaska.objects.filter(seznamy=self.seznam).order_by(
'org__osoba__user__first_name', 'org__osoba__user__last_name'
'org__user__first_name', 'org__user__last_name'
)
return prednasky

View file

@ -17,7 +17,7 @@ django-solo # Singleton model (speciálně Nastavení)
django-ckeditor-5 # Editor htmlka (hlavně v adminu u flatpages)
django-cleanup # Uklízí media/ od smazaných „databázových“ souborů
django-taggit # Taggy v djangu (speciálně zaměření problémů)
django-autocomplete-light>=3.9.0,<3.12.0 # Automatické doplňování (problémů, účastníků, …) ve formulářích
django-autocomplete-light>=3.9.0 # Automatické doplňování (problémů, účastníků, …) ve formulářích
django-imagekit # Všechny možné obrázky v Djangu
django-polymorphic # Polymorfismus na django modelech (hlavně Problém nebo treenode)
django-sitetree # Struktura stránek, hlavně pro meníčko

View file

@ -36,16 +36,12 @@
{% endfor %}
{% endif %}
{% if soustredeni.kontaktnicek_pdf or soustredeni.kontaktnicek_vcf %}
{% for i in soustredeni.ucastnici.all %}
{% if i.osoba.user == user %}
<div class="mam-resitel-only">
{% if soustredeni.kontaktnicek_pdf %} <li><a href="../{{soustredeni.pk}}/kontaktnicek_pdf">kontaktnicek pdf</a></li>{% endif %}
{% if soustredeni.kontaktnicek_vcf %} <li><a href="../{{soustredeni.pk}}/kontaktnicek_vcf">kontaktnicek vcf</a></li>{% endif %}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% for i in soustredeni.ucastnici.all %}
{% if i.osoba.user == user %}
{% if soustredeni.kontaktnicek_pdf %} <li><a href="../{{soustredeni.pk}}/kontaktnicek_pdf">kontaktnicek pdf</a></li>{% endif %}
{% if soustredeni.kontaktnicek_vcf %} <li><a href="../{{soustredeni.pk}}/kontaktnicek_vcf">kontaktnicek vcf</a></li>{% endif %}
{% endif %}
{% endfor %}
</ul>
{% if user.je_org %}

View file

@ -1,27 +0,0 @@
# Generated by Django 4.2.16 on 2025-01-21 20:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('personalni', '0019_rename_upozorneni_resitel_upozornovat_na_opravy_reseni'),
('tvorba', '0007_alter_deadline_typ'),
]
operations = [
migrations.SeparateDatabaseAndState(
database_operations=[],
state_operations=[
migrations.AlterField(
model_name='problem',
name='opravovatele',
field=models.ManyToManyField(blank=True, db_table='seminar_problemy_opravovatele', related_name='opravovatele_%(class)s', to='personalni.organizator', verbose_name='opravovatelé'),
),
migrations.DeleteModel(
name='Problemy_Opravovatele',
),
]
),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 4.2.16 on 2024-11-26 22:06
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('tvorba', '0007_alter_deadline_typ'),
]
operations = [
migrations.AlterModelOptions(
name='rocnik',
options={'ordering': ['-rocnik'], 'verbose_name': 'ChRočník', 'verbose_name_plural': 'Ročníky'},
),
]

View file

@ -41,8 +41,8 @@ class Rocnik(SeminarModelBase):
class Meta:
db_table = 'seminar_rocniky'
verbose_name = 'Ročník'
verbose_name_plural = 'Ročníky'
verbose_name = 'ChRočník'
verbose_name_plural = 'ChRočníky'
ordering = ['-rocnik']
# Interní ID
@ -393,6 +393,20 @@ class ZmrazenaVysledkovka(SeminarModelBase):
html = models.TextField(null=False, blank=False)
class Problemy_Opravovatele(SeminarModelBase):
"""Jen vazebná tabulka pro opravovatele.
Ona stejně existovala, při přesunu mezi aplikacemi jen potřebujeme zajistit nepřejmenování DB tabulky.
Proto taky nepotřebuje žádná specifika, ze :py:class:SeminarModelBase: dědí ze zvyku než že by to k něčemu kdy měo být.
"""
class Meta:
db_table = 'seminar_problemy_opravovatele'
id = models.AutoField(primary_key = True)
problem = models.ForeignKey('Problem', on_delete=models.CASCADE)
organizator = models.ForeignKey(Organizator, on_delete=models.CASCADE)
@reversion.register(ignore_duplicates=True)
# Pozor na následující řádek. *Nekrmit, asi kouše!*
class Problem(SeminarModelBase,PolymorphicModel):
@ -448,7 +462,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
on_delete=models.SET_NULL)
opravovatele = models.ManyToManyField(Organizator, verbose_name='opravovatelé',
blank=True, related_name='opravovatele_%(class)s', db_table='seminar_problemy_opravovatele')
blank=True, related_name='opravovatele_%(class)s', through=Problemy_Opravovatele)
kod = models.CharField('lokální kód', max_length=32, blank=True, default='',
help_text='Číslo/kód úlohy v čísle nebo kód tématu/článku/seriálu v ročníku')

View file

@ -1,17 +1,5 @@
\ifnum\mmrocnik=0{{vysledkovka.cislo.rocnik.rocnik}} \else\TODO[Ročník výsledkovky se neshoduje s ročníkem čísla! Pokud je to tak správně, smaž tento řádek.]\par\fi
\ifnum\mmcislo=0{{vysledkovka.cislo.poradi|add:1}} \else\TODO[Číslo výsledkovky se neshoduje s pořadovým číslem čísla! Nestáhnul jsi špatnou výsledkovku? Pokud je to tak správně, smaž tento řádek.]\par\fi
{% if rocnik %}\ifmmposledni\else\TODO[Importoval jsi výsledkovku posledního čísla do čísla, které není poslední (v headru nebylo \texttt{documentclass[\ldots,posledni]\{mam\}})! Pokud je to tak správně, smaž tento řádek.]\par\fi{% endif %}
%
\VysledkyCisla{Výsledky {% if vysledkovka.od_deadlinu %}2.~deadlinu {{vysledkovka.od_deadlinu.cislo.poradi}}.~čísla a~{% endif %}{% if rocnik %}celého{% else %}1.~deadlinu{% endif %} {{vysledkovka.cislo.poradi}}.~čísla}
\vspace{-1em}\nobreak
\begin{center}
%
\setlength{\tabcolsep}{3pt}
\renewcommand{\arraystretch}{1.2}
\noindent\small
%
{% if vysledkovka.je_nejake_ostatni %}\global\vysledkovkaostatnitrue{% else %}\global\vysledkovkaostatnifalse{% endif %}
{% if vysledkovka.od_deadlinu %}\global\VysledkovkaJedenDeadlinefalse{% else %}\global\VysledkovkaJedenDeadlinetrue{% endif %}
\begin{longtable}{|r|l|c|r|{% for p in vysledkovka.temata_a_spol %}c@{\hskip.5em}{% endfor %}{% if vysledkovka.je_nejake_ostatni %}|c@{\hskip.5em}{% endif %}|r|r|}\hline
& & & & \multicolumn{ {{ vysledkovka.temata_a_spol|length}} }{c|}{\textbf{Témata}} & & {% if vysledkovka.je_nejake_ostatni %}&{\hskip.5em}{% endif %} \\\textbf{Poř.}& \textbf{Jméno}& \textbf{R.}& \raisebox{0.7mm}{$\sum_{-1}$}& {% for p in vysledkovka.temata_a_spol %}\textbf{ {{ p.kod_v_rocniku }} }&{% endfor %}{% if vysledkovka.je_nejake_ostatni %}\textbf{O}&{% endif %}\raisebox{0.7mm}{$\sum_0$}&\raisebox{0.7mm}{$\sum_1$}\\\hline
\endhead
@ -20,4 +8,3 @@
{% for rv in vysledkovka.radky_vysledkovky %}{{rv.poradi}}&{% if rv.titul %}\titul{ {{ rv.titul}}}{% endif %}{{rv.resitel.osoba.jmeno|slice:":1"}}. {{rv.resitel.osoba.prijmeni}}&{{rv.rocnik_resitele|default:""}}&{{rv.body_celkem_odjakziva}}&{% for b in rv.body_za_temata_seznam %}{{b}}&{% endfor %}{{rv.body_cislo}}&{{rv.body_rocnik|default:0}}\\
{% endfor %}
\end{longtable}
\end{center}

View file

@ -1,27 +1,14 @@
{% with lb="{" %}
{% with rb="}" %}
{% with vysledkovka=vysledkovka_neverejna %}
%
\ifnum\mmrocnik=0{{rocnik.rocnik}} \else\TODO[Ročník výsledkovky se neshoduje s ročníkem čísla! Pokud je to tak správně, smaž tento řádek.]\par\fi
\ifmmposledni\else\TODO[Importoval jsi výsledkovku ročníku do čísla, které není poslední (v headru nebylo \texttt{documentclass[\ldots,posledni]\{mam\}})! Pokud je to tak správně, smaž tento řádek.]\par\fi
%
\VysledkyRocniku{Výsledková listina {{rocnik.rocnik}}.~ročníku}
\vspace{-1em}\nobreak
\begin{center}
%
\setlength{\tabcolsep}{3pt}
\renewcommand{\arraystretch}{1.2}
\noindent
%
\begin{longtable}{|r|l|c|r|{% for cislo in vysledkovka.cisla_rocniku %}c{% if not forloop.last %}@{\hskip.5em}{% endif %}{% endfor %}|r|}\hline
& & & & \multicolumn{{ lb }}{{ vysledkovka.cisla_rocniku|length }}}{c|}{\textbf{Číslo}} & \\\textbf{Poř.} & \textbf{Jméno} & \textbf{R.} & \raisebox{0.7mm}{$\sum_{-1}$} & {% for cislo in vysledkovka.cisla_rocniku %}\textbf{{ lb }}{{ cislo.poradi }}{{ rb }} & {% endfor %}\raisebox{0.7mm}{$\sum_1$} \\\hline
\endhead
\hline
\endfoot
{% for rv in vysledkovka.radky_vysledkovky %}{{ rv.poradi }} & {% if rv.titul %}\titul{{ lb }}{{ rv.titul }}}~{% endif %}{{ rv.resitel.osoba.jmeno|slice:":1" }}.~{{ rv.resitel.osoba.prijmeni }} & {% if rv.rocnik_resitele %}{{ rv.rocnik_resitele }}{% endif %} & {{ rv.body_celkem_odjakziva }} {% for b in rv.body_cisla_seznam %} & {{ b }}{% endfor %} & {{ rv.body_rocnik }} \\
{% endfor %}
\end{longtable}
\end{center}
{% endfor %}\end{longtable}
{% endwith %}
{% endwith %}
{% endwith %}

View file

@ -1,10 +1,3 @@
{% if cislo is None %}
\ifmmposledni\else\AtBeginDocument{\TODO[Importoval jsi tituly posledního čísla do čísla, které není poslední (v headru nebylo \texttt{documentclass[\ldots,posledni]\{mam\}})! Pokud je to tak správně, smaž tento řádek v \texttt{tituly.tex}.]\par}\fi
{% else %}
\ifmmposledni\AtBeginDocument{\TODO[Importoval jsi průběžné tituly do posledního čísla (v headru bylo \texttt{documentclass[\ldots,posledni]\{mam\}})! Pokud je to tak správně, smaž tento řádek v \texttt{tituly.tex}.]\par}\fi
\ifnum\mmcislo=0{{cislo|add:1}} \else\AtBeginDocument{\TODO[Číslo titulů se neshoduje s pořadovým číslem čísla! Nestáhnul jsi špatné tituly? Pokud je to tak správně, smaž tento řádek v \texttt{tituly.tex}.]\par}\fi
{% endif %}
{% if broken %}
POZOR! Kolize jmen! Dva řešitelé mají stejné makro!
{% endif %}

View file

@ -18,7 +18,7 @@
Termíny pro odeslání řešení {{ac.poradi}}. série:<br>
{% for deadline in ac.deadline_v_cisle.all %}
{% if deadline.typ == deadline.TYP_SOUS or deadline.typ == deadline.TYP_PRVNI_A_SOUS or deadline.typ == deadline.TYP_CISLA_A_SOUS %}
{% if deadline.typ == deadline.TYP_SOUS or deadline.typ == deadline.TYP_PRVNI_A_SOUS %}
<span class="AKTUALNI_ZADANI_datum">{{deadline.deadline.date}}</span> pro účast na soustředění<br>
{% endif %}
@ -26,7 +26,7 @@
<span class="AKTUALNI_ZADANI_datum">{{deadline.deadline.date}}</span> pro otištění v dalším čísle<br>
{% endif %}
{% if deadline.typ == deadline.TYP_CISLA or deadline.typ == deadline.TYP_CISLA_A_SOUS %}
{% if deadline.typ == deadline.TYP_CISLA %}
<span class="AKTUALNI_ZADANI_datum">{{deadline.deadline.date}}</span> definitivní deadline<br>
{% endif %}
{% endfor %}

View file

@ -523,7 +523,7 @@ def TitulyView(request, rocnik, cislo):
jmenovci = True
return render(request, 'tvorba/archiv/tituly.tex',
{'resitele': resitele,'jmenovci':jmenovci,'cislo':cislo},content_type="text/plain")
{'resitele': resitele,'jmenovci':jmenovci},content_type="text/plain")
### Články

View file

@ -0,0 +1,30 @@
from django.core.management.base import BaseCommand
from django.contrib.sessions.models import Session
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
import json
import argparse
class Command(BaseCommand):
"""
"""
def add_arguments(self, parser):
parser.add_argument('file', nargs=1, type=argparse.FileType('r', encoding='utf8'))
def handle(self, *args, **options):
try:
orgroup = Group.objects.get(name='org')
except ObjectDoesNotExist:
orgroup = Group(name='org')
orgroup.save()
permissions = json.load(options['file'][0])
orgroup.permissions.clear()
for jp in permissions:
ct = ContentType.objects.get(app_label = jp['ct_app_label'], model = jp['ct_model'])
perm = Permission.objects.get(content_type = ct, codename = jp['codename'])
orgroup.permissions.add(perm)
orgroup.save()

View file

@ -0,0 +1,20 @@
from django.core.management.base import BaseCommand
from django.contrib.sessions.models import Session
from django.contrib.auth.models import Group, Permission
import json
class Command(BaseCommand):
"""
Dump permissions for group 'org' such that them can be used on an other machine.
"""
def handle(self, *args, **options):
orgroup = Group.objects.get(name='org')
permissions = []
for p in orgroup.permissions.all():
permissions.append({
'codename': p.codename,
'ct_app_label': p.content_type.app_label,
'ct_model': p.content_type.model})
print(json.dumps(permissions))

View file

@ -1,20 +0,0 @@
# Generated by Django 4.2.16 on 2025-01-21 20:34
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('soustredeni', '0013_alter_soustredeni_kontaktnicek_pdf_and_more'),
('various', '0006_tvorba_post'),
]
operations = [
migrations.AddField(
model_name='nastaveni',
name='aktualni_sous',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='soustredeni.soustredeni', verbose_name='Aktuálně připravovaný sous'),
),
]

View file

@ -26,11 +26,6 @@ class Nastaveni(SingletonModel):
verbose_name="Účastnický poplatek za soustředění",
default=1000)
aktualni_sous = models.ForeignKey(
"soustredeni.Soustredeni", verbose_name='Aktuálně připravovaný sous',
null=True, blank=True, on_delete=models.PROTECT,
)
@property
def aktualni_rocnik(self):
return self.aktualni_cislo.rocnik