Browse Source

Merge branch 'develop' into django3.2

export_seznamu_prednasek
Pavel "LEdoian" Turinsky 3 years ago
parent
commit
882f8e2228
  1. 2
      data/flat.json
  2. 173
      docs/zapisy/2021-12-06-testovani_dokumentace_codereview.md
  3. 3
      galerie/templates/galerie/Galerie.html
  4. 24
      korektury/admin.py
  5. 18
      korektury/migrations/0018_korekturovanepdf_poslat_mail.py
  6. 4
      korektury/models.py
  7. 1
      korektury/templates/korektury/opraf.html
  8. 3
      korektury/templates/korektury/seskupeny_seznam.html
  9. 2
      korektury/views.py
  10. 13
      mamweb/settings_common.py
  11. 19
      mamweb/static/css/mamweb.css
  12. 17
      mamweb/templates/400.html
  13. 17
      mamweb/templates/403.html
  14. 23
      mamweb/templates/404.html
  15. 18
      mamweb/templates/500.html
  16. 2
      mamweb/templates/base.html
  17. 19
      mamweb/templates/error_base.html
  18. 6
      mamweb/urls.py
  19. 2
      odevzdavatko/templates/odevzdavatko/detail.html
  20. 1
      personalni/admin.py
  21. 5
      personalni/templates/personalni/udaje/prihlaska_field.html
  22. 2
      requirements.txt
  23. 24
      seminar/migrations/0101_auto_20211213_2306.py
  24. 2
      seminar/models/soustredeni.py
  25. 3
      seminar/models/tvorba.py
  26. 10
      seminar/templates/seminar/archiv/obalky.tex
  27. 10
      seminar/testutils.py

2
data/flat.json

@ -16,7 +16,7 @@
},
{
"fields": {
"content": "<h1 id=\"co-je-mm\">Co je M&amp;M?</h1>\r\n\r\n<h3 id=\"mm-je-mezioborový-korespondenční-seminář-pro-středoškoláky\">M&amp;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&nbsp;pošleme zpět. Nabízíme témata z&nbsp;různých oblastí matematiky, fyziky, informatiky i&nbsp;dalších oborů, takže si u&nbsp;nás určitě najdeš to svoje. Při řešení si můžeš vyzkoušet, jak vypadá vědecká práce, a&nbsp;mnoho zajímavého se naučit. Podívej se na tipy v&nbsp;sekci <a href=\"/jak-resit/\">Jak řešit</a> a&nbsp;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&amp;M jsou témata</h3>\r\n\r\n<p style=\"text-align: justify;\">Jádro M&amp;M tvoří takzvaná témata, tedy texty doplněné o&nbsp;úlohy a&nbsp;náměty vyzývající k&nbsp;přemýšlení a&nbsp;experimentování. Přijímáme i&nbsp;originální přístup k&nbsp;problémům, takže můžeš například vyřešit fyzikální problém naprogramováním simulace. v&nbsp;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&nbsp;tramvaji v&nbsp;průběhu cesty nebo programovali strategie v&nbsp;jednoduché hře a&nbsp;pak je nechávali soupeřit v&nbsp;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&amp;M je časopis</h3>\r\n\r\n<p style=\"text-align: justify;\">Zadání a&nbsp;texty od organizátorů vydáváme formou časopisu. Kromě toho zde rovněž otiskujeme řešení a&nbsp;příspěvky našich řešitelů k&nbsp;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&nbsp;výsledky jejich vlastního výzkumu. Díky tomu jsme si například mohli přečíst o&nbsp;<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&nbsp;placatém světě</a>. Během ročníku obvykle vyjde šest čísel časopisu, prohlédnout si je můžeš v&nbsp;<a href=\"/archiv/rocniky/\">Archivu</a>.</p>\r\n\r\n<h3 id=\"mm-je-soutěž\">M&amp;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&nbsp;udělujeme za ně body. Vítězové semináře se mohou těšit na zajímavé knihy a&nbsp;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&amp;M jsou soustředění</h3>\r\n\r\n<p style=\"text-align: justify;\">Aktivní řešitelé mají možnost s&nbsp;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&nbsp;přírodě plný odborného programu a&nbsp;nejrůznější zábavy s&nbsp;partou kamarádů. Čekají tě malé vědecké projekty, přednášky, workshopy, šifrovačka, výlet a&nbsp;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&amp;M jsme my</h3>\r\n\r\n<p style=\"text-align: justify;\">Spolu s&nbsp;řešiteli jsme tu i&nbsp;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&nbsp;informatiky a&nbsp;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&nbsp;pojeď s&nbsp;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&nbsp;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&amp;M?</h1>\r\n\r\n<h3 id=\"mm-je-mezioborový-korespondenční-seminář-pro-středoškoláky\">M&amp;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&nbsp;pošleme zpět. Nabízíme témata z&nbsp;různých oblastí matematiky, fyziky, informatiky i&nbsp;dalších oborů, takže si u&nbsp;nás určitě najdeš to svoje. Při řešení si můžeš vyzkoušet, jak vypadá vědecká práce, a&nbsp;mnoho zajímavého se naučit. Podívej se na tipy v&nbsp;sekci <a href=\"/jak-resit/\">Jak řešit</a> a&nbsp;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&amp;M jsou témata</h3>\r\n\r\n<p style=\"text-align: justify;\">Jádro M&amp;M tvoří takzvaná témata, tedy texty doplněné o&nbsp;úlohy a&nbsp;náměty vyzývající k&nbsp;přemýšlení a&nbsp;experimentování. Přijímáme i&nbsp;originální přístup k&nbsp;problémům, takže můžeš například vyřešit fyzikální problém naprogramováním simulace. V&nbsp;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&nbsp;tramvaji v&nbsp;průběhu cesty nebo programovali strategie v&nbsp;jednoduché hře a&nbsp;pak je nechávali soupeřit v&nbsp;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&amp;M je časopis</h3>\r\n\r\n<p style=\"text-align: justify;\">Zadání a&nbsp;texty od organizátorů vydáváme formou časopisu. Kromě toho zde rovněž otiskujeme řešení a&nbsp;příspěvky našich řešitelů k&nbsp;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&nbsp;výsledky jejich vlastního výzkumu. Díky tomu jsme si například mohli přečíst o&nbsp;<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&nbsp;placatém světě</a>. Během ročníku obvykle vyjde šest čísel časopisu, prohlédnout si je můžeš v&nbsp;<a href=\"/archiv/rocniky/\">Archivu</a>.</p>\r\n\r\n<h3 id=\"mm-je-soutěž\">M&amp;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&nbsp;udělujeme za ně body. Vítězové semináře se mohou těšit na zajímavé knihy a&nbsp;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&amp;M jsou soustředění</h3>\r\n\r\n<p style=\"text-align: justify;\">Aktivní řešitelé mají možnost s&nbsp;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&nbsp;přírodě plný odborného programu a&nbsp;nejrůznější zábavy s&nbsp;partou kamarádů. Čekají tě malé vědecké projekty, přednášky, workshopy, šifrovačka, výlet a&nbsp;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&amp;M jsme my</h3>\r\n\r\n<p style=\"text-align: justify;\">Spolu s&nbsp;řešiteli jsme tu i&nbsp;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&nbsp;informatiky a&nbsp;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&nbsp;pojeď s&nbsp;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&nbsp;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

@ -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.

3
galerie/templates/galerie/Galerie.html

@ -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 %}

24
korektury/admin.py

@ -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

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

4
korektury/models.py

@ -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

1
korektury/templates/korektury/opraf.html

@ -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> |

3
korektury/templates/korektury/seskupeny_seznam.html

@ -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}},

2
korektury/views.py

@ -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)

13
mamweb/settings_common.py

@ -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')

19
mamweb/static/css/mamweb.css

@ -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 */
}
}
/**/

17
mamweb/templates/400.html

@ -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 %}

17
mamweb/templates/403.html

@ -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 %}

23
mamweb/templates/404.html

@ -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>
{% block errorheading %}
Požadovaná stránka nenalezena
{% endblock %}
{% block errortext %}
Tuto stránku jsme na našem serveru nenalezli.
{% endblock %}
<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 errorimage %}
<img src="{% static '404.png' %}">
{% endblock %}

18
mamweb/templates/500.html

@ -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 %}

2
mamweb/templates/base.html

@ -6,7 +6,7 @@
<title>{% block title %}{% block nadpis1a %}{% endblock %} – Korespondenční seminář M&amp;M{% endblock title %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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

@ -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 %}

6
mamweb/urls.py

@ -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()

2
odevzdavatko/templates/odevzdavatko/detail.html

@ -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>

1
personalni/admin.py

@ -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:

5
personalni/templates/personalni/udaje/prihlaska_field.html

@ -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 }}:

2
requirements.txt

@ -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

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

2
seminar/models/soustredeni.py

@ -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)

3
seminar/models/tvorba.py

@ -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

10
seminar/templates/seminar/archiv/obalky.tex

@ -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 %}

10
seminar/testutils.py

@ -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…
Cancel
Save