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": {
|
||||
"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,
|
||||
"registration_required": false,
|
||||
"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>
|
||||
{% endwith %}
|
||||
{% endif%}
|
||||
<span id="nahoru" class="kotva_obrazku"></span>
|
||||
<img src="{{obrazek.obrazek_stredni.url}}"
|
||||
height="{{vyska}}"
|
||||
width="{{sirka}}"
|
||||
alt="{{obrazek.popis}}"
|
||||
class="obrazek" id="nahoru">
|
||||
class="obrazek">
|
||||
|
||||
{% if obrazky_dalsi %}
|
||||
{% with obrazky_dalsi|first as dalsi_obrazek %}
|
||||
|
|
|
@ -2,6 +2,8 @@ from django.contrib import admin
|
|||
from reversion.admin import VersionAdmin
|
||||
from korektury.models import KorekturovanePDF
|
||||
|
||||
from django.core.mail import send_mail
|
||||
from django.urls import reverse
|
||||
|
||||
# Register your models here.
|
||||
class KorekturovanePDFAdmin(VersionAdmin):
|
||||
|
@ -16,11 +18,31 @@ class KorekturovanePDFAdmin(VersionAdmin):
|
|||
fieldsets = [
|
||||
(None,
|
||||
{'fields':
|
||||
['pdf', 'cas', 'org', 'stran', 'nazev', 'komentar']}),
|
||||
['pdf', 'cas', 'org', 'stran', 'nazev', 'komentar', 'poslat_mail']}),
|
||||
# (u'PDF', {'fields': ['pdf']}),
|
||||
]
|
||||
list_display = ['nazev', 'cas', 'stran', 'org']
|
||||
list_filter = []
|
||||
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)
|
||||
|
|
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,
|
||||
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
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<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> |
|
||||
|
|
|
@ -22,9 +22,8 @@
|
|||
<ul>
|
||||
{% for pdf in skupina.list %}
|
||||
<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>
|
||||
<a href="/korektury/{{pdf.id}}">{{pdf.pdf.name}}</a>
|
||||
(k opravě: {{pdf.k_oprave_cnt}},
|
||||
opraveno: {{pdf.opraveno_cnt}},
|
||||
není chyba: {{pdf.neni_chyba_cnt}},
|
||||
|
|
|
@ -166,7 +166,7 @@ class KorekturyView(generic.TemplateView):
|
|||
texty = [(oprava.autor.osoba.plne_jmeno(),oprava.text)]
|
||||
for kom in Komentar.objects.filter(oprava=oprava):
|
||||
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\
|
||||
\nodkaz do korekturovátka: {}\n\
|
||||
\nVaše korekturovátko\n".format(optext, odkaz)
|
||||
|
|
|
@ -336,3 +336,16 @@ CISLO_IMG_DIR = os.path.join('cislo', 'img')
|
|||
|
||||
# E-MAIL NOTIFICATIONS
|
||||
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;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'OpenSans';
|
||||
background-color: #fffbf6;
|
||||
|
@ -1113,6 +1117,21 @@ div.zadani_termin .datum {
|
|||
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 %}
|
||||
|
||||
{% block content %}
|
||||
<h2>
|
||||
{% block nadpis1a %}{% block nadpis1b %}
|
||||
{% block errorheading %}
|
||||
O-jo-jo-jo-joj
|
||||
{% endblock %}{% endblock %}
|
||||
</h2>
|
||||
{% endblock %}
|
||||
|
||||
<p>
|
||||
{% block errortext %}
|
||||
Chybička se vloudila.
|
||||
Zkuste přejít na <a href="/">titulní stránku</a>
|
||||
nebo se podívat na <a href="{% url 'seminar_aktualni_zadani' %}">aktuální zadání</a>.
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block errorimage %}
|
||||
<img src="{% static '500.png' %}">
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "error_base.html" %}
|
||||
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block content %}
|
||||
<h2>
|
||||
{% block nadpis1a %}{% block nadpis1b %}
|
||||
{% block errorheading %}
|
||||
Vrrrrrrrrr
|
||||
{% endblock %}{% endblock %}
|
||||
</h2>
|
||||
{% endblock %}
|
||||
|
||||
<p>
|
||||
{% block errortext %}
|
||||
Tady pravděpodobně nemáte co dělat.
|
||||
Zkuste přejít na <a href="/">titulní stránku</a>
|
||||
nebo se podívat na <a href="{% url 'seminar_aktualni_zadani' %}">aktuální zadání</a>.
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block errorimage %}
|
||||
<img src="{% static '500.png' %}">
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "error_base.html" %}
|
||||
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block content %}
|
||||
<h2>
|
||||
{% block nadpis1a %}{% block nadpis1b %}
|
||||
Požadovaná stránka nenalezena
|
||||
{% endblock %}{% endblock%}
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
Tuto stránku jsme na našem serveru nenalezli.
|
||||
Zkuste přejít na <a href="/">titulní stránku</a>
|
||||
nebo se podívat na <a href="{% url 'seminar_aktualni_zadani' %}">aktuální zadání</a>.
|
||||
</p>
|
||||
<img src="{% static '404.png' %}">
|
||||
{% block errorheading %}
|
||||
Požadovaná stránka nenalezena
|
||||
{% endblock %}
|
||||
|
||||
{% block errortext %}
|
||||
Tuto stránku jsme na našem serveru nenalezli.
|
||||
{% endblock %}
|
||||
|
||||
{% block errorimage %}
|
||||
<img src="{% static '404.png' %}">
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "error_base.html" %}
|
||||
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block content %}
|
||||
<h2>
|
||||
{% block nadpis1a %}{% block nadpis1b %}
|
||||
{% block errorheading %}
|
||||
O-jo-jo-jo-joj
|
||||
{% endblock %}{% endblock %}
|
||||
</h2>
|
||||
{% endblock %}
|
||||
|
||||
<p>
|
||||
{% block errortext %}
|
||||
Chybička se vloudila.
|
||||
Zkuste přejít na <a href="/">titulní stránku</a>
|
||||
{# 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>.
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block errorimage %}
|
||||
<img src="{% static '500.png' %}">
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<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">
|
||||
<link rel="shortcut icon" href="{% static 'images/MATFYZ_MM_barevne.svg' %}" type="image/x-icon">
|
||||
{% render_block css %}
|
||||
{# {% render_block css %}#}
|
||||
{% block custom_css %}{% endblock %}
|
||||
<link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/bootstrap.css' %}" rel="stylesheet">
|
||||
|
|
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 += [
|
||||
path('media/<path:path>', views.static.serve, # NOQA
|
||||
{'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()
|
||||
|
|
|
@ -119,7 +119,7 @@ $(document).ready(function(){
|
|||
<td>{{ form.empty_form.problem }}</td>
|
||||
<td>{{ form.empty_form.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>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import seminar.models as m
|
|||
@admin.register(m.Osoba)
|
||||
class OsobaAdmin(admin.ModelAdmin):
|
||||
actions = ['synchronizuj_maily', 'udelej_orgem']
|
||||
search_fields = ['jmeno', 'prijmeni', 'prezdivka']
|
||||
|
||||
def synchronizuj_maily(self, request, queryset):
|
||||
for o in queryset:
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
|
||||
{% if id %}
|
||||
<tr id="{{ id }}" >
|
||||
{% else %}
|
||||
<tr>
|
||||
{% endif %}
|
||||
<td>
|
||||
<label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
|
||||
{{ field.label }}:
|
||||
|
|
|
@ -23,7 +23,7 @@ django-solo
|
|||
django-ckeditor
|
||||
django-flat-theme
|
||||
django-taggit
|
||||
django-autocomplete-light
|
||||
django-autocomplete-light>=3.9.0rc1
|
||||
django-crispy-forms
|
||||
django-imagekit
|
||||
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_PODZIMNI = 'podzimni'
|
||||
TYP_VIKEND = 'vikend'
|
||||
TYP_VYLET = 'vylet'
|
||||
TYP_CHOICES = [
|
||||
(TYP_JARNI, 'Jarní soustředění'),
|
||||
(TYP_PODZIMNI, 'Podzimní soustředění'),
|
||||
(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)
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import tempfile
|
|||
import logging
|
||||
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
|
@ -646,7 +645,7 @@ class Nastaveni(SingletonModel):
|
|||
# aktualni_rocnik = models.ForeignKey(Rocnik, verbose_name='aktuální ročník',
|
||||
# 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)
|
||||
|
||||
@property
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
\ifx \skola \empty
|
||||
{}
|
||||
\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
|
||||
\vskip .2 em
|
||||
\hbox{\tofont{\ulice}}
|
||||
|
@ -98,24 +98,22 @@
|
|||
|
||||
{% for r in resitele %}
|
||||
{% with o=r.osoba %}
|
||||
{% with s=r.osoba.skola %}
|
||||
{% with s=r.skola %}
|
||||
{% spaceless %}
|
||||
{% 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}}
|
||||
{% else %}
|
||||
\obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{s.nazev|sloz}}{{s.ulice|sloz}}{{s.psc|sloz}}{{s.mesto|sloz}}{{o.stat.name|sloz}}
|
||||
{% endif %}
|
||||
|
||||
{% 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}}
|
||||
{% else %}
|
||||
\obalka{{o.jmeno|sloz}}{{o.prijmeni|sloz}}{{''|sloz}}{{o.ulice|sloz}}{{o.psc|sloz}}{{o.mesto|sloz}}{{o.stat.name|sloz}}
|
||||
{% endif %}
|
||||
{% 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 %}
|
||||
{% endspaceless %}
|
||||
{% endwith %}
|
||||
|
|
|
@ -292,8 +292,14 @@ def gen_reseni_ulohy(rnd, cisla, uloha, pocet_resitelu, poradi_cisla, resitele_c
|
|||
res_vyber.remove(resitele[0])
|
||||
|
||||
# Vytvoření řešení.
|
||||
res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES)[0])
|
||||
# Problím a řešitele přiřadíme později, ManyToManyField
|
||||
if uloha.cislo_zadani.datum_deadline is not None:
|
||||
# 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().
|
||||
res.resitele.set(res_vyber)
|
||||
res.save()
|
||||
|
|
Loading…
Reference in a new issue