Merge branch 'master' into static-files-upgrade

This commit is contained in:
Jonas Havelka 2024-10-22 19:29:54 +02:00
commit 05e6e5fb59
219 changed files with 499 additions and 809 deletions

12
.gitignore vendored
View file

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

View file

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

View file

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

View file

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

View file

@ -1,8 +1,5 @@
"""
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
"""
from django.apps import AppConfig from django.apps import AppConfig
class AesopConfig(AppConfig): class AesopConfig(AppConfig):
name = 'aesop' name = 'aesop'
verbose_name = 'Export do AESOPa'

View file

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

View file

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

View file

@ -1,8 +1,6 @@
"""
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
"""
from django.apps import AppConfig from django.apps import AppConfig
class ApiConfig(AppConfig): class ApiConfig(AppConfig):
name = 'api' name = 'api'
verbose_name = 'Různá webová API'

View file

@ -1,15 +1,3 @@
"""
Soubor sloužící jako router, tj. zde se definují url adresy a na co ukazují:
- ``api/expor/skoly/`` (export_skoly) :func:`~api.views.exports.exportSkolView`
- ``api/autocomplete/skola/`` (autocomplete_skola) :class:`~api.views.autocomplete.SkolaAutocomplete`
- ``api/autocomplete/resitel/`` (autocomplete_resitel) :class:`~api.views.autocomplete.ResitelAutocomplete`
- ``api/autocomplete/problem/odevzdatelny`` (autocomplete_problem_odevzdatelny) :class:`~api.views.autocomplete.OdevzdatelnyProblemAutocomplete`
Na autocomplete v3 čeká:
- ``autocomplete/organizatori/`` (seminar_autocomplete_organizator) :class:`~api.views.autocomplete.OrganizatorAutocomplete`
"""
from django.urls import path from django.urls import path
from . import views from . import views
from seminar.utils import org_required from seminar.utils import org_required

View file

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

View file

@ -1079,5 +1079,29 @@
}, },
"model": "sitetree.treeitem", "model": "sitetree.treeitem",
"pk": 53 "pk": 53
},
{
"fields": {
"access_guest": false,
"access_loggedin": false,
"access_perm_type": 1,
"access_permissions": [],
"access_restricted": true,
"alias": null,
"description": "",
"hidden": false,
"hint": "",
"inbreadcrumbs": true,
"inmenu": true,
"insitetree": true,
"parent": 20,
"sort_order": 54,
"title": "Export do abstraktů sousu {{ soustredeni.id }}",
"tree": 1,
"url": "seminar_soustredeni_abstrakty soustredeni.id",
"urlaspattern": true
},
"model": "sitetree.treeitem",
"pk": 54
} }
] ]

View file

@ -331,22 +331,22 @@
}, },
{ {
"codename": "add_novinky", "codename": "add_novinky",
"ct_app_label": "seminar", "ct_app_label": "novinky",
"ct_model": "novinky" "ct_model": "novinky"
}, },
{ {
"codename": "change_novinky", "codename": "change_novinky",
"ct_app_label": "seminar", "ct_app_label": "novinky",
"ct_model": "novinky" "ct_model": "novinky"
}, },
{ {
"codename": "delete_novinky", "codename": "delete_novinky",
"ct_app_label": "seminar", "ct_app_label": "novinky",
"ct_model": "novinky" "ct_model": "novinky"
}, },
{ {
"codename": "view_novinky", "codename": "view_novinky",
"ct_app_label": "seminar", "ct_app_label": "novinky",
"ct_model": "novinky" "ct_model": "novinky"
}, },
{ {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,3 @@
#coding: utf-8
from django import forms from django import forms
from seminar.models import Soustredeni from seminar.models import Soustredeni

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,3 @@
# coding: utf-8
import random import random
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404

View file

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

View file

@ -1,8 +1,6 @@
"""
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
"""
from django.apps import AppConfig from django.apps import AppConfig
class HeaderFotkyConfig(AppConfig): class HeaderFotkyConfig(AppConfig):
name = 'header_fotky' name = 'header_fotky'
verbose_name = 'Fotky v záhlaví'

View file

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

View file

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

View file

@ -1,13 +1,3 @@
"""
Soubor sloužící k definici toho, co bude v adminu. Většinou pouhým zavoláním
funkce :func:`django.contrib.admin.site.register`, v případě, že chceme něco
upravit, tak jako třída rozšiřující :class:`django.contrib.admin.ModelAdmin`
s dekorátorem :func:`django.contrib.admin.register`.
Zde se definuje admin pro:
- :class:`korektury.models.KorekturovanePDF`
"""
from django.contrib import admin 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
@ -15,7 +5,6 @@ from korektury.models import KorekturovanePDF
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
from django.urls import reverse from django.urls import reverse
# Register your models here.
class KorekturovanePDFAdmin(VersionAdmin): class KorekturovanePDFAdmin(VersionAdmin):
""" """
nastaví čas vložení (:attr:`~koretkury.models.KorekturovanePDF.cas`) a počet nastaví čas vložení (:attr:`~koretkury.models.KorekturovanePDF.cas`) a počet

View file

@ -1,13 +1,3 @@
"""
Formuláře (:class:`django.forms.Form`) umožňují jednoduchou tvorbu formulářů,
které lze pak jednoduše dát do frontendu i zpracovat na backendu.
Pro přidání políčka do formuláře je potřeba
- mít v modelu tu položku, kterou chci upravovat
- přidat do views (prihlaskaView, resitelEditView)
- přidat do forms
- includovat do html
"""
from django import forms from django import forms
class OpravaForm(forms.Form): class OpravaForm(forms.Form):

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,11 +1,3 @@
"""
Soubor sloužící jako router, tj. zde se definují url adresy a na co ukazují:
- ``korektury/`` (korektury_list) :class:`~korektury.views.KorekturySeskupeneListView`
- ``korektury/neseskupene/`` (korektury_neseskupene_list) :class:`~korektury.views.KorekturyAktualniListView`
- ``korektury/zastarale/`` (korektury_stare_list) :class:`~korektury.views.KorekturyZastaraleListView`
- ``korektury/<int:pdf>/`` (korektury) :class:`~korektury.views.KorekturyView`
"""
from django.urls import path from django.urls import path
from seminar.utils import org_required from seminar.utils import org_required
from . import views from . import views

View file

@ -1,8 +1,3 @@
"""
Soubor sloužící k deklaraci jednotlivých views (nejčastěji funkce beroucí request
a vracející :func:`django.shortcuts.render` respektive nějakou response, nebo
třídy většinou rozšiřující nějakou třídu z :mod:`django.views.generic`)
"""
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.views import generic from django.views import generic
from django.conf import settings from django.conf import settings
@ -199,13 +194,6 @@ class KorekturyView(generic.TemplateView):
if email: if email:
emails.discard(email) emails.discard(email)
if not settings.POSLI_MAILOVOU_NOTIFIKACI:
print("Poslal bych upozornění na tyto adresy: ", " ".join(emails))
print("---- Upozornění:")
print(text)
print("---- Konec upozornění")
return
EmailMessage( EmailMessage(
subject=subject, subject=subject,
body=text, body=text,

View file

@ -7,5 +7,5 @@ make/install_web
ensure_venv ensure_venv
./manage.py testdata ./manage.py testdata
./manage.py loaddata data/* ./manage.py loaddata data/*
make/sync_prod_flatpages #make/sync_prod_flatpages
./manage.py load_org_permissions deploy_v2/admin_org_prava.json ./manage.py load_org_permissions deploy_v2/admin_org_prava.json

View file

@ -42,8 +42,18 @@ def get_app_list(self, request, app_label=None):
""" """
app_dict = self._build_app_dict(request, label=app_label) app_dict = self._build_app_dict(request, label=app_label)
# Sort the apps alphabetically. aplikace_nahore = [
app_list = sorted(app_dict.values(), key=lambda x: locale.strxfrm('!') if (x['name'] == "Seminar") else locale.strxfrm(x['name'].lower())) 'seminar',
'personalni',
'novinky',
'korektury',
'various',
'prednasky',
'soustredeni',
]
# Odhlášený admin má prázdný app_dict :-/
app_list = [app_dict[label] for label in aplikace_nahore if label in app_dict] + [app_dict[label] for label in app_dict if label not in aplikace_nahore]
# Sort the models alphabetically within each app. # Sort the models alphabetically within each app.
for app in app_list: for app in app_list:

View file

@ -1,88 +0,0 @@
from datetime import datetime, date
from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect
class LoggedInHintCookieMiddleware(object):
"""Middleware to securely help with 'logged-in' detection for dual HTTP/HTTPS sites.
On insecure requests: Checks for a (non-secure) cookie settings.LOGGED_IN_HINT_COOKIE_NAME
and if present, redirects to HTTPS (same adress).
Note this usually breaks non-GET (POST) requests.
On secure requests: Updates cookie settings.LOGGED_IN_HINT_COOKIE_NAME to reflect
whether an user is logged in in the current session (cookie set to 'True' or cleared).
The cookie is set to expire at the same time as the sessionid cookie.
By default, LOGGED_IN_HINT_COOKIE_NAME = 'logged_in_hint'.
"""
def __init__(self):
if hasattr(settings, 'LOGGED_IN_HINT_COOKIE_NAME'):
self.cookie_name = settings.LOGGED_IN_HINT_COOKIE_NAME
else: self.cookie_name = 'logged_in_hint'
self.cookie_value = 'True'
def cookie_correct(self, request):
return self.cookie_name in request.COOKIES and request.COOKIES[self.cookie_name] == self.cookie_value
def process_request(self, request):
if not request.is_secure():
if self.cookie_correct(request):
# redirect insecure (assuming http) requests with hint cookie to https
url = request.build_absolute_uri()
assert url[:5] == 'http:'
return HttpResponseRedirect('https:' + url[5:])
return None
def process_response(self, request, response):
if request.is_secure():
# assuming full session info (as the conn. is secure)
try:
user = request.user
except AttributeError: # no user - ajax or other special request
return response
if user.is_authenticated():
if not self.cookie_correct(request):
expiry = None if request.session.get_expire_at_browser_close() else request.session.get_expiry_date()
response.set_cookie(self.cookie_name, value=self.cookie_value, expires=expiry, secure=False)
else:
if self.cookie_name in request.COOKIES:
response.delete_cookie(self.cookie_name)
return response
class vzhled:
def process_request(self, request):
return None
def process_view(self, request, view_func, view_args, view_kwargs):
#print "====== process_request ======"
#print view_func
#print view_args
#print view_kwargs
#print "============================="
return None
def process_template_response(self, request, response):
hodin = datetime.now().hour
if (hodin <= 6) or (hodin >= 14): # TODO 20
response.context_data['noc'] = True
else:
response.context_data['noc'] = False
return response
def process_response(self, request, response):
#hodin = datetime.now().hour
#if (hodin <= 6) or (hodin >= 14): # TODO 20
#response.context_data['noc'] = True
#else:
#response.context_data['noc'] = False
return response
##def process_exception(request, exception):
#pass

View file

@ -68,9 +68,6 @@ MIDDLEWARE = (
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
# FIXME: rozbilo se při přechodu na Django 2.0, nevím, jestli
# se to dá zahodit bez náhrady
# 'mamweb.middleware.LoggedInHintCookieMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
@ -149,6 +146,7 @@ INSTALLED_APPS = (
'treenode', 'treenode',
'vyroci', 'vyroci',
'sifrovacka', 'sifrovacka',
'novinky',
# Admin upravy: # Admin upravy:
@ -344,10 +342,6 @@ KOREKTURY_IMG_DIR = os.path.join('korektury', 'img')
CISLO_IMG_DIR = os.path.join('cislo', 'img') CISLO_IMG_DIR = os.path.join('cislo', 'img')
# E-MAIL NOTIFICATIONS
POSLI_MAILOVOU_NOTIFIKACI = False
# Logování chyb # Logování chyb
class InvalidTemplateVariable(str): class InvalidTemplateVariable(str):

View file

@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
import os.path import os.path
# #
@ -70,5 +68,4 @@ LOGGING['handlers']['registration_error_log']['filename'] = '/home/mam-web/logs/
# E-MAIL NOTIFICATIONS # E-MAIL NOTIFICATIONS
POSLI_MAILOVOU_NOTIFIKACI = True
LOCAL_TEST_PROD = "prod" LOCAL_TEST_PROD = "prod"

View file

@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
import os.path import os.path
# #
@ -74,7 +72,6 @@ LOGGING['handlers']['registration_error_log']['filename'] = '/home/mam-web/logs/
FILE_UPLOAD_PERMISSIONS = 0o440 FILE_UPLOAD_PERMISSIONS = 0o440
# Testování e-mailů # Testování e-mailů
POSLI_MAILOVOU_NOTIFIKACI = True
EMAIL_BACKEND = 'various.mail_prefixer.PrefixingMailBackend' EMAIL_BACKEND = 'various.mail_prefixer.PrefixingMailBackend'
# TODO Pouze na otestování testu… Zvolit konferu! # TODO Pouze na otestování testu… Zvolit konferu!
# XXX: Je to pole, protože implementační detail backendu. # XXX: Je to pole, protože implementační detail backendu.

View file

@ -1,18 +1,5 @@
""" """
Soubor sloužící jako základní router, tj. zde se includují veškeré ostatní urls: Soubor sloužící jako základní router, tj. zde se includují veškeré ostatní urls.
- ``admin/`` :mod:`django.contrib.admin.site.urls`
- ``ckeditor/`` :mod:`ckeditor_uploader.urls`
- :mod:`seminar.urls`
- :mod:`odevzdavatko.urls`
- :mod:`korektury.urls`
- :mod:`prednasky.urls`
- :mod:`soustredeni.urls`
- :mod:`personalni.urls`
- :mod:`various.autentizace.urls`
- :mod:`api.urls`
- :mod:`treenode.urls`
- :mod:`aesop.urls`
""" """
from django.urls import path, include from django.urls import path, include
from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.contrib.staticfiles.urls import staticfiles_urlpatterns

0
novinky/__init__.py Normal file
View file

5
novinky/admin.py Normal file
View file

@ -0,0 +1,5 @@
from django.contrib import admin
from .models import Novinky
admin.site.register(Novinky)

5
novinky/apps.py Normal file
View file

@ -0,0 +1,5 @@
from django.apps import AppConfig
class NovinkyConfig(AppConfig):
name = 'novinky'
verbose_name = 'Novinky'

View file

@ -0,0 +1,45 @@
# Generated by Django 4.2.13 on 2024-05-13 20:43
from django.db import migrations, models
def nastav_nove_contenttypes(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType')
for m in ('novinka'):
oct = ContentType.objects.filter(app_label='seminar', model=m)
oct.update(app_label='novinky')
def nastav_stare_contenttypes(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType')
for m in ('novinka'):
nct = ContentType.objects.filter(app_label='novinky', model=m)
nct.update(app_label='seminar')
class Migration(migrations.Migration):
initial = True
dependencies = [
('seminar', '0127_unmanage_novinky'),
]
operations = [
migrations.RunPython(nastav_nove_contenttypes, nastav_stare_contenttypes),
migrations.CreateModel(
name='Novinky',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('datum', models.DateField(auto_now_add=True)),
('text', models.TextField(blank=True, null=True, verbose_name='Text novinky')),
('obrazek', models.ImageField(blank=True, null=True, upload_to='image_novinky/%Y/%m/%d/', verbose_name='Obrázek')),
('autor', models.ForeignKey(to='personalni.organizator', verbose_name='Autor novinky', null=True, on_delete=models.SET_NULL)),
('zverejneno', models.BooleanField(default=False, verbose_name='Zveřejněno')),
],
options={
'verbose_name': 'Novinka',
'verbose_name_plural': 'Novinky',
'db_table': 'seminar_novinky',
'ordering': ['-datum'],
'managed': False,
},
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.2.13 on 2024-05-13 20:58
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('novinky', '0001_initial'),
('seminar', '0128_delete_novinky'),
]
operations = [
migrations.AlterModelOptions(
name='novinky',
options={'ordering': ['-datum'], 'verbose_name': 'Novinka', 'verbose_name_plural': 'Novinky'},
),
]

View file

@ -0,0 +1,13 @@
# Generated by Django 4.2.13 on 2024-05-13 21:00
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('novinky', '0002_manage_novinky'),
]
operations = [
]

View file

View file

@ -13,6 +13,7 @@ class Novinky(models.Model):
verbose_name = 'Novinka' verbose_name = 'Novinka'
verbose_name_plural = 'Novinky' verbose_name_plural = 'Novinky'
ordering = ['-datum'] ordering = ['-datum']
db_table = 'seminar_novinky'
datum = models.DateField(auto_now_add=True) datum = models.DateField(auto_now_add=True)

0
novinky/views.py Normal file
View file

View file

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

View file

@ -1,8 +1,6 @@
"""
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
"""
from django.apps import AppConfig from django.apps import AppConfig
class OdevzdavatkoConfig(AppConfig): class OdevzdavatkoConfig(AppConfig):
name = 'odevzdavatko' name = 'odevzdavatko'
verbose_name = 'Odevzdávátko'

View file

@ -1,17 +1,3 @@
"""
Soubor sloužící jako router, tj. zde se definují url adresy a na co ukazují:
- ``org/add_solution`` (seminar_vloz_reseni) :class:`~odevzdavatko.views.PosliReseniView`
- ``resitel/nahraj_reseni`` (seminar_nahraj_reseni) :class:`~odevzdavatko.views.NahrajReseniView`
- ``resitel/odevzdana_reseni/`` (seminar_resitel_odevzdana_reseni) :class:`~odevzdavatko.views.PrehledOdevzdanychReseni`
- ``org/reseni/`` (odevzdavatko_tabulka) :class:`~odevzdavatko.views.TabulkaOdevzdanychReseniView`
- ``org/reseni/rocnik/<int:rocnik>/`` (odevzdavatko_tabulka) :class:`~odevzdavatko.views.TabulkaOdevzdanychReseniView`
- ``org/reseni/<int:problem>/<int:resitel>/`` (odevzdavatko_reseni_resitele_k_problemu) :class:`~odevzdavatko.views.ReseniProblemuView`
- ``org/reseni/<int:pk>/`` (odevzdavatko_detail_reseni) :func:`~seminar.utils.viewMethodSwitch` + :class:`~odevzdavatko.views.DetailReseniView` + :func:`~odevzdavatko.views.hodnoceniReseniView`
- ``org/reseni/all`` :class:`~odevzdavatko.views.SeznamReseniView`
- ``org/reseni/akt`` :class:`~odevzdavatko.views.TabulkaOdevzdanychReseniView`
- ``resitel/reseni/<int:pk>`` (odevzdavatko_resitel_reseni) :class:`~odevzdavatko.views.ResitelReseniView`
"""
from django.urls import path from django.urls import path
from seminar.utils import org_required, resitel_required, viewMethodSwitch, \ from seminar.utils import org_required, resitel_required, viewMethodSwitch, \

View file

@ -504,7 +504,7 @@ class NahrajReseniView(LoginRequiredMixin, CreateView):
EmailMessage( EmailMessage(
subject="Nové řešení k " + seznam_do_subjectu, subject="Nové řešení k " + seznam_do_subjectu,
body=f"Řešitel{ '' if resitel.pohlavi_muz else 'ka' } { resitel } právě nahrál{'' if resitel.pohlavi_muz else 'a' } nové řešení k { seznam }.\n\nHurá do opravování: { self.object.absolute_url() }", body=f"{resitel} posílá nové řešení k { seznam }.\n\nHurá do opravování: { self.object.absolute_url() }",
from_email="submitovatko@mam.mff.cuni.cz", # FIXME: Chceme to mít radši tady, nebo v nastavení? from_email="submitovatko@mam.mff.cuni.cz", # FIXME: Chceme to mít radši tady, nebo v nastavení?
to=list(prijemci), to=list(prijemci),
).send() ).send()

View file

@ -5,10 +5,52 @@ from django.contrib.messages import WARNING, ERROR, SUCCESS
import seminar.models as m import seminar.models as m
from datetime import datetime from datetime import datetime
@admin.action(description="Sjednoť telefony")
def sjednot_telefony(admin, request, queryset):
for o in queryset:
if o.telefon == '':
continue
try:
telefon = int(o.telefon.replace(" ", "").replace("+", ""))
# 6 míst
if len(str(telefon)) == 9:
o.telefon = "+420 " + str(telefon)[0:3] + " " + str(telefon)[3:6] + " " + str(telefon)[6:9]
o.save()
# 12 míst
elif len(str(telefon)) == 12:
o.telefon = "+" + str(telefon)[0:3] + " " + str(telefon)[3:6] + " " + str(telefon)[6:9] + " " + str(telefon)[9:12]
o.save()
else:
raise ValueError
except:
admin.message_user(request, f"{o.jmeno} {o.prijmeni} (id: {o.id}) má divný telefon: {o.telefon}", level=ERROR)
admin.message_user(request, "Telefony sjednoceny.", level=SUCCESS)
# Tohle chceme umět použít i z ResitelAdmin
@admin.action(description="Udělej z vybraných osob organizátory")
def udelej_orgem(admin, request, queryset):
org_group = Group.objects.get(name='org')
uspesne_vytvoreni_orgove = 0
for o in queryset:
if m.Organizator.objects.filter(osoba=o).exists():
# Ref: https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.message_user
admin.message_user(request, f"Osoba {o} už je org, přeskakuji.", level=WARNING)
continue
user = o.user
if user is None:
admin.message_user(request, f"Osoba {o} nemá uživatele! Přeskakuji.", level=ERROR)
continue
user.groups.add(org_group)
user.is_staff = True
user.save()
org = m.Organizator.objects.create(osoba=o, organizuje_od=datetime.now())
org.save()
uspesne_vytvoreni_orgove += 1
admin.message_user(request, f'Úspěšně vytvořeno {uspesne_vytvoreni_orgove} orgů.', level=SUCCESS)
@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, sjednot_telefony]
search_fields = ['jmeno', 'prijmeni', 'prezdivka'] search_fields = ['jmeno', 'prijmeni', 'prezdivka']
def synchronizuj_maily(self, request, queryset): def synchronizuj_maily(self, request, queryset):
@ -20,27 +62,6 @@ class OsobaAdmin(admin.ModelAdmin):
self.message_user(request, "E-maily synchronizovány.") self.message_user(request, "E-maily synchronizovány.")
synchronizuj_maily.short_description = "Synchronizuj vybraným osobám e-maily do uživatelů" synchronizuj_maily.short_description = "Synchronizuj vybraným osobám e-maily do uživatelů"
def udelej_orgem(self,request,queryset):
org_group = Group.objects.get(name='org')
uspesne_vytvoreni_orgove = 0
for o in queryset:
if m.Organizator.objects.filter(osoba=o).exists():
# Ref: https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.message_user
self.message_user(request, f"Osoba {o} už je org, přeskakuji.", level=WARNING)
continue
user = o.user
if user is None:
self.message_user(request, f"Osoba {o} nemá uživatele! Přeskakuji.", level=ERROR)
continue
user.groups.add(org_group)
user.is_staff = True
user.save()
org = m.Organizator.objects.create(osoba=o, organizuje_od=datetime.now())
org.save()
uspesne_vytvoreni_orgove += 1
self.message_user(request, f'Úspěšně vytvořeno {uspesne_vytvoreni_orgove} orgů.', level=SUCCESS)
udelej_orgem.short_description = "Udělej z vybraných osob organizátory"
class OsobaInline(admin.TabularInline): class OsobaInline(admin.TabularInline):
model = m.Osoba model = m.Osoba
@ -53,9 +74,16 @@ class OrganizatorAdmin(ReverseModelAdmin):
@admin.register(m.Resitel) @admin.register(m.Resitel)
class ResitelAdmin(ReverseModelAdmin): class ResitelAdmin(ReverseModelAdmin):
search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__prezdivka'] search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__prezdivka']
list_filter = ['zasilat', 'zasilat_cislo_papirove', 'zasilat_cislo_emailem', 'rok_maturity']
ordering = ('osoba__prijmeni', 'osoba__jmeno') ordering = ('osoba__prijmeni', 'osoba__jmeno')
inline_type = 'stacked' inline_type = 'stacked'
inline_reverse = ['osoba'] inline_reverse = ['osoba']
actions = ['udelej_resitele_orgem']
@admin.action(description="Udělej z řešitelů organizátory")
def udelej_resitele_orgem(self, req, qs):
osoby = m.Osoba.objects.filter(resitel__in=qs)
udelej_orgem(self, req, osoby)
admin.site.register(m.Skola) admin.site.register(m.Skola)
admin.site.register(m.Prijemce) admin.site.register(m.Prijemce)

View file

@ -1,8 +1,6 @@
"""
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
"""
from django.apps import AppConfig from django.apps import AppConfig
class PersonalniConfig(AppConfig): class PersonalniConfig(AppConfig):
name = 'personalni' name = 'personalni'
verbose_name = 'Personální' # Má to nějaký použitelnější název?

View file

@ -32,7 +32,7 @@ class UdajeForm(forms.Form):
jmeno = forms.CharField(label='Jméno', max_length=256, required=True) jmeno = forms.CharField(label='Jméno', max_length=256, required=True)
prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False) prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False)
prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True)
pohlavi_muz = forms.ChoiceField(label='Pohlaví', choices=((True, 'muž'), (False, 'žena')), required=True) osloveni = forms.ChoiceField(label='Oslovení', choices=Osoba.OSLOVENI_CHOICES, required=False)
email = forms.EmailField(label='E-mail', max_length=256, required=True) email = forms.EmailField(label='E-mail', max_length=256, required=True)
telefon = forms.CharField(widget=TelInput(), label='Telefon', max_length=256, required=False) telefon = forms.CharField(widget=TelInput(), label='Telefon', max_length=256, required=False)
datum_narozeni = forms.DateField(widget=DateInput(), label='Datum narození', required=False) datum_narozeni = forms.DateField(widget=DateInput(), label='Datum narození', required=False)

View file

@ -0,0 +1,14 @@
# Generated by Django 4.2.11 on 2024-04-30 21:53
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('personalni', '0006_pre_split_soustredeni'),
('soustredeni', '0003_post_split_soustredeni'),
]
operations = [
]

View file

@ -0,0 +1,40 @@
# Generated by Django 4.2.11 on 2024-04-12 14:03
from django.db import migrations, models
# V migracích nemáme Osoba.OSLOVENI_*, tak si to sem nakopíruji.
OSLOVENI_MUZSKE = 'resitel'
OSLOVENI_ZENSKE = 'resitelka'
OSLOVENI_ZADNE = ''
def pohlavi_to_osloveni(apps, schema_editor):
Osoba = apps.get_model('personalni', 'Osoba')
Osoba.objects.filter(pohlavi_muz=True).update(osloveni=OSLOVENI_MUZSKE)
Osoba.objects.filter(pohlavi_muz=False).update(osloveni=OSLOVENI_ZENSKE)
def osloveni_to_pohlavi(apps, schema_editor):
Osoba = apps.get_model('personalni', 'Osoba')
nebinarni = Osoba.objects.filter(osloveni=OSLOVENI_ZADNE)
if nebinarni.count() > 0:
raise Exception("Nelze odmigrovat: v databázi jsou nebinární osoby, které starý model nereprezentuje správně.")
Osoba.objects.filter(osloveni=OSLOVENI_MUZSKE).update(pohlavi_muz=True)
Osoba.objects.filter(osloveni=OSLOVENI_MUZSKE).update(pohlavi_muz=False)
class Migration(migrations.Migration):
dependencies = [
('personalni', '0007_post_split_soustredeni'),
]
operations = [
migrations.AddField(
model_name='osoba',
name='osloveni',
field=models.CharField(blank=True, choices=[('resitel', 'Řešitel'), ('resitelka', 'Řešitelka')], max_length=32, verbose_name='Oslovení'),
),
migrations.RunPython(pohlavi_to_osloveni, osloveni_to_pohlavi),
migrations.RemoveField(
model_name='osoba',
name='pohlavi_muz',
),
]

View file

@ -0,0 +1,13 @@
# Generated by Django 4.2.13 on 2024-05-13 20:35
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('personalni', '0008_reforma_pohlavi'),
]
operations = [
]

View file

@ -0,0 +1,14 @@
# Generated by Django 4.2.13 on 2024-05-13 20:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('personalni', '0009_novinky_pre'),
('novinky', '0003_novinky_post'),
]
operations = [
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.2.13 on 2024-06-03 14:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('personalni', '0010_novinky_post'),
]
operations = [
migrations.AlterField(
model_name='osoba',
name='osloveni',
field=models.CharField(blank=True, choices=[('resitel', 'Řešitel'), ('resitelka', 'Řešitelka'), ('', 'Cokoliv jiného')], max_length=32, verbose_name='Oslovení'),
),
]

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
import logging import logging
from django.db import models from django.db import models
@ -38,8 +37,16 @@ class Osoba(SeminarModelBase):
user = models.OneToOneField(settings.AUTH_USER_MODEL, blank=True, null=True, user = models.OneToOneField(settings.AUTH_USER_MODEL, blank=True, null=True,
verbose_name='uživatel', on_delete=models.DO_NOTHING) verbose_name='uživatel', on_delete=models.DO_NOTHING)
# Pohlaví. Že ho neznáme se snad nestane (a ušetří to práci při programování) # Pohlaví nás prakticky nezajímá, reálně.
pohlavi_muz = models.BooleanField('pohlaví (muž)', default=False) OSLOVENI_MUZSKE = 'resitel'
OSLOVENI_ZENSKE = 'resitelka'
OSLOVENI_ZADNE = ''
OSLOVENI_CHOICES = [
(OSLOVENI_MUZSKE, 'Řešitel'),
(OSLOVENI_ZENSKE, 'Řešitelka'),
(OSLOVENI_ZADNE, 'Cokoliv jiného'), # Reálně nás u nikoho jiného oslovení nezajímá? (A pohlaví už vůbec)
]
osloveni = models.CharField('Oslovení', choices=OSLOVENI_CHOICES, max_length=32, blank=True)
email = models.EmailField('e-mail', max_length=256, blank=True, default='') email = models.EmailField('e-mail', max_length=256, blank=True, default='')
@ -246,11 +253,19 @@ class Resitel(SeminarModelBase):
def export_row(self): def export_row(self):
"Slovnik pro pouziti v AESOP exportu" "Slovnik pro pouziti v AESOP exportu"
# Ref: https://opmk.mff.cuni.cz/wiki/aesop/import#telo
# FUJ: Oslovení nemusí souviset s genderem.
gender = {
Osoba.OSLOVENI_MUZSKE: 'M',
Osoba.OSLOVENI_ZENSKE: 'F',
Osoba.OSLOVENI_ZADNE: '',
}[self.osoba.osloveni]
return { return {
'id': self.id, 'id': self.id,
'name': self.osoba.jmeno, 'name': self.osoba.jmeno,
'surname': self.osoba.prijmeni, 'surname': self.osoba.prijmeni,
'gender': 'M' if self.osoba.pohlavi_muz else 'F', 'gender': gender,
'born': self.osoba.datum_narozeni.isoformat() if self.osoba.datum_narozeni else '', 'born': self.osoba.datum_narozeni.isoformat() if self.osoba.datum_narozeni else '',
'email': self.osoba.email, 'email': self.osoba.email,
'end-year': self.rok_maturity or '', 'end-year': self.rok_maturity or '',

View file

@ -13,18 +13,18 @@
<li>soustředění</li> <li>soustředění</li>
</ul> </ul>
</li> </li>
<li><a href="/admin/seminar/novinky/add/"><strong>přidat novinku</strong></a> na web</li> <li><a href="{% url 'admin:novinky_novinky_add' %}"><strong>přidat novinku</strong></a> na web</li>
</ul> </ul>
<hr /> <hr />
<h2><strong>Tvorba čísla</strong></h2> <h2><strong>Tvorba čísla</strong></h2>
<ul> <ul>
<li><a href="/admin/seminar/problem/add/"><strong>přidat téma</strong></a></li> <li><a href="{% url 'admin:seminar_problem_add' %}"><strong>přidat téma</strong></a></li>
<li><strong>korektury</strong> <li><strong>korektury</strong>
<ul> <ul>
<li><a href="/korektury/">korekturování</a></li> <li><a href="{% url 'korektury_list' %}">korekturování</a></li>
<li><a href="/admin/korektury/korekturovanepdf/add/">přidat pdf k opravám</a></li> <li><a href="{% url 'admin:korektury_korekturovanepdf_add' %}">přidat pdf k opravám</a></li>
</ul> </ul>
</li> </li>
<li> <li>
@ -70,15 +70,15 @@
<h2><strong>Soustředění</strong></h2> <h2><strong>Soustředění</strong></h2>
<ul> <ul>
<li><a href="/admin/seminar/soustredeni/add/">přidat soustředění</a></li> <li><a href="{% url 'admin:soustredeni_soustredeni_add' %}">přidat soustředění</a></li>
<li><strong>přednášky</strong> <li><strong>přednášky</strong>
<ul> <ul>
<li><a href="/admin/prednasky/prednaska/">vypisování přednášek</a></li> <li><a href="{% url 'admin:prednasky_prednaska_add' %}">vypisování přednášek</a></li>
<li>hlasování o přednáškách</li> <li>hlasování o přednáškách</li>
</ul> </ul>
</li> </li>
<li><a href="/soustredeni/probehlo/">proběhlá soustředění</a> <li><a href="{% url 'seminar_seznam_soustredeni' %}">proběhlá soustředění</a>
<ul> <ul>
<li>vytvoření galerie</li> <li>vytvoření galerie</li>
<li>stažení seznamu účastníků</li> <li>stažení seznamu účastníků</li>
@ -91,7 +91,7 @@
<h2><strong>Můj profil</strong></h2> <h2><strong>Můj profil</strong></h2>
<ul> <ul>
<li><a href="/admin/seminar/organizator/{{ organizator.id }}/change/"><strong>upravit </strong></a></li> <li><a href="{% url 'admin:personalni_organizator_change' organizator.id %}"><strong>upravit </strong></a></li>
</ul> </ul>
<hr/> <hr/>
@ -108,6 +108,6 @@
</ul> </ul>
<hr /> <hr />
<p>Nemůžeš najít, co hledáš? Může to být v <a href="/admin/">administračním rozhraní webu</a>.</p> <p>Nemůžeš najít, co hledáš? Může to být v <a href="{% url 'admin:index' %}">administračním rozhraní webu</a>.</p>
{% endblock content %} {% endblock content %}

View file

@ -24,7 +24,7 @@
{% include "personalni/udaje/prihlaska_field.html" with field=form.jmeno %} {% include "personalni/udaje/prihlaska_field.html" with field=form.jmeno %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.prezdivka_resitele %} {% include "personalni/udaje/prihlaska_field.html" with field=form.prezdivka_resitele %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.prijmeni %} {% include "personalni/udaje/prihlaska_field.html" with field=form.prijmeni %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.pohlavi_muz%} {% include "personalni/udaje/prihlaska_field.html" with field=form.osloveni%}
{% include "personalni/udaje/prihlaska_field.html" with field=form.email %} {% include "personalni/udaje/prihlaska_field.html" with field=form.email %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.telefon %} {% include "personalni/udaje/prihlaska_field.html" with field=form.telefon %}
{% include "personalni/udaje/prihlaska_field.html" with field=form.datum_narozeni %} {% include "personalni/udaje/prihlaska_field.html" with field=form.datum_narozeni %}

View file

@ -1,17 +1,3 @@
"""
Soubor sloužící jako router, tj. zde se definují url adresy a na co ukazují:
- ``org/add_solution`` (seminar_vloz_reseni) :class:`~odevzdavatko.views.PosliReseniView`
- ``resitel/nahraj_reseni`` (seminar_nahraj_reseni) :class:`~odevzdavatko.views.NahrajReseniView`
- ``resitel/odevzdana_reseni/`` (seminar_resitel_odevzdana_reseni) :class:`~odevzdavatko.views.PrehledOdevzdanychReseni`
- ``org/reseni/`` (odevzdavatko_tabulka) :class:`~odevzdavatko.views.TabulkaOdevzdanychReseniView`
- ``org/reseni/rocnik/<int:rocnik>/`` (odevzdavatko_tabulka) :class:`~odevzdavatko.views.TabulkaOdevzdanychReseniView`
- ``org/reseni/<int:problem>/<int:resitel>/`` (odevzdavatko_reseni_resitele_k_problemu) :class:`~odevzdavatko.views.ReseniProblemuView`
- ``org/reseni/<int:pk>/`` (odevzdavatko_detail_reseni) :func:`~seminar.utils.viewMethodSwitch` + :class:`~odevzdavatko.views.DetailReseniView` + :func:`~odevzdavatko.views.hodnoceniReseniView`
- ``org/reseni/all`` :class:`~odevzdavatko.views.SeznamReseniView`
- ``org/reseni/akt`` :class:`~odevzdavatko.views.TabulkaOdevzdanychReseniView`
- ``resitel/reseni/<int:pk>`` (odevzdavatko_resitel_reseni) :class:`~odevzdavatko.views.ResitelReseniView`
"""
from django.urls import path from django.urls import path
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from . import views from . import views

View file

@ -4,7 +4,7 @@ from django.views import generic
from django.db.models import Q, Count, Min from django.db.models import Q, Count, Min
from django.views.decorators.debug import sensitive_post_parameters from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.contrib.auth.models import User, Permission, Group from django.contrib.auth.models import User, Permission, Group, AnonymousUser
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction from django.db import transaction
from django.http import HttpResponse from django.http import HttpResponse
@ -139,7 +139,7 @@ def resitelEditView(request):
form_logger.info("EDIT:" + str(fcd) + str(form_hash)) # TODO možná logovat jinak form_logger.info("EDIT:" + str(fcd) + str(form_hash)) # TODO možná logovat jinak
osoba_edit.jmeno = fcd['jmeno'] osoba_edit.jmeno = fcd['jmeno']
osoba_edit.prijmeni = fcd['prijmeni'] osoba_edit.prijmeni = fcd['prijmeni']
osoba_edit.pohlavi_muz = fcd['pohlavi_muz'] osoba_edit.osloveni = fcd['osloveni']
osoba_edit.email = fcd['email'] osoba_edit.email = fcd['email']
osoba_edit.telefon = fcd['telefon'] osoba_edit.telefon = fcd['telefon']
osoba_edit.ulice = fcd['ulice'] osoba_edit.ulice = fcd['ulice']
@ -209,7 +209,7 @@ def prihlaskaView(request):
o = s.Osoba( o = s.Osoba(
jmeno = fcd['jmeno'], jmeno = fcd['jmeno'],
prijmeni = fcd['prijmeni'], prijmeni = fcd['prijmeni'],
pohlavi_muz = fcd['pohlavi_muz'], osloveni = fcd['osloveni'],
email = fcd['email'], email = fcd['email'],
telefon = fcd.get('telefon',''), telefon = fcd.get('telefon',''),
datum_narozeni = fcd.get('datum_narozeni',None), datum_narozeni = fcd.get('datum_narozeni',None),
@ -242,7 +242,7 @@ def prihlaskaView(request):
# Porovnání údajů # Porovnání údajů
assert orig_osoba.user is None, "Právě-registrující-se osoba už má Uživatele!" assert orig_osoba.user is None, "Právě-registrující-se osoba už má Uživatele!"
osoba_attrs = ['jmeno', 'prijmeni', 'pohlavi_muz', 'email', 'telefon', 'datum_narozeni', 'ulice', 'mesto', 'psc', 'stat', 'datum_souhlasu_udaje', 'datum_souhlasu_zasilani', 'datum_registrace'] osoba_attrs = ['jmeno', 'prijmeni', 'osloveni', 'email', 'telefon', 'datum_narozeni', 'ulice', 'mesto', 'psc', 'stat', 'datum_souhlasu_udaje', 'datum_souhlasu_zasilani', 'datum_registrace']
diffattrs = [] diffattrs = []
for attr in osoba_attrs: for attr in osoba_attrs:
new = getattr(o, attr) new = getattr(o, attr)
@ -318,6 +318,12 @@ def prihlaskaView(request):
# Jen hloupé rozhazovátko # Jen hloupé rozhazovátko
def profilView(request): def profilView(request):
user = request.user user = request.user
if not isinstance(user, AnonymousUser) and m.Osoba.objects.filter(user=user).count() != 1:
# m.Osoba.objects.get() v ostatních views selže
return render(request, "universal.html", {
'title': 'Krize identity.',
'raw_html': r'<blockquote>Zvláštní pocit, že jo?<br>[…]<br>Co to znamená?<br>— Že ti MaMweb neumí říct, kdo jsi.<br>A <a href="/admin">Admin</a> ano?<br>— V tom je rozdíl.</blockquote> — Matrix (1999), parafrázováno',
})
if user.has_perm('auth.org'): if user.has_perm('auth.org'):
return OrgoRozcestnikView.as_view()(request) return OrgoRozcestnikView.as_view()(request)
if user.has_perm('auth.resitel'): if user.has_perm('auth.resitel'):
@ -339,7 +345,7 @@ def dataResiteluCsvResponse(queryset, columns=None, with_header=True):
'osoba__telefon', 'osoba__telefon',
'osoba__user__username', 'osoba__user__username',
'osoba__datum_narozeni', 'osoba__datum_narozeni',
'osoba__pohlavi_muz', 'osoba__osloveni',
'osoba__ulice', 'osoba__ulice',
'osoba__mesto', 'osoba__mesto',
'osoba__psc', 'osoba__psc',
@ -367,7 +373,7 @@ def dataResiteluCsvResponse(queryset, columns=None, with_header=True):
'osoba__telefon': 'telefon', 'osoba__telefon': 'telefon',
'osoba__user__username': 'user', 'osoba__user__username': 'user',
'osoba__datum_narozeni': 'datum_narozeni', 'osoba__datum_narozeni': 'datum_narozeni',
'osoba__pohlavi_muz': 'pohlavi_muz', 'osoba__osloveni': 'osloveni',
'osoba__ulice': 'ulice', 'osoba__ulice': 'ulice',
'osoba__mesto': 'mesto', 'osoba__mesto': 'mesto',
'osoba__psc': 'psc', 'osoba__psc': 'psc',

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from django.contrib import admin from django.contrib import admin
from django.contrib import messages from django.contrib import messages
from reversion.admin import VersionAdmin from reversion.admin import VersionAdmin

View file

@ -1,4 +1,3 @@
# coding: utf-8
from django import forms from django import forms
class NewPrednaskyForm(forms.Form): class NewPrednaskyForm(forms.Form):

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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