Compare commits

...

389 commits

Author SHA1 Message Date
23620e178b Merge branch 'korekturovatko' 2025-02-12 13:48:45 +01:00
b81648cdc8 Přidáni ?version=… pro vyhození cachí prohlížeče 2025-02-12 13:47:19 +01:00
83efe094b8 Méně zesvětlené tagy 2025-02-12 13:45:12 +01:00
c2ed4b9cc2 Tlačítko na refresh (FUJ!) 2025-02-12 13:01:06 +01:00
074c9414b2 Autorefresh korektur 2025-02-12 12:46:07 +01:00
63285485ca Schování tlačítek v adminu za pomoci css 2025-02-11 21:35:34 +01:00
d59cba7c0d fix: Když po chybě znovu otevřu komentovací okénko, nemá být disabed 2025-02-11 21:08:58 +01:00
9a6b66f7d9 Fix přijímání prázdné množiny tagů 2025-02-11 21:07:28 +01:00
283320b161 Buttonky další/předchozí korektura 2025-02-11 20:53:46 +01:00
773cd7d419 Tagy u korektur 2025-02-11 18:54:15 +01:00
326be3eaa0 Znemožnění poslání editace/přidání komentáře vícekrát 2025-02-11 15:59:44 +01:00
6bfeab0a5a Umožnění rozdílu mezi autory komentářů a orgy informovanými při přidání komentáře 2025-02-11 15:44:39 +01:00
befb013e58 fix: zobrazování tlačítek na okomentování 2025-02-11 14:57:20 +01:00
82a1efc965 Odkaz na úpravu korektury 2025-02-11 14:52:40 +01:00
aed8e0ea44 button má mít asi type 2025-02-11 12:21:22 +01:00
7237364ba5 Hotfix: chybějící mezery za korekturami 2025-02-11 12:03:47 +01:00
6eb4633af0 Dynamické přidávání korektur a komentářů a úprava komentářů 2025-02-11 12:00:47 +01:00
9ccacaecb5 Merge branch 'master' into korekturovatko 2025-02-11 08:56:18 +01:00
955dd60235 Aktualizace přidávátka úloh a problémů (desetinná čísla a číslo místo dílu) 2025-02-09 22:46:29 +01:00
0a58751155 Přednášky odřádkování (odstavce) 2025-02-09 22:32:16 +01:00
d1ba5057f1 Překlep (HlasovaniOZnalostech.Odpoved) 2025-02-09 22:11:46 +01:00
683796ea7e Merge branch 'refs/heads/prednasky' 2025-02-06 16:57:15 +01:00
4a771b802b Průhledné pruhy 2025-02-06 14:48:32 +01:00
84ed9e09a7 Průhledné pruhy 2025-02-06 13:50:01 +01:00
9460c484f7 Zobrazení Znalostí (stejně jako Přednášek) u daného seznamu 2025-02-04 23:09:47 +01:00
2767e82f11 Merge branch 'master' into prednasky 2025-02-04 22:49:06 +01:00
42c651ceb7 Zlepšení dokumentace Djanga ve Sphinxu 2025-02-04 22:47:18 +01:00
5d4b600b00 Otočení významu odpovědí na hlasování o znalostech + WTF proč to byl string 2025-02-04 21:21:15 +01:00
c1da67dbb4 Dobře, příště už při dokumentaci nebudu hrabat na typové anotace. 2025-02-04 20:33:03 +01:00
5125525238 Dokumentace aplikace prednasky 2025-01-29 01:06:00 +01:00
34f0dffd79 Merge branch 'master' into prednasky 2025-01-29 00:57:24 +01:00
9e513bba9a Kopírování je častým zdrojem chyb 2025-01-29 00:30:55 +01:00
ef9d51d922 hotfix: WTF se stalo v django-autocomplete-light=3.12.0 (%20 místo mezer apod.) 2025-01-28 19:03:51 +01:00
ca5e6728dd hotfix: Tohle by mělo opravit problém s ukládáním bodů. Nejsem si tím ale moc jistý. 2025-01-28 18:48:57 +01:00
7563dd728c Fix make/deploy 2025-01-24 22:51:09 +01:00
cb14e4a91e A očividně nevygeneroval migraci k přepsání stringů u Hlasovani.Body v commitu e933c697 2025-01-24 21:07:06 +01:00
1719e8be9a Zapomněl jsem přidat CSS místo smazaného <i> 2025-01-24 21:03:44 +01:00
0634cdad87 Očividně každý systém žere uvozovky v f-stringu jinak 2025-01-24 20:42:44 +01:00
90e7b97b85 Zakomentován starý export 2025-01-24 20:35:24 +01:00
4001822842 Oprava práv pro aplikaci přednášky 2025-01-24 20:32:28 +01:00
7ca7093371 Export hlasování do CSV 2025-01-24 20:22:38 +01:00
fbd75d2f72 Hlasování o přednáškách pomocí formsetů… 2025-01-24 19:40:54 +01:00
e12b614e1c ODPOVED -> Odpoved 2025-01-24 16:01:39 +01:00
bcda95f0b3 Stringifikace hlasování o znalostech 2025-01-24 15:51:06 +01:00
6c35a5b6f3 Uhlazení prednasky.models 2025-01-24 15:49:55 +01:00
e933c6978d Choices na Enum (u přednášek) 2025-01-24 15:36:33 +01:00
2f814956a7 Nepoužívaný kus kódu 2025-01-24 15:20:00 +01:00
f61533df0a Přidání Znalosti do modelu 2025-01-24 15:13:37 +01:00
7676b0ef60 Merge branch 'korekturovatko-full' into korekturovatko 2025-01-22 20:28:31 +01:00
95b46541c0 Uhlazení JavaScriptu… 2025-01-22 20:28:24 +01:00
0af99d4f3e Aktualizace všech komentářů jako funkce (a aktualizace, ne vytvoření) 2025-01-22 20:23:12 +01:00
f369110cd3 Stránky PDF zvlášť 2025-01-22 19:36:44 +01:00
c54e11f25a Uhlazení JavaScriptu 2025-01-22 19:31:42 +01:00
e205ca52d3 Korektury načtené z API (místo v templatu)… 2025-01-22 18:38:28 +01:00
44a8649d0e Vytváření korektur z jednoho prototypu 2025-01-22 15:39:34 +01:00
a4175f836e Zvýrazňování čar (pointrů) pomocí atributu místo třídy 2025-01-22 11:25:19 +01:00
174087edc7 Merge pull request 'Zpřístupnění informací z "jak se o nás dozvěděli" propagaci' () from zpristupneni_jak_jste_se_dozvedeli into master
Reviewed-on: 
Reviewed-by: Pavel Turinský <ksgitea@pokemon.ledoian.cz>
2025-01-21 22:15:10 +01:00
4906f82365 Inteligentní hláška, pokud nejsou žádné přednášky. 2025-01-21 22:05:04 +01:00
41032be9eb Žádné vzpomínky na seminar.models! 2025-01-21 21:59:29 +01:00
422caadb9e Smazání nadbytečné vazebné tabulky (vazba bude zase viditelná v adminu) 2025-01-21 21:58:42 +01:00
aa997bfcd8 Aktuální sous jsme chtěli blank=True 2025-01-21 21:51:30 +01:00
1a2bef328b Inteligentnější přiřazování seznamu přednášek hlasovátku a upozornění na neexistující seznam 2025-01-21 21:43:43 +01:00
a84df1909b Lepší hláška po odeslání přednášek. 2025-01-21 21:14:19 +01:00
0724030bef nazev branche splnen 2025-01-21 20:39:31 +01:00
833893f233 Merge pull request 'odevzdavatko: odesílání emailu řešiteli při změně zpětné vazby' () from notifikace-zpetne-vazby into master
Reviewed-on: 
2025-01-21 18:10:48 +01:00
a7746cddda Merge branch 'master' into notifikace-zpetne-vazby 2025-01-21 18:05:10 +01:00
2c627b3d60 Když už jsem u toho, tak event.keyCode -> event.code 2025-01-21 13:01:57 +01:00
5f904b5c66 Vytažení commform konstant z funkce showform (budu potřebovat pro submit) 2025-01-21 12:58:23 +01:00
94ca903cec Chybějící const 2025-01-21 12:01:47 +01:00
50936e2b50 Prázdné okno editace komentáře klidně zavřít 2025-01-21 11:53:12 +01:00
4a35a63f31 Zbavení se deprecated věci 2025-01-21 10:49:14 +01:00
4006ecd6b8 A ještě jedno uhlazení CSS korekturovátka 2025-01-21 10:24:43 +01:00
ce2d183446 Ještě jedno uhlazení CSS korekturovátka 2025-01-21 10:23:48 +01:00
1ff69f943e Uhlazení CSS korekturovátka 2025-01-21 10:15:42 +01:00
050ebba03b Nepoužívaná css 2025-01-21 10:06:11 +01:00
443a226943 box -> oprava 2025-01-21 10:05:27 +01:00
7da9aa5fe3 Upozorňovat při zavírání okénka editace komentáře 2025-01-21 09:40:42 +01:00
e257f31ea5 x,y uložené v opravě (nemusíme tahat z čáry (pointru)) 2025-01-21 09:28:46 +01:00
87466ce2b6 box -> oprava 2025-01-21 09:23:20 +01:00
291f39990d Vyčištění IDček v html opravy 2025-01-21 09:12:36 +01:00
b637aed7ab Zapomenutý switch podle document.body.class místo podle atributu 2025-01-21 08:22:34 +01:00
3e2469fc45 Tady je těch prázných stringů nějak moc 2025-01-21 08:20:34 +01:00
d5c57da921 Čára (pointer) jako atribut opravy místo grepování "opid-pointer" 2025-01-21 08:17:12 +01:00
370dd7d841 Už nemáme text v opravě, takže nemá smysl ho editovat 2025-01-21 08:12:42 +01:00
d818ce251b Box_edit za pomoci objektu opravy místo id 2025-01-21 08:10:13 +01:00
4121de260e Ha, tohle jsem chtěl tady 2025-01-21 07:48:05 +01:00
a8b7788d35 Merge branch 'master' into korekturovatko 2025-01-21 07:40:42 +01:00
9aa3a5154d Přesnější query (aby nebral i jiné formuláře) 2025-01-21 07:39:55 +01:00
7a4c8239f6 Čára (pointer) opravy nemá vůbec interagovat s klikáním 2025-01-21 07:37:36 +01:00
0d67b5ff83 Prozatím takhle (proházel jsem kanály) 2025-01-21 00:07:14 +01:00
2deccfada4 Oprava URL 2025-01-20 23:48:54 +01:00
d2e199e509 Dynamický update stavu opravy 2025-01-20 23:40:06 +01:00
9b0fe3d32f Tohle tu nějak zůstalo 2025-01-20 22:35:46 +01:00
af41ca5784 Čistka scrollování 2025-01-20 22:11:53 +01:00
ad2d1e676c Zobrazení tlačítek podle atributu (ne v podle stavu v templatech) 2025-01-20 22:11:02 +01:00
00e0ed0a50 Skrývání korektur pomocí atributu 2025-01-20 21:45:37 +01:00
5563eb681c Status korektury jako atribut a ne třída 2025-01-20 21:06:33 +01:00
3b74772949 Přeházení JavaScriptových věcí 2025-01-20 19:12:27 +01:00
ee69bf4c4f Drobný úklid 2025-01-20 18:38:47 +01:00
071c66ee10 personalni: změna nastavení upozorňování u existujících řešitelů 2025-01-15 18:24:22 +01:00
1bee36d9b6 personalni: přejmenování sloupce pro upozornění na zpětnou vazbu 2025-01-14 21:00:33 +01:00
aa364b3f49 Výsledkovky do TeXu (a tituly) si odteď více hlídají, že jsou správně stažené. 2025-01-09 20:28:38 +01:00
9a11491dcc Merge pull request 'Admin strxfrm mac' () from strxfrm_pro_mac into master
Reviewed-on: 
2025-01-07 18:30:51 +01:00
a97071cd03 not dumb error log message 2025-01-07 17:49:16 +01:00
9c4c60765e logger done 2025-01-07 17:44:22 +01:00
d67d2f372b Oprava zobrazování deadlinů v aktuálním zadání 2025-01-03 18:00:47 +01:00
dd86fc1fcb Dynamický update stavu 2024-12-12 13:52:55 +01:00
341ae7ce45 Rozlišení lokálního/testovacího/produkčního webu v korekturovátku 2024-12-12 12:51:32 +01:00
7906c87733 Zanášení a zastaralé pomocí atributu místo třídy 2024-12-12 12:50:56 +01:00
daf24ff981 Rozstřílení korekturovátka (html) 2024-12-12 12:33:33 +01:00
0dde05f102 Odstranění textu a autora z opravy (přesun do prvního komentáře) 2024-12-12 11:50:17 +01:00
3528a44d3c Úprava chování korektury (schovává text korektury!!!) 2024-12-12 11:24:17 +01:00
524593b7ef Merge branch 'master' into korekturovatko 2024-12-10 19:03:22 +01:00
65ec9bfaed Fix přednášek 2024-12-10 16:33:25 +01:00
7038de2e25 Merge pull request 'Dokumentace zkratek do zdrojáků' () from doc_zkratky into master
Reviewed-on: 
2024-12-03 22:33:16 +01:00
c43575d8d2 Merge pull request 'Vnořené rámečky mají být vidět' () from nested_ramecky into master
Reviewed-on: 
2024-12-03 22:32:35 +01:00
8d6b352545 Merge pull request 'Práva v data/* a načítané pomocí ./manage.py loaddata' () from prava into master
Reviewed-on: 
2024-12-03 22:32:08 +01:00
51eeffd0c5 Ještě právo řešitele a trochu jiné řazení 2024-12-03 22:23:53 +01:00
42d57e7b42 Přebývající dump práv 2024-12-03 22:19:40 +01:00
edde41e1ab Chybějící data/groups.json 2024-12-03 22:19:10 +01:00
6ea212cdf8 odevzdavatko: odesílání emailu řešiteli při změně zpětné vazby
Toto se rozbíjí, když dojde ke smazání hodnocení v pořadí dříve, než
nějaké hodnocení s neprázdnou zpětnou vazbou, neboť řádky formsetu jsou
přečíslovány a pak špatně spárovány s původními hodnotami, takže se
nesprávně detekuje změna.
2024-12-03 21:30:35 +01:00
Pavel "LEdoian" Turinsky
497bb054ee Vnitřní rámečky by měly jít vidět
Vnořený rámeček totiž značí, co dalšího ostatní neuvidí po zveřejnění
vnějšího rámečku.
2024-12-03 21:27:40 +01:00
e9451ed62e Merge pull request 'Řešitelský rámeček (aneb resitel-only; pro neveřejné věci řešitele)' () from ucastnicky-ramecek into master
Reviewed-on: 
2024-12-03 21:22:30 +01:00
MaM Web user
e87b84b028 Fix rámečku u soustředění, kde jsem nebyl účastník (Jidáš) 2024-12-03 20:59:03 +01:00
22e88daf02 Korektury api init 2024-12-03 20:10:41 +01:00
04508206bb Funkce na posílání e-mailu rozhodně nemá být uvnitř View 2024-12-03 19:41:12 +01:00
8d09fd5389 Status opravy řešit přes enum 2024-12-03 19:10:36 +01:00
9df34c22e0 Moderní přístup k choices (umožňuje např. vytáhnout seznam všech hodnot) 2024-12-03 19:01:33 +01:00
d3d5484d0e Form se nikde nepoužívá 2024-12-03 18:37:23 +01:00
62160e8440 PDF už dostáváme v URL, není to potřeba shánět znovu 2024-12-03 18:33:26 +01:00
1e6e6118a7 Nepoužívat náhodné stringy, když už máme nějaké definované… 2024-12-03 18:20:25 +01:00
c1440687aa Nepotřebné importy… 2024-12-03 17:51:33 +01:00
69e870f958 Podle mě funguje… 2024-12-03 17:50:48 +01:00
ddd12b684d komentar 2024-12-02 11:51:19 +01:00
eb2b861d48 try except na sort 2024-12-01 15:47:49 +01:00
9020f5551d Oprava testdat KorekturovanePDF 2024-11-26 23:12:43 +01:00
ca462289a9 Zúžení except klauzule 2024-11-26 23:10:08 +01:00
80b20f5290 Práva v data/* a načítané pomocí ./manage.py loaddata 2024-11-26 20:05:49 +01:00
dbe8c39b37 Merge pull request 'Korektury Link Z Admina' () from korektury-link-z-admina into master
Reviewed-on: 
2024-11-26 19:37:18 +01:00
0aee5b9bdb Řešitelský rámeček (aneb resitel-only; pro neveřejné věci řešitele) 2024-11-26 19:33:44 +01:00
aee7637fcf Oprava křížku pro mazání hodnocení 2024-11-26 19:03:06 +01:00
5bf8df0218 Merge pull request 'Upgrade CKEditoru na verzi 5' () from ckeditor5 into master
Reviewed-on: 
2024-11-26 18:36:07 +01:00
5853b243dd Komentář 2024-11-26 18:34:54 +01:00
Pavel "LEdoian" Turinsky
5f87045b31 Ještě jedna aktualizace :-) 2024-11-19 22:39:18 +01:00
Pavel "LEdoian" Turinsky
36b261580c Aktualizace toho, jak se používá Sphinx u nás 2024-11-19 22:38:46 +01:00
Pavel "LEdoian" Turinsky
3920ac72aa Sepsané zkratky pro zdrojáky 2024-11-19 22:38:34 +01:00
dc91ef571f Upgrade CKEditoru na verzi 5 2024-11-19 22:05:12 +01:00
f0fbd8021f Merge pull request 'Přidání CKEditoru do Soustředění a Novinek (#1294)' (!75) from ckeditor-dalsi-veci into master
Reviewed-on: #75
2024-11-19 20:31:18 +01:00
3d035b994a Přidání CKEditoru do Soustředění a Novinek 2024-11-19 20:22:12 +01:00
db3dd39696 Merge pull request 'Možnost mít deadline celého čísla a sousu zároveň' (!74) from deadline-cisla-a-sousu into master
Reviewed-on: #74
2024-11-13 12:16:21 +01:00
e0e1dfda41 Merge remote-tracking branch 'origin/master' into deadline-cisla-a-sousu
# Conflicts:
#	tvorba/models.py
2024-11-13 12:14:33 +01:00
MaM Web user
44766efe2a Ještě migrace
— LEdo
2024-11-12 21:47:10 +01:00
d129f8a764 Merge remote-tracking branch 'refs/remotes/origin/master' 2024-11-12 21:45:59 +01:00
5b330567f8 generating file names with three functions 2024-11-12 21:44:17 +01:00
e6a21a5f1b Komentář, abychom kdyžtak uměli duplikovat přidání deadlinu 2024-11-12 21:41:32 +01:00
042246e948 dalsí do masteru zobrazovani kontaktnicku 2024-11-12 21:39:17 +01:00
e224ee66a7 push to master quick fix zobratzeni pro orrrgy 2024-11-12 21:23:13 +01:00
5ccb94d155 Merge pull request 'verejny kontaktnicek' (!71) from kontaktnicek_pro_vsecny into master
Reviewed-on: #71
2024-11-12 21:15:24 +01:00
fa00652a69 Merge branch 'master' into kontaktnicek_pro_vsecny 2024-11-12 21:14:10 +01:00
036c68bc2a another lambad function 2024-11-12 21:07:13 +01:00
fcc2c7c374 lol komentar 2024-11-12 20:37:50 +01:00
1b755ad1f7 deduplikace listu 2024-11-12 20:37:14 +01:00
ad5a242f8d upravy generate filename 2024-11-12 20:31:08 +01:00
6186914a7c aaaaa another bug 2024-11-12 20:27:51 +01:00
7a781e463f lol docker tu nemel byt 2024-11-12 20:20:43 +01:00
2dbbb588d0 opravy pro pull 2024-11-12 20:15:09 +01:00
eada7920f0 Možnost mít deadline celého čísla a sousu zároveň 2024-11-12 20:10:19 +01:00
6a7e4b1a39 Možnost mít deadline celého čísla a sousu zároveň 2024-11-12 19:58:14 +01:00
5883a5cd28 Merge pull request 'Předělání sousových views' (!57) from predelani_sousovych_view into master
Reviewed-on: #57
2024-11-12 19:33:10 +01:00
7e8092c30c tex -> tex_prikaz 2024-11-12 19:32:19 +01:00
f01a808ac2 Komentář 2024-11-12 19:29:17 +01:00
c8dd54e8ba opravy bad designu 2024-11-12 18:37:21 +01:00
Pavel 'LEdoian' Turinsky
f2825a97cf Přidání odkazu z Admina do korekturovátka 2024-11-11 07:46:34 +01:00
0f6f6a85b6 verejny kontaktnicek 2024-11-05 22:47:18 +01:00
502588fd3a Merge pull request 'soucet_bodu' (!70) from soucet_bodu into master
Reviewed-on: #70
2024-11-05 22:27:54 +01:00
b4b6c7c0ce seminar.models se načítá automaticky, budiž to mamweb.vsechno 2024-11-05 22:25:40 +01:00
om
0e83f96318 <p> se souctem bodu pod odevzdana reseni 2024-11-05 22:20:48 +01:00
om
e660a96df2 <p> se souctem bodu pod odevzdana reseni 2024-11-05 22:10:45 +01:00
854c902322 Merge branch 'master' into predelani_sousovych_view 2024-11-05 20:36:43 +01:00
024f8e0a80 Merge pull request 'Podezřelé semináře (#1465)' (!65) from podezrele-seminare into master
Reviewed-on: #65
2024-11-05 20:31:54 +01:00
bf726df117 Přepsání loggeru, protože to vypadá lépe (i kdyby to nefungovalo) 2024-11-05 20:30:55 +01:00
227d438ebd Poslední obrana proti importování seminar.models 2024-11-05 20:22:04 +01:00
71948383d2 Upraven popis aplikace seminar 2024-11-05 20:19:34 +01:00
6df9665af3 Migrace utišující Django (stejně se default nikdy nepoužívá). 2024-11-05 20:15:41 +01:00
c1938c8ff7 Odstřel funkcí pro migrace 2024-11-05 19:56:07 +01:00
4536c56a83 Merge pull request '+5 let limit maturity' (!69) from vek_maturity into master
Reviewed-on: #69
2024-11-05 19:53:43 +01:00
om
8156f7828e +5 let limit maturity 2024-11-05 19:25:36 +01:00
f5c2e22121 Zapomenutý seminar.models 2024-11-05 18:54:01 +01:00
62a42675f8 mv SeminarModelBase a OverwriteStorage 2024-11-05 18:53:38 +01:00
a372aa1bc2 Seminar v dokumentaci 2024-11-05 17:46:27 +01:00
d0cb46b658 Název url seznamu všech soustředění 2024-11-05 17:40:36 +01:00
ac6c41cc88 Název url seznamu všech soustředění 2024-11-05 15:10:36 +01:00
1c146ac5c3 Admin ReseniNode 2024-11-05 15:07:51 +01:00
527a7b3ea6 Pojmenované URL místo čistého URL 2024-11-05 14:58:25 +01:00
e4a72940e8 Merge remote-tracking branch 'origin/master' into podezrele-seminare 2024-11-05 14:46:50 +01:00
7b3708d7ab Merge pull request 'Oprava Testu Delani Orgem' (!68) from oprava_testu_delani_orgem into master
Reviewed-on: #68
2024-11-05 14:40:37 +01:00
c0825691a6 Merge branch 'master' into podezrele-seminare 2024-11-05 14:29:02 +01:00
b606f03191 Merge pull request 'Odstřel modelu TreeNode' (!67) from odstrel_modelu_treenode into master
Reviewed-on: #67
2024-11-05 14:19:50 +01:00
Pavel "LEdoian" Turinsky
461cfa4253 Treenode: komentář o tom, proč tam je i Text a Obrazek 2024-11-03 03:20:52 +01:00
Pavel "LEdoian" Turinsky
a2517abade Odstřel: závěrečná migrace 2024-11-03 03:12:16 +01:00
Pavel "LEdoian" Turinsky
51618e0d89 Oprava testu dělání orgem 2024-11-03 02:51:27 +01:00
Pavel "LEdoian" Turinsky
9b14e4a333 Treenode: žádné pomocné treenody nebudou. 2024-11-03 01:46:18 +01:00
Pavel "LEdoian" Turinsky
8283b530e9 Merge remote-tracking branch 'gitea/podezrele-seminare' into bez_treenodu_i_bez_podezrelych_seminaru
Zatím tak, jak se namergeovalo, změny k funkčnosti v dalších commitech
(ať neděláme zbytečně magické merge)
2024-11-03 01:42:56 +01:00
Pavel "LEdoian" Turinsky
e10747aa9f odstřel Treenode: zapomenutá závislost na contenttypes 2024-11-02 22:46:14 +01:00
Pavel "LEdoian" Turinsky
8ae19988b1 Vyrábět schéma semináře už nemá moc smysl :-) 2024-11-02 22:21:47 +01:00
Pavel "LEdoian" Turinsky
2659d72d2e odstřel TreeNode: 🔫💥💥💥 2024-11-02 22:00:08 +01:00
007332804e Fix: Ať to alespoň nehází chybu. 2024-11-01 16:40:21 +01:00
7f21d10c26 Ha, tak jsem se někde zamotal do import cyklu a musel jsem ReseniNode dát tam, kam patří 2024-11-01 14:02:07 +01:00
dc0ff80632 Přehlídnutý import seminar.models 2024-11-01 13:51:43 +01:00
07d1505e2a Odstřel (importů) treenodů 2024-11-01 13:50:48 +01:00
9ca5967261 Přesun vue (zatím) do treenodů 2024-11-01 13:20:28 +01:00
eb6eb2d6fb Přejmenování loggerů 2024-11-01 13:17:39 +01:00
28fef9a393 Pojmenované URL místo relativních URL 2024-11-01 12:58:02 +01:00
f8b1f0978c Přejmenování URLs 2024-11-01 12:38:47 +01:00
5f931c49a5 Merge branch 'master' into podezrele-seminare 2024-11-01 12:10:07 +01:00
MaM Web user
5c7710ed3a Formátování jsonu (jidáš) 2024-11-01 12:09:04 +01:00
6cdc37e80b Synchronizace sitetree s produkcí (než se v tom začnu hrabat) 2024-11-01 12:01:24 +01:00
8fd582d194 Další částečné řešení #1465 (Podezřelé seminare). Záměrně se vyhýbá treenode. 2024-11-01 11:44:17 +01:00
27a16719be Merge remote-tracking branch 'origin/master' into podezrele-seminare 2024-10-31 10:56:48 +01:00
87a76b17ef Merge pull request 'Odstrel Modelu Tvorba' (!66) from odstrel_modelu_tvorba into master
Reviewed-on: #66
2024-10-31 10:54:50 +01:00
Pavel "LEdoian" Turinsky
ad9a496cee Kus kódu není potřeba (a navíc obsahuje slovo seminář :-P) 2024-10-31 00:03:00 +01:00
Pavel "LEdoian" Turinsky
26d37d96f7 Frontendové náhrady semináře
(některé netestované, smůla.)
2024-10-31 00:01:07 +01:00
Pavel 'LEdoian' Turinsky
062f70e947 odstřel tvorby: relink – post 2024-10-30 22:41:11 +01:00
5db14ea242 Částečné řešení #1465 (Podezřelé seminare) 2024-10-30 15:03:17 +01:00
Pavel 'LEdoian' Turinsky
92c05342fb odstřel tvorby: pre – relink 2024-10-30 14:36:06 +01:00
b8f377b15d Merge pull request 'Odstrel Modelu Odevzdavatko' (!64) from odstrel_modelu_odevzdavatko into master
Reviewed-on: #64
2024-10-29 19:31:54 +01:00
a6085a64f4 Přepojení importů 2024-10-29 19:21:00 +01:00
c71195fba1 Merge branch 'master' into odstrel_modelu_odevzdavatko 2024-10-29 19:15:36 +01:00
9ee82f72a7 SeminarModelBase.admin_url nyní umí i modely v jiných appkách… 2024-10-29 19:12:42 +01:00
ce83247fe0 Doplnění nepovinného nesting selektoru &, abychom rozšířili support na starší prohlížeče 2024-10-28 12:29:08 +01:00
46a8f136fa Fix formularOKView (TemplateDoesNotExist) 2024-10-25 20:21:47 +02:00
e0dc75763c Jiný pokus o opravu stylů na starých iOSech 2024-10-25 13:31:50 +02:00
788e8d22a2 Pokus o opravu stylů na starých iOSech 2024-10-25 12:57:07 +02:00
11eb3c3665 Pohrobek splitu semináře (předchozího merge) 2024-10-24 11:51:28 +02:00
446515a52e Merge branch 'master' into predelani_sousovych_view
# Conflicts:
#	soustredeni/views.py
#	various/views/generic.py
2024-10-24 11:44:04 +02:00
Pavel "LEdoian" Turinsky
c7fe1cb386 post – odevzdávátko odstřeleno! 2024-10-23 23:11:56 +02:00
Pavel "LEdoian" Turinsky
07e9c8b7e4 manage 2024-10-23 23:09:19 +02:00
Pavel "LEdoian" Turinsky
10a824719b delete 2024-10-23 23:01:54 +02:00
Pavel "LEdoian" Turinsky
d288fefecc Zrušení dočasných odkazů do seminar.models.*
Poznámky:
- `seminar.models.base` je v pořádku (není to dočasný soubor)
- dočasné importy v `seminar/models/*.py` jsou taky validní, protože
  odtamtud zmizí. Jde mi o to, aby náhodné věci buď používaly
  už-správnou aplikaci, nebo postaru `seminar.models` jako celek, aby
  během odstřelu nebylo potřeba všechny věci přepisovat.

Ano, tohle je potenciálně kontroverzní commit. Ale je dočasný a mně
poněkud rozbíjí workflow, když mi v náhodné okamžiky odmítne běžet
náhodná část webu na kterou nesahám jen kvůli tomu, že importuje věci
odněkud, odkud to nečekám.

Alternativní řešení: dát správné importy (s dočasnými
`seminar.models.*`) do správných `aplikace/models.py` už teď a
importovat věci rovnou z výsledných modulů. To zajišťuje jak
konzistenci, tak to, že při odstřelu se cesta změní na jednom očekávaném
místě (resp. spíš se prostě smaže) a všechno ostatní bude pokračovat ve
fungování.
2024-10-23 22:54:14 +02:00
Pavel "LEdoian" Turinsky
130907174d relink 2024-10-23 21:54:49 +02:00
Pavel "LEdoian" Turinsky
33381b4307 create 2024-10-23 21:46:19 +02:00
c7910ed72a Merge pull request 'Více orgů k jednomu PDF v korekturovátku' (!52) from vice_orgu_v_korekturovatku into master
Reviewed-on: #52
2024-10-23 12:47:49 +02:00
35fa97d828 Merge branch 'master' into vice_orgu_v_korekturovatku 2024-10-23 12:25:19 +02:00
35131c96ec Novinky byly bůhví proč BigAutoField 2024-10-23 12:22:46 +02:00
acdadc06ab Merge branch 'ghoul_font' 2024-10-23 11:57:29 +02:00
2ae906495d Opravil jsem font (aby fungovala diakritika apod.) 2024-10-23 11:49:48 +02:00
Pavel "LEdoian" Turinsky
49e93025c0 unm 2: změna jména 2024-10-23 01:01:09 +02:00
Pavel "LEdoian" Turinsky
d1172b9d38 unm 2024-10-23 00:31:58 +02:00
Pavel "LEdoian" Turinsky
792a8fa4dc pre 2024-10-23 00:31:21 +02:00
622b632773 Merge pull request 'ghoul_font' (!63) from ghoul_font into master
Reviewed-on: #63
2024-10-22 23:49:55 +02:00
91b6220f24 Merge branch 'master' into ghoul_font 2024-10-22 22:31:05 +02:00
bb0cf871ec Merge pull request 'Oddělení sousových věcí' (!56) from split_sous into master
Reviewed-on: #56
2024-10-22 22:15:14 +02:00
3db6231a77 Název id v url 2024-10-22 22:11:59 +02:00
d5d55d76a9 Lepší komentář 2024-10-22 21:57:01 +02:00
0423bce762 Merge branch 'master' into split_sous
# Conflicts:
#	seminar/testutils.py
#	soustredeni/urls.py
2024-10-22 21:49:15 +02:00
f9a28689b0 views_all do __init__ 2024-10-22 21:30:33 +02:00
7108702e36 Merge pull request 'Rozstřílení seminářové aplikace' (!60) from split into master
Reviewed-on: #60
2024-10-22 21:27:20 +02:00
e443ecf33d views_all do __init__ 2024-10-22 21:23:11 +02:00
8d846647f6 Merge branch 'master' into split
# Conflicts:
#	various/templates/various/titulnistrana/titulnistrana.html
2024-10-22 20:18:48 +02:00
8ff66cb631 WTF? 2024-10-22 20:15:58 +02:00
227b83b701 halloween do settings 2024-10-22 20:10:27 +02:00
192f5d2ee7 Merge pull request 'Velká revize stylů (a některých JS)' (!44) from static-files-upgrade into master
Reviewed-on: #44
2024-10-22 20:00:11 +02:00
77d158a3a7 Změna version, aby počítače přenačetly CSSka 2024-10-22 19:56:08 +02:00
05e6e5fb59 Merge branch 'master' into static-files-upgrade 2024-10-22 19:29:54 +02:00
fbd5087c02 Změna version, aby počítače přenačetly CSSka 2024-10-22 19:29:29 +02:00
8dca676edc script presunut dolu pod april 2024-10-22 19:29:28 +02:00
ffcc2e04a3 TS -> TITULNI_STRANA a AZAD -> AKTUALNI_ZADANI 2024-10-22 19:28:12 +02:00
b491dcff7e Komentář k kontejneru 2024-10-22 19:19:31 +02:00
592ae29d35 ghoul font na posledních 7 dní října 2024 2024-10-22 19:05:41 +02:00
133c487637 Sloupeček ostatní ve výsledkovce (nová makra) 2024-10-13 23:39:47 +02:00
9f421e9d77 Sloupeček ostatní ve výsledkovce (nová makra) 2024-10-13 23:38:17 +02:00
e87bbe6048 Sloupeček ostatní ve výsledkovce (nová makra) 2024-10-13 23:31:05 +02:00
6ec2a10bf5 setuptools v requirements.txt 2024-10-10 13:23:51 +02:00
c45bf88d40 Merge pull request 'Export do abstraktů (soustředění)' (!61) from sbornicek into master
Reviewed-on: #61
2024-10-10 09:08:09 +02:00
733484b503 Export do abstraktů (soustředění) 2024-10-02 21:20:44 +02:00
e250f1d5dc Admin_url soustředění (aby mohlo být v login-baru) 2024-10-02 21:16:53 +02:00
d8d37adc1f Merge branch 'refs/heads/split_sous' into predelani_sousovych_view 2024-08-06 02:41:19 +02:00
1b01fe54d2 Merge branch 'refs/heads/master' into predelani_sousovych_view 2024-08-06 02:40:04 +02:00
b41b912aa4 Merge branch 'refs/heads/master' into split_sous 2024-08-06 02:39:08 +02:00
348096024e seminar/testutils.py 2024-08-06 02:33:53 +02:00
d952ab13a5 Generování konfer s konkrétními řešiteli 2024-08-05 13:15:29 +02:00
bf748b55ee Odstraněn zakomentovaný zbytečně složitý kód 2024-08-05 13:15:25 +02:00
6a781323e0 Typové anotace a další detaily v generování testdat k soustredeni 2024-08-05 13:15:21 +02:00
0b0a939de5 Oddělení generování testdat k sous věcem 2024-08-05 13:15:17 +02:00
c34716e134 seminar/utils.py 2024-08-05 11:46:38 +02:00
85c3969c50 seminar/templatetags 2024-08-04 19:21:46 +02:00
18364eb531 seminar/static 2024-08-04 19:15:15 +02:00
95ab0ee1dc Commandy zatím do various… 2024-08-04 19:08:24 +02:00
731c795ee6 Text a Obrazek 2024-08-04 19:01:09 +02:00
31b7cbb8d7 Tvorba (templates, admin, views) 2024-08-04 18:53:35 +02:00
ba2ea74a04 Obálky do personálního 2024-08-04 18:23:58 +02:00
a6eebb2d59 Seznam organizátorů do personálního 2024-08-04 18:15:01 +02:00
be8c9810e4 Rozdělení varous.views, aby odpovídali 5f7ec853 2024-08-04 17:51:26 +02:00
47894ce335 Přesun csrf_error 2024-08-04 17:43:29 +02:00
5f7ec853fa Přesun náhodných views do various 2024-08-04 17:41:24 +02:00
0cab9a8286 Přesun csrf_error 2024-08-04 17:02:25 +02:00
9920465f99 Split novinek 2024-08-04 16:57:39 +02:00
99a1fd9a9f Merge pull request 'Vyčištění náhodných věcí (co mě tak kde štvalo)' (!58) from vycisteni into master
Reviewed-on: #58

Není tam nic sporného ani kritického[^1], takže rovnou mergeuji…

[^1]: a máme docela málo kapacity na pročítání pull requestů.
2024-08-03 13:08:46 +02:00
431978e626 Starý kus kódu, který by se mohl hodit, ale je příšerně zastaralý (ObrazekAutocomplete) 2024-08-03 13:03:09 +02:00
69635b4234 TODO jsou v kanboardu 2024-08-03 13:01:10 +02:00
f0b642ca44 Nepoužívaný kus kódu 2024-08-03 12:58:38 +02:00
8dc3a2ba98 Odstraněňo staré testování e-mailů 2024-08-03 11:50:14 +02:00
8fef21900c Autogenerované komentáře a prázdné testy 2024-08-03 11:28:03 +02:00
1d36cd0761 Tohle nastavení už je v settings 2024-08-03 11:09:39 +02:00
e21a93f9e7 Middleware řešící sessioh mezi http a https se už fakt dlouho nepoužívá a navíc je toto téma dnes dávno pasé 2024-08-03 11:06:00 +02:00
ead2a4ede3 Tahle middleware se vůbec nepoužívá (používá se contextprocessor vzhled) 2024-08-03 11:04:19 +02:00
5f9bda9afe Ha, tohle mělo smazáno být už v 75344c2c 2024-08-03 10:56:51 +02:00
0817012130 Tahle moje „dokumentace“ je k ničemu, mažu 2024-08-03 10:55:03 +02:00
7a6a7cb0f5 Návod na nahrátí obrázků do odměn (a jinak o flatpage) nemá smysl mít v kořenové složce 2024-08-03 10:42:31 +02:00
75344c2c3a Kontroly codestylu nechceme 2024-08-03 10:40:03 +02:00
350623c6ac Python už je dávno defaultně utf-8, netřeba deklarace na začátku souboru 2024-08-03 10:38:00 +02:00
2bb732959a Nepoužívaný kód 2024-08-03 10:31:20 +02:00
d55199d6ae Achich ouvej, on je to Soustredeni_Ucastnici model 2024-08-02 23:44:37 +02:00
05a710185c Předělání sousových views do hodně inheritance stavu
Vím, že je toho tady trochu moc najednou, ale napadalo mě to tak propleteně…
2024-08-02 23:36:12 +02:00
4a3681b1a6 Drobnost 2024-08-02 20:32:07 +02:00
ccf3ec07f7 Generování konfer s konkrétními řešiteli 2024-08-02 20:17:31 +02:00
b44bdadb0a Odstraněn zakomentovaný zbytečně složitý kód 2024-08-02 20:15:02 +02:00
a6220e8d50 Typové anotace a další detaily v generování testdat k soustredeni 2024-08-02 20:13:45 +02:00
27beb34153 Oddělení generování testdat k sous věcem 2024-08-02 19:38:06 +02:00
62a65af40e Odstranění zbytečného importu 2024-08-02 19:29:13 +02:00
036af434c6 Oddělení urlpatterns konkrétního sousu 2024-08-02 19:25:25 +02:00
d1db1b952f Obsah modulu soustredeni 2024-08-02 19:17:49 +02:00
ddda7052ae Zbavení se zbytečného importu modelu Resitel 2024-08-02 19:17:11 +02:00
0fa2fb8e2b Úprava importů v soustredeni 2024-08-02 19:01:50 +02:00
b094347b7c Vytažení prefixu 'soustredeni/' do aplikace soustredeni 2024-08-02 18:34:05 +02:00
3188e024da Logy týracího skriptu do .gitignore 2024-08-02 13:24:29 +02:00
69019baf4e Merge pull request 'Přidání chybové hlášky :3' (!55) from divni-uzivatele into master
Reviewed-on: #55
2024-08-02 11:52:40 +02:00
ec474530e4 add .DS_store to .gitignore 2024-07-19 11:41:53 +02:00
f564d4e145 Správný odkaz na diff (na wiki)? 2024-07-09 19:32:09 +02:00
49aea5b8b4 Změny (z gimliho) v konfiguraci nginxu, které asi chceme 2024-07-09 19:30:32 +02:00
Pavel "LEdoian" Turinsky
ca8e8506b3 Přebytečná HttpResponse 2024-07-08 22:52:58 +02:00
Pavel "LEdoian" Turinsky
2444e5f985 Nemusím shazovat web 2024-07-08 22:39:46 +02:00
476f8263d4 Merge pull request 'Otevírání článků na správné straně' (!54) from clanek-strana into master
Reviewed-on: #54
2024-06-20 14:42:39 +02:00
1ce9cb445f Tady bylo „.cislo“ navíc… 2024-06-20 14:38:27 +02:00
6225630f9f Migrační kekel 2024-06-20 14:31:58 +02:00
0bebee5329 Merge branch 'master' into clanek-strana 2024-06-19 20:34:56 +02:00
Riki
3c3b9f755a Add strana column to Clanek
Optionally add page fragment to `resitelske_clanky.html`
2024-06-15 23:35:46 +02:00
40ca76d414 Merge pull request 'akce na sjednoceni cisel do +420 123 456 789' (!53) from sjednoceni_telefonu into master
Reviewed-on: #53
2024-06-15 23:33:24 +02:00
cf3c9f6f80 prazdy string -> continue 2024-06-15 23:27:42 +02:00
fad2c6940d oprava chybové hlášky 2024-06-15 23:20:35 +02:00
491f91cf47 akce na sjednoceni cisel do +420 123 456 78 2024-06-15 22:54:26 +02:00
Pavel "LEdoian" Turinsky
2304a8282c PDF nemusí mít zodpovědného orga! 2024-06-15 22:50:20 +02:00
Pavel "LEdoian" Turinsky
8a5659420d Na výběr orgů pro PDF chceme autocomplete 2024-06-12 02:25:01 +02:00
Pavel "LEdoian" Turinsky
d895cd0636 Víc orgů k jednomu PDF v korekturovátku 2024-06-12 02:02:37 +02:00
af9f244207 Drobný nesting 2024-05-13 23:26:16 +02:00
20691f483a Merge remote-tracking branch 'origin/master' into static-files-upgrade 2024-05-13 22:41:09 +02:00
4d13b0eb25 Tohle je myslím zastaralé (stará verze bootstrapu) 2024-04-30 23:57:55 +02:00
6cc1b1fbe7 Tohle je spíše nepoužívané 2024-04-30 23:57:32 +02:00
72f11a25ce Myslím, že funguje, že jsem byl jen hloupý 2024-04-30 23:54:57 +02:00
3f1a570878 Nějaké další přechody na CSS nesting 2024-04-30 23:53:50 +02:00
53caf7f73a Novinka je rozhodně modul (můžeme ji použít kdekoliv, nejen na jedné konkrétní stránce) 2024-04-30 23:28:37 +02:00
ed703b10a1 Vize, jak by měly vypadat CSSka konkrétních stránek (a možná CSSka obecně) 2024-04-30 23:27:53 +02:00
b8b0c5440f Nějaký základ nové verze CSSek 2024-04-30 22:47:03 +02:00
48123a8ce2 Merge branch 'refs/heads/master' into static-files-upgrade
# Conflicts:
#	mamweb/templates/base.html
2024-04-30 21:03:12 +02:00
5eb936d891 Fix: z flip-card mi vypadlo jejich zarovnání na střed 2024-03-19 21:52:04 +01:00
df5ae2c12a Fix: bootstrap upravuje .container 2024-03-12 22:09:32 +01:00
bd1d04802b Oprava výsledkovek 2024-02-24 11:15:01 +01:00
8cd3250bb0 Zkrocení stylů okolo otáčecích karet 2024-02-24 10:42:54 +01:00
cc09980632 Lepší řešení otáčecích karet na dotykových zařízeních 2024-02-24 08:55:09 +01:00
3363fbdc7c Tohle asi sem 2024-02-24 08:33:08 +01:00
3f8756148d Drobné úpravy CSSek 2024-02-20 19:34:50 +01:00
7b1e3ab58b Rozhození layoutovací @media (styly na menších displejích) 2024-02-20 19:26:57 +01:00
ee7771bdb3 Přesun CSS menu mimo hlavní layout 2024-02-20 19:16:47 +01:00
10c252cd16 Rozházení @media, o kterých je jasné, kam patří 2024-02-20 19:14:17 +01:00
a4a4af5f93 Tohle asi patří sem 2024-02-20 18:52:18 +01:00
5048439aee Nějaké nepoužívané css třídy a hodnoty tagů 2024-02-20 18:46:26 +01:00
14e8520b20 Úprava tabulky odevzdaných = mých řešení 2024-02-20 17:51:01 +01:00
31ee8937f8 Pruhy (local/test/prod) dozadu 2024-02-14 17:24:46 +01:00
d469019c44 Oprava mobilního meníčka na nový bootstrap (ještě jsem zapomněl jednu věc) 2024-02-14 17:00:06 +01:00
a1fa654bec Oprava mobilního meníčka na nový bootstrap 2024-02-14 16:56:47 +01:00
81004d7cdc Upgrade výsledkovky (uchycení druhého sloupce – toho se jménem) 2024-02-14 15:53:09 +01:00
da705927c2 Drobné opravy v tabulce uchycující první řádek a sloupec 2024-02-14 15:46:51 +01:00
ce54684680 Drobné opravy v tabulce uchycující první řádek a sloupec 2024-02-14 15:44:53 +01:00
837986bad8 Drobné opravy v oramovane tabulce a tabulce uchycující první řádek a sloupec 2024-02-14 12:35:44 +01:00
d7195a42f1 Drobné opravy v barevné tabulce a tabulce uchycující první řádek a sloupec 2024-02-14 11:43:28 +01:00
264f4d7646 Chybějící tag v nastylování barevné tabulky 2024-02-14 11:02:00 +01:00
5bf2df563b Rozdělení stylu tabulky došlých řešení na jednotlivé části a použití jinde 2024-02-14 10:58:21 +01:00
6d270b7af5 Ještě jedna drobná úprava stylů výsledkovky 2024-02-14 10:07:46 +01:00
d41eb64ab5 Oprava předchozího commitu (Předělání stylů výsledkovky) 2024-02-14 09:48:59 +01:00
805ed9204c Oprava předchozího commitu (Předělání stylů výsledkovky) 2024-02-14 09:42:08 +01:00
3d2f0f08c3 Předělání stylů výsledkovky 2024-02-14 09:35:49 +01:00
9cca7beba5 Update bootstrapu 2024-02-14 09:19:45 +01:00
c5b81871d2 Přemýšlel jsem, zda apríly nevyhodit do *.js, ale nakonec jen takhto do separátního template 2024-02-14 09:03:15 +01:00
52dc337a20 Dospěl jsem k názoru, že jCarousel se na webu také nepoužívá 2024-02-14 08:41:13 +01:00
eec9abb9c1 Dospěl jsem k názoru, že PrettyPhoto se na webu nepoužívá 2024-02-14 08:32:36 +01:00
c731af9ccd Přesun css galerie do galerie 2024-02-14 08:28:30 +01:00
f5e8f5bb77 První krůčky předělání css 2024-02-13 22:17:41 +01:00
72c20d2b94 Separace prettyPhoto 2024-02-12 19:04:46 +01:00
b2911d5e9f Separace bootstrapu 2024-02-12 18:55:41 +01:00
531 changed files with 28741 additions and 20307 deletions
.gitignore
_git_hooks
aesop
api
data
deploy_v2
docs
galerie
header_fotky
korektury

12
.gitignore vendored
View file

@ -31,9 +31,15 @@ TODO
# reversion kvůli historii objektů v reversion
**/reversion
# pro lidi, co programují v nástrojích od JetBrains
.idea
# dokumentace
docs/_build
docs/modules
# logy týracího skriptu (./checklinks.sh)
/wget.log.*
# pro lidi, co programují v nástrojích od JetBrains
.idea
# Mac users
.DS_Store

View file

@ -1,16 +0,0 @@
git hooks
=========
Kontrola stylu pythoních zdrojáků pomocí flake8. Kontrolujeme jen změny,
abychom nenutili lidi dělat nesouvisející úpravy, které by rozbíjely historii
(git blame).
pre-commit
----------
* kontrola změn před commitnutím
* instalace: lokálně zkopírovat do .git/hooks (musí být spustitelný)
update
------
* kontrola změn přicházejících s pushem
* instalace: na atreyi zkopírovat do /akce/MaM/MaMweb/mamweb.git/hooks

View file

@ -1,30 +0,0 @@
#!/bin/sh
#
# Git hook script to verify what is about to be committed.
# Checks that the changes don't introduce new flake8 errors.
TMPDIFF=`tempfile`
FLAKE8="`git rev-parse --show-toplevel`/bin/flake8"
status=0
# select only changed python files which are not migrations
changed=`git diff --cached --name-only | grep 'py$' | grep -v 'migrations/[0-9]'`
if [ -z $changed ] ; then
# Nothing to check. Note the exit is necessary -- we would not pass any
# paths to git diff below and it would output the diff unfiltered.
exit 0
fi
git diff --unified=1 --cached HEAD -- $changed > $TMPDIFF
# only do the check when there are some changes to be commited
# otherwise flake8 would hang waiting for input
if [ -s $TMPDIFF ] ; then
cat $TMPDIFF | $FLAKE8 --diff
status=$?
fi
rm -f $TMPDIFF
exit $status

View file

@ -1,61 +0,0 @@
#!/bin/sh
# git update hook to check that pushed changes don't introduce new flake8
# errors
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
TMPDIR=`mktemp -d`
TMPDIFF=`tempfile`
[ $refname != "refs/heads/master" -a $refname != "refs/heads/stable" ] && exit 0
# select only changed python files which are not migrations
changed=`git diff --name-only $oldrev $newrev | grep 'py$' | grep -v 'migrations/[0-9]'`
if [ -z $changed ] ; then
# Nothing to check. Note the exit is necessary -- we would not pass any
# paths to git diff below and it would output the diff unfiltered.
exit 0
fi
git diff --unified=1 $oldrev $newrev -- $changed >${TMPDIFF}
# there is no working tree in bare git repository, so we recreate it for flake8
git archive $newrev | tar -x -C ${TMPDIR}
cd ${TMPDIR}
# report only errors on lines in diff
# (if threre was flake8 installed on atrey, we could just call flake8)
/akce/MaM/WWW/mamweb-test/bin/flake8 --diff <${TMPDIFF}
status=$?
if [ $status != 0 ] ; then
echo
echo -n "Změny, které se snažíte pushnout, obsahují kód v pythonu "
echo -n "nevyhovující flake8 (viz výše). Opravte je a zkuste to znovu. "
echo -n "Nezapomeňte, že můžete editovat historii (git commit --amend, "
echo -n "git rebase -i). Pokud byste chybu příště raději odhalili už při "
echo "commitu, zkopírujte si pre-commit hook z _git_hooks do .git/hooks."
echo
fi
rm -rf ${TMPDIR}
rm -f ${TMPDIFF}
exit $status

View file

@ -1,6 +1,3 @@
"""
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
"""
from django.apps import AppConfig
class AesopConfig(AppConfig):

View file

@ -1,10 +1,3 @@
"""
Soubor sloužící jako router, tj. zde se definují url adresy a na co ukazují:
- ``aesop-export/mam-rocnik-<int:prvni_rok>.csv`` (seminar_export_rocnik) :class:`~aesop.views.ExportRocnikView`
- ``aesop-export/mam-sous-<str:datum_zacatku>.csv`` (seminar_export_sous) :class:`~aesop.views.ExportSousView`
- ``aesop-export/index.csv`` (seminar_export_index) :class:`~aesop.views.ExportIndexView`
"""
from django.urls import path
from aesop import views
@ -12,16 +5,16 @@ urlpatterns = [
path(
'aesop-export/mam-rocnik-<int:prvni_rok>.csv',
views.ExportRocnikView.as_view(),
name='seminar_export_rocnik'
name='aesop_export_rocnik'
),
path(
'aesop-export/mam-sous-<str:datum_zacatku>.csv',
views.ExportSousView.as_view(),
name='seminar_export_sous'
name='aesop_export_sous'
),
path(
'aesop-export/index.csv',
views.ExportIndexView.as_view(),
name='seminar_export_index'
name='aesop_export_index'
),
]

View file

@ -1,8 +1,3 @@
"""
Soubor sloužící k deklaraci jednotlivých views (nejčastěji funkce beroucí request
a vracející :func:`django.shortcuts.render` respektive nějakou response, nebo
třídy většinou rozšiřující nějakou třídu z :mod:`django.views.generic`)
"""
import django
from django.shortcuts import get_object_or_404
from django.http import HttpResponse
@ -11,18 +6,19 @@ from django.views import generic
from django.utils.encoding import force_str
from .utils import default_ovvpfile
from seminar.models import Rocnik, Soustredeni
from soustredeni.models import Soustredeni
from tvorba.models import Rocnik
from vysledkovky import utils
from seminar.utils import aktivniResitele
from tvorba.utils import aktivniResitele
class ExportIndexView(generic.View):
def get(self, request):
ls = []
for r in Rocnik.objects.filter(exportovat = True):
url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok})
url = reverse('aesop_export_rocnik', kwargs={'prvni_rok': r.prvni_rok})
ls.append(url.split('/')[-1])
for s in Soustredeni.objects.filter(exportovat = True):
url = reverse('seminar_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()})
url = reverse('aesop_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()})
ls.append(url.split('/')[-1])
return HttpResponse('\n'.join(ls) + '\n', content_type='text/plain; charset=utf-8')

View file

@ -1,6 +1,3 @@
"""
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
"""
from django.apps import AppConfig

View file

@ -1,8 +1,7 @@
from django.test import TestCase, tag
from django.urls import reverse
import seminar.models as m
import seminar.views as v
from seminar.utils import sync_skoly
from personalni.models import Skola
from personalni.utils import sync_skoly
@tag('stejny-model-na-produkci')
class OrgSkolyAutocompleteTestCase(TestCase):
@ -49,7 +48,7 @@ class OrgSkolyAutocompleteTestCase(TestCase):
"""Testuje, že pro každého orga je jeho škola ve výsledném QuerySetu"""
for pfx, id in self.spravna_data:
with self.subTest(prefix=pfx, spravne_id=id):
spravna_skola = m.Skola.objects.get(id=id)
spravna_skola = Skola.objects.get(id=id)
# Zeptáme se view, co si myslí
resp = self.client.get(reverse('autocomplete_skola')+'?q='+pfx).json()
ids = [int(x['id']) for x in resp['results']]

View file

@ -1,18 +1,6 @@
"""
Soubor sloužící jako router, tj. zde se definují url adresy a na co ukazují:
- ``api/expor/skoly/`` (export_skoly) :func:`~api.views.exports.exportSkolView`
- ``api/autocomplete/skola/`` (autocomplete_skola) :class:`~api.views.autocomplete.SkolaAutocomplete`
- ``api/autocomplete/resitel/`` (autocomplete_resitel) :class:`~api.views.autocomplete.ResitelAutocomplete`
- ``api/autocomplete/problem/odevzdatelny`` (autocomplete_problem_odevzdatelny) :class:`~api.views.autocomplete.OdevzdatelnyProblemAutocomplete`
Na autocomplete v3 čeká:
- ``autocomplete/organizatori/`` (seminar_autocomplete_organizator) :class:`~api.views.autocomplete.OrganizatorAutocomplete`
"""
from django.urls import path
from . import views
from seminar.utils import org_required
from personalni.utils import org_required
urlpatterns = [
# Export škol
@ -29,5 +17,5 @@ urlpatterns = [
# Ceka na autocomplete v3
# path('autocomplete/organizatori/',
# org_member_required(views.OrganizatorAutocomplete.as_view()),
# name='seminar_autocomplete_organizator')
# name='autocomplete_organizator')
]

View file

@ -1,7 +1,2 @@
"""
Soubory sloužící k deklaraci jednotlivých views (nejčastěji funkce beroucí request
a vracející :func:`django.shortcuts.render` respektive nějakou response, nebo
třídy většinou rozšiřující nějakou třídu z :mod:`django.views.generic`)
"""
from .autocomplete import *
from .exports import *

View file

@ -5,7 +5,9 @@ from dal import autocomplete
from django.shortcuts import get_object_or_404
from django.db.models import Q
import seminar.models as m
from personalni.models import Skola, Resitel
from tvorba.models import Problem
from various.models import Nastaveni
from .helpers import LoginRequiredAjaxMixin
# TODO filosofie - zkratky, jak v databázi, tak ve vyhledávání (SPŠE, GASOŠ, Kpt., soukr)
@ -13,7 +15,7 @@ class SkolaAutocomplete(autocomplete.Select2QuerySetView):
""" View k :mod:`dal.autocomplete` pro vyhledávání škol hlavně při registraci. """
def get_queryset(self):
# Don't forget to filter out results depending on the visitor !
qs = m.Skola.objects.all()
qs = Skola.objects.all()
if self.q:
words = self.q.split(' ') #TODO re split podle bileho znaku
partq = Q()
@ -31,7 +33,7 @@ class SkolaAutocomplete(autocomplete.Select2QuerySetView):
class ResitelAutocomplete(LoginRequiredAjaxMixin,autocomplete.Select2QuerySetView):
""" View k :mod:`dal.autocomplete` pro vyhledávání řešitelů především v odevzdávátku. """
def get_queryset(self):
qs = m.Resitel.objects.all()
qs = Resitel.objects.all()
if self.q:
parts = self.q.split()
query = Q()
@ -51,8 +53,8 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer
především v odevzdávátku.
"""
def get_queryset(self):
letos = m.Nastaveni.get_solo().aktualni_rocnik
qs = m.Resitel.objects.filter(
letos = Nastaveni.get_solo().aktualni_rocnik
qs = Resitel.objects.filter(
rok_maturity__gte=letos.druhy_rok()
).filter(
prezdivka_resitele__isnull=False
@ -70,7 +72,7 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer
class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView):
""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """
def get_queryset(self):
qs = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY)
qs = Problem.objects.filter(stav=Problem.STAV_ZADANY)
if self.q:
qs = qs.filter(
Q(nazev__icontains=self.q))
@ -87,12 +89,12 @@ class ProblemAutocomplete(autocomplete.Select2QuerySetView):
""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """
def get_queryset(self):
# FIXME i starší úlohy
nastaveni = get_object_or_404(m.Nastaveni)
nastaveni = get_object_or_404(Nastaveni)
rocnik = nastaveni.aktualni_rocnik
temaQ = Q(Tema___rocnik = rocnik)
ulohaQ = Q(Uloha___cislo_zadani__rocnik=rocnik)
clanekQ = Q(Clanek___cislo__rocnik=rocnik)
qs = m.Problem.objects.filter(temaQ | ulohaQ | clanekQ).order_by("-stav", "nazev")
qs = Problem.objects.filter(temaQ | ulohaQ | clanekQ).order_by("-stav", "nazev")
if self.q:
qs = qs.filter(
Q(nazev__icontains=self.q))

View file

@ -1,4 +1,4 @@
import seminar.models as m
import personalni.models as m
from django.core import serializers as ser
from django.http import HttpResponse
def exportSkolView(request):

655
data/groups.json Normal file
View file

@ -0,0 +1,655 @@
[
{
"fields": {
"name": "org",
"permissions": [
[
"org",
"auth",
"user"
],
[
"add_flatpage",
"flatpages",
"flatpage"
],
[
"change_flatpage",
"flatpages",
"flatpage"
],
[
"delete_flatpage",
"flatpages",
"flatpage"
],
[
"view_flatpage",
"flatpages",
"flatpage"
],
[
"add_galerie",
"galerie",
"galerie"
],
[
"change_galerie",
"galerie",
"galerie"
],
[
"delete_galerie",
"galerie",
"galerie"
],
[
"view_galerie",
"galerie",
"galerie"
],
[
"add_obrazek",
"galerie",
"obrazek"
],
[
"change_obrazek",
"galerie",
"obrazek"
],
[
"delete_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"
],
[
"change_komentar",
"korektury",
"komentar"
],
[
"delete_komentar",
"korektury",
"komentar"
],
[
"view_komentar",
"korektury",
"komentar"
],
[
"add_korekturovanepdf",
"korektury",
"korekturovanepdf"
],
[
"change_korekturovanepdf",
"korektury",
"korekturovanepdf"
],
[
"delete_korekturovanepdf",
"korektury",
"korekturovanepdf"
],
[
"view_korekturovanepdf",
"korektury",
"korekturovanepdf"
],
[
"add_oprava",
"korektury",
"oprava"
],
[
"change_oprava",
"korektury",
"oprava"
],
[
"delete_oprava",
"korektury",
"oprava"
],
[
"view_oprava",
"korektury",
"oprava"
],
[
"add_novinky",
"novinky",
"novinky"
],
[
"change_novinky",
"novinky",
"novinky"
],
[
"delete_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"
],
[
"change_prijemce",
"personalni",
"prijemce"
],
[
"delete_prijemce",
"personalni",
"prijemce"
],
[
"view_prijemce",
"personalni",
"prijemce"
],
[
"change_resitel",
"personalni",
"resitel"
],
[
"view_resitel",
"personalni",
"resitel"
],
[
"add_skola",
"personalni",
"skola"
],
[
"change_skola",
"personalni",
"skola"
],
[
"delete_skola",
"personalni",
"skola"
],
[
"view_skola",
"personalni",
"skola"
],
[
"view_hlasovani",
"prednasky",
"hlasovani"
],
[
"view_hlasovanioznalostech",
"prednasky",
"hlasovanioznalostech"
],
[
"add_prednaska",
"prednasky",
"prednaska"
],
[
"change_prednaska",
"prednasky",
"prednaska"
],
[
"delete_prednaska",
"prednasky",
"prednaska"
],
[
"view_prednaska",
"prednasky",
"prednaska"
],
[
"add_seznam",
"prednasky",
"seznam"
],
[
"change_seznam",
"prednasky",
"seznam"
],
[
"delete_seznam",
"prednasky",
"seznam"
],
[
"view_seznam",
"prednasky",
"seznam"
],
[
"add_znalost",
"prednasky",
"znalost"
],
[
"change_znalost",
"prednasky",
"znalost"
],
[
"delete_znalost",
"prednasky",
"znalost"
],
[
"view_znalost",
"prednasky",
"znalost"
],
[
"add_konfera",
"soustredeni",
"konfera"
],
[
"change_konfera",
"soustredeni",
"konfera"
],
[
"delete_konfera",
"soustredeni",
"konfera"
],
[
"view_konfera",
"soustredeni",
"konfera"
],
[
"add_konfery_ucastnici",
"soustredeni",
"konfery_ucastnici"
],
[
"change_konfery_ucastnici",
"soustredeni",
"konfery_ucastnici"
],
[
"delete_konfery_ucastnici",
"soustredeni",
"konfery_ucastnici"
],
[
"view_konfery_ucastnici",
"soustredeni",
"konfery_ucastnici"
],
[
"add_soustredeni",
"soustredeni",
"soustredeni"
],
[
"change_soustredeni",
"soustredeni",
"soustredeni"
],
[
"delete_soustredeni",
"soustredeni",
"soustredeni"
],
[
"view_soustredeni",
"soustredeni",
"soustredeni"
],
[
"add_soustredeni_organizatori",
"soustredeni",
"soustredeni_organizatori"
],
[
"change_soustredeni_organizatori",
"soustredeni",
"soustredeni_organizatori"
],
[
"delete_soustredeni_organizatori",
"soustredeni",
"soustredeni_organizatori"
],
[
"view_soustredeni_organizatori",
"soustredeni",
"soustredeni_organizatori"
],
[
"add_soustredeni_ucastnici",
"soustredeni",
"soustredeni_ucastnici"
],
[
"change_soustredeni_ucastnici",
"soustredeni",
"soustredeni_ucastnici"
],
[
"delete_soustredeni_ucastnici",
"soustredeni",
"soustredeni_ucastnici"
],
[
"view_soustredeni_ucastnici",
"soustredeni",
"soustredeni_ucastnici"
],
[
"add_tag",
"taggit",
"tag"
],
[
"change_tag",
"taggit",
"tag"
],
[
"delete_tag",
"taggit",
"tag"
],
[
"view_tag",
"taggit",
"tag"
],
[
"add_taggeditem",
"taggit",
"taggeditem"
],
[
"change_taggeditem",
"taggit",
"taggeditem"
],
[
"delete_taggeditem",
"taggit",
"taggeditem"
],
[
"view_taggeditem",
"taggit",
"taggeditem"
],
[
"add_cislo",
"tvorba",
"cislo"
],
[
"change_cislo",
"tvorba",
"cislo"
],
[
"delete_cislo",
"tvorba",
"cislo"
],
[
"view_cislo",
"tvorba",
"cislo"
],
[
"add_clanek",
"tvorba",
"clanek"
],
[
"change_clanek",
"tvorba",
"clanek"
],
[
"delete_clanek",
"tvorba",
"clanek"
],
[
"view_clanek",
"tvorba",
"clanek"
],
[
"add_deadline",
"tvorba",
"deadline"
],
[
"change_deadline",
"tvorba",
"deadline"
],
[
"view_deadline",
"tvorba",
"deadline"
],
[
"add_pohadka",
"tvorba",
"pohadka"
],
[
"change_pohadka",
"tvorba",
"pohadka"
],
[
"delete_pohadka",
"tvorba",
"pohadka"
],
[
"view_pohadka",
"tvorba",
"pohadka"
],
[
"add_problem",
"tvorba",
"problem"
],
[
"change_problem",
"tvorba",
"problem"
],
[
"delete_problem",
"tvorba",
"problem"
],
[
"view_problem",
"tvorba",
"problem"
],
[
"add_rocnik",
"tvorba",
"rocnik"
],
[
"change_rocnik",
"tvorba",
"rocnik"
],
[
"delete_rocnik",
"tvorba",
"rocnik"
],
[
"view_rocnik",
"tvorba",
"rocnik"
],
[
"add_tema",
"tvorba",
"tema"
],
[
"change_tema",
"tvorba",
"tema"
],
[
"delete_tema",
"tvorba",
"tema"
],
[
"view_tema",
"tvorba",
"tema"
],
[
"add_uloha",
"tvorba",
"uloha"
],
[
"change_uloha",
"tvorba",
"uloha"
],
[
"delete_uloha",
"tvorba",
"uloha"
],
[
"view_uloha",
"tvorba",
"uloha"
],
[
"add_nastaveni",
"various",
"nastaveni"
],
[
"change_nastaveni",
"various",
"nastaveni"
],
[
"delete_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

@ -73,7 +73,7 @@
"sort_order": 3,
"title": "Aktuální<br/> ročník",
"tree": 1,
"url": "seminar_aktualni_zadani",
"url": "tvorba_aktualni_zadani",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -121,7 +121,7 @@
"sort_order": 5,
"title": "Archiv",
"tree": 1,
"url": "seminar_archiv_rocniky",
"url": "tvorba_archiv_rocniky",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -289,7 +289,7 @@
"sort_order": 43,
"title": "Výsledková listina",
"tree": 1,
"url": "seminar_aktualni_vysledky",
"url": "tvorba_aktualni_vysledky",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -361,7 +361,7 @@
"sort_order": 20,
"title": "Proběhlo",
"tree": 1,
"url": "seminar_seznam_soustredeni",
"url": "soustredeni_seznam",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -409,7 +409,7 @@
"sort_order": 23,
"title": "Osobní údaje",
"tree": 1,
"url": "seminar_resitel_edit",
"url": "personalni_resitel_edit",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -439,7 +439,7 @@
"sort_order": 36,
"title": "Nahrát řešení",
"tree": 1,
"url": "seminar_nahraj_reseni",
"url": "odevzdavatko_nahraj_reseni",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -463,7 +463,7 @@
"sort_order": 35,
"title": "Témata",
"tree": 1,
"url": "seminar_archiv_temata",
"url": "tvorba_archiv_temata",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -589,7 +589,7 @@
"sort_order": 15,
"title": "Aktuální číslo",
"tree": 1,
"url": "seminar_aktualni_zadani",
"url": "tvorba_aktualni_zadani",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -613,7 +613,7 @@
"sort_order": 24,
"title": "Čísla",
"tree": 1,
"url": "seminar_archiv_rocniky",
"url": "tvorba_archiv_rocniky",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -721,7 +721,7 @@
"sort_order": 36,
"title": "Vložit řešení",
"tree": 1,
"url": "seminar_vloz_reseni",
"url": "odevzdavatko_vloz_reseni",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -804,7 +804,7 @@
"sort_order": 37,
"title": "Moje řešení",
"tree": 1,
"url": "seminar_resitel_odevzdana_reseni",
"url": "odevzdavatko_resitel_odevzdana_reseni",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -828,7 +828,7 @@
"sort_order": 33,
"title": "Aktuální ročník",
"tree": 1,
"url": "seminar_aktualni_rocnik",
"url": "tvorba_aktualni_rocnik",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -900,7 +900,7 @@
"sort_order": 46,
"title": "Ročník {{rocnik.rocnik}}",
"tree": 1,
"url": "seminar_rocnik rocnik.rocnik",
"url": "tvorba_rocnik rocnik.rocnik",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -924,7 +924,7 @@
"sort_order": 47,
"title": "Číslo {{ cislo.rocnik.rocnik }}.{{ cislo.poradi }}",
"tree": 1,
"url": "seminar_cislo cislo.rocnik.rocnik cislo.poradi",
"url": "tvorba_cislo cislo.rocnik.rocnik cislo.poradi",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -1007,7 +1007,18 @@
"access_guest": false,
"access_loggedin": false,
"access_perm_type": 1,
"access_permissions": [],
"access_permissions": [
[
"org",
"auth",
"user"
],
[
"resitel",
"auth",
"user"
]
],
"access_restricted": true,
"alias": null,
"description": "",
@ -1050,7 +1061,7 @@
"sort_order": 52,
"title": "Nahrát řešení k nadproblému {{nadproblem_id}}",
"tree": 1,
"url": "seminar_nahraj_reseni nadproblem_id",
"url": "odevzdavatko_nahraj_reseni nadproblem_id",
"urlaspattern": true
},
"model": "sitetree.treeitem",
@ -1079,5 +1090,29 @@
},
"model": "sitetree.treeitem",
"pk": 53
},
{
"fields": {
"access_guest": false,
"access_loggedin": false,
"access_perm_type": 1,
"access_permissions": [],
"access_restricted": false,
"alias": null,
"description": "",
"hidden": false,
"hint": "",
"inbreadcrumbs": true,
"inmenu": true,
"insitetree": true,
"parent": 20,
"sort_order": 54,
"title": "Export do abstraktů sousu {{ soustredeni.id }}",
"tree": 1,
"url": "soustredeni_abstrakty soustredeni.id",
"urlaspattern": true
},
"model": "sitetree.treeitem",
"pk": 54
}
]

View file

@ -1,622 +0,0 @@
[
{
"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": "seminar",
"ct_model": "cislo"
},
{
"codename": "change_cislo",
"ct_app_label": "seminar",
"ct_model": "cislo"
},
{
"codename": "delete_cislo",
"ct_app_label": "seminar",
"ct_model": "cislo"
},
{
"codename": "view_cislo",
"ct_app_label": "seminar",
"ct_model": "cislo"
},
{
"codename": "add_clanek",
"ct_app_label": "seminar",
"ct_model": "clanek"
},
{
"codename": "change_clanek",
"ct_app_label": "seminar",
"ct_model": "clanek"
},
{
"codename": "delete_clanek",
"ct_app_label": "seminar",
"ct_model": "clanek"
},
{
"codename": "view_clanek",
"ct_app_label": "seminar",
"ct_model": "clanek"
},
{
"codename": "add_deadline",
"ct_app_label": "seminar",
"ct_model": "deadline"
},
{
"codename": "change_deadline",
"ct_app_label": "seminar",
"ct_model": "deadline"
},
{
"codename": "view_deadline",
"ct_app_label": "seminar",
"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": "seminar",
"ct_model": "pohadka"
},
{
"codename": "change_pohadka",
"ct_app_label": "seminar",
"ct_model": "pohadka"
},
{
"codename": "delete_pohadka",
"ct_app_label": "seminar",
"ct_model": "pohadka"
},
{
"codename": "view_pohadka",
"ct_app_label": "seminar",
"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": "seminar",
"ct_model": "problem"
},
{
"codename": "change_problem",
"ct_app_label": "seminar",
"ct_model": "problem"
},
{
"codename": "delete_problem",
"ct_app_label": "seminar",
"ct_model": "problem"
},
{
"codename": "view_problem",
"ct_app_label": "seminar",
"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": "seminar",
"ct_model": "rocnik"
},
{
"codename": "change_rocnik",
"ct_app_label": "seminar",
"ct_model": "rocnik"
},
{
"codename": "delete_rocnik",
"ct_app_label": "seminar",
"ct_model": "rocnik"
},
{
"codename": "view_rocnik",
"ct_app_label": "seminar",
"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": "seminar",
"ct_model": "tema"
},
{
"codename": "change_tema",
"ct_app_label": "seminar",
"ct_model": "tema"
},
{
"codename": "delete_tema",
"ct_app_label": "seminar",
"ct_model": "tema"
},
{
"codename": "view_tema",
"ct_app_label": "seminar",
"ct_model": "tema"
},
{
"codename": "add_uloha",
"ct_app_label": "seminar",
"ct_model": "uloha"
},
{
"codename": "change_uloha",
"ct_app_label": "seminar",
"ct_model": "uloha"
},
{
"codename": "delete_uloha",
"ct_app_label": "seminar",
"ct_model": "uloha"
},
{
"codename": "view_uloha",
"ct_app_label": "seminar",
"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,7 +13,6 @@ 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

@ -36,6 +36,7 @@ extensions = [
'sphinx.ext.intersphinx',
'sphinx.ext.autosectionlabel',
'myst_parser',
'sphinxcontrib_django',
]
# Add any paths that contain templates here, relative to this directory.

27
docs/css.rst Normal file
View file

@ -0,0 +1,27 @@
CSS (a další styly na webu)
===========================
Inspirován `css-trick článkem <https://css-tricks.com/methods-organize-css/>`_ jsem se rozhodl rozdělit
CSSka do
- Konstant (``constants.css``), které jsou využívány na mnoha místech CSSek
- Nastylování html tagů (``base.css``)
- Layoutu (``layout.css``), což je to, co určuje celkové rozložení stránky
- Jednotlivých prvků (``modules.css``)
Dále jsem separoval CSSka pro **galerii** (potřebuje hodně specifických stylů). Stejně tak **korekturovátko** má styly separátně.
Dále web (asi) používá externí frameworky (v separátních složkách mají k sobě i JS a podobné věci):
- bootstrap: dělá nějaké basic stylování, *web je na něm hodně závislý* (například jsem zjistil, že bootstrap kdysi přidával ``font-size:14px``, bez čehož se web úplně rozpadnul) (také na něm běží mobilní meníčko, které navíc vyžaduje Popper, tedy bootstrap.bundle.js místo bootstrap.js)
Pak jsou tu ``mamweb-dev.css`` a ``printtable.css``, co jsem si ještě nerozmyslel, co s tím.
Pár myšlenek
------------
- Až na pár výjimek (galerii a korekturovátko) bych styly držel v jedné složce a málo souborech,
protože CSS šíleně dědí všechno možné
- Chce to dobře pojmenovávat třídy (speciálně aby bylo vidět, co ta třída dělá nebo kde se používá)
- Chce to hodně komentovat kód (speciálně tam, kde není splněn předchozí bod)

View file

@ -9,12 +9,6 @@ static
------
Složka, kam django nakopíruje všechno ze složek static a pak na to z templatů / kódu jde ukazovat pomocí ``static``.
_git_hooks
----------
Hooky do gitu pro kontrolu Pythoního stylu. Především ``flake8``.
Zbylo tu z minulosti mamwebu.
data
----
Obsahuje data, která patří do databáze, ale jsou přímo součástí webu jako

View file

@ -30,6 +30,7 @@ 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,3 +1,4 @@
FIXME přepsat do rst, přidat i další věci a případně přesunout na wiki
Přidání obrázků do odměn:
admin -> flatpage odměn -> ikona přidat obrázek
záložka odeslat, vybrat obrázek, odeslat

View file

@ -1,13 +1,15 @@
Sphinx na našem webu
====================
Dokumentace se zkompiluje příkazem ``make html`` ve složce ``doc``.
Dokumentace se zkompiluje příkazem ``make html`` ve složce ``docs``. (Musíte mít zapnutý virtualenv)
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 ``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).
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).
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

@ -10,11 +10,9 @@ věci jako chybové hlášky a vzhled M&M stránek (menu, patička, atd.). Aktu
i veškeré csv.
Další jsou pak jednotlivé aplikace (pokud něco hledáte, tak zřejmě chcete najít
tu aplikaci, která tomu odpovídá, respektive se k ní dostat přes url), za
zmínku stojí seminar, kde jsou takové ty věci, co zbyly. Plus jsou tam aktuálně
téměř všechny modely, protože je těžké je přesunout jinam.
tu aplikaci, která tomu odpovídá, respektive se k ní dostat přes url).
**TLDR: Nevšímejte si složky data/ a souborů přímo v kořenové složce.**
**TLDR: Nevšímejte si složek data/ seminar/ a souborů přímo v kořenové složce.**
Kromě věcí potřebných ke gitu, :doc:`ke spuštění <vyvoj>` a fukci djanga,
dalších drobností, lokální databáze a již zmíněných aplikací jsou tu ``data``,
kde je takový ten obsah webu, co by se měl dát snadno měnit (tudíž musí být v
@ -22,6 +20,9 @@ databázi), tj. statické stránky, menu a obrázky v pozadí menu. Ten je třeb
měnit hlavně na produkci a sekundárně tady (může to dělat i newebař a nechcete
přepsat jeho práci). Vše, co nejsou aplikace je popsáno :doc:`tady <dalsi_soubory>`.
Ještě je tu aplikace ``seminar/``, kde bylo původně skoro všechno, a tak nám
tam zbývá spoustu historických migrací (čehož se jen tak nezbavíme).
Základy djanga
--------------

View file

@ -116,7 +116,7 @@ Aktuálně: Jakýsi coding style zhruba existuje, není popsaný, šíří se li
- Nesmí být striktně vynucovaný
- Musel by být hodně nastavitelný
- Nechceme mít kód plný `#NOQA: WTF42`
- Nejspíš vždycky bude mít false positives (`seminar.utils.roman_numerals`) i false negatives (`seminar.models.tvorba.Cislo.posli_cislo_mailem`)
- Nejspíš vždycky bude mít false positives (`tvorba.utils.roman_numerals`) i false negatives (`tvorba.models.Cislo.posli_cislo_mailem`)
- Možná dobrý sluha, ale určitě špatný pán (also: špatná zkušenost ☺)
- __Důsledek:__ Hrozí, že těch falešných varování bude moc, čímž to ztratí smysl úplně
- Potenciálně by šlo aplikovat jen lokálně na změny?

86
docs/zkratky.rst Normal file
View file

@ -0,0 +1,86 @@
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.

View file

@ -1,25 +0,0 @@
========
| TODO |
|======|
Aktualni
* co s titulni fotkou
* do CSS
* nahledy
* nastylovat tabulku s nahledy
* komentare uz na nahledy?
* detail
* nahledy pred a po
* opravit prechodove sipky
* vyrobit prechodove sipky ve M&M-stylu
Dlouhodobe
* sipky na prechazeni mezi fotkami
* hromadne PRIDANI fotek do jiz existujici galerie
Fylozoficke
* zvolit velikosti velke a male fotky
* je potreba i jine razeni nez automaticky podle casu nebo staci podgalerie?
* napr. dve hry na dvou ruznych mistech ve stejny cas
* fotky od ucastniku ze hry (skupinky se pohybuji ve stejny cas, ale maji sled fotek) -- nestaci to pripadne vrazit do podgalerii?

View file

@ -1,5 +1,3 @@
#coding: utf-8
from galerie.models import Obrazek, Galerie
from django.contrib import admin
from django.http import HttpResponseRedirect

View file

@ -1,47 +0,0 @@
# -*- coding: utf-8 -*-
from autocomplete_light import shortcuts as autocomplete_light
from .models import Obrazek, Galerie
from .views import cesta_od_korene
class ObrazekAutocomplete(autocomplete_light.AutocompleteModelBase):
model = Obrazek
search_fields = ['nazev', 'popis']
split_words = True
limit_choices = 15
attrs = {
# This will set the input placeholder attribute:
'placeholder': u'Obrázek',
# This will set the yourlabs.Autocomplete.minimumCharacters
# options, the naming conversion is handled by jQuery
'data-autocomplete-minimum-characters': 1,
}
choice_html_format = '''
<span class="block" data-value="{}">
<span class="block">
{}
<span class="block">{}</span>
</span>
</span>
'''
def choice_label(self, obrazek):
cesta = "/".join(g.nazev for g in cesta_od_korene(obrazek.galerie))
popis = "{}<br>".format(obrazek.popis) if obrazek.popis else ""
return '{}<br>{}{}'.format(obrazek.nazev, popis, cesta)
def choice_html(self, obrazek):
"""Vrátí kus html i s obrázkem, které se pak ukazuje v nabídce"""
return self.choice_html_format.format(self.choice_value(obrazek),
obrazek.obrazek_maly_tag(), self.choice_label(obrazek))
widget_attrs={
'data-widget-maximum-values': 15,
'class': 'modern-style',
}
autocomplete_light.register(ObrazekAutocomplete)

View file

@ -1,7 +1,4 @@
#coding: utf-8
from django import forms
from seminar.models import Soustredeni
class KomentarForm(forms.Form):
komentar = forms.CharField(label = "Komentář:", max_length = 300, required=False)

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-30 21:40
from __future__ import unicode_literals

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.21 on 2019-06-10 21:58
from __future__ import unicode_literals

View file

@ -1,5 +1,3 @@
# coding: utf-8
from django.db import models
#from django.db.models import Q
from imagekit.models import ImageSpecField

View file

@ -0,0 +1,186 @@
@charset "utf-8"; /* vynuť utf-8 */
/* Galerie */
/* velká fotka */
/* zmenšování spolu s oknem prohlížeče */
.galerie .obrazek, .titulni_obrazek {
max-width: 100%;
height: auto;
width: auto\9; /* ie8 */
}
.predchozi_obrazek{
position: absolute;
z-index: 1;
width: 33%;
height: 100%;
left: 0;
top: 0;
}
.predchozi_obrazek:hover{
background-image: url("/static/galerie/prvky/predchozi.svg");
filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
background-position: left center;
background-repeat: no-repeat;
}
.dalsi_obrazek{
position: absolute;
z-index: 1;
width: 33%;
height: 100%;
left: 67%;
top: 0;
}
.dalsi_obrazek:hover{
background-image: url("/static/galerie/prvky/dalsi.svg");
filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
background-position: right center;
background-repeat: no-repeat;
}
.galerie {
position: relative;
text-align: center;
margin: 20px auto 0 auto;
}
.galerie h1 {
text-align: center;
}
.galerie_hlavicka {
margin: 30px auto 30px auto;
}
.popis {
margin: 10px 10px 30px 0px;
text-align: center;
}
#nahoru {
text-align: center;
}
/* titulní obrázek hlavní galerie soustředění */
.galerie_nahledy{
/*margin: 1em 0;*/
margin: auto;
padding: 10px;
text-align: center;
overflow: auto;
}
.galerie_nahledy img {
margin: 10px;
}
.galerie_nahledy div.navigace {
display: inline-block;
}
.galerie_nahled, .podgalerie_nahled { /* frame */
display: block;
position: relative;
float: left;
width: 200px;
height: 200px;
text-align: center;
border: solid;
border-width: 1px;
border-radius: 4px;
border-color: var(--svetla-oranzova);
background-color: var(--barva-pozadi);
white-space: nowrap;
margin: 10px;
font-weight: bold;
}
.galerie_nahled:hover, .podgalerie_nahled:hover {
background-color: var(--svetla-oranzova);
filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
color: var(--tmava-oranzova);
}
.vystredeno{ /* helper */
display: inline-block;
height: 100%;
vertical-align: middle;
}
.galerie_nahled img {
vertical-align: middle;
max-height: 180px;
max-width: 180px;
}
.galerie_nahled div {
position: absolute;
bottom: 0px;
width: 100%;
text-align: center;
}
.podgalerie_nahled img {
margin-top: 20px;
margin-bottom: 15px;
max-height: 125px;
max-width: 167px;
}
.podgalerie_nahled .nazev_galerie {
position: absolute;
width: 100%;
top: 160px;
}
/* Odkazy na předchozí a následující podgalerii */
.galerie_predchozi_nasledujici {
overflow: auto;
margin: 10px auto 10px auto;
}
.galerie_predchozi_nasledujici .predchozi {
float: left;
}
.galerie_predchozi_nasledujici .nasledujici {
float: right;
}
/* posune kotvu obrázku v galerii o oranžový pruh dolu, aby se pod ním obrázek neschovával */
/* https://stackoverflow.com/questions/10732690/offsetting-an-html-anchor-to-adjust-for-fixed-header */
.kotva_obrazku {
position: absolute;
width: 0;
height: 55px; /* viz #title */
margin-top: -55px; /* viz #title */
}
@media(max-width: 860px) {
.kotva_obrazku {
height: 3em; /* #FIXME nemám páru, jak zjistit výšku toho elementu */
margin-top: -3em; /* #FIXME */
}
}
/* plus a minus tlacitka */
.mam-org-only-galerie {
background: var(--orgovska-svetla-fialova);
padding: 10px;
margin: 10px 10px 10px -20px;
border: #333 2px dashed;
float: left;
}
.mam-org-only-galerie a{
padding: 3px 5px;
margin: 5px;
border-radius: 20px;
background-color: var(--tmava-oranzova);;
color: var(--barva-pozadi);
float: left;
}

View file

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

View file

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

View file

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

View file

@ -0,0 +1,6 @@
{% extends "base.html" %}
{% load static %}
{% block custom_css %}
<link href="{% static 'css/galerie.css' %}?version=1" rel="stylesheet">
{% endblock %}

View file

@ -1,14 +1,5 @@
"""
Soubor sloužící jako router, tj. zde se definují url adresy a na co ukazují:
- ``<int:pk>/`` :func:`~galerie.views.nahled`
- ``<int:pk>/<int:fotka>/`` :func:`~galerie.views.detail`
- ``<int:galerie>/new/`` :func:`~galerie.views.new_galerie`
- ``<int:galerie>/plus/<int:subgalerie>/`` :func:`~galerie.views.plus_galerie`
- ``<int:galerie>/minus/<int:subgalerie>/`` :func:`~galerie.views.minus_galerie`
"""
from django.urls import path
from seminar.utils import org_required
from personalni.utils import org_required
from . import views
urlpatterns = [

View file

@ -1,5 +1,3 @@
# coding: utf-8
import random
from django.http import HttpResponse, Http404
@ -8,7 +6,7 @@ from django.template import RequestContext
from datetime import datetime
from galerie.models import Obrazek, Galerie
from seminar.models import Soustredeni
from soustredeni.models import Soustredeni
from galerie.forms import KomentarForm, NewGalerieForm
def zobrazit(galerie, request):

View file

@ -1,14 +1,3 @@
"""
Soubor sloužící k definici toho, co bude v adminu. Většinou pouhým zavoláním
funkce :func:`django.contrib.admin.site.register`, v případě, že chceme něco
upravit, tak jako třída rozšiřující :class:`django.contrib.admin.ModelAdmin`
s dekorátorem :func:`django.contrib.admin.register`.
Zde se definuje admin pro:
- :class:`~header_fotky.models.FotkaHeader`
- :class:`~header_fotky.models.FotkaUrlVazba`
"""
from django.contrib import admin
from django.contrib.admin import ModelAdmin
import header_fotky.models as m

View file

@ -1,6 +1,3 @@
"""
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
"""
from django.apps import AppConfig

View file

@ -1,17 +1,3 @@
"""
Tento soubor slouží k definici databázového modelu.
Třídy rozšiřují většinou :class:`django.db.models.Model` a jejich atributy jsou
většinou sloupce v databázi (tj. nastaví se na hodnotu něčeho z :mod:`django.db.models`).
Na výběr jsou:
- :class:`django.db.models.TextField`
- :class:`django.db.models.ForeignKey`
- :class:`django.db.models.DateField`
- :class:`django.db.models.DateTimeField`
- :class:`django.db.models.ImageField`
- :class:`django.db.models.CharField`
"""
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone

View file

@ -1,11 +0,0 @@
- korektura potrebuje reakci
+ komentáře fixně na username
- používat skutečné jméno?
- vyžádat pozornost autora obsahu
- zvednout upload limit na 5MB
- sbalit a rozbalit korekturu
- nahrávání jiných věcí než PDF - kontrolovat?
- stylování
- seznam PDF - co zobrazovat?

View file

@ -1,21 +1,10 @@
"""
Soubor sloužící k definici toho, co bude v adminu. Většinou pouhým zavoláním
funkce :func:`django.contrib.admin.site.register`, v případě, že chceme něco
upravit, tak jako třída rozšiřující :class:`django.contrib.admin.ModelAdmin`
s dekorátorem :func:`django.contrib.admin.register`.
Zde se definuje admin pro:
- :class:`korektury.models.KorekturovanePDF`
"""
from django.contrib import admin
from reversion.admin import VersionAdmin
from korektury.models import KorekturovanePDF
from korektury.models import KorekturovanePDF, Oprava, KorekturaTag
from django.core.mail import EmailMessage
from django.urls import reverse
# Register your models here.
class KorekturovanePDFAdmin(VersionAdmin):
"""
nastaví čas vložení (:attr:`~koretkury.models.KorekturovanePDF.cas`) a počet
@ -36,12 +25,13 @@ class KorekturovanePDFAdmin(VersionAdmin):
fieldsets = [
(None,
{'fields':
['pdf', 'cas', 'org', 'stran', 'nazev', 'komentar', 'poslat_mail']}),
['pdf', 'cas', 'stran', 'nazev', 'orgove', 'komentar', 'poslat_mail']}),
# (u'PDF', {'fields': ['pdf']}),
]
list_display = ['nazev', 'cas', 'stran', 'org']
list_display = ['nazev', 'cas', 'stran']
list_filter = []
search_fields = []
autocomplete_fields = ['orgove']
def save_model(self, request, obj, form, change):
"""
@ -72,3 +62,11 @@ Korekturovátko
).send()
admin.site.register(KorekturovanePDF, KorekturovanePDFAdmin)
class OpravaAdmin(admin.ModelAdmin):
model = Oprava
filter_horizontal = ("informovani_orgove", "tagy",)
admin.site.register(Oprava, OpravaAdmin)
admin.site.register(KorekturaTag)

7
korektury/api/apps.py Normal file
View file

@ -0,0 +1,7 @@
from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'korektury.api'
label = 'korektury_api' # Protože jedno api už máme.

9
korektury/api/urls.py Normal file
View file

@ -0,0 +1,9 @@
from django.urls import path
from personalni.utils import org_required
from . import views
urlpatterns = [
path('<int:pdf_id>/stav', org_required(views.korektury_stav_view), name='korektury_api_pdf_stav'),
path('oprava/stav', org_required(views.oprava_stav_view), name='korektury_api_oprava_stav'),
path('<int:pdf_id>/opravy_a_komentare', org_required(views.opravy_a_komentare_view), name='korektury_api_opravy_a_komentare'),
]

109
korektury/api/views.py Normal file
View file

@ -0,0 +1,109 @@
from django.http import HttpResponseForbidden, JsonResponse
from django.shortcuts import get_object_or_404
from django.utils.html import linebreaks
from django.views.decorators.csrf import csrf_exempt
from rest_framework import serializers
from korektury.utils import send_email_notification_komentar
from korektury.models import Oprava, KorekturovanePDF, Komentar, KorekturaTag
from personalni.models import Organizator, Osoba
def korektury_stav_view(request, pdf_id: int, **kwargs):
q = request.POST
pdf = get_object_or_404(KorekturovanePDF, id=pdf_id)
status = q.get('state')
if status is not None:
assert status in KorekturovanePDF.STATUS.values
pdf.status = status
pdf.save()
return JsonResponse({'status': pdf.status})
def oprava_stav_view(request, **kwargs):
q = request.POST
op_id_str = q.get('id')
assert op_id_str is not None
op_id = int(op_id_str)
op = get_object_or_404(Oprava, id=op_id)
status = q.get('action')
if status is not None:
assert status in Oprava.STATUS.values
op.status = status
op.save()
return JsonResponse({'status': op.status})
class KomentarSerializer(serializers.ModelSerializer):
class Meta:
model = Komentar
fields = '__all__'
def to_representation(self, instance):
ret = super().to_representation(instance)
ret["autor"] = str(instance.autor)
ret["text"] = linebreaks(ret["text"], autoescape=True) # Autora není třeba escapovat, ten se vkládá jako text.
return ret
class KorekturaTagSerializer(serializers.ModelSerializer):
class Meta:
model = KorekturaTag
fields = '__all__'
class OpravaSerializer(serializers.ModelSerializer):
class Meta:
model = Oprava
fields = '__all__'
def to_representation(self, instance):
ret = super().to_representation(instance)
ret["komentare"] = [KomentarSerializer(komentar).data for komentar in instance.komentar_set.all()]
ret["tagy"] = [KorekturaTagSerializer(tag).data for tag in instance.tagy.all()]
return ret
# komentar_set = serializers.ListField(child=KomentarSerializer())
def opravy_a_komentare_view(request, pdf_id: int, **kwargs):
if request.method == 'POST':
q = request.POST
x = int(q.get('x'))
y = int(q.get('y'))
img_id = int(q.get('img_id'))
oprava_id = int(q.get('oprava_id'))
komentar_id = int(q.get('komentar_id'))
text = q.get('text')
# prirazeni autora podle prihlaseni
autor_user = request.user
# pokud existuje ucet (user), ale neni to organizator = 403
autor = Organizator.objects.filter(osoba__user=autor_user).first()
if komentar_id != -1:
komentar = get_object_or_404(Komentar, id=komentar_id)
komentar.text = text
komentar.autor = autor
komentar.save()
else:
if oprava_id != -1:
oprava = get_object_or_404(Oprava, id=oprava_id)
else:
pdf = get_object_or_404(KorekturovanePDF, id=pdf_id)
oprava = Oprava.objects.create(
pdf=pdf,
strana=img_id,
x=x,
y=y,
)
tagy_raw = q.get('tagy')
if tagy_raw != "":
tagy = list(map(int, tagy_raw.split(",")))
oprava.tagy.add(*KorekturaTag.objects.filter(id__in=tagy))
Komentar.objects.create(oprava=oprava, autor=autor, text=text)
opravy = Oprava.objects.filter(pdf=pdf_id).all()
# Serializovat list je prý security vulnerability, tedy je přidán slovník pro bezpečnost
return JsonResponse({"context": [OpravaSerializer(oprava).data for oprava in opravy]})

View file

@ -1,24 +0,0 @@
"""
Formuláře (:class:`django.forms.Form`) umožňují jednoduchou tvorbu formulářů,
které lze pak jednoduše dát do frontendu i zpracovat na backendu.
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
"""
from django import forms
class OpravaForm(forms.Form):
""" formulář k přidání opravy (:class:`korektury.models.Oprava`) """
text = forms.CharField(max_length=256)
autor = forms.CharField(max_length=20)
x = forms.IntegerField()
y = forms.IntegerField()
scroll = forms.CharField(max_length=256)
pdf = forms.CharField(max_length=256)
img_id = forms.CharField(max_length=256)
id = forms.CharField(max_length=256)
action = forms.CharField(max_length=256)

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-30 21:40
from __future__ import unicode_literals

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.21 on 2019-06-10 21:58
from __future__ import unicode_literals

View file

@ -0,0 +1,41 @@
# Generated by Django 4.2.13 on 2024-06-11 23:53
from django.db import migrations, models
def pridej_orgy(apps, schema_editor):
PDF = apps.get_model('korektury', 'KorekturovanePDF')
for pdf in PDF.objects.all(): # Tohle by asi mělo jít udělat pomocí update, ale moc práce a rychlé hledání taky nepomohlo.
if pdf.org is not None: pdf.orgove.add(pdf.org)
pdf.save() # ig?
def vyber_orga(apps, schema_editor):
PDF = apps.get_model('korektury', 'KorekturovanePDF')
for pdf in PDF.objects.all():
orgove = pdf.orgove.all()
if len(orgove) > 1:
raise migrations.exceptions.IrreversibleError(f'PDF {pdf.id} má víc než jednoho zodpovědného orga, nejde odmigrovat na verzi, která umí jen jednoho.')
if len(orgove) == 0:
pdf.org = None
else:
pdf.org = orgove[0]
pdf.save()
class Migration(migrations.Migration):
dependencies = [
('personalni', '0011_osloveni_vsechny_choices'),
('korektury', '0023_personalni_post_migrate'),
]
operations = [
migrations.AddField(
model_name='korekturovanepdf',
name='orgove',
field=models.ManyToManyField(blank=True, default=None, help_text='Zodpovědní organizátoři za obsah (chodí jim maily o nových korekturách)', to='personalni.organizator'),
),
migrations.RunPython(pridej_orgy, vyber_orga),
migrations.RemoveField(
model_name='korekturovanepdf',
name='org',
),
]

View file

@ -0,0 +1,45 @@
# Generated by Django 4.2.16 on 2024-12-12 10:25
from django.db import migrations
import datetime
from django.utils import timezone
def oprava2komentar(apps, schema_editor):
Oprava = apps.get_model('korektury', 'Oprava')
Komentar = apps.get_model('korektury', 'Komentar')
for o in Oprava.objects.all():
Komentar.objects.create(oprava=o, text=o.text, autor=o.autor, cas=timezone.make_aware(datetime.datetime.fromtimestamp(0)))
def komentar2oprava(apps, schema_editor):
Oprava = apps.get_model('korektury', 'Oprava')
Komentar = apps.get_model('korektury', 'Komentar')
for o in Oprava.objects.all():
k = Komentar.objects.filter(oprava=o).first()
o.text = k.text
o.autor = k.autor
o.save()
k.delete()
class Migration(migrations.Migration):
dependencies = [
('korektury', '0024_vic_orgu_k_pdf'),
]
operations = [
migrations.RunPython(oprava2komentar, komentar2oprava),
migrations.RemoveField(
model_name='oprava',
name='autor',
),
migrations.RemoveField(
model_name='oprava',
name='text',
),
]

View file

@ -0,0 +1,29 @@
# Generated by Django 4.2.16 on 2025-02-11 14:28
from django.db import migrations, models
def pridani_orgu(apps, _schema_editor):
Komentar = apps.get_model('korektury','Komentar')
for komentar in Komentar.objects.all():
org = komentar.autor
if org is not None:
# Tohle jde asi udělat lépe než .all(…). Ale nejhorší na tom je, že .add(…) funguje jinak tady v migracích.
if org not in komentar.oprava.informovani_orgove.all():
komentar.oprava.informovani_orgove.add(org)
class Migration(migrations.Migration):
dependencies = [
('personalni', '0019_rename_upozorneni_resitel_upozornovat_na_opravy_reseni'),
('korektury', '0025_remove_oprava_autor_remove_oprava_text'),
]
operations = [
migrations.AddField(
model_name='oprava',
name='informovani_orgove',
field=models.ManyToManyField(blank=True, default=None, help_text='Orgové informovaní při přidání komentáře ke korektuře', related_name='informovan_o_opravach', to='personalni.organizator', verbose_name='Informovaní organizátoři'),
),
migrations.RunPython(pridani_orgu, migrations.RunPython.noop),
]

View file

@ -0,0 +1,27 @@
# Generated by Django 4.2.16 on 2025-02-11 16:07
import colorfield.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('korektury', '0026_oprava_informovani_orgove'),
]
operations = [
migrations.CreateModel(
name='KorekturaTag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nazev', models.CharField(help_text='Název daného tagu, <20 znaků', max_length=20, verbose_name='název tagu')),
('barva', colorfield.fields.ColorField(default='#FFFFFF', image_field=None, max_length=25, samples=None, verbose_name='barva daného tagu')),
],
),
migrations.AddField(
model_name='oprava',
name='tagy',
field=models.ManyToManyField(blank=True, default=None, to='korektury.korekturatag'),
),
]

View file

@ -1,19 +1,9 @@
"""
Tento soubor slouží k definici databázového modelu.
Třídy rozšiřují většinou :class:`django.db.models.Model` a jejich atributy jsou
většinou sloupce v databázi (tj. nastaví se na hodnotu něčeho z :mod:`django.db.models`).
Na výběr jsou:
- :class:`django.db.models.TextField`
- :class:`django.db.models.ForeignKey`
- :class:`django.db.models.DateField`
- :class:`django.db.models.DateTimeField`
- :class:`django.db.models.ImageField`
- :class:`django.db.models.CharField`
"""
import os
from colorfield.fields import ColorField
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
@ -40,7 +30,6 @@ def generate_filename(self, filename):
clean)
return os.path.join(settings.KOREKTURY_PDF_DIR, fname)
#@reversion.register(ignore_duplicates=True)
class KorekturovanePDF(models.Model):
class Meta:
@ -60,22 +49,19 @@ class KorekturovanePDF(models.Model):
pdf = models.FileField(u'PDF', upload_to = generate_filename)
org = models.ForeignKey(Organizator, blank=True,
help_text='Zodpovědný organizátor za obsah',
null=True, default=None, on_delete=models.SET_NULL)
orgove = models.ManyToManyField(Organizator, blank=True,
help_text='Zodpovědní organizátoři za obsah (chodí jim maily o nových korekturách)',
default=None)
stran = models.IntegerField(u'počet stran', help_text='Počet stran PDF',
default=0)
STATUS_PRIDAVANI = 'pridavani'
STATUS_ZANASENI = 'zanaseni'
STATUS_ZASTARALE = 'zastarale'
STATUS_CHOICES = (
(STATUS_PRIDAVANI, u'Přidávání korektur'),
(STATUS_ZANASENI, u'Korektury jsou zanášeny'),
(STATUS_ZASTARALE, u'Stará verze, nekorigovat'),
)
status = models.CharField(u'stav PDF',max_length=16, choices=STATUS_CHOICES, blank=False,
default = STATUS_PRIDAVANI)
class STATUS(models.TextChoices):
PRIDAVANI = 'pridavani', 'Přidávání korektur'
ZANASENI = 'zanaseni', 'Korektury jsou zanášeny'
ZASTARALE = 'zastarale', 'Stará verze, nekorigovat'
status = models.CharField(u'stav PDF',max_length=16, choices=STATUS.choices, blank=False, default = STATUS.PRIDAVANI)
poslat_mail = models.BooleanField('Poslat mail o novém PDF', default=True,
help_text='Určuje, zda se má o nově nahraném PDF poslat e-mail do mam-org. Při upravování existujícího souboru už nemá žádný vliv.',
@ -144,6 +130,17 @@ class KorekturovanePDF(models.Model):
except IndexError:
return self.nazev
def get_absolute_url(self):
return reverse('korektury', kwargs={'pdf': self.id})
class KorekturaTag(models.Model):
nazev = models.CharField("název tagu", blank = False, max_length=20, help_text="Název daného tagu, <20 znaků")
barva = ColorField("barva daného tagu", default="#FFFFFF")
def __str__(self):
return self.nazev
@reversion.register(ignore_duplicates=True)
class Oprava(models.Model):
@ -163,32 +160,22 @@ class Oprava(models.Model):
x = models.IntegerField(u'x-ová souřadnice bugu')
y = models.IntegerField(u'y-ová souřadnice bugu')
STATUS_K_OPRAVE = 'k_oprave'
STATUS_OPRAVENO = 'opraveno'
STATUS_NENI_CHYBA = 'neni_chyba'
STATUS_K_ZANESENI = 'k_zaneseni'
STATUS_CHOICES = (
(STATUS_K_OPRAVE, u'K opravě'),
(STATUS_OPRAVENO, u'Opraveno'),
(STATUS_NENI_CHYBA, u'Není chyba'),
(STATUS_K_ZANESENI, u'K zanesení do TeXu'),
class STATUS(models.TextChoices):
K_OPRAVE = 'k_oprave', 'K opravě'
OPRAVENO = 'opraveno', 'Opraveno'
NENI_CHYBA = 'neni_chyba', 'Není chyba'
K_ZANESENI = 'k_zaneseni', 'K zanesení do TeXu'
status = models.CharField(u'stav opravy',max_length=16, choices=STATUS.choices, blank=False, default = STATUS.K_OPRAVE)
informovani_orgove = models.ManyToManyField(
Organizator, blank=True, default=None,
verbose_name='Informovaní organizátoři',
help_text="Orgové informovaní při přidání komentáře ke korektuře",
related_name='informovan_o_opravach',
)
status = models.CharField(u'stav opravy',max_length=16, choices=STATUS_CHOICES, blank=False,
default = STATUS_K_OPRAVE)
autor = models.ForeignKey(Organizator, blank = True,
help_text='Autor opravy',
null = True, on_delete=models.SET_NULL)
text = models.TextField(u'text opravy',blank = True, help_text='Text opravy')
# def __init__(self,dictionary):
# for k,v in dictionary.items():
# setattr(self,k,v)
def __str__(self):
return '{} od {}: {}'.format(self.status,self.autor,self.text)
tagy = models.ManyToManyField(KorekturaTag, blank=True, default=None,)
@reversion.register(ignore_duplicates=True)
@ -214,5 +201,7 @@ class Komentar(models.Model):
def __str__(self):
return '{} od {}: {}'.format(self.cas,self.autor,self.text)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self.autor is not None:
self.oprava.informovani_orgove.add(self.autor)

Binary file not shown.

Before

(image error) Size: 697 B

After

(image error) Size: 1.1 KiB

Binary file not shown.

Before

(image error) Size: 717 B

After

(image error) Size: 1.4 KiB

Binary file not shown.

Before

(image error) Size: 270 B

After

(image error) Size: 307 B

Binary file not shown.

Before

(image error) Size: 702 B

After

(image error) Size: 1.1 KiB

Binary file not shown.

Before

(image error) Size: 617 B

After

(image error) Size: 1.1 KiB

View file

@ -1,136 +1,227 @@
body,
.adding{
.textzanaseni { display:none; }
.textzastarale { display:none; }
#prekomentar, #preoprava, #prepointer { display: none; }
body {
&[data-status="pridavani"] {
background: #f3f3f3;
color: black;
}
.comitting
{
}
&[data-status="zanaseni"] {
background: yellow;
}
.deprecated {
.textzanaseni { display: unset; }
}
&[data-status="zastarale"] {
background: red;
.textzastarale { display: unset; }
}
}
img{background:white;}
/* Barvy korektur */
.k_oprave {
[data-opravastatus="k_oprave"] {
--rgb: 255, 0, 0;
[value="k_oprave"] { display: none }
.komentovat_disabled { display: none }
}
.opraveno {
[data-opravastatus="opraveno"] {
--rgb: 0, 0, 255;
[value="opraveno"] { display: none }
.komentovat { display: none }
}
.neni_chyba {
[data-opravastatus="neni_chyba"] {
--rgb: 128, 128, 128;
[value="neni_chyba"] { display: none }
.komentovat { display: none }
}
.k_zaneseni {
[data-opravastatus="k_zaneseni"] {
--rgb: 0, 255, 0;
[value="k_zaneseni"] { display: none }
.komentovat { display: none }
}
.pointer-hi,
/* Skrývání korektur */
[data-opravazobrazit="false"] {
.corr-body { display: none; }
.corr-buttons { display: none; }
.toggle-button { transform: rotate(180deg); }
}
/* Tlačítko na aktualizaci */
#korektury-aktualizace {
position: absolute;
right: 10px;
top: 10px;
border-radius: 10px;
/* copy-paste .button */
margin: 10px 0 10px 0;
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));
&:hover {
background-color: #df490e;
}
}
/* Čára od textu k místu korektury */
.pointer{
position:absolute;
/*border-bottom-left-radius: 10px; */
border-left: 2px solid yellow;
border-bottom: 2px solid yellow;
border-color: rgb(var(--rgb),var(--alpha));
}
border-bottom-left-radius: 10px;
border-left: 1px solid rgb(var(--rgb),var(--alpha));
border-bottom: 1px solid rgb(var(--rgb),var(--alpha));
pointer-events: none;
.pointer {
border-width: 1px;
--alpha: 0.35;
}
.pointer-hi {
/* Zvýraznění čáry při najetí na korekturu */
&[data-highlight="true"] {
border-width: 3px;
--alpha: 1;
}
}
.box:hover{
border-width:3px;
margin: 0px;
}
.box {
/* Korektura samotná */
.oprava {
margin: 1px;
background-color: white;
width:300px;
/*position:absolute;*/
width: 300px;
padding: 3px;
border: 2px solid black;
border: 2px solid rgb(var(--rgb));
border-radius: 10px;
border-color: rgb(var(--rgb));
}
form {
display:inline;
}
.float-right{
float:right;
}
.imgdiv {
position:relative;
left:0px;
top:0px;
}
#commform-div {
display: none;
position: absolute;
background-color: white;
border: 1px solid;
padding: 3px;
/*
width: 310;
height: 220;
*/
z-index: 10;
border: 4px solid red;
border-radius: 10px;
background-color: white;
opacity: 80%;
}
.close-button{
background-color: yellow;
}
&:hover {
border-width:3px;
margin: 0;
}
.box button,
.box img,
.box-done button,
.box-done img,
.box-ready button,
.box-ready img,
.box-wontfix button,
.box-wontfix img{
button, img {
border: 1px solid white;
background-color:transparent;
margin:0;
padding: 1px;
}
.box button:hover,
.box img:hover,
.box-done img:hover,
.box-done button:hover,
.box-ready img:hover,
.box-ready button:hover,
.box-wontfix img:hover,
.box-wontfix button:hover{
&:hover {
border: 1px solid black;
}
}
}
.comment hr {
height: 0px;
}
button img { pointer-events: none; }
.corr-header {
.corr-header {
overflow: auto;
}
}
.author {
.author {
font-weight: bold;
float: left;
margin-top: 3px;
}
.float-right{
float:right;
}
}
form {
display:inline;
}
/* Zobrazované PDF */
.imgdiv {
position:relative;
left:0;
top:0;
}
/* Přidávání korektury / úprava komentáře */
#commform-div {
position: absolute;
background-color: white;
padding: 3px;
z-index: 10;
border: 4px solid red;
border-radius: 10px;
opacity: 80%;
}
.korektury-tag {
border-radius: 5px;
margin: 2px;
padding: 2px;
&[data-selected="false"] { opacity: 0.7; }
}
/* Šipky na posouvání korektur */
#korektury-sipky {
position: fixed;
bottom: 5px;
left: 5px;
button, img {
border: 1px solid white;
background-color:transparent;
margin:0;
padding: 1px;
border-radius: 5px;
&:hover {
border: 1px solid black;
}
}
button img { pointer-events: none; }
#predchozi-korektura, #dalsi-korektura {
background-color: #EEEEEE;
}
#predchozi-korektura-k-oprave, #dalsi-korektura-k-oprave {
background-color: #FF0000;
}
#predchozi-korektura-k-zaneseni, #dalsi-korektura-k-zaneseni {
background-color: #00FF00;
}
}
/**** ROZLIŠENÍ MEZI LOKÁLNÍM, TESTOVACÍM A PRODUKČNÍM WEBEM ****/
body.localweb, body.testweb, body.suprodweb {
&:before, &:after {
content: "";
position: fixed;
width: 20px;
height: 100%;
top: 0;
z-index: -1000;
}
&:before { left: 0; }
&:after { right: 0; }
}
body.localweb { &:before, &:after { background: greenyellow; } }
body.testweb { &:before, &:after { background: darkorange; } }
body.suprodweb { &:before, &:after { background: red; } }
/****************************************************************/

View file

@ -1,283 +1,46 @@
const W_SKIP = 10;
const H_SKIP = 5;
const POINTER_MIN_H = 30;
function place_comments_one_div(img_id, comments)
{
var img = document.getElementById(img_id);
if( img == null ) {
return;
}
var par = img.parentNode;
var w = img.clientWidth;
var h = img.clientHeight;
var w_skip = 10;
var h_skip = 5;
var pointer_min_h = 30;
const img = document.getElementById("img-"+img_id);
if( img == null ) return;
const comments_sorted = comments.sort((a, b) => a.y - b.y);
var bott_max = 0;
var comments_sorted = comments.sort(function (a,b) {
return a[2] - b[2];
//pokus o hezci kladeni poiteru, ale nic moc
if( a[3] < b[3] ) {
return (a[2] + pointer_min_h)- b[2];
} else {
return (a[2] - pointer_min_h)- b[2];
const par = img.parentNode;
const w = img.clientWidth;
let bott_max = 0;
for (const oprava of comments_sorted) {
const x = oprava.x;
const y = oprava.y;
const htmlElement = oprava.htmlElement;
const pointer = oprava.pointer;
par.appendChild(pointer);
par.appendChild(htmlElement);
const delta_y = (y > bott_max) ? 0: bott_max - y + H_SKIP;
pointer.style.left = x;
pointer.style.top = y;
pointer.style.width = w - x + W_SKIP;
pointer.style.height = POINTER_MIN_H + delta_y;
htmlElement.style.left = w + W_SKIP;
htmlElement.style.top = y + delta_y;
bott_max = Math.max(bott_max, htmlElement.offsetTop + htmlElement.offsetHeight + H_SKIP); // FIXME nemám páru, proč +H_SKIP funguje, ale opravuje to bug, že nově vytvořené korektury za sebou neměly mezeru
}
});
//console.log("w:" + w);
for (c in comments_sorted) {
var id = comments_sorted[c][0];
var x = comments_sorted[c][1];
var y = comments_sorted[c][2];
var el = document.getElementById(id);
var elp = document.getElementById(id + "-pointer");
if( el == null || elp == null ) {
continue;
}
par.appendChild(elp);
par.appendChild(el);
var delta_y = (y > bott_max) ? 0: bott_max - y + h_skip;
elp.style.left = x;
elp.style.top = y ;
elp.style.width = w - x + w_skip;
elp.style.height = pointer_min_h + delta_y;
elp.img_id = img_id;
el.img_id = img_id;
el.style.position = 'absolute';
el.style.left = w + w_skip;
el.style.top = y + delta_y;
var bott = el.offsetTop + el.offsetHeight;
bott_max = ( bott_max > bott ) ? bott_max : bott;
//console.log( "par.w:" + par.style.width);
}
if( par.offsetHeight < bott_max ) {
//par.style.height = bott_max;
//alert("preteklo to:"+ par.offsetHeight +",mx:" + bott_max );
par.style.height = bott_max;
}
if (par.offsetHeight < bott_max) par.style.height = bott_max;
}
function place_comments() {
for (var i=0; i < comments.length-1; i++) {
place_comments_one_div(comments[i][0], comments[i][1])
for (let [img_id, opravy] of Object.entries(comments)) {
place_comments_one_div(img_id, opravy)
}
}
// ctrl-enter submits form
function textarea_onkey(ev)
{
//console.log("ev:" + ev.keyCode + "," + ev.ctrlKey);
if( (ev.keyCode == 13 || ev.keyCode == 10 ) && ev.ctrlKey ) {
var form = document.getElementById('commform');
if( form ) {
save_scroll(form);
//form.action ='';
form.submit();
}
return true;
}
return false;
}
//hide comment form
function close_commform() {
var formdiv = document.getElementById('commform-div');
if( formdiv == null ) {
alert("form null");
return true;
}
formdiv.style.display = 'none';
return false;
}
// show comment form, when clicked to image
function img_click(element, ev) {
var body_class = document.body.className;
switch(body_class){
case "comitting":
if (!confirm("Právě jsou zanášeny korektury, opravdu chcete přidat novou?"))
return;
break;
case "deprecated":
if (!confirm("Toto PDF je již zastaralé, opravdu chcete vytvořit korekturu?"))
return;
break;
}
var dx, dy;
var par = element.parentNode;
if( ev.pageX != null ) {
dx = ev.pageX - par.offsetLeft;
dy = ev.pageY - par.offsetTop;
} else { //IE
dx = ev.offsetX;
dy = ev.offsetY;
}
var img_id = element.id;
if( element.img_id != null ) {
// click was to '-pointer'
img_id = element.img_id;
}
return show_form(img_id, dx, dy, '', '', '', '');
}
// hide or show text of correction
function toggle_visibility(oid){
var buttondiv = document.getElementById(oid+'-buttons')
var text = document.getElementById(oid+'-body');
if (text.style.display == 'none'){
text.style.display = 'block';
buttondiv.style.display = 'inline-block';
}else {
text.style.display = 'none';
buttondiv.style.display = 'none';
}
for (var i=0;i<comments.length-1;i++){
place_comments_one_div(comments[i][0], comments[i][1])
}
}
// show comment form, when 'edit' or 'comment' button pressed
function box_edit(oid, action)
{
var divpointer = document.getElementById(oid + '-pointer');
var text;
if (action == 'update') {
var text_el = document.getElementById(oid + '-text');
text = text_el.textContent; // FIXME původně tu bylo innerHTML.unescapeHTML()
} else {
text = '';
}
var dx = parseInt(divpointer.style.left);
var dy = parseInt(divpointer.style.top);
var divbox = document.getElementById(oid);
//alert('not yet 2:' + text + text_el); // + divpointer.style.top "x" + divpo );
id = oid.substring(2);
return show_form(divbox.img_id, dx, dy, id, text, action);
}
// show comment form when 'update-comment' button pressed
function update_comment(oid,ktid)
{
var divpointer = document.getElementById(oid + '-pointer');
var dx = parseInt(divpointer.style.left);
var dy = parseInt(divpointer.style.top);
var divbox = document.getElementById(oid);
var text = document.getElementById(ktid).textContent; // FIXME původně tu bylo innerHTML.unescapeHTML()
return show_form(divbox.img_id, dx, dy, ktid.substring(2), text, 'update-comment');
}
//fill up comment form and show him
function show_form(img_id, dx, dy, id, text, action) {
var form = document.getElementById('commform');
var formdiv = document.getElementById('commform-div');
var textarea = document.getElementById('commform-text');
var inputX = document.getElementById('commform-x');
var inputY = document.getElementById('commform-y');
var inputImgId = document.getElementById('commform-img-id');
var inputId = document.getElementById('commform-id');
var inputAction = document.getElementById('commform-action');
var img = document.getElementById(img_id);
if( formdiv == null || textarea == null ) {
alert("form null");
return 1;
}
//form.action = "#" + img_id;
// set hidden values
inputX.value = dx;
inputY.value = dy;
inputImgId.value = img_id;
inputId.value = id;
inputAction.value = action;
textarea.value = text;
//textarea.value = "dxy:"+ dx + "x" + dy + "\n" + 'id:' + img_id;
// show form
formdiv.style.display = 'block';
formdiv.style.left = dx;
formdiv.style.top = dy;
img.parentNode.appendChild(formdiv);
textarea.focus();
return true;
}
function box_onmouseover(box)
{
var id = box.id;
var pointer = document.getElementById(box.id + '-pointer');
pointer.classList.remove('pointer');
pointer.classList.add('pointer-hi');
}
function box_onmouseout(box)
{
var id = box.id;
var pointer = document.getElementById(box.id + '-pointer');
pointer.classList.remove('pointer-hi');
pointer.classList.add('pointer');
}
function save_scroll(form)
{
//alert('save_scroll:' + document.body.scrollTop);
form.scroll.value = document.body.scrollTop;
//alert('save_scroll:' + form.scroll.value);
return true;
}
function toggle_corrections(aclass)
{
var stylesheets = document.styleSheets;
var ssheet = null;
for (var i=0;i<stylesheets.length; i++){
if (stylesheets[i].title === "opraf-css"){
ssheet = stylesheets[i];
break;
}
}
if (! ssheet){
return;
}
for (var i=0;i<ssheet.cssRules.length;i++){
var rule = ssheet.cssRules[i];
if (rule.selectorText === '.'+aclass){
if (rule.style.display === ""){
rule.style.display = "none";
} else {
rule.style.display = "";
}
}
}
place_comments();
}
String.prototype.unescapeHTML = function () {
return(
this.replace(/&amp;/g,'&').
replace(/&gt;/g,'>').
replace(/&lt;/g,'<').
replace(/&quot;/g,'"')
);
};

View file

@ -0,0 +1,69 @@
{% load static %}
<div id="korektury-sipky">
<button type='button' id="predchozi-korektura" title='Předchozí korektura'>
<img class='toggle-button' src='{% static "korektury/imgs/hide.png" %}' alt='⬆'/>
</button>
<button type='button' id="predchozi-korektura-k-oprave" title='Předchozí korektura k opravě'>
<img class='toggle-button' src='{% static "korektury/imgs/hide.png" %}' alt='⬆'/>
</button>
<button type='button' id="predchozi-korektura-k-zaneseni" title='Předchozí korektura k zaneseni'>
<img class='toggle-button' src='{% static "korektury/imgs/hide.png" %}' alt='⬆'/>
</button>
<br>
<button type='button' id="dalsi-korektura" title='Další korektura'>
<img class='toggle-button' src='{% static "korektury/imgs/hide.png" %}' alt='⬇' style="transform: rotate(180deg);"/>
</button>
<button type='button' id="dalsi-korektura-k-oprave" title='Další korektura k opravě'>
<img class='toggle-button' src='{% static "korektury/imgs/hide.png" %}' alt='⬇' style="transform: rotate(180deg);"/>
</button>
<button type='button' id="dalsi-korektura-k-zaneseni" title='Další korektura k zaneseni'>
<img class='toggle-button' src='{% static "korektury/imgs/hide.png" %}' alt='⬇' style="transform: rotate(180deg);"/>
</button>
</div>
<script>
const predchozi_k = document.getElementById('predchozi-korektura');
const dalsi_k = document.getElementById('dalsi-korektura');
const predchozi_k_o = document.getElementById('predchozi-korektura-k-oprave');
const dalsi_k_o = document.getElementById('dalsi-korektura-k-oprave');
const predchozi_k_z = document.getElementById('predchozi-korektura-k-zaneseni');
const dalsi_k_z = document.getElementById('dalsi-korektura-k-zaneseni');
function dalsi_nebo_predchozi_korektura(dalsi=true, stav=null) {
let predchozi = null;
for (let [_, opravy] of Object.entries(comments)) {
for (const oprava of opravy) {
if (stav == null || oprava.status === stav) {
console.log(oprava, oprava.htmlElement.getBoundingClientRect().y);
const y = oprava.htmlElement.getBoundingClientRect().y;
if (y >= -1) {
if (dalsi) {
if (y > 1) {
oprava.htmlElement.scrollIntoView();
return;
}
} else {
console.log(predchozi);
if (predchozi !== null) predchozi.htmlElement.scrollIntoView(); else alert("Výše už není žádná taková korektura.");
return;
}
}
predchozi = oprava;
}
}
}
if (!dalsi && predchozi !== null) {
predchozi.htmlElement.scrollIntoView();
return;
}
alert("Žádná další korektura.");
}
predchozi_k.addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(false) });
dalsi_k.addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(true) });
predchozi_k_o.addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(false, "k_oprave") });
dalsi_k_o.addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(true, "k_oprave") });
predchozi_k_z.addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(false, "k_zaneseni") });
dalsi_k_z.addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(true, "k_zaneseni") });
</script>

View file

@ -0,0 +1,97 @@
<div id="commform-div" style="display: none">
<input size="24" name="au" value="{{user.first_name}} {{user.last_name}}" readonly/>
<button type="button" id="commform-submit">Oprav!</button>
<button type="button" id="commform-close">Zavřít</button>
<br/>
<textarea id="commform-text" cols=40 rows=10 name="txt"></textarea>
<br/>
<span id="commform-tagy">
{% for tag in tagy %}
<button type="button" class="korektury-tag" value="{{tag.id}}" data-selected="false" style="background: {{ tag.barva }};">{{tag.nazev}}</button>
{% endfor %}
</span>
</div>
<script>
class _CommForm {
constructor() {
this.div = document.getElementById('commform-div');
this.text = document.getElementById('commform-text');
this.submit_button = document.getElementById('commform-submit');
const close_button = document.getElementById('commform-close');
this.tagy = document.getElementById('commform-tagy');
// ctrl-enter submits form
this.text.addEventListener("keydown", ev => {
if (ev.code === "Enter" && ev.ctrlKey) this.submit();
});
close_button.addEventListener("click", _ => { this.close(); });
this.submit_button.addEventListener("click", _ => { this.submit(); });
for (const tag of this.tagy.getElementsByTagName("button")) tag.addEventListener("click", event => { this.toggle_tag(event); });
}
toggle_tag(event) {
const button = event.target;
button.dataset.selected = String(button.dataset.selected === "false");
}
// schová commform
close() { this.div.style.display = 'none'; }
// zobrazí commform (bez vyplňování)
_show(img_id, x, y) {
this.submit_button.disabled = false;
this.div.style.display = 'block';
this.div.style.left = x;
this.div.style.top = y;
const img = document.getElementById("img-" + img_id);
img.parentNode.appendChild(commform.div);
this.text.focus();
}
// fill up comment form and show him
show(img_id, x, y, text, oprava_id=-1, komentar_id=-1) {
if (this.div.style.display !== 'none' && this.text.value !== "" && !confirm("Zavřít předchozí okénko přidávání korektury / editace komentáře?")) return;
// set hidden values
this.x = x;
this.y = y;
this.imgID = img_id;
this.oprava_id = oprava_id;
this.komentar_id = komentar_id;
this.text.value = text;
// show form
if (oprava_id === -1 && komentar_id === -1) this.tagy.style.display = 'unset'; else this.tagy.style.display = 'none';
this._show(img_id, x, y);
}
submit() {
this.submit_button.disabled = true;
const data = new FormData(CSRF_FORM);
data.append('x', this.x);
data.append('y', this.y);
data.append('img_id', this.imgID);
data.append('oprava_id', this.oprava_id);
data.append('komentar_id', this.komentar_id);
if (this.oprava_id === -1 && this.komentar_id === -1) {
const tagy = [];
for (const tag of this.tagy.getElementsByTagName("button")) {
if (tag.dataset.selected !== "false") tagy.push(tag.value);
}
data.append('tagy', String(tagy));
}
data.append('text', this.text.value);
update_all({method: 'POST', body: data}, true, () => {this.close(); this.submit_button.disabled = false;});
}
}
const commform = new _CommForm();
</script>

View file

@ -0,0 +1,86 @@
{% load static %}
<div class='comment' id='prekomentar' {# id='k{{k.id}}' #}>
<div class='corr-header'>
<div class='author'>{# {{k.autor}} #}</div>
<div class='float-right'>
<button type='button' style='display: none' class='del-comment' title='Smaž komentář'>
<img src='{% static "korektury/imgs/delete.png" %}' alt='del'/>
</button>
<button type='button' class='update-comment' title='Uprav komentář'>
<img src='{% static "korektury/imgs/edit.png"%}' alt='edit'/>
</button>
</div>
</div>
<div class='komtext'>{# {{k.text|linebreaks}} #}</div>
</div>
<script>
const prekomentar = document.getElementById('prekomentar');
const komentare = {};
class Komentar {
static update_or_create(komentar_data, oprava) {
const id = komentar_data['id'];
if (id in komentare) komentare[id].update(komentar_data);
else new Komentar(komentar_data, oprava);
}
#autor; #text;
htmlElement;
id; oprava; {# komentar_data; #}
/**
*
* @param komentar_data
* @param {Oprava} oprava
*/
constructor(komentar_data, oprava) {
this.htmlElement = prekomentar.cloneNode(true);
this.#autor = this.htmlElement.getElementsByClassName('author')[0];
this.#text = this.htmlElement.getElementsByClassName('komtext')[0];
this.id = komentar_data['id'];
this.htmlElement.id = 'k' + this.id;
this.oprava = oprava;
this.oprava.add_komentar_htmlElement(this.htmlElement);
this.update(komentar_data);
this.htmlElement.getElementsByClassName('update-comment')[0].addEventListener('click', _ => this.#update_comment());
this.htmlElement.getElementsByClassName('del-comment')[0].addEventListener('click', _ => this.#delete_comment());
komentare[this.id] = this;
}
update(komentar_data) {
{# this.komentar_data = komentar_data; #}
this.set_autor(komentar_data['autor']);
this.set_text(komentar_data['text']);
};
set_autor(autor) {this.#autor.textContent=autor;};
set_text(text) {
this.#text.innerHTML=text;
};
// show comment form when 'update-comment' button pressed
#update_comment() {
return commform.show(this.oprava.img_id, this.oprava.x, this.oprava.y, this.#text.textContent, -1, this.id);
}
#delete_comment() {
if (confirm('Opravdu smazat komentář?')) {
throw {name : 'NotImplementedError', message: '(Webaři jsou) too lazy to implement'};
}
}
}
</script>

View file

@ -0,0 +1,165 @@
{% load static %}
<div id='prepointer' {# id='op{{o.id}}-pointer' #}
class='pointer'
data-highlight='false'
{# data-opravastatus='{{o.status}}' #}
></div>
<div id='preoprava' {# name='op{{o.id}}' id='op{{o.id}}' #}
class='oprava'
{# data-opravastatus='{{o.status}}' #}
data-opravazobrazit='true'
>
<div class='corr-tagy'>
{# {% for tag in o.tagy %} <span style="background:{{ tag.barva }}>{{ tag.text }}<span/> #}
</div>
<div class='corr-body'>
{# {% for k in o.komentare %} {% include "korektury/korekturovatko/__komentar.html" %} <hr> {% endfor %} #}
</div>
<div class='corr-header'>
<span class='float-right'>
<span class='corr-buttons'>
<button type='button' style='display: none' class='del' title='Smaž opravu'>
<img src='{% static "korektury/imgs/delete.png"%}' alt='🗑️'/>
</button>
<button type='button' class='action' value='k_oprave' title='Označ jako neopravené'>
<img src='{% static "korektury/imgs/undo.png"%}' alt='↪'/>
</button>
<button type='button' class='action' value='opraveno' title='Označ jako opravené'>
<img src='{% static "korektury/imgs/check.png"%}' alt='✔️'/>
</button>
<button type='button' class='action' value='neni_chyba' title='Označ, že se nebude měnit'>
<img src='{% static "korektury/imgs/cross.png" %}' alt='❌'/>
</button>
<button type='button' class='action' value='k_zaneseni' title='Označ jako připraveno k zanesení'>
<img src='{% static "korektury/imgs/tex.png" %}' alt='TeX'/>
</button>
<a href='{% url "admin:korektury_oprava_change" -1 %}' class='edit' title='Uprav korekturu jako takovou.' style="text-decoration: none;"> {# FIXME Udělat z toho tlačítko? #}
<img src='{% static "korektury/imgs/edit.png"%}' alt='✏️' style="opacity: 0.5;"/> {# FIXME Odlišit jinak než pomocí opacity? #}
</a>
<button type='button' class='komentovat_disabled' title='Korekturu nelze komentovat, protože už je uzavřená' disabled=''>
<img src='{% static "korektury/imgs/comment-gr.png" %}' alt='💭'/>
</button>
<button type='button' class='komentovat' title='Komentovat'>
<img src='{% static "korektury/imgs/comment.png" %}' alt='💭'/>
</button>
</span>
<button type='button' class='toggle-vis' title='Skrýt/Zobrazit'>
<img class='toggle-button' src='{% static "korektury/imgs/hide.png" %}' alt='⬆'/>
</button>
</span>
</div>
</div>
<script>
const preoprava = document.getElementById('preoprava');
const prepointer = document.getElementById('prepointer');
const opravy = {};
class Oprava {
static update_or_create(oprava_data) {
const id = oprava_data['id'];
if (id in opravy) return opravy[id].update(oprava_data);
else return new Oprava(oprava_data);
}
#komentare; #tagy;
htmlElement; pointer;
id; x; y; img_id; status; zobrazit = true; {# oprava_data; #}
constructor(oprava_data) {
this.htmlElement = preoprava.cloneNode(true);
this.pointer = prepointer.cloneNode(true);
this.#komentare = this.htmlElement.getElementsByClassName('corr-body')[0];
this.#tagy = this.htmlElement.getElementsByClassName('corr-tagy')[0];
this.id = oprava_data['id'];
this.htmlElement.id = 'op' + this.id;
this.pointer.id = 'op' + this.id + '-pointer';
this.x = oprava_data['x'];
this.y = oprava_data['y'];
this.img_id = oprava_data['strana'];
this.update(oprava_data);
this.htmlElement.getElementsByClassName('toggle-vis')[0].addEventListener('click', _ => this.#toggle_visibility());
for (const button of this.htmlElement.getElementsByClassName('action'))
button.addEventListener('click', async event => this.#zmenStavKorektury(event));
this.htmlElement.getElementsByClassName('komentovat')[0].addEventListener('click', _ => this.#comment())
this.htmlElement.getElementsByClassName('del')[0].addEventListener('click', _ => this.#delete());
const odkaz_editace = this.htmlElement.getElementsByClassName('edit')[0];
odkaz_editace.href = odkaz_editace.href.replace("-1", this.id);
odkaz_editace.onclick = ev => { if (!confirm("Editace korektury je velmi pokročilá featura umožňující přesouvat korekturu nebo přidávat informované orgy, opravdu chceš pokračovat do adminu?")) ev.preventDefault(); };
this.htmlElement.addEventListener('mouseover', _ => this.pointer.dataset.highlight = 'true');
this.htmlElement.addEventListener('mouseout', _ => this.pointer.dataset.highlight = 'false');
opravy[this.id] = this;
if (this.img_id in comments) comments[this.img_id].push(this); else alert("Někdo korekturoval stranu, která neexistuje. Dejte vědět webařům :)");
}
update(oprava_data) {
{# this.oprava_data = oprava_data; #}
this.set_status(oprava_data['status']);
this.#tagy.innerHTML = "";
for (const tag of oprava_data["tagy"]) {
const span = document.createElement("span");
span.innerHTML = tag["nazev"];
span.classList.add("korektury-tag");
span.style.backgroundColor = tag["barva"];
this.#tagy.appendChild(span);
}
return this;
};
set_status(status) {
this.status = status;
this.htmlElement.dataset.opravastatus=status;
this.pointer.dataset.opravastatus=status;
};
add_komentar_htmlElement(htmlElement) {
this.#komentare.appendChild(htmlElement);
this.#komentare.appendChild(document.createElement('hr'));
}
// hide or show text of correction
#toggle_visibility(){
this.zobrazit = !this.zobrazit;
this.htmlElement.dataset.opravazobrazit = String(this.zobrazit);
place_comments()
}
// show comment form, when 'comment' button pressed
#comment() { commform.show(this.img_id, this.x, this.y, "", this.id); }
#zmenStavKorektury(event) {
const data = new FormData(CSRF_FORM);
data.append('id', this.id);
data.append('action', event.target.value);
fetch('{% url "korektury_api_oprava_stav" %}', {method: 'POST', body: data})
.then(response => {
if (!response.ok) {alert('Něco se nepovedlo:' + response.statusText);}
else response.json().then(data => this.set_status(data['status']));
})
.catch(error => {alert('Něco se nepovedlo:' + error);});
}
#delete() {
if (confirm('Opravdu smazat korekturu?')) {
throw {name : 'NotImplementedError', message: '(Webaři jsou) too lazy to implement'};
}
}
}
</script>

View file

@ -0,0 +1,51 @@
{% for i in img_indexes %}
<div class='imgdiv'>
<img
id='img-{{i}}'
width='1021' height='1448'
src='/media/korektury/img/{{img_prefix}}-{{i}}.png'
alt='Strana {{ i|add:1 }}'
class="strana"
/>
</div>
<hr/>
{% endfor %}
<script>
// Mapování stránka -> korektury
const comments = {
{% for s in opravy_strany %}
{{s.strana}}: []{% if not forloop.last %},{% endif %}
{% endfor %}
};
// show comment form, when clicked to image
for (const image of document.getElementsByClassName('strana')) {
image.addEventListener('click', ev => {
switch (document.body.dataset.status) {
case 'zanaseni':
if (!confirm('Právě jsou zanášeny korektury, opravdu chcete přidat novou?'))
return;
break;
case 'zastarale':
if (!confirm('Toto PDF je již zastaralé, opravdu chcete vytvořit korekturu?'))
return;
break;
}
let dx, dy;
const par = image.parentNode;
if (ev.pageX != null) {
dx = ev.pageX - par.offsetLeft;
dy = ev.pageY - par.offsetTop;
} else { //IE a další
dx = ev.offsetX;
dy = ev.offsetY;
}
const img_id = image.id.substring(4);
commform.show(img_id, dx, dy, '');
console.log("Pro přesun korektur: strana = " + img_id + ", x = " + dx + ", y = " + dy);
});
}
</script>

View file

@ -0,0 +1,52 @@
{% include "korektury/korekturovatko/__edit_komentar.html" %}
{% include "korektury/korekturovatko/__stranky.html" %}
{# {% for o in opravy %} {% include "korektury/korekturovatko/__oprava.html" %} {% endfor %} #}
{% include "korektury/korekturovatko/__oprava.html" %}
{% include "korektury/korekturovatko/__komentar.html" %}
{% include "korektury/korekturovatko/__dalsi_korektura.html" %}
<button type="button" id="korektury-aktualizace">Aktualizuj korektury.</button>
<script>
/**
*
* @param {RequestInit} data
* @param {Boolean} catchError
* @param pri_uspechu Akce, která se má provést při úspěchu (speciálně zavřít formulář)
*/
function update_all(data={}, catchError=true, pri_uspechu=null) { // FIXME není mi jasné, zda v {} nemá být `cache: "no-store"`, aby prohlížeč necachoval GET.
fetch('{% url "korektury_api_opravy_a_komentare" pdf.id %}', data)
.then(response => {
if (!response.ok && catchError) {alert('Něco se nepovedlo:' + response.statusText);}
else response.json().then(data => {
if (pri_uspechu) pri_uspechu();
for (const oprava_data of data["context"]) {
const oprava = Oprava.update_or_create(oprava_data);
for (const komentar_data of oprava_data["komentare"]) {
Komentar.update_or_create(komentar_data, oprava);
}
}
place_comments();
});
})
.catch(error => {if (catchError) alert('Něco se nepovedlo:' + error);});
}
update_all();
// FIXME není mi jasné, zda v {} nemá být `cache: "no-store"`, aby prohlížeč necachoval GET.
document.getElementById("korektury-aktualizace").addEventListener("click", _ => update_all({}, false));
// FIXME není mi jasné, zda v {} nemá být `cache: "no-store"`, aby prohlížeč necachoval GET.
setInterval(() => update_all({}, false), 120000); // Každý dvě minuty fetchni korektury
</script>
<form id='CSRF_form' style='display: none'>{% csrf_token %}</form>
<script>
const CSRF_FORM = document.getElementById('CSRF_form');
</script>

View file

@ -0,0 +1,51 @@
Zobrazit:
<input type="checkbox"
id="k_oprave_checkbox"
name="k_oprave_checkbox"
onchange="toggle_corrections('k_oprave')" checked>
<label for="k_oprave_checkbox">K opravě ({{k_oprave_cnt}})</label>
<input type="checkbox"
id="opraveno_checkbox"
name="opraveno_checkbox"
onchange="toggle_corrections('opraveno')" checked>
<label for="opraveno_checkbox">Opraveno ({{opraveno_cnt}})</label>
<input type="checkbox"
id="neni_chyba_checkbox"
name="neni_chyba_checkbox"
onchange="toggle_corrections('neni_chyba')" checked>
<label for="neni_chyba_checkbox">Není chyba ({{neni_chyba_cnt}})</label>
<input type="checkbox"
id="k_zaneseni_checkbox"
name="k_zaneseni_checkbox"
onchange="toggle_corrections('k_zaneseni')" checked>
<label for="k_zaneseni_checkbox">K zanesení ({{k_zaneseni_cnt}})</label>
<hr/>
<script>
function toggle_corrections(aclass)
{
const stylesheets = document.styleSheets;
let ssheet = null;
for (let i=0; i<stylesheets.length; i++){
if (stylesheets[i].title === "opraf-css"){
ssheet = stylesheets[i];
break;
}
}
if (! ssheet){
return;
}
for (let i=0; i<ssheet.cssRules.length; i++){
const rule = ssheet.cssRules[i];
if (rule.selectorText === '[data-opravastatus="'+aclass+'"]'){
if (rule.style.display === ""){
rule.style.display = "none";
} else {
rule.style.display = "";
}
}
}
place_comments();
}
</script>

View file

@ -0,0 +1,44 @@
<h4>Změnit stav PDF:</h4>
<i>Aktuální: {{pdf.status}}</i>
<br>
<form method="post" id="PDFSTAV_FORM">
{% csrf_token %}
<input type="radio" name="state" value="{{ pdf.STATUS.PRIDAVANI }}" {% if pdf.status == pdf.STATUS.PRIDAVANI %} checked {% endif %}>Přidávání korektur
<br>
<input type="radio" name="state" value="{{ pdf.STATUS.ZANASENI }}" {% if pdf.status == pdf.STATUS.ZANASENI %} checked {% endif %}>Zanášení korektur
<br>
<input type="radio" name="state" value="{{ pdf.STATUS.ZASTARALE }}" {% if pdf.status == pdf.STATUS.ZASTARALE %} checked {% endif %}>Zastaralé, nekorigovat
<br>
<input type='submit' value='Změnit stav PDF'/>
</form>
<script>
const pdfstav_form = document.getElementById('PDFSTAV_FORM');
/**
*
* @param {RequestInit} data
* @param {Boolean} catchError
*/
function fetchStav(data, catchError=true) {
fetch("{% url 'korektury_api_pdf_stav' pdf.id %}", data
)
.then(response => {
if (!response.ok) { if (catchError) alert("Něco se nepovedlo:" + response.statusText);}
else response.json().then(data => document.body.dataset.status = data["status"]);
})
.catch(error => {if (catchError) alert("Něco se nepovedlo:" + error);});
}
pdfstav_form.addEventListener('submit', async event => {
event.preventDefault();
const data = new FormData(pdfstav_form);
fetchStav({method: "POST", body: data});
});
// FIXME není mi jasné, zda v {} nemá být `cache: "no-store"`, aby prohlížeč necachoval get.
setInterval(() => fetchStav({}, false), 120000); // Každý dvě minuty fetchni stav
</script>

View file

@ -0,0 +1,44 @@
{% load static %}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" title="opraf-css" type="text/css" media="screen, projection" href="{% static "korektury/opraf.css"%}?version=1" />
<link href="{% static 'css/rozliseni.css' %}?version=1" rel="stylesheet">
<script src="{% static "korektury/opraf.js"%}?version=1"></script>
<title>Korektury {{pdf.nazev}}</title>
</head>
<body class="{{ LOCAL_TEST_PROD }}web" data-status="{{ pdf.status }}" onload='place_comments()'>
<h1>Korektury {{pdf.nazev}}</h1>
<h2 class="textzanaseni"> Probíhá zanášení korektur, zvažte, zda chcete přidávat nové </h2>
<h2 class="textzastarale"> Toto PDF je již zastaralé, nepřidávejte nové korektury </h2>
<i>{{pdf.komentar}}</i>
<br>
<i>Klikni na chybu, napiš komentář</i> |
<a href="{{pdf.pdf.url}}">stáhnout PDF (bez korektur)</a> |
<a href="../">seznam souborů</a> |
<a href="/admin/korektury/korekturovanepdf/">Spravovat PDF</a> |
<a href="../help">nápověda</a> |
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|
<a href="/">hlavní stránka</a> |
<a href="https://mam.mff.cuni.cz/wiki">wiki</a> |
<hr />
{% include "korektury/korekturovatko/_schovani_korektur.html" %}
{% include "korektury/korekturovatko/_main.html" %}
{% include "korektury/korekturovatko/_zmena_stavu.html" %}
<hr/>
<p>
Děkujeme opravovatelům:
{% for z in zasluhy %}
{{z.autor}} ({{z.pocet}}){% if not forloop.last %},{% endif %}
{% endfor %}</p>
<hr>
</body>
</html>

View file

@ -1,244 +0,0 @@
{% load static %}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" title="opraf-css" type="text/css" media="screen, projection" href="{% static "korektury/opraf.css"%}" />
<link href="{% static 'css/rozliseni.css' %}?version=1" rel="stylesheet">
<script src="{% static "korektury/opraf.js"%}"></script>
<title>Korektury {{pdf.nazev}}</title>
</head>
<body class="{{ LOCAL_TEST_PROD }}web{% if pdf.status == 'zanaseni'%} comitting{% elif pdf.status == 'zastarale' %} deprecated{% endif %}" onload='place_comments()'>
<h1>Korektury {{pdf.nazev}}</h1>
{% if pdf.status == 'zanaseni' %} <h2> Probíhá zanášení korektur, zvažte, zda chcete přidávat nové </h2> {% endif %}
{% if pdf.status == 'zastarale' %} <h2> Toto PDF je již zastaralé, nepřidávejte nové korektury </h2> {% endif %}
<i>{{pdf.komentar}}</i>
<br>
<i>Klikni na chybu, napiš komentář</i> |
<a href="{{pdf.pdf.url}}">stáhnout PDF (bez korektur)</a> |
<a href="../">seznam souborů</a> |
<a href="/admin/korektury/korekturovanepdf/">Spravovat PDF</a> |
<a href="../help">nápověda</a> |
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|
<a href="/">hlavní stránka</a> |
<a href="https://mam.mff.cuni.cz/wiki">wiki</a> |
<hr />
Zobrazit:
<input type="checkbox"
id="k_oprave_checkbox"
name="k_oprave_checkbox"
onchange="toggle_corrections('k_oprave')" checked>
<label for="k_oprave_checkbox">K opravě ({{k_oprave_cnt}})</label>
<input type="checkbox"
id="opraveno_checkbox"
name="opraveno_checkbox"
onchange="toggle_corrections('opraveno')" checked>
<label for="opraveno_checkbox">Opraveno ({{opraveno_cnt}})</label>
<input type="checkbox"
id="neni_chyba_checkbox"
name="neni_chyba_checkbox"
onchange="toggle_corrections('neni_chyba')" checked>
<label for="neni_chyba_checkbox">Není chyba ({{neni_chyba_cnt}})</label>
<input type="checkbox"
id="k_zaneseni_checkbox"
name="k_zaneseni_checkbox"
onchange="toggle_corrections('k_zaneseni')" checked>
<label for="k_zaneseni_checkbox">K zanesení ({{k_zaneseni_cnt}})</label>
<hr/>
<div id="commform-div">
<!-- Pridat korekturu / komentar !-->
<form action='' onsubmit='save_scroll(this)' id="commform" method="POST">
{% csrf_token %}
<input size="24" name="au" value="{{user.first_name}} {{user.last_name}}" readonly/>
<input type=submit value="Oprav!"/>
<button type="button" onclick="close_commform()">Zavřít</button>
<br/>
<textarea onkeypress="textarea_onkey(event);" id="commform-text" cols=40 rows=10 name="txt"></textarea>
<br/>
<input type="hidden" size="3" name="pdf" value='{{pdf.id}}'/>
<input type="hidden" size="3" id="commform-x" name="x"/>
<input type="hidden" size="3" id="commform-y" name="y"/>
<input type="hidden" size="3" id="commform-img-id" name="img-id"/>
<input type="hidden" size="3" id="commform-id" name="id"/>
<input type="hidden" size="3" id="commform-action" name="action"/>
<input type="hidden" size="3" id="commform-action" name="scroll"/>
</form>
<!-- /Pridat korekturu / komentar !-->
</div>
{% for i in img_indexes %}
<div class='imgdiv'>
<img width='1021' height='1448'
onclick='img_click(this,event)' id='img-{{i}}'
src='/media/korektury/img/{{img_prefix}}-{{i}}.png'/>
</div>
<hr/>
{% endfor %}
<h4>Změnit stav PDF:</h4>
<i>Aktuální: {{pdf.status}}</i>
<br>
<!-- Zmenit stav PDF !-->
<form method="post">
{% csrf_token %}
<input type='hidden' name='action' value='set-state'/>
<input type='hidden' name='pdf' value='{{pdf.id}}'/>
<input type="radio" name="state" value="adding" {% if pdf.status == 'pridavani' %} checked {% endif %}>Přidávání korektur
<br>
<input type="radio" name="state" value="comitting" {% if pdf.status == 'zanaseni' %} checked {% endif %}>Zanášení korektur
<br>
<input type="radio" name="state" value="deprecated" {% if pdf.status == 'zastarale' %} checked {% endif %}>Zastaralé, nekorigovat
<br>
<input type='submit' value='Změnit stav PDF'/>
</form>
<!-- /Zmenit stav PDF !-->
<hr/>
<p>
Děkujeme opravovatelům:
{% for z in zasluhy %}
{{z.autor}} ({{z.pocet}}){% if not forloop.last %},{% endif %}
{% endfor %}</p>
<hr>
{% for o in opravy %}
<div onclick='img_click(this,event)'
id='op{{o.id}}-pointer'
class='pointer {{o.status}}'>
</div>
<div name='op{{o.id}}' id='op{{o.id}}'
class='box {{o.status}}'
onmouseover='box_onmouseover(this)'
onmouseout='box_onmouseout(this)'>
<div class='corr-header'>
<span class='author' id='op{{o.id}}-autor'>{{o.autor}}</span>
<span class='float-right'>
<span id='op{{o.id}}-buttons'>
<!-- Existujici korektura !-->
<form action='' onsubmit='save_scroll(this)' method='POST'>
{% csrf_token %}
<input type='hidden' name="au" value="{{o.autor}}"/>
<input type='hidden' name='pdf' value='{{pdf.id}}'>
<input type='hidden' name='id' value='{{o.id}}'>
<input type='hidden' name='scroll'>
{% if o.komentare %}
<button name='action' value='del' type='button'
title="Opravu nelze smazat &ndash; už ji někdo okomentoval">
<img src="{% static "korektury/imgs/delete-gr.png"%}"/>
</button>
{% else %}
<button type='submit' name='action' value='del' title='Smaž opravu'>
<img src="{% static "korektury/imgs/delete.png"%}"/>
</button>
{% endif %}
{% if o.status != 'k_oprave' %}
<button type='submit' name='action' value='undone' title='Označ jako neopravené'>
<img src="{% static "korektury/imgs/undo.png"%}"/>
</button>
{% endif %}
{% if o.status != 'opraveno' %}
<button type='submit' name='action' value='done' title='Označ jako opravené'>
<img src="{% static "korektury/imgs/check.png"%}"/>
</button>
{% endif %}
{% if o.status != 'neni_chyba' %}
<button type='submit' name='action' value='wontfix' title='Označ, že se nebude měnit'>
<img src="{% static "korektury/imgs/cross.png" %}"/>
</button>
{% endif %}
{% if o.status != 'k_zaneseni' %}
<button type='submit' name='action' value='ready' title='Označ jako připraveno k zanesení'>
<img src="{% static "korektury/imgs/tex.png" %}"/>
</button>
{% endif %}
</form>
<!-- /Existujici korektura !-->
{% if o.komentare %}
<button type='button' title="Korekturu nelze upravit &ndash; už ji někdo okomentoval">
<img src="{% static "korektury/imgs/edit-gr.png" %}"/>
</button>
{% else %}
<button type='button' onclick='box_edit("op{{o.id}}","update");' title='Oprav opravu'>
<img src="{% static "korektury/imgs/edit.png" %}"/>
</button>
{% endif %}
{% if o.status == 'opraveno' or o.status == 'neni_chyba' %}
<button type='button' title='Korekturu nelze komentovat, protože už je uzavřená'>
<img src="{% static "korektury/imgs/comment-gr.png" %}"/>
</button>
{% else %}
<button type='button' onclick='box_edit("op{{o.id}}", "comment");' title='Komentovat'>
<img src="{% static "korektury/imgs/comment.png" %}"/>
</button>
{% endif %}
</span>
<button type='button' onclick='toggle_visibility("op{{o.id}}");' title='Skrýt/Zobrazit'>
<img src="{% static "korektury/imgs/hide.png" %}"/>
</button>
</span>
</div>
<div class='corr-body' id='op{{o.id}}-body'>
<div id='op{{o.id}}-text'>{{o.text|linebreaks}}</div>
{% for k in o.komentare %}
<hr>
<div class='comment' id='k{{k.id}}'>
<div class='corr-header'>
<div class='author'>{{k.autor}}</div>
<div class="float-right">
<!-- Komentar !-->
<form action='' onsubmit='save_scroll(this)' method='POST'>
{% csrf_token %}
<input type='hidden' name='pdf' value='{{pdf.id}}'>
<input type='hidden' name='id' value='{{k.id}}'>
<input type='hidden' name='scroll'>
{% if forloop.last %}
<button type='submit' name='action' value='del-comment' title='Smaž komentář'
onclick='return confirm("Opravdu smazat komentář?")'>
<img src="{% static "korektury/imgs/delete.png" %}"/>
</button>
{% else %}
<button name='action' value='del-comment' type='button'
title="Komentář nelze smazat &ndash; existuje novější">
<img src="{% static "korektury/imgs/delete-gr.png"%}"/>
</button>
{% endif %}
</form>
<!-- /Komentar !-->
{% if forloop.last %}
<button type='button' onclick="update_comment('op{{o.id}}','kt{{k.id}}');" title='Uprav komentář'>
<img src="{% static "korektury/imgs/edit.png"%}"/>
</button>
{% else %}
<button type='button' title="Komentář nelze upravit &ndash; existuje novější">
<img src="{% static "korektury/imgs/edit-gr.png" %}"/>
</button>
{% endif %}
</div>
</div>
<div id='kt{{k.id}}'>{{k.text|linebreaks}}</div>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
<script>
var comments = [
{% for s in opravy_strany %}
["img-{{s.strana}}", [{% for o in s.op_id %}["op{{o.id}}",{{o.x}},{{o.y}}],{% endfor %}[]]],
{% endfor %}
[]]
{% if scroll %}
window.scrollTo(0,{{scroll}});
{% endif %}
</script>
</body>
</html>

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -35,24 +35,27 @@ def create_test_pdf(rnd, organizatori):
# 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='B', komentar='Neuronové sítě', 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?', org=rnd.choice(organizatori), pdf=gen_filename(filename='A.pdf'),
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'),
status='zanaseni'
)
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?', pdf=gen_filename(filename='A.pdf'),
status='zastarale'
)
except (FileNotFoundError, Exception) as e:
korekturovane_pdf.orgove.set((rnd.choice(organizatori),))
except OSError 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

@ -1,13 +1,7 @@
"""
Soubor sloužící jako router, tj. zde se definují url adresy a na co ukazují:
- ``korektury/`` (korektury_list) :class:`~korektury.views.KorekturySeskupeneListView`
- ``korektury/neseskupene/`` (korektury_neseskupene_list) :class:`~korektury.views.KorekturyAktualniListView`
- ``korektury/zastarale/`` (korektury_stare_list) :class:`~korektury.views.KorekturyZastaraleListView`
- ``korektury/<int:pdf>/`` (korektury) :class:`~korektury.views.KorekturyView`
"""
from django.urls import path
from seminar.utils import org_required
from django.urls import include
from personalni.utils import org_required
from . import views
urlpatterns = [
@ -15,4 +9,6 @@ urlpatterns = [
path('korektury/neseskupene/', org_required(views.KorekturyAktualniListView.as_view()), name='korektury_neseskupene_list'),
path('korektury/zastarale/', org_required(views.KorekturyZastaraleListView.as_view()), name='korektury_stare_list'),
path('korektury/<int:pdf>/', org_required(views.KorekturyView.as_view()), name='korektury'),
path('korektury/api/', include('korektury.api.urls')),
]

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