Velká revize stylů (a některých JS) #44
219 changed files with 499 additions and 809 deletions
12
.gitignore
vendored
12
.gitignore
vendored
|
@ -31,9 +31,15 @@ TODO
|
|||
# reversion kvůli historii objektů v 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
|
||||
.idea
|
||||
|
||||
# dokumentace
|
||||
docs/_build
|
||||
docs/modules
|
||||
# Mac users
|
||||
.DS_Store
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,8 +1,5 @@
|
|||
"""
|
||||
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
|
||||
"""
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AesopConfig(AppConfig):
|
||||
name = 'aesop'
|
||||
verbose_name = 'Export do AESOPa'
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
"""
|
||||
Soubor sloužící jako „router“, tj. zde se definují url adresy a na co ukazují:
|
||||
|
||||
- ``aesop-export/mam-rocnik-<int:prvni_rok>.csv`` (seminar_export_rocnik) :class:`~aesop.views.ExportRocnikView`
|
||||
- ``aesop-export/mam-sous-<str:datum_zacatku>.csv`` (seminar_export_sous) :class:`~aesop.views.ExportSousView`
|
||||
- ``aesop-export/index.csv`` (seminar_export_index) :class:`~aesop.views.ExportIndexView`
|
||||
"""
|
||||
from django.urls import path
|
||||
from aesop import views
|
||||
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
"""
|
||||
Soubor sloužící k deklaraci jednotlivých „views“ (nejčastěji funkce beroucí request
|
||||
a vracející :func:`django.shortcuts.render` respektive nějakou response, nebo
|
||||
třídy většinou rozšiřující nějakou třídu z :mod:`django.views.generic`)
|
||||
"""
|
||||
import django
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.http import HttpResponse
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""
|
||||
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
|
||||
"""
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ApiConfig(AppConfig):
|
||||
name = 'api'
|
||||
verbose_name = 'Různá webová API'
|
||||
|
|
12
api/urls.py
12
api/urls.py
|
@ -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 . import views
|
||||
from seminar.utils import org_required
|
||||
|
|
|
@ -1,7 +1,2 @@
|
|||
"""
|
||||
Soubory sloužící k deklaraci jednotlivých „views“ (nejčastěji funkce beroucí request
|
||||
a vracející :func:`django.shortcuts.render` respektive nějakou response, nebo
|
||||
třídy většinou rozšiřující nějakou třídu z :mod:`django.views.generic`)
|
||||
"""
|
||||
from .autocomplete import *
|
||||
from .exports import *
|
||||
|
|
|
@ -1079,5 +1079,29 @@
|
|||
},
|
||||
"model": "sitetree.treeitem",
|
||||
"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
|
||||
}
|
||||
]
|
||||
|
|
|
@ -331,22 +331,22 @@
|
|||
},
|
||||
{
|
||||
"codename": "add_novinky",
|
||||
"ct_app_label": "seminar",
|
||||
"ct_app_label": "novinky",
|
||||
"ct_model": "novinky"
|
||||
},
|
||||
{
|
||||
"codename": "change_novinky",
|
||||
"ct_app_label": "seminar",
|
||||
"ct_app_label": "novinky",
|
||||
"ct_model": "novinky"
|
||||
},
|
||||
{
|
||||
"codename": "delete_novinky",
|
||||
"ct_app_label": "seminar",
|
||||
"ct_app_label": "novinky",
|
||||
"ct_model": "novinky"
|
||||
},
|
||||
{
|
||||
"codename": "view_novinky",
|
||||
"ct_app_label": "seminar",
|
||||
"ct_app_label": "novinky",
|
||||
"ct_model": "novinky"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -9,12 +9,6 @@ static
|
|||
------
|
||||
Složka, kam django nakopíruje všechno ze složek static a pak na to z templatů / kódu jde ukazovat pomocí ``static``.
|
||||
|
||||
_git_hooks
|
||||
----------
|
||||
Hooky do gitu pro kontrolu Pythoního stylu. Především ``flake8``.
|
||||
|
||||
Zbylo tu z minulosti mamwebu.
|
||||
|
||||
data
|
||||
----
|
||||
Obsahuje data, která patří do databáze, ale jsou přímo součástí webu jako
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
FIXME přepsat do rst, přidat i další věci a případně přesunout na wiki
|
||||
Přidání obrázků do odměn:
|
||||
admin -> flatpage odměn -> ikona přidat obrázek
|
||||
záložka odeslat, vybrat obrázek, odeslat
|
25
galerie/TODO
25
galerie/TODO
|
@ -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?
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
#coding: utf-8
|
||||
|
||||
from galerie.models import Obrazek, Galerie
|
||||
from django.contrib import admin
|
||||
from django.http import HttpResponseRedirect
|
||||
|
|
|
@ -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)
|
|
@ -1,5 +1,3 @@
|
|||
#coding: utf-8
|
||||
|
||||
from django import forms
|
||||
from seminar.models import Soustredeni
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.20 on 2019-04-30 21:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.21 on 2019-06-10 21:58
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# coding: utf-8
|
||||
|
||||
from django.db import models
|
||||
#from django.db.models import Q
|
||||
from imagekit.models import ImageSpecField
|
||||
|
|
|
@ -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 seminar.utils import org_required
|
||||
from . import views
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# coding: utf-8
|
||||
|
||||
import random
|
||||
|
||||
from django.http import HttpResponse, Http404
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
"""
|
||||
Soubor sloužící k definici toho, co bude v adminu. Většinou pouhým zavoláním
|
||||
funkce :func:`django.contrib.admin.site.register`, v případě, že chceme něco
|
||||
upravit, tak jako třída rozšiřující :class:`django.contrib.admin.ModelAdmin`
|
||||
s dekorátorem :func:`django.contrib.admin.register`.
|
||||
|
||||
Zde se definuje admin pro:
|
||||
|
||||
- :class:`~header_fotky.models.FotkaHeader`
|
||||
- :class:`~header_fotky.models.FotkaUrlVazba`
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin import ModelAdmin
|
||||
import header_fotky.models as m
|
||||
|
@ -22,4 +11,4 @@ class FotkaPozadiAdmin(ModelAdmin):
|
|||
readonly_fields = ['cas']
|
||||
|
||||
admin.site.register(m.FotkaHeader, FotkaPozadiAdmin)
|
||||
admin.site.register(m.FotkaUrlVazba)
|
||||
admin.site.register(m.FotkaUrlVazba)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""
|
||||
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
|
||||
"""
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class HeaderFotkyConfig(AppConfig):
|
||||
name = 'header_fotky'
|
||||
verbose_name = 'Fotky v záhlaví'
|
||||
|
|
|
@ -1,17 +1,3 @@
|
|||
"""
|
||||
Tento soubor slouží k definici databázového modelu.
|
||||
|
||||
Třídy rozšiřují většinou :class:`django.db.models.Model` a jejich atributy jsou
|
||||
většinou sloupce v databázi (tj. nastaví se na hodnotu něčeho z :mod:`django.db.models`).
|
||||
Na výběr jsou:
|
||||
|
||||
- :class:`django.db.models.TextField`
|
||||
- :class:`django.db.models.ForeignKey`
|
||||
- :class:`django.db.models.DateField`
|
||||
- :class:`django.db.models.DateTimeField`
|
||||
- :class:`django.db.models.ImageField`
|
||||
- :class:`django.db.models.CharField`
|
||||
"""
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
@ -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 reversion.admin import VersionAdmin
|
||||
from korektury.models import KorekturovanePDF
|
||||
|
@ -15,7 +5,6 @@ from korektury.models import KorekturovanePDF
|
|||
from django.core.mail import EmailMessage
|
||||
from django.urls import reverse
|
||||
|
||||
# Register your models here.
|
||||
class KorekturovanePDFAdmin(VersionAdmin):
|
||||
"""
|
||||
nastaví čas vložení (:attr:`~koretkury.models.KorekturovanePDF.cas`) a počet
|
||||
|
|
|
@ -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
|
||||
|
||||
class OpravaForm(forms.Form):
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.20 on 2019-04-30 21:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.21 on 2019-06-10 21:58
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
|
|
@ -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
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -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 seminar.utils import org_required
|
||||
from . import views
|
||||
|
|
|
@ -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.views import generic
|
||||
from django.conf import settings
|
||||
|
@ -199,13 +194,6 @@ class KorekturyView(generic.TemplateView):
|
|||
if 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(
|
||||
subject=subject,
|
||||
body=text,
|
||||
|
|
|
@ -7,5 +7,5 @@ make/install_web
|
|||
ensure_venv
|
||||
./manage.py testdata
|
||||
./manage.py loaddata data/*
|
||||
make/sync_prod_flatpages
|
||||
#make/sync_prod_flatpages
|
||||
./manage.py load_org_permissions deploy_v2/admin_org_prava.json
|
||||
|
|
|
@ -42,8 +42,18 @@ def get_app_list(self, request, app_label=None):
|
|||
"""
|
||||
|
||||
app_dict = self._build_app_dict(request, label=app_label)
|
||||
# Sort the apps alphabetically.
|
||||
app_list = sorted(app_dict.values(), key=lambda x: locale.strxfrm('!') if (x['name'] == "Seminar") else locale.strxfrm(x['name'].lower()))
|
||||
aplikace_nahore = [
|
||||
'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.
|
||||
for app in app_list:
|
||||
|
|
|
@ -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
|
|
@ -68,9 +68,6 @@ MIDDLEWARE = (
|
|||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'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.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
|
@ -149,6 +146,7 @@ INSTALLED_APPS = (
|
|||
'treenode',
|
||||
'vyroci',
|
||||
'sifrovacka',
|
||||
'novinky',
|
||||
|
||||
# Admin upravy:
|
||||
|
||||
|
@ -344,10 +342,6 @@ KOREKTURY_IMG_DIR = os.path.join('korektury', 'img')
|
|||
CISLO_IMG_DIR = os.path.join('cislo', 'img')
|
||||
|
||||
|
||||
# E-MAIL NOTIFICATIONS
|
||||
POSLI_MAILOVOU_NOTIFIKACI = False
|
||||
|
||||
|
||||
|
||||
# Logování chyb
|
||||
class InvalidTemplateVariable(str):
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os.path
|
||||
|
||||
#
|
||||
|
@ -70,5 +68,4 @@ LOGGING['handlers']['registration_error_log']['filename'] = '/home/mam-web/logs/
|
|||
|
||||
|
||||
# E-MAIL NOTIFICATIONS
|
||||
POSLI_MAILOVOU_NOTIFIKACI = True
|
||||
LOCAL_TEST_PROD = "prod"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os.path
|
||||
|
||||
#
|
||||
|
@ -74,7 +72,6 @@ LOGGING['handlers']['registration_error_log']['filename'] = '/home/mam-web/logs/
|
|||
FILE_UPLOAD_PERMISSIONS = 0o440
|
||||
|
||||
# Testování e-mailů
|
||||
POSLI_MAILOVOU_NOTIFIKACI = True
|
||||
EMAIL_BACKEND = 'various.mail_prefixer.PrefixingMailBackend'
|
||||
# TODO Pouze na otestování testu… Zvolit konferu!
|
||||
# XXX: Je to pole, protože implementační detail backendu.
|
||||
|
|
|
@ -1,18 +1,5 @@
|
|||
"""
|
||||
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`
|
||||
Soubor sloužící jako základní „router“, tj. zde se includují veškeré ostatní urls.
|
||||
"""
|
||||
from django.urls import path, include
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
|
|
0
novinky/__init__.py
Normal file
0
novinky/__init__.py
Normal file
5
novinky/admin.py
Normal file
5
novinky/admin.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Novinky
|
||||
|
||||
admin.site.register(Novinky)
|
5
novinky/apps.py
Normal file
5
novinky/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
class NovinkyConfig(AppConfig):
|
||||
name = 'novinky'
|
||||
verbose_name = 'Novinky'
|
45
novinky/migrations/0001_initial.py
Normal file
45
novinky/migrations/0001_initial.py
Normal 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,
|
||||
},
|
||||
),
|
||||
]
|
18
novinky/migrations/0002_manage_novinky.py
Normal file
18
novinky/migrations/0002_manage_novinky.py
Normal 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'},
|
||||
),
|
||||
]
|
13
novinky/migrations/0003_novinky_post.py
Normal file
13
novinky/migrations/0003_novinky_post.py
Normal 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 = [
|
||||
]
|
0
novinky/migrations/__init__.py
Normal file
0
novinky/migrations/__init__.py
Normal file
|
@ -13,6 +13,7 @@ class Novinky(models.Model):
|
|||
verbose_name = 'Novinka'
|
||||
verbose_name_plural = 'Novinky'
|
||||
ordering = ['-datum']
|
||||
db_table = 'seminar_novinky'
|
||||
|
||||
datum = models.DateField(auto_now_add=True)
|
||||
|
0
novinky/views.py
Normal file
0
novinky/views.py
Normal 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_reverse_admin import ReverseModelAdmin
|
||||
import seminar.models as m
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""
|
||||
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
|
||||
"""
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class OdevzdavatkoConfig(AppConfig):
|
||||
name = 'odevzdavatko'
|
||||
verbose_name = 'Odevzdávátko'
|
||||
|
|
|
@ -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 seminar.utils import org_required, resitel_required, viewMethodSwitch, \
|
||||
|
|
|
@ -504,7 +504,7 @@ class NahrajReseniView(LoginRequiredMixin, CreateView):
|
|||
|
||||
EmailMessage(
|
||||
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í?
|
||||
to=list(prijemci),
|
||||
).send()
|
||||
|
|
|
@ -5,10 +5,52 @@ from django.contrib.messages import WARNING, ERROR, SUCCESS
|
|||
import seminar.models as m
|
||||
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)
|
||||
class OsobaAdmin(admin.ModelAdmin):
|
||||
actions = ['synchronizuj_maily', 'udelej_orgem']
|
||||
actions = ['synchronizuj_maily', udelej_orgem, sjednot_telefony]
|
||||
search_fields = ['jmeno', 'prijmeni', 'prezdivka']
|
||||
|
||||
def synchronizuj_maily(self, request, queryset):
|
||||
|
@ -20,27 +62,6 @@ class OsobaAdmin(admin.ModelAdmin):
|
|||
self.message_user(request, "E-maily synchronizovány.")
|
||||
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):
|
||||
model = m.Osoba
|
||||
|
||||
|
@ -53,9 +74,16 @@ class OrganizatorAdmin(ReverseModelAdmin):
|
|||
@admin.register(m.Resitel)
|
||||
class ResitelAdmin(ReverseModelAdmin):
|
||||
search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__prezdivka']
|
||||
list_filter = ['zasilat', 'zasilat_cislo_papirove', 'zasilat_cislo_emailem', 'rok_maturity']
|
||||
ordering = ('osoba__prijmeni', 'osoba__jmeno')
|
||||
inline_type = 'stacked'
|
||||
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.Prijemce)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""
|
||||
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
|
||||
"""
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PersonalniConfig(AppConfig):
|
||||
name = 'personalni'
|
||||
verbose_name = 'Personální' # Má to nějaký použitelnější název?
|
||||
|
|
|
@ -32,7 +32,7 @@ class UdajeForm(forms.Form):
|
|||
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)
|
||||
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)
|
||||
telefon = forms.CharField(widget=TelInput(), label='Telefon', max_length=256, required=False)
|
||||
datum_narozeni = forms.DateField(widget=DateInput(), label='Datum narození', required=False)
|
||||
|
|
14
personalni/migrations/0007_post_split_soustredeni.py
Normal file
14
personalni/migrations/0007_post_split_soustredeni.py
Normal 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 = [
|
||||
]
|
40
personalni/migrations/0008_reforma_pohlavi.py
Normal file
40
personalni/migrations/0008_reforma_pohlavi.py
Normal 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',
|
||||
),
|
||||
]
|
13
personalni/migrations/0009_novinky_pre.py
Normal file
13
personalni/migrations/0009_novinky_pre.py
Normal 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 = [
|
||||
]
|
14
personalni/migrations/0010_novinky_post.py
Normal file
14
personalni/migrations/0010_novinky_post.py
Normal 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 = [
|
||||
]
|
18
personalni/migrations/0011_osloveni_vsechny_choices.py
Normal file
18
personalni/migrations/0011_osloveni_vsechny_choices.py
Normal 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í'),
|
||||
),
|
||||
]
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
|
||||
from django.db import models
|
||||
|
@ -38,8 +37,16 @@ class Osoba(SeminarModelBase):
|
|||
user = models.OneToOneField(settings.AUTH_USER_MODEL, blank=True, null=True,
|
||||
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í)
|
||||
pohlavi_muz = models.BooleanField('pohlaví (muž)', default=False)
|
||||
# Pohlaví nás prakticky nezajímá, reálně.
|
||||
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='')
|
||||
|
||||
|
@ -246,11 +253,19 @@ class Resitel(SeminarModelBase):
|
|||
|
||||
def export_row(self):
|
||||
"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 {
|
||||
'id': self.id,
|
||||
'name': self.osoba.jmeno,
|
||||
'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 '',
|
||||
'email': self.osoba.email,
|
||||
'end-year': self.rok_maturity or '',
|
||||
|
|
|
@ -13,18 +13,18 @@
|
|||
<li>soustředění</li>
|
||||
</ul>
|
||||
</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>
|
||||
|
||||
<hr />
|
||||
<h2><strong>Tvorba čísla</strong></h2>
|
||||
|
||||
<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>
|
||||
<ul>
|
||||
<li><a href="/korektury/">korekturování</a></li>
|
||||
<li><a href="/admin/korektury/korekturovanepdf/add/">přidat pdf k opravám</a></li>
|
||||
<li><a href="{% url 'korektury_list' %}">korekturování</a></li>
|
||||
<li><a href="{% url 'admin:korektury_korekturovanepdf_add' %}">přidat pdf k opravám</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -70,15 +70,15 @@
|
|||
<h2><strong>Soustředění</strong></h2>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
</ul>
|
||||
</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>
|
||||
<li>vytvoření galerie</li>
|
||||
<li>stažení seznamu účastníků</li>
|
||||
|
@ -91,7 +91,7 @@
|
|||
<h2><strong>Můj profil</strong></h2>
|
||||
|
||||
<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>
|
||||
|
||||
<hr/>
|
||||
|
@ -108,6 +108,6 @@
|
|||
</ul>
|
||||
|
||||
<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 %}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
{% 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.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.telefon %}
|
||||
{% include "personalni/udaje/prihlaska_field.html" with field=form.datum_narozeni %}
|
||||
|
|
|
@ -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.contrib.auth.decorators import login_required
|
||||
from . import views
|
||||
|
|
|
@ -4,7 +4,7 @@ from django.views import generic
|
|||
from django.db.models import Q, Count, Min
|
||||
from django.views.decorators.debug import sensitive_post_parameters
|
||||
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.db import transaction
|
||||
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
|
||||
osoba_edit.jmeno = fcd['jmeno']
|
||||
osoba_edit.prijmeni = fcd['prijmeni']
|
||||
osoba_edit.pohlavi_muz = fcd['pohlavi_muz']
|
||||
osoba_edit.osloveni = fcd['osloveni']
|
||||
osoba_edit.email = fcd['email']
|
||||
osoba_edit.telefon = fcd['telefon']
|
||||
osoba_edit.ulice = fcd['ulice']
|
||||
|
@ -209,7 +209,7 @@ def prihlaskaView(request):
|
|||
o = s.Osoba(
|
||||
jmeno = fcd['jmeno'],
|
||||
prijmeni = fcd['prijmeni'],
|
||||
pohlavi_muz = fcd['pohlavi_muz'],
|
||||
osloveni = fcd['osloveni'],
|
||||
email = fcd['email'],
|
||||
telefon = fcd.get('telefon',''),
|
||||
datum_narozeni = fcd.get('datum_narozeni',None),
|
||||
|
@ -242,7 +242,7 @@ def prihlaskaView(request):
|
|||
|
||||
# Porovnání údajů
|
||||
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 = []
|
||||
for attr in osoba_attrs:
|
||||
new = getattr(o, attr)
|
||||
|
@ -318,6 +318,12 @@ def prihlaskaView(request):
|
|||
# Jen hloupé rozhazovátko
|
||||
def profilView(request):
|
||||
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'):
|
||||
return OrgoRozcestnikView.as_view()(request)
|
||||
if user.has_perm('auth.resitel'):
|
||||
|
@ -339,7 +345,7 @@ def dataResiteluCsvResponse(queryset, columns=None, with_header=True):
|
|||
'osoba__telefon',
|
||||
'osoba__user__username',
|
||||
'osoba__datum_narozeni',
|
||||
'osoba__pohlavi_muz',
|
||||
'osoba__osloveni',
|
||||
'osoba__ulice',
|
||||
'osoba__mesto',
|
||||
'osoba__psc',
|
||||
|
@ -367,7 +373,7 @@ def dataResiteluCsvResponse(queryset, columns=None, with_header=True):
|
|||
'osoba__telefon': 'telefon',
|
||||
'osoba__user__username': 'user',
|
||||
'osoba__datum_narozeni': 'datum_narozeni',
|
||||
'osoba__pohlavi_muz': 'pohlavi_muz',
|
||||
'osoba__osloveni': 'osloveni',
|
||||
'osoba__ulice': 'ulice',
|
||||
'osoba__mesto': 'mesto',
|
||||
'osoba__psc': 'psc',
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from django.contrib import admin
|
||||
from django.contrib import messages
|
||||
from reversion.admin import VersionAdmin
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# coding: utf-8
|
||||
from django import forms
|
||||
|
||||
class NewPrednaskyForm(forms.Form):
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue