Merge branch 'develop' into django3.2
This commit is contained in:
		
						commit
						882f8e2228
					
				
					 27 changed files with 359 additions and 66 deletions
				
			
		|  | @ -16,7 +16,7 @@ | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"fields": { | 		"fields": { | ||||||
| 			"content": "<h1 id=\"co-je-mm\">Co je M&M?</h1>\r\n\r\n<h3 id=\"mm-je-mezioborový-korespondenční-seminář-pro-středoškoláky\">M&M je mezioborový korespondenční seminář pro středoškoláky</h3>\r\n\r\n<p style=\"text-align: justify;\">Ptáš se, co že je to ten korespondenční seminář? Je to jednoduché, zamysli se nad <a href=\"/aktualni/zadani/\">zadanou úlohou či problémem</a>, <a href=\"/resitel/nahraj_reseni\">odevzdej řešení</a>, my ti jej opravíme a pošleme zpět. Nabízíme témata z různých oblastí matematiky, fyziky, informatiky i dalších oborů, takže si u nás určitě najdeš to svoje. Při řešení si můžeš vyzkoušet, jak vypadá vědecká práce, a mnoho zajímavého se naučit. Podívej se na tipy v sekci <a href=\"/jak-resit/\">Jak řešit</a> a pusť se do toho! Můžeš se připojit kdykoliv během roku.</p>\r\n\r\n<h3 id=\"mm-jsou-témata\">M&M jsou témata</h3>\r\n\r\n<p style=\"text-align: justify;\">Jádro M&M tvoří takzvaná témata, tedy texty doplněné o úlohy a náměty vyzývající k přemýšlení a experimentování. Přijímáme i originální přístup k problémům, takže můžeš například vyřešit fyzikální problém naprogramováním simulace. v minulých letech řešitelé sestavovali spektrometry, pomocí laserových ukazovátek měřili index lomu různých látek, zkoumali křivky popisující vývoj počtu cestujících v tramvaji v průběhu cesty nebo programovali strategie v jednoduché hře a pak je nechávali soupeřit v turnajích. Podívej se, jaká témata nabízíme <a href=\"/aktualni/zadani/\">právě teď</a>.</p>\r\n\r\n<h3 id=\"mm-je-časopis\">M&M je časopis</h3>\r\n\r\n<p style=\"text-align: justify;\">Zadání a texty od organizátorů vydáváme formou časopisu. Kromě toho zde rovněž otiskujeme řešení a příspěvky našich řešitelů k tématům, články shrnující výsledky <a href=\"/soustredeni/\">konfer</a> – projektů, kterými se zabývali na soustředění, i výsledky jejich vlastního výzkumu. Díky tomu jsme si například mohli přečíst o <a href=\"https://mam.mff.cuni.cz/media/cislo/pdf/25/25-6.pdf#page=45\">Lichtenbergových obrazcích</a> či <a href=\"https://mam.mff.cuni.cz/media/cislo/pdf/23/23-6.pdf#page=19\">gravitaci v placatém světě</a>. Během ročníku obvykle vyjde šest čísel časopisu, prohlédnout si je můžeš v <a href=\"/archiv/rocniky/\">Archivu</a>.</p>\r\n\r\n<h3 id=\"mm-je-soutěž\">M&M je soutěž</h3>\r\n\r\n<p style=\"text-align: justify;\">Ke všem příspěvkům posíláme řešitelům zpětnou vazbu a udělujeme za ně body. Vítězové semináře se mohou těšit na zajímavé knihy a deskové hry, autora nejlepšího otištěného článku každoročně odměňujeme dortem. <a href=\"/o-nas/odmeny/\">Úspěšným řešitelům</a> jsou navíc prominuty přijímací zkoušky na MFF UK.</p>\r\n\r\n<h3 id=\"mm-jsou-soustředění\">M&M jsou soustředění</h3>\r\n\r\n<p style=\"text-align: justify;\">Aktivní řešitelé mají možnost s námi za odměnu jet dvakrát do roka na soustředění. Pojeď taky! Budeš mít možnost strávit týden v přírodě plný odborného programu a nejrůznější zábavy s partou kamarádů. Čekají tě malé vědecké projekty, přednášky, workshopy, šifrovačka, výlet a mnoho dalšího. Chceš-li se dozvědět víc, přečti si stránku <a href=\"/soustredeni/\">Soustředění</a> nebo se podívej na <a href=\"/soustredeni/probehlo/\">fotky</a>.</p>\r\n\r\n<h3 id=\"mm-jsme-my\">M&M jsme my</h3>\r\n\r\n<p style=\"text-align: justify;\">Spolu s řešiteli jsme tu i my, organizátoři. Většina z nás jsou studenti Matfyzu, tedy Matematicko-fyzikální fakulty Univerzity Karlovy. Společně se snažíme předávat dál radost z poznávání zajímavých zákoutí matematiky, fyziky a informatiky a budovat komunitu aktivních lidí, kteří se budou rádi scházet, ať už na soustředěních, víkendovkách či jiných akcích. Chceš nás poznat blíž? Podívej se na stránku <a href=\"/o-nas/organizatori/\">Organizátoři</a> nebo rovnou něco vyřeš a pojeď s námi na soustředění!</p>\r\n\r\n<h3 id=\"zaujali-jsme-tě-zapoj-se-přečti-si-jak-řešit-a-podívej-se-na-aktuální-zadání.-už-se-těšíme-na-tvé-příspěvky\" style=\"text-align: center;\">Zaujali jsme tě? Zapoj se! Přečti si <a href=\"/jak-resit/podrobneji/\">jak řešit</a> a podívej se na <a href=\"/aktualni/zadani/\">aktuální zadání</a>. Už se těšíme na tvé příspěvky!</h3>", | 			"content": "<h1 id=\"co-je-mm\">Co je M&M?</h1>\r\n\r\n<h3 id=\"mm-je-mezioborový-korespondenční-seminář-pro-středoškoláky\">M&M je mezioborový korespondenční seminář pro středoškoláky</h3>\r\n\r\n<p style=\"text-align: justify;\">Ptáš se, co že je to ten korespondenční seminář? Je to jednoduché, zamysli se nad <a href=\"/aktualni/zadani/\">zadanou úlohou či problémem</a>, <a href=\"/resitel/nahraj_reseni\">odevzdej řešení</a>, my ti jej opravíme a pošleme zpět. Nabízíme témata z různých oblastí matematiky, fyziky, informatiky i dalších oborů, takže si u nás určitě najdeš to svoje. Při řešení si můžeš vyzkoušet, jak vypadá vědecká práce, a mnoho zajímavého se naučit. Podívej se na tipy v sekci <a href=\"/jak-resit/\">Jak řešit</a> a pusť se do toho! Můžeš se připojit kdykoliv během roku.</p>\r\n\r\n<h3 id=\"mm-jsou-témata\">M&M jsou témata</h3>\r\n\r\n<p style=\"text-align: justify;\">Jádro M&M tvoří takzvaná témata, tedy texty doplněné o úlohy a náměty vyzývající k přemýšlení a experimentování. Přijímáme i originální přístup k problémům, takže můžeš například vyřešit fyzikální problém naprogramováním simulace. V minulých letech řešitelé sestavovali spektrometry, pomocí laserových ukazovátek měřili index lomu různých látek, zkoumali křivky popisující vývoj počtu cestujících v tramvaji v průběhu cesty nebo programovali strategie v jednoduché hře a pak je nechávali soupeřit v turnajích. Podívej se, jaká témata nabízíme <a href=\"/aktualni/zadani/\">právě teď</a>.</p>\r\n\r\n<h3 id=\"mm-je-časopis\">M&M je časopis</h3>\r\n\r\n<p style=\"text-align: justify;\">Zadání a texty od organizátorů vydáváme formou časopisu. Kromě toho zde rovněž otiskujeme řešení a příspěvky našich řešitelů k tématům, články shrnující výsledky <a href=\"/soustredeni/\">konfer</a> – projektů, kterými se zabývali na soustředění, i výsledky jejich vlastního výzkumu. Díky tomu jsme si například mohli přečíst o <a href=\"https://mam.mff.cuni.cz/media/cislo/pdf/25/25-6.pdf#page=45\">Lichtenbergových obrazcích</a> či <a href=\"https://mam.mff.cuni.cz/media/cislo/pdf/23/23-6.pdf#page=19\">gravitaci v placatém světě</a>. Během ročníku obvykle vyjde šest čísel časopisu, prohlédnout si je můžeš v <a href=\"/archiv/rocniky/\">Archivu</a>.</p>\r\n\r\n<h3 id=\"mm-je-soutěž\">M&M je soutěž</h3>\r\n\r\n<p style=\"text-align: justify;\">Ke všem příspěvkům posíláme řešitelům zpětnou vazbu a udělujeme za ně body. Vítězové semináře se mohou těšit na zajímavé knihy a deskové hry, autora nejlepšího otištěného článku každoročně odměňujeme dortem. <a href=\"/o-nas/odmeny/\">Úspěšným řešitelům</a> jsou navíc prominuty přijímací zkoušky na MFF UK.</p>\r\n\r\n<h3 id=\"mm-jsou-soustředění\">M&M jsou soustředění</h3>\r\n\r\n<p style=\"text-align: justify;\">Aktivní řešitelé mají možnost s námi za odměnu jet dvakrát do roka na soustředění. Pojeď taky! Budeš mít možnost strávit týden v přírodě plný odborného programu a nejrůznější zábavy s partou kamarádů. Čekají tě malé vědecké projekty, přednášky, workshopy, šifrovačka, výlet a mnoho dalšího. Chceš-li se dozvědět víc, přečti si stránku <a href=\"/soustredeni/\">Soustředění</a> nebo se podívej na <a href=\"/soustredeni/probehlo/\">fotky</a>.</p>\r\n\r\n<h3 id=\"mm-jsme-my\">M&M jsme my</h3>\r\n\r\n<p style=\"text-align: justify;\">Spolu s řešiteli jsme tu i my, organizátoři. Většina z nás jsou studenti Matfyzu, tedy Matematicko-fyzikální fakulty Univerzity Karlovy. Společně se snažíme předávat dál radost z poznávání zajímavých zákoutí matematiky, fyziky a informatiky a budovat komunitu aktivních lidí, kteří se budou rádi scházet, ať už na soustředěních, víkendovkách či jiných akcích. Chceš nás poznat blíž? Podívej se na stránku <a href=\"/o-nas/organizatori/\">Organizátoři</a> nebo rovnou něco vyřeš a pojeď s námi na soustředění!</p>\r\n\r\n<h3 id=\"zaujali-jsme-tě-zapoj-se-přečti-si-jak-řešit-a-podívej-se-na-aktuální-zadání.-už-se-těšíme-na-tvé-příspěvky\" style=\"text-align: center;\">Zaujali jsme tě? Zapoj se! Přečti si <a href=\"/jak-resit/podrobneji/\">jak řešit</a> a podívej se na <a href=\"/aktualni/zadani/\">aktuální zadání</a>. Už se těšíme na tvé příspěvky!</h3>", | ||||||
| 			"enable_comments": false, | 			"enable_comments": false, | ||||||
| 			"registration_required": false, | 			"registration_required": false, | ||||||
| 			"sites": [ | 			"sites": [ | ||||||
|  |  | ||||||
							
								
								
									
										173
									
								
								docs/zapisy/2021-12-06-testovani_dokumentace_codereview.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								docs/zapisy/2021-12-06-testovani_dokumentace_codereview.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,173 @@ | ||||||
|  | # Postup zkrášlení kódu M&Mího webu | ||||||
|  | 
 | ||||||
|  | ## Obecně o webu | ||||||
|  | 
 | ||||||
|  | - Python, Django, spousta nějakých rozšíření, frontend HTML + CSS + trocha JS | ||||||
|  | - Velké břímě historie, kterou nejspíš nechceme zahodit | ||||||
|  |     - Změny v M&M někdy dost zamotají potřebný kód (tituly) | ||||||
|  | - Občas je potřeba dělat opravy rychle | ||||||
|  | 
 | ||||||
|  | ## Aktuální stav | ||||||
|  | 
 | ||||||
|  | - Zběsile zbastlený kód | ||||||
|  |     - „Co je to ‚single responsibility principle‘?“ ☺ | ||||||
|  | - Dost netriviální množství objektů a jejich vazeb | ||||||
|  |     - Dost možná do velké míry inherentní složitost | ||||||
|  | - Webaři aktuálně relativně zběhlí v programování (ale je potřeba myslet na to, že to tak být nemusí) | ||||||
|  | - Webaři stárnou (Jethro, Kristý, Anet) a mizí (Pavel, Káťa), je potřeba web připravit na předání | ||||||
|  | - Kód je rozdělený mezi orgy a jeden „nerozumí“ tomu, co druhý napsal (musí to vyčíst z kódu, nezná souvislosti, …) | ||||||
|  |     - Noví orgové se aktuálně musí ptát, což je jim nepříjemné a nutí je umět formulovat dotazy | ||||||
|  | 
 | ||||||
|  | ### Invarianty | ||||||
|  | 
 | ||||||
|  | - Není to práce, ale zábava-ish → libovolný proces nesmí být (moc) na obtíž. | ||||||
|  |     - I malé nepohodlí je potřeba vyvážit relativně velkým přínosem | ||||||
|  |         - nebo dostatečně zřejmou vidinou budoucího pohodlí / minimalizace nepohodlí | ||||||
|  | - Nejsme programátoři, spíš jsme bastlíři kódu (kteří znají rozumnou podmnožinu syntaxe Pythonu) | ||||||
|  |     - Zvlášť noví orgové | ||||||
|  |     - Nechceme cílit na mega-profi kód, je to nedosažitelný cíl | ||||||
|  |         - Nejspíš to do nějaké míry ubastlené bude pořád, ta míra závisí na zkušenosti aktuálních webařů | ||||||
|  |     - Nástroje nás nesmí moc mást. | ||||||
|  | - Děláme to zadarmo jeden večer v týdnu | ||||||
|  |     - Vývoj jde pomalu, často pomaleji než vývoj knihoven | ||||||
|  |         - → kód se rozbíjí i sám | ||||||
|  | - Běží to na Gimlim | ||||||
|  |     - Debian (old)stable → nemůžeme používat moc nové featury Pythonu | ||||||
|  |         - Aktuálně Python 3.7.3 | ||||||
|  | - Webaři jsou náhodně vzniklá skupina lidí. | ||||||
|  |     - Různé nástroje, různé operační systémy | ||||||
|  |     - Nechceme vynucovat konkrétní metody, multiplatformní nástroje asi požadovat můžeme | ||||||
|  |     - Na serveru může běžet cokoliv, co tam jde rozběhnout | ||||||
|  |     - Kód by neměl být moc složitý / matoucí / kompaktní (?) | ||||||
|  |         - případně fakt hodně okomentovaný | ||||||
|  |      | ||||||
|  | ## O co se snažíme | ||||||
|  | 
 | ||||||
|  | - Zpřístupnit vývoj novým webařům | ||||||
|  | - Umožnit chápání i cizího kódu co nejjednodušeji | ||||||
|  | - Nevzít si s sebou implementační tajemství ~~do hrobu~~ pryč z M&Mka | ||||||
|  | 
 | ||||||
|  | ```graphviz | ||||||
|  | digraph "Závislosti věcí" { | ||||||
|  |     ss -> sdil -> doku -> cs; | ||||||
|  |     ss -> cit ->ref -> cs; | ||||||
|  |     ref -> nrt -> tst -> cs; | ||||||
|  |     sdil -> cr -> cs | ||||||
|  |     ss -> nrt; | ||||||
|  |     ss[label="Současný stav",shape=box]; | ||||||
|  |     cit[label="čitelný kód"]; | ||||||
|  |     cs[label="Cílový stav",shape=box]; | ||||||
|  |     ref[label="refactoring"]; | ||||||
|  |     nrt[label="nerozbít to"]; | ||||||
|  |     tst[label="testy"]; | ||||||
|  |     doku[label="dokumentace (vývojářská)"]; | ||||||
|  |     sdil[label="chápání kódu ostatních / stávajícího"]; | ||||||
|  |     cr[label="code review"]; | ||||||
|  |     nrt,sdil,cit[shape=hexagon]; | ||||||
|  |     tst,doku,cr[color=blue]; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Code review | ||||||
|  | 
 | ||||||
|  | Aktuálně: Pavel občas z rozmaru čte diffy; párkrát jsme zkoušeli [programovat v páru](https://mam.mff.cuni.cz/wiki/Web/Tipy/PairProgramming), je to relativně časově náročné. | ||||||
|  | 
 | ||||||
|  | - Nevynucovat | ||||||
|  | - Primární motivace je umožnit nějak vidět změny a případně k nim dávat komentáře, jak stylu „tohle mi není jasné“, tak i „tohle by chtělo přepsat“. | ||||||
|  | - Chceme hlavně vytvořit příležitost ke čtení cizího kódu a seznamování se s ním (i v zájmu zaučování nových webařů) | ||||||
|  | 
 | ||||||
|  | ### Názory | ||||||
|  | 
 | ||||||
|  | - spíš post-hoc | ||||||
|  | - Možná code-review toho, co jde na produkci | ||||||
|  | - Chceme umět komentovat konkrétní řádky kódu | ||||||
|  | 
 | ||||||
|  | - Gitea/gitlab? | ||||||
|  |     - Klikátko a barevný řádky a vyhledávání jsou fajn (gitlab, gitea) | ||||||
|  |         - Jethro: je fajn umět skočit na definici | ||||||
|  |     - Kombinace s CI | ||||||
|  |     - Pokud bude gitea v něčem nedostatečná, tak hrozí, že bude potřeba migrovat znovu, což je nepraktické | ||||||
|  |     - Gitlab je asi častější než gitea → je lepší názor si na to zvyknout | ||||||
|  |      | ||||||
|  | __Závěr:__ Zkusíme to hodit do GitLabu (nejspíš veřejného\*), zavedeme pull-requesty do `master` větve, náhodně se budeme přiřazovat a používat ho nějak intuitivně. | ||||||
|  | 
 | ||||||
|  | \*: Ve fakultním neumíme přidávat další uživatele, v KAMím zas možná není CI. | ||||||
|  | 
 | ||||||
|  | ## Testy | ||||||
|  | 
 | ||||||
|  | Aktuálně: pár testů na dohromady řádově 4 funkce, drobný pokus o TDD, jenž narazil na úskalí reálného světa. Lokální spuštění testů trvá relativně dlouho, nejspíš kvůli spoustě migrací. | ||||||
|  | 
 | ||||||
|  | - Potřebujeme ověřit, že to funguje a že to _pořád_ funguje | ||||||
|  | 
 | ||||||
|  | - CI? Coverage? | ||||||
|  | 
 | ||||||
|  | ### Názory | ||||||
|  | 
 | ||||||
|  | - PyTest je fajn | ||||||
|  | - Testovat frontend? | ||||||
|  |     - Jethro: při nasazení by se mohly dělat screenshoty celých vybraných stránek přes Selenium (nebo obdobné) a hlásit rozdíly | ||||||
|  | 
 | ||||||
|  | __Závěr:__ Backend testujeme PyTestem (`./manage.py test`), u frontendu výhledově zkusíme ty vizuální diffy a pak se uvidí, CI podle webového klikátka na code review. Bylo by dobré mít rozumná testdata, ať se nemusí mockovat moc věcí.  | ||||||
|  | 
 | ||||||
|  | ## Formát kódu | ||||||
|  | 
 | ||||||
|  | Aktuálně: Jakýsi coding style zhruba existuje, není popsaný, šíří se lidovou slovesností. | ||||||
|  | 
 | ||||||
|  | - 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`) | ||||||
|  |     - 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? | ||||||
|  | 
 | ||||||
|  | ### Názory | ||||||
|  | 
 | ||||||
|  | - P: nemyslím si, že zvládneme mít „průhledný kód“ (dostatečně konzistentní kód, aby ho člověk přestal vnímat a spíš viděl myšlenky). | ||||||
|  | 
 | ||||||
|  | - P: Kecadla do kódu trochu zavání větším peklem než užitkem (takže black a flake8 jsou ze hry); isort možná dává smysl; je otázka, jestli použít mypy, ale typové značky v kódu spíš chceme (zvlášť u věcí, které nejsou prostě django view – typicky utils.) | ||||||
|  |     - J: Divné (=Pavlovo) groupování importů je spíš matoucí, spíš moc nepomáhalo | ||||||
|  | 
 | ||||||
|  | - P (doplněno zpětně): pydocstyle vynucuje PEP-257, který se možná tluče se sphinxem… | ||||||
|  | - P (též zpětně): Možná by se mohl dát použít pylint, tomu jde aspoň vysvětlit coding style a nerazí tupě PEP-8, ale nastavovat ho je asi větší porod, než jak moc pomůže… | ||||||
|  | 
 | ||||||
|  | __Závěr:__ Kecadla na formát spíš nechceme; isort by mohl být fajn, ale bylo by dobré mít rozdělené bloky „náš kód“, „standardní knihovna“ a „Django a další balíčky z PyPA“; u našeho kódu (utils, obecně ne-Django věci) chceme držet záměr (na úrovni dohody) psát signatury funkcí a v případě jejich přítomnosti se nechat varovat při porušení signatury. | ||||||
|  | 
 | ||||||
|  | - P (večerní prokrastinace): Bandit vypadá, že hlásí jen strašně obvious věci by default, nepřijde mi jako moc úžasné vylepšení. Do CI možná dobrý | ||||||
|  | 
 | ||||||
|  | ## Dokumentace | ||||||
|  | 
 | ||||||
|  | Aktuálně: něco málo je na wiki (`/Web/`), občas má nějaká funkce docstring, obecně je toho málo | ||||||
|  | 
 | ||||||
|  | ### Požadavky | ||||||
|  | 
 | ||||||
|  | - Jedno autoritativní místo a dá se najít | ||||||
|  | - Dostatečně „blízko“ kódu | ||||||
|  |     - nastavit mindset na psaní dokumentace „rovnou“? | ||||||
|  | - Umožnit i obecný text, ne jen komentáře kódu (modulů, funkcí) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ### Bonusy | ||||||
|  | 
 | ||||||
|  | - Zajišťování konzistence s uživatelskou dokumentací | ||||||
|  |     - aktuálně wiki | ||||||
|  | - Podpora i dalších jazyků (Vue, Javascript, CSS, možná django-templates) | ||||||
|  | 
 | ||||||
|  | ### Názory | ||||||
|  | 
 | ||||||
|  | - Jde to dělat sphinxem | ||||||
|  |     - Stínovlas by mohl vědět v CZ.NICu se sphinx jede. Případně zkusit zjistit, co umí jejich Akademie | ||||||
|  | - Free-textová dokumentace (architektura ap.) má být nezávislá na dokumentaci konkrétního kódu, ale je fajn, když se to pak spojí dohromady, jde-li to. | ||||||
|  |     - Lepší, když se obojí dá dělat stejným nástrojem | ||||||
|  | - Káťa má někdy pocit, že tráví spoustu času tím, že hledá který soubor vůbec upravit; to má v naší dokumentaci být. | ||||||
|  | 
 | ||||||
|  | __Závěr:__ Zkusíme použít sphinx (z nedostatku vlastních zkušeností a kvůli jeho popularitě), když se nám to nebude líbit, tak budeme řešit dál. Bylo by fajn najít nějaký workshop, bude to rychlejší nalejvárna než číst dokumentaci. V krátkodobém výhledu stáhneme vývojovou dokumentaci z webu do repozitáře a zprovozníme někde automatické buildy (aby se dala číst jako člověk a ne jako stroj). | ||||||
|  | 
 | ||||||
|  | ## Uživatelská dokumentace | ||||||
|  | 
 | ||||||
|  | - K: Dělat ji ve spolupráci s těma uživatelema | ||||||
|  | - P: Dávný Hedgedoc může případně sloužit jako základ osnovy | ||||||
|  | - K: Dost možná nevíme, co bolí víc a co míň | ||||||
|  | - Jethro: Musí být na wiki, jinak tím zmateme oržstvo | ||||||
|  | 
 | ||||||
|  | __Závěr:__ Dokumentace bude na wiki (<https://mam.mff.cuni.cz/wiki/Web_user/Dokumentace>, výhledově možná ve stejné složce v dalších souborech), bude vznikat podle našich pocitů a dotazů od ostatních; výhledově bude schůzka na ukázání featur nového webu a tam se dosbírají náměty na to, co sepsat. | ||||||
|  | @ -62,11 +62,12 @@ | ||||||
|         </div> |         </div> | ||||||
|       {% endwith %} |       {% endwith %} | ||||||
|     {% endif%} |     {% endif%} | ||||||
|  |     <span id="nahoru" class="kotva_obrazku"></span> | ||||||
|     <img src="{{obrazek.obrazek_stredni.url}}" |     <img src="{{obrazek.obrazek_stredni.url}}" | ||||||
|          height="{{vyska}}" |          height="{{vyska}}" | ||||||
|          width="{{sirka}}" |          width="{{sirka}}" | ||||||
|          alt="{{obrazek.popis}}" |          alt="{{obrazek.popis}}" | ||||||
|          class="obrazek" id="nahoru"> |          class="obrazek"> | ||||||
|           |           | ||||||
|     {% if obrazky_dalsi %} |     {% if obrazky_dalsi %} | ||||||
|       {% with obrazky_dalsi|first as dalsi_obrazek %} |       {% with obrazky_dalsi|first as dalsi_obrazek %} | ||||||
|  |  | ||||||
|  | @ -2,6 +2,8 @@ from django.contrib import admin | ||||||
| from reversion.admin import VersionAdmin | from reversion.admin import VersionAdmin | ||||||
| from korektury.models import KorekturovanePDF | from korektury.models import KorekturovanePDF | ||||||
| 
 | 
 | ||||||
|  | from django.core.mail import send_mail | ||||||
|  | from django.urls import reverse | ||||||
| 
 | 
 | ||||||
| # Register your models here. | # Register your models here. | ||||||
| class KorekturovanePDFAdmin(VersionAdmin): | class KorekturovanePDFAdmin(VersionAdmin): | ||||||
|  | @ -16,11 +18,31 @@ class KorekturovanePDFAdmin(VersionAdmin): | ||||||
| 	fieldsets = [ | 	fieldsets = [ | ||||||
| 			(None, | 			(None, | ||||||
| 				{'fields': | 				{'fields': | ||||||
| 					['pdf', 'cas', 'org', 'stran', 'nazev', 'komentar']}), | 					['pdf', 'cas', 'org', 'stran', 'nazev', 'komentar', 'poslat_mail']}), | ||||||
| 			# (u'PDF',       {'fields': ['pdf']}), | 			# (u'PDF',       {'fields': ['pdf']}), | ||||||
| 				] | 				] | ||||||
| 	list_display = ['nazev', 'cas', 'stran', 'org'] | 	list_display = ['nazev', 'cas', 'stran', 'org'] | ||||||
| 	list_filter = [] | 	list_filter = [] | ||||||
| 	search_fields = [] | 	search_fields = [] | ||||||
| 
 | 
 | ||||||
|  | 	def save_model(self, request, obj, form, change): | ||||||
|  | 		super().save_model(request, obj, form, change) | ||||||
|  | 		if not change and obj.poslat_mail: # Je nový a má se poslat mail | ||||||
|  | 			odkaz = request.build_absolute_uri(reverse('korektury', kwargs={'pdf': obj.id})) | ||||||
|  | 			odesilatel = 'korekturovatko-nove-pdf@mam.mff.cuni.cz' | ||||||
|  | 			prijemce = 'org@mam.mff.cuni.cz' | ||||||
|  | 			predmet = f'Nové korektury: {obj.nazev}' | ||||||
|  | 			text = f'''\ | ||||||
|  | V korekturovátku se objevil nový soubor: {obj.nazev} | ||||||
|  | {odkaz} | ||||||
|  | 
 | ||||||
|  | Popis souboru: | ||||||
|  | {obj.komentar} | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | S pozdravem a korekturám zdar! | ||||||
|  | Korekturovátko | ||||||
|  | ''' | ||||||
|  | 			send_mail(predmet,text,odesilatel,[prijemce]) | ||||||
|  | 
 | ||||||
| admin.site.register(KorekturovanePDF, KorekturovanePDFAdmin) | admin.site.register(KorekturovanePDF, KorekturovanePDFAdmin) | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								korektury/migrations/0018_korekturovanepdf_poslat_mail.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								korektury/migrations/0018_korekturovanepdf_poslat_mail.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | # Generated by Django 2.2.24 on 2021-12-05 23:09 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('korektury', '0017_auto_20190610_2358'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='korekturovanepdf', | ||||||
|  |             name='poslat_mail', | ||||||
|  |             field=models.BooleanField(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.', verbose_name='Poslat mail o novém PDF'), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -63,6 +63,10 @@ class KorekturovanePDF(models.Model): | ||||||
| 	status = models.CharField(u'stav PDF',max_length=16, choices=STATUS_CHOICES, blank=False, | 	status = models.CharField(u'stav PDF',max_length=16, choices=STATUS_CHOICES, blank=False, | ||||||
| 			default = STATUS_PRIDAVANI) | 			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.', | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	#TODO Nepovinný foreign key k číslu | 	#TODO Nepovinný foreign key k číslu | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ | ||||||
| 	<i>{{pdf.komentar}}</i> | 	<i>{{pdf.komentar}}</i> | ||||||
| 	<br> | 	<br> | ||||||
| 	<i>Klikni na chybu, napiš komentář</i>  | | 	<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="../">seznam souborů</a> | | ||||||
| 	<a href="/admin/korektury/korekturovanepdf/">Spravovat PDF</a> | | 	<a href="/admin/korektury/korekturovanepdf/">Spravovat PDF</a> | | ||||||
| 	<a href="../help">nápověda</a> | | 	<a href="../help">nápověda</a> | | ||||||
|  |  | ||||||
|  | @ -22,9 +22,8 @@ | ||||||
| <ul> | <ul> | ||||||
|   {% for pdf in skupina.list %} |   {% for pdf in skupina.list %} | ||||||
| 	  <li><span {% if pdf.status == 'zanaseni'%} class="comitting-text" {% elif pdf.status == 'zastarale' %} class="deprecated-text" {% endif %}> | 	  <li><span {% if pdf.status == 'zanaseni'%} class="comitting-text" {% elif pdf.status == 'zastarale' %} class="deprecated-text" {% endif %}> | ||||||
| 	  	<b>{{ pdf.nazev }}</b> |         <b><a href="/korektury/{{pdf.id}}">{{ pdf.nazev }}</a></b> | ||||||
| 		<i>{{pdf.komentar}}</i> | 		<i>{{pdf.komentar}}</i> | ||||||
| 		<a href="/korektury/{{pdf.id}}">{{pdf.pdf.name}}</a> |  | ||||||
| 		(k opravě: {{pdf.k_oprave_cnt}},  | 		(k opravě: {{pdf.k_oprave_cnt}},  | ||||||
| 		opraveno: {{pdf.opraveno_cnt}}, | 		opraveno: {{pdf.opraveno_cnt}}, | ||||||
| 		není chyba: {{pdf.neni_chyba_cnt}}, | 		není chyba: {{pdf.neni_chyba_cnt}}, | ||||||
|  |  | ||||||
|  | @ -166,7 +166,7 @@ class KorekturyView(generic.TemplateView): | ||||||
| 		texty = [(oprava.autor.osoba.plne_jmeno(),oprava.text)] | 		texty = [(oprava.autor.osoba.plne_jmeno(),oprava.text)] | ||||||
| 		for kom in Komentar.objects.filter(oprava=oprava): | 		for kom in Komentar.objects.filter(oprava=oprava): | ||||||
| 			texty.append((kom.autor.osoba.plne_jmeno(),kom.text)) | 			texty.append((kom.autor.osoba.plne_jmeno(),kom.text)) | ||||||
| 		optext = "\n".join([": ".join(t) for t in texty]) | 		optext = "\n\n\n".join([": ".join(t) for t in texty]) | ||||||
| 		text = u"Text komentáře:\n\n{}\n\n=== Konec textu komentáře ===\n\ | 		text = u"Text komentáře:\n\n{}\n\n=== Konec textu komentáře ===\n\ | ||||||
| 				\nodkaz do korekturovátka: {}\n\ | 				\nodkaz do korekturovátka: {}\n\ | ||||||
| 				\nVaše korekturovátko\n".format(optext, odkaz) | 				\nVaše korekturovátko\n".format(optext, odkaz) | ||||||
|  |  | ||||||
|  | @ -336,3 +336,16 @@ CISLO_IMG_DIR = os.path.join('cislo', 'img') | ||||||
| 
 | 
 | ||||||
| # E-MAIL NOTIFICATIONS | # E-MAIL NOTIFICATIONS | ||||||
| POSLI_MAILOVOU_NOTIFIKACI = False | POSLI_MAILOVOU_NOTIFIKACI = False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Logování chyb | ||||||
|  | class InvalidTemplateVariable(str): | ||||||
|  |     def __mod__(self, variable): | ||||||
|  |         import logging | ||||||
|  |         logger = logging.getLogger(__name__) | ||||||
|  |         logger.warning("Proměnná '%s' neexistuje" % variable) | ||||||
|  |         return '' | ||||||
|  | TEMPLATES[0]['OPTIONS']['string_if_invalid'] = InvalidTemplateVariable('%s') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -6,6 +6,10 @@ src: url("../fonts/OpenSans/OpenSans-Regular.ttf"); | ||||||
| font-weight: normal; | font-weight: normal; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | p { | ||||||
|  | 	text-align: justify; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| body { | body { | ||||||
| 	font-family: 'OpenSans'; | 	font-family: 'OpenSans'; | ||||||
| 	background-color: #fffbf6; | 	background-color: #fffbf6; | ||||||
|  | @ -1113,6 +1117,21 @@ div.zadani_termin .datum { | ||||||
|     float: right; |     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 { | ||||||
|  | 	display: block; | ||||||
|  | 	position: relative; | ||||||
|  | 	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 */ | ||||||
|  | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /**/ | /**/ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,19 +1,16 @@ | ||||||
| {% extends "base.html" %} | {% extends "error_base.html" %} | ||||||
| 
 | 
 | ||||||
| {% load staticfiles %} | {% load staticfiles %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block errorheading %} | ||||||
|   <h2> |  | ||||||
|     {% block nadpis1a %}{% block nadpis1b %} |  | ||||||
|       O-jo-jo-jo-joj |       O-jo-jo-jo-joj | ||||||
|     {% endblock %}{% endblock %} | {% endblock %} | ||||||
|   </h2> |  | ||||||
| 
 | 
 | ||||||
|   <p> | {% block errortext %} | ||||||
|     Chybička se vloudila. |     Chybička se vloudila. | ||||||
|     Zkuste přejít na <a href="/">titulní stránku</a> | {% endblock %} | ||||||
|     nebo se podívat na <a href="{% url 'seminar_aktualni_zadani' %}">aktuální zadání</a>. | 
 | ||||||
|   </p> | {% block errorimage %} | ||||||
|   <img src="{% static '500.png' %}"> |   <img src="{% static '500.png' %}"> | ||||||
| {% endblock %} | {% endblock %} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,19 +1,16 @@ | ||||||
| {% extends "base.html" %} | {% extends "error_base.html" %} | ||||||
| 
 | 
 | ||||||
| {% load staticfiles %} | {% load staticfiles %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block errorheading %} | ||||||
|   <h2> |  | ||||||
|     {% block nadpis1a %}{% block nadpis1b %} |  | ||||||
|       Vrrrrrrrrr |       Vrrrrrrrrr | ||||||
|     {% endblock %}{% endblock %} | {% endblock %} | ||||||
|   </h2> |  | ||||||
| 
 | 
 | ||||||
|   <p> | {% block errortext %} | ||||||
|     Tady pravděpodobně nemáte co dělat. |     Tady pravděpodobně nemáte co dělat. | ||||||
|     Zkuste přejít na <a href="/">titulní stránku</a> | {% endblock %} | ||||||
|     nebo se podívat na <a href="{% url 'seminar_aktualni_zadani' %}">aktuální zadání</a>. | 
 | ||||||
|   </p> | {% block errorimage %} | ||||||
|   <img src="{% static '500.png' %}"> |   <img src="{% static '500.png' %}"> | ||||||
| {% endblock %} | {% endblock %} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,19 +1,16 @@ | ||||||
| {% extends "base.html" %} | {% extends "error_base.html" %} | ||||||
| 
 | 
 | ||||||
| {% load staticfiles %} | {% load staticfiles %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block errorheading %} | ||||||
|   <h2> | Požadovaná stránka nenalezena | ||||||
|     {% block nadpis1a %}{% block nadpis1b %} | {% endblock %} | ||||||
|       Požadovaná stránka nenalezena | 
 | ||||||
|     {% endblock %}{% endblock%} | {% block errortext %} | ||||||
|   </h2> | Tuto stránku jsme na našem serveru nenalezli. | ||||||
| 
 | {% endblock %} | ||||||
|   <p> | 
 | ||||||
|     Tuto stránku jsme na našem serveru nenalezli. | {% block errorimage %} | ||||||
|     Zkuste přejít na <a href="/">titulní stránku</a> | <img src="{% static '404.png' %}"> | ||||||
|     nebo se podívat na <a href="{% url 'seminar_aktualni_zadani' %}">aktuální zadání</a>. |  | ||||||
|   </p> |  | ||||||
|   <img src="{% static '404.png' %}"> |  | ||||||
| {% endblock %} | {% endblock %} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,20 +1,16 @@ | ||||||
| {% extends "base.html" %} | {% extends "error_base.html" %} | ||||||
| 
 | 
 | ||||||
| {% load staticfiles %} | {% load staticfiles %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block errorheading %} | ||||||
|   <h2> |  | ||||||
|     {% block nadpis1a %}{% block nadpis1b %} |  | ||||||
|       O-jo-jo-jo-joj |       O-jo-jo-jo-joj | ||||||
|     {% endblock %}{% endblock %} | {% endblock %} | ||||||
|   </h2> |  | ||||||
| 
 | 
 | ||||||
|   <p> | {% block errortext %} | ||||||
|     Chybička se vloudila. |     Chybička se vloudila. | ||||||
|     Zkuste přejít na <a href="/">titulní stránku</a> | {% endblock %} | ||||||
|     {# Při pádu webu nechceme, aby se rozbily odkazy, nevěříme URLconfu. #} | 
 | ||||||
|     nebo se podívat na <a href="/aktualni/zadani/">aktuální zadání</a>. | {% block errorimage %} | ||||||
|   </p> |  | ||||||
|   <img src="{% static '500.png' %}"> |   <img src="{% static '500.png' %}"> | ||||||
| {% endblock %} | {% endblock %} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
|     <title>{% block title %}{% block nadpis1a %}{% endblock %} – Korespondenční seminář M&M{% endblock title %}</title> |     <title>{% block title %}{% block nadpis1a %}{% endblock %} – Korespondenční seminář M&M{% endblock title %}</title> | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|     <link rel="shortcut icon" href="{% static 'images/MATFYZ_MM_barevne.svg' %}" type="image/x-icon"> |     <link rel="shortcut icon" href="{% static 'images/MATFYZ_MM_barevne.svg' %}" type="image/x-icon"> | ||||||
|     {% render_block css %} | {#    {% render_block css %}#} | ||||||
|     {% block custom_css %}{% endblock %} |     {% block custom_css %}{% endblock %} | ||||||
|     <link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet"> |     <link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet"> | ||||||
|     <link href="{% static 'css/bootstrap.css' %}" rel="stylesheet"> |     <link href="{% static 'css/bootstrap.css' %}" rel="stylesheet"> | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								mamweb/templates/error_base.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								mamweb/templates/error_base.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |   <h2> | ||||||
|  |     {% block nadpis1a %}{% block nadpis1b %} | ||||||
|  |     {% block errorheading %} | ||||||
|  |     {% endblock %} | ||||||
|  |     {% endblock %}{% endblock%} | ||||||
|  |   </h2> | ||||||
|  | 
 | ||||||
|  |   <p> | ||||||
|  |     {% block errortext %} | ||||||
|  |     {% endblock %} | ||||||
|  |     Zkuste přejít na <a href="/">titulní stránku</a>. | ||||||
|  |   </p> | ||||||
|  |   {% block errorimage %} | ||||||
|  |   {% endblock %} | ||||||
|  | {% endblock %} | ||||||
|  | 
 | ||||||
|  | @ -59,6 +59,10 @@ if settings.DEBUG: | ||||||
| 	urlpatterns += [ | 	urlpatterns += [ | ||||||
| 		path('media/<path:path>', views.static.serve,  # NOQA | 		path('media/<path:path>', views.static.serve,  # NOQA | ||||||
| 			{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}), | 			{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}), | ||||||
| 	path('__debug__/', include(debug_toolbar.urls)), | 		path('__debug__/', include(debug_toolbar.urls)), | ||||||
|  | 		path('400.html', TemplateView.as_view(template_name="400.html")), | ||||||
|  | 		path('403.html', TemplateView.as_view(template_name="403.html")), | ||||||
|  | 		path('404.html', TemplateView.as_view(template_name="404.html")), | ||||||
|  | 		path('500.html', TemplateView.as_view(template_name="500.html")), | ||||||
| 		] | 		] | ||||||
| 	urlpatterns += staticfiles_urlpatterns() | 	urlpatterns += staticfiles_urlpatterns() | ||||||
|  |  | ||||||
|  | @ -119,7 +119,7 @@ $(document).ready(function(){ | ||||||
| 		<td>{{ form.empty_form.problem }}</td> | 		<td>{{ form.empty_form.problem }}</td> | ||||||
| 		<td>{{ form.empty_form.body }}</td> | 		<td>{{ form.empty_form.body }}</td> | ||||||
| 		<td>{{ form.empty_form.cislo_body }}</td> | 		<td>{{ form.empty_form.cislo_body }}</td> | ||||||
| 		<td><a href="#" class="smazat_hodnoceni" id="id_{{subform.prefix}}-jsremove"><img src="{% static "odevzdavatko/cross.png" %}" alt="Smazat"></a></td> | 		<td><a href="#" class="smazat_hodnoceni" id="id_{{form.empty_form.prefix}}-jsremove"><img src="{% static "odevzdavatko/cross.png" %}" alt="Smazat"></a></td> | ||||||
| 	</tr> | 	</tr> | ||||||
| </table> | </table> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ import seminar.models as m | ||||||
| @admin.register(m.Osoba) | @admin.register(m.Osoba) | ||||||
| class OsobaAdmin(admin.ModelAdmin): | class OsobaAdmin(admin.ModelAdmin): | ||||||
| 	actions = ['synchronizuj_maily', 'udelej_orgem'] | 	actions = ['synchronizuj_maily', 'udelej_orgem'] | ||||||
|  | 	search_fields = ['jmeno', 'prijmeni', 'prezdivka'] | ||||||
| 
 | 
 | ||||||
| 	def synchronizuj_maily(self, request, queryset): | 	def synchronizuj_maily(self, request, queryset): | ||||||
| 		for o in queryset: | 		for o in queryset: | ||||||
|  |  | ||||||
|  | @ -1,5 +1,8 @@ | ||||||
| 
 | {% if id %} | ||||||
| <tr id="{{ id }}" > | <tr id="{{ id }}" > | ||||||
|  | {% else %} | ||||||
|  | <tr> | ||||||
|  | {% endif %} | ||||||
|   <td> |   <td> | ||||||
|     <label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}"> |     <label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}"> | ||||||
|       {{ field.label }}: |       {{ field.label }}: | ||||||
|  |  | ||||||
|  | @ -23,7 +23,7 @@ django-solo | ||||||
| django-ckeditor | django-ckeditor | ||||||
| django-flat-theme | django-flat-theme | ||||||
| django-taggit | django-taggit | ||||||
| django-autocomplete-light | django-autocomplete-light>=3.9.0rc1 | ||||||
| django-crispy-forms | django-crispy-forms | ||||||
| django-imagekit | django-imagekit | ||||||
| django-polymorphic | django-polymorphic | ||||||
|  |  | ||||||
							
								
								
									
										24
									
								
								seminar/migrations/0101_auto_20211213_2306.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								seminar/migrations/0101_auto_20211213_2306.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | ||||||
|  | # Generated by Django 2.2.24 on 2021-12-13 22:06 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('seminar', '0100_auto_20211129_2354'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='nastaveni', | ||||||
|  |             name='aktualni_cislo', | ||||||
|  |             field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='seminar.Cislo', verbose_name='Aktuální číslo'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='soustredeni', | ||||||
|  |             name='typ', | ||||||
|  |             field=models.CharField(choices=[('jarni', 'Jarní soustředění'), ('podzimni', 'Podzimní soustředění'), ('vikend', 'Víkendový sraz'), ('vylet', 'Výlet')], default='podzimni', max_length=16, verbose_name='typ akce'), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -55,10 +55,12 @@ class Soustredeni(SeminarModelBase): | ||||||
| 	TYP_JARNI = 'jarni' | 	TYP_JARNI = 'jarni' | ||||||
| 	TYP_PODZIMNI = 'podzimni' | 	TYP_PODZIMNI = 'podzimni' | ||||||
| 	TYP_VIKEND = 'vikend' | 	TYP_VIKEND = 'vikend' | ||||||
|  | 	TYP_VYLET = 'vylet' | ||||||
| 	TYP_CHOICES = [ | 	TYP_CHOICES = [ | ||||||
| 		(TYP_JARNI, 'Jarní soustředění'), | 		(TYP_JARNI, 'Jarní soustředění'), | ||||||
| 		(TYP_PODZIMNI, 'Podzimní soustředění'), | 		(TYP_PODZIMNI, 'Podzimní soustředění'), | ||||||
| 		(TYP_VIKEND, 'Víkendový sraz'), | 		(TYP_VIKEND, 'Víkendový sraz'), | ||||||
|  | 		(TYP_VYLET, 'Výlet'), | ||||||
| 		] | 		] | ||||||
| 	typ = models.CharField('typ akce', max_length=16, choices=TYP_CHOICES, blank=False, default=TYP_PODZIMNI) | 	typ = models.CharField('typ akce', max_length=16, choices=TYP_CHOICES, blank=False, default=TYP_PODZIMNI) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,6 @@ import tempfile | ||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| from django.contrib.sites.shortcuts import get_current_site | from django.contrib.sites.shortcuts import get_current_site | ||||||
| from django.core.files.storage import FileSystemStorage |  | ||||||
| from django.db import models | from django.db import models | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
|  | @ -646,7 +645,7 @@ class Nastaveni(SingletonModel): | ||||||
| #	aktualni_rocnik = models.ForeignKey(Rocnik, verbose_name='aktuální ročník', | #	aktualni_rocnik = models.ForeignKey(Rocnik, verbose_name='aktuální ročník', | ||||||
| #		null=False, on_delete=models.PROTECT) | #		null=False, on_delete=models.PROTECT) | ||||||
| 
 | 
 | ||||||
| 	aktualni_cislo = models.ForeignKey(Cislo, verbose_name='poslední vydané číslo',  | 	aktualni_cislo = models.ForeignKey(Cislo, verbose_name='Aktuální číslo',  | ||||||
| 		null=False, on_delete=models.PROTECT) | 		null=False, on_delete=models.PROTECT) | ||||||
| 
 | 
 | ||||||
| 	@property | 	@property | ||||||
|  |  | ||||||
|  | @ -72,7 +72,7 @@ | ||||||
| \ifx \skola \empty | \ifx \skola \empty | ||||||
| {} | {} | ||||||
| \else | \else | ||||||
| \hbox{\tofont{\skola}} | \predsunout{\hbox{\tofont{\skola}}} %FIXME Vyřešit jinak (škola bývá dlouhá a tak se nevejde do konce řádku, tak jsem ji hodil doleva) | ||||||
| \fi | \fi | ||||||
| \vskip .2 em | \vskip .2 em | ||||||
| \hbox{\tofont{\ulice}} | \hbox{\tofont{\ulice}} | ||||||
|  | @ -98,24 +98,22 @@ | ||||||
| 
 | 
 | ||||||
| {% for r in resitele %} | {% for r in resitele %} | ||||||
| 	{% with o=r.osoba %} | 	{% with o=r.osoba %} | ||||||
| 	{% with s=r.osoba.skola %} | 	{% with s=r.skola %} | ||||||
| 	{% spaceless %} | 	{% spaceless %} | ||||||
| 	{% if r.zasilat == "do_skoly" %}  | 	{% if r.zasilat == "do_skoly" %}  | ||||||
| 		{% if r.stat == "CZ" %} | 		{% if o.stat == "CZ" %} | ||||||
| \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{s.nazev|sloz}}{{s.ulice|sloz}}{{s.psc|sloz}}{{s.mesto|sloz}}{{''|sloz}} | \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{s.nazev|sloz}}{{s.ulice|sloz}}{{s.psc|sloz}}{{s.mesto|sloz}}{{''|sloz}} | ||||||
| 		{% else %} | 		{% else %} | ||||||
| \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{s.nazev|sloz}}{{s.ulice|sloz}}{{s.psc|sloz}}{{s.mesto|sloz}}{{o.stat.name|sloz}} | \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{s.nazev|sloz}}{{s.ulice|sloz}}{{s.psc|sloz}}{{s.mesto|sloz}}{{o.stat.name|sloz}} | ||||||
| 		{% endif %} | 		{% endif %} | ||||||
| 
 | 
 | ||||||
| 	{% elif r.zasilat == "domu" %} | 	{% elif r.zasilat == "domu" %} | ||||||
| 		{% if r.stat == "CZ" %} | 		{% if o.stat == "CZ" %} | ||||||
| \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{''|sloz}}{{o.ulice|sloz}}{{o.psc|sloz}}{{o.mesto|sloz}}{{''|sloz}} | \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{''|sloz}}{{o.ulice|sloz}}{{o.psc|sloz}}{{o.mesto|sloz}}{{''|sloz}} | ||||||
| 		{% else %} | 		{% else %} | ||||||
| \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{''|sloz}}{{o.ulice|sloz}}{{o.psc|sloz}}{{o.mesto|sloz}}{{o.stat.name|sloz}} | \obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{''|sloz}}{{o.ulice|sloz}}{{o.psc|sloz}}{{o.mesto|sloz}}{{o.stat.name|sloz}} | ||||||
| 		{% endif %} | 		{% endif %} | ||||||
| 	{% else %} | 	{% else %} | ||||||
| % zasilat: {{r.zasilat}} |  | ||||||
| %\obalka{{r.jmeno|sloz}}{{r.prijmeni|sloz}}{{''|sloz}}{{r.ulice|sloz}}{{r.psc|sloz}}{{r.mesto|sloz}}{{r.stat.name|sloz}} |  | ||||||
| 	{% endif %} | 	{% endif %} | ||||||
| 	{% endspaceless %} | 	{% endspaceless %} | ||||||
| 	{% endwith %} | 	{% endwith %} | ||||||
|  |  | ||||||
|  | @ -292,8 +292,14 @@ def gen_reseni_ulohy(rnd, cisla, uloha, pocet_resitelu, poradi_cisla, resitele_c | ||||||
| 			res_vyber.remove(resitele[0]) | 			res_vyber.remove(resitele[0]) | ||||||
| 
 | 
 | ||||||
| 		# Vytvoření řešení. | 		# Vytvoření řešení. | ||||||
| 		res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES)[0]) | 		if uloha.cislo_zadani.datum_deadline is not None: | ||||||
| 		# Problím a řešitele přiřadíme později, ManyToManyField | 			# combine, abychom dostali plný čas a ne jen datum | ||||||
|  | 			cas_doruceni = datetime.datetime.combine(uloha.cislo_zadani.datum_deadline, datetime.datetime.min.time()) - datetime.timedelta(days=random.randint(0, 40)) - datetime.timedelta(minutes=random.randint(0, 60*24)) | ||||||
|  | 			# astimezone, protože jinak vyhazuje warning o nenastavené TZ | ||||||
|  | 			res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES)[0], cas_doruceni=cas_doruceni.astimezone(datetime.timezone.utc)) | ||||||
|  | 		else: | ||||||
|  | 			res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES)[0]) | ||||||
|  | 		# Problém a řešitele přiřadíme později, ManyToManyField | ||||||
| 		# se nedá vyplnit v create(). | 		# se nedá vyplnit v create(). | ||||||
| 		res.resitele.set(res_vyber) | 		res.resitele.set(res_vyber) | ||||||
| 		res.save() | 		res.save() | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Pavel "LEdoian" Turinsky
						Pavel "LEdoian" Turinsky