AESOP přestal býti aktuální
This commit is contained in:
parent
1868f96594
commit
3631ec3c5b
13 changed files with 2 additions and 236 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -25,9 +25,6 @@ TODO
|
||||||
# .htpasswd kvůli přihlášení
|
# .htpasswd kvůli přihlášení
|
||||||
.htpasswd
|
.htpasswd
|
||||||
|
|
||||||
# .htpasswd pro AESOPa
|
|
||||||
/.htpasswd-aesop
|
|
||||||
|
|
||||||
# reversion kvůli historii objektů v reversion
|
# reversion kvůli historii objektů v reversion
|
||||||
**/reversion
|
**/reversion
|
||||||
|
|
||||||
|
@ -36,4 +33,4 @@ TODO
|
||||||
|
|
||||||
# dokumentace
|
# dokumentace
|
||||||
docs/_build
|
docs/_build
|
||||||
docs/modules
|
docs/modules
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
"""
|
|
||||||
Obsahuje vše, co se týká aesopu (exportu, který po nás vyžaduje OPMK).
|
|
||||||
"""
|
|
|
@ -1,8 +0,0 @@
|
||||||
"""
|
|
||||||
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
|
|
||||||
"""
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class AesopConfig(AppConfig):
|
|
||||||
name = 'aesop'
|
|
|
@ -1,30 +0,0 @@
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.utils.encoding import force_text
|
|
||||||
|
|
||||||
|
|
||||||
class OvvpFile:
|
|
||||||
def __init__(self):
|
|
||||||
# { header: value, ... }
|
|
||||||
self.headers = {}
|
|
||||||
# [ 'column-name', ... ]
|
|
||||||
self.columns = []
|
|
||||||
# [ { column: value, ...}, ...]
|
|
||||||
self.rows = []
|
|
||||||
|
|
||||||
def to_lines(self):
|
|
||||||
# header
|
|
||||||
for hk in sorted(self.headers.keys()):
|
|
||||||
yield f'{hk}\t{self.headers[hk]}\n'
|
|
||||||
yield '\n'
|
|
||||||
# columns
|
|
||||||
yield '\t'.join(self.columns) + '\n'
|
|
||||||
# rows
|
|
||||||
for r in self.rows:
|
|
||||||
yield '\t'.join([force_text(r[c]) for c in self.columns]) + '\n'
|
|
||||||
|
|
||||||
def to_string(self):
|
|
||||||
return ''.join(self.to_lines())
|
|
||||||
|
|
||||||
# Pozn: tohle je ta jediná funkce, která se reálně používá…
|
|
||||||
def to_HttpResponse(self):
|
|
||||||
return HttpResponse(self.to_string(), content_type='text/plain; charset=utf-8')
|
|
|
@ -1,27 +0,0 @@
|
||||||
"""
|
|
||||||
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
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path(
|
|
||||||
'aesop-export/mam-rocnik-<int:prvni_rok>.csv',
|
|
||||||
views.ExportRocnikView.as_view(),
|
|
||||||
name='seminar_export_rocnik'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'aesop-export/mam-sous-<str:datum_zacatku>.csv',
|
|
||||||
views.ExportSousView.as_view(),
|
|
||||||
name='seminar_export_sous'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'aesop-export/index.csv',
|
|
||||||
views.ExportIndexView.as_view(),
|
|
||||||
name='seminar_export_index'
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,16 +0,0 @@
|
||||||
import datetime
|
|
||||||
|
|
||||||
from django.utils.encoding import force_text
|
|
||||||
|
|
||||||
from aesop.ovvpfile import OvvpFile
|
|
||||||
|
|
||||||
|
|
||||||
def default_ovvpfile(event, rocnik):
|
|
||||||
of = OvvpFile()
|
|
||||||
of.headers['version'] = '1'
|
|
||||||
of.headers['event'] = event
|
|
||||||
of.headers['year'] = force_text(rocnik.prvni_rok)
|
|
||||||
of.headers['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
of.headers['id-scope'] = 'mam'
|
|
||||||
of.headers['id-generation'] = '1'
|
|
||||||
return of
|
|
101
aesop/views.py
101
aesop/views.py
|
@ -1,101 +0,0 @@
|
||||||
"""
|
|
||||||
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
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.views import generic
|
|
||||||
from django.utils.encoding import force_text
|
|
||||||
|
|
||||||
from .utils import default_ovvpfile
|
|
||||||
from seminar.models import Rocnik, Soustredeni
|
|
||||||
from vysledkovky import utils
|
|
||||||
from seminar.utils import aktivniResitele
|
|
||||||
|
|
||||||
class ExportIndexView(generic.View):
|
|
||||||
def get(self, request):
|
|
||||||
ls = []
|
|
||||||
for r in Rocnik.objects.filter(exportovat = True):
|
|
||||||
url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok})
|
|
||||||
ls.append(url.split('/')[-1])
|
|
||||||
for s in Soustredeni.objects.filter(exportovat = True):
|
|
||||||
url = reverse('seminar_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()})
|
|
||||||
ls.append(url.split('/')[-1])
|
|
||||||
|
|
||||||
return HttpResponse('\n'.join(ls) + '\n', content_type='text/plain; charset=utf-8')
|
|
||||||
|
|
||||||
|
|
||||||
class ExportSousView(generic.View):
|
|
||||||
|
|
||||||
def get(self, request, datum_zacatku=None):
|
|
||||||
try:
|
|
||||||
dz = django.utils.dateparse.parse_date(datum_zacatku)
|
|
||||||
except:
|
|
||||||
dz = None
|
|
||||||
if dz is None:
|
|
||||||
raise django.http.Http404()
|
|
||||||
|
|
||||||
s = get_object_or_404(Soustredeni, datum_zacatku=dz, exportovat=True)
|
|
||||||
|
|
||||||
akce = {Soustredeni.TYP_JARNI: 'MaM.sous.jaro',
|
|
||||||
Soustredeni.TYP_PODZIMNI: 'MaM.sous.podzim',
|
|
||||||
Soustredeni.TYP_VIKEND: 'MaM.vikend',
|
|
||||||
}[s.typ]
|
|
||||||
|
|
||||||
of = default_ovvpfile(akce, s.rocnik)
|
|
||||||
of.headers['x-event-begin'] = s.datum_zacatku.isoformat()
|
|
||||||
of.headers['x-event-end'] = s.datum_konce.isoformat()
|
|
||||||
of.headers['x-event-location'] = s.misto
|
|
||||||
of.headers['comment'] = u'MaM-Web export ucastniku soustredeni v {x-event-location} od {x-event-begin} do {x-event-end}'.format(**of.headers)
|
|
||||||
of.columns = ['id', 'name', 'surname', 'gender', 'email', 'end-year', 'school', 'school-name']
|
|
||||||
|
|
||||||
for u in s.ucastnici.all():
|
|
||||||
of.rows.append(u.export_row())
|
|
||||||
|
|
||||||
return of.to_HttpResponse()
|
|
||||||
|
|
||||||
# POZOR! Předělání na nový model neotestováno v reálu (ale zase jen drobné změny)
|
|
||||||
class ExportRocnikView(generic.View):
|
|
||||||
|
|
||||||
def get(self, request, prvni_rok=None):
|
|
||||||
try:
|
|
||||||
pr = int(prvni_rok)
|
|
||||||
except:
|
|
||||||
pr = None
|
|
||||||
if pr is None:
|
|
||||||
raise django.http.Http404()
|
|
||||||
|
|
||||||
rocnik = get_object_or_404(Rocnik, prvni_rok=pr, exportovat=True)
|
|
||||||
cislo = rocnik.posledni_zverejnena_vysledkovka_cislo()
|
|
||||||
resitele = aktivniResitele(cislo, True)
|
|
||||||
slovnik_body = utils.secti_body_za_rocnik(cislo, resitele, False)
|
|
||||||
setrizeni_resitele, body = utils.setrid_resitele_a_body(slovnik_body)
|
|
||||||
|
|
||||||
of = default_ovvpfile('MaM.rocnik', rocnik)
|
|
||||||
of.headers['comment'] = u'MaM-Web export aktivnich resitelu rocniku {rocnik} do cisla {cislo}'.format(rocnik=rocnik, cislo=cislo)
|
|
||||||
of.columns = ['id', 'name', 'surname', 'gender', 'born', 'email', 'end-year',
|
|
||||||
'street', 'town', 'postcode', 'country', 'spam-flag', 'spam-date',
|
|
||||||
'school', 'school-name', 'points', 'rank',]
|
|
||||||
|
|
||||||
resitele_slovnik = {}
|
|
||||||
for r in resitele:
|
|
||||||
resitele_slovnik[r.id] = r
|
|
||||||
|
|
||||||
# počítání pořadí řešitelů
|
|
||||||
posledni_body = 100000
|
|
||||||
posledni_poradi = 0
|
|
||||||
for i in range(len(setrizeni_resitele)):
|
|
||||||
rd = resitele_slovnik[setrizeni_resitele[i]].export_row()
|
|
||||||
|
|
||||||
if posledni_body > body[i]:
|
|
||||||
posledni_body = body[i]
|
|
||||||
posledni_poradi = i + 1
|
|
||||||
rd['rank'] = posledni_poradi
|
|
||||||
rd['points'] = body[i]
|
|
||||||
|
|
||||||
of.rows.append(rd)
|
|
||||||
|
|
||||||
return of.to_HttpResponse()
|
|
|
@ -144,7 +144,6 @@ INSTALLED_APPS = (
|
||||||
'various',
|
'various',
|
||||||
'various.autentizace',
|
'various.autentizace',
|
||||||
'api',
|
'api',
|
||||||
'aesop',
|
|
||||||
'odevzdavatko',
|
'odevzdavatko',
|
||||||
'vysledkovky',
|
'vysledkovky',
|
||||||
'personalni',
|
'personalni',
|
||||||
|
|
|
@ -12,7 +12,6 @@ Soubor sloužící jako základní „router“, tj. zde se includují veškeré
|
||||||
- :mod:`various.autentizace.urls`
|
- :mod:`various.autentizace.urls`
|
||||||
- :mod:`api.urls`
|
- :mod:`api.urls`
|
||||||
- :mod:`treenode.urls`
|
- :mod:`treenode.urls`
|
||||||
- :mod:`aesop.urls`
|
|
||||||
- ``comments_dj/`` :mod:`django_comments.urls`
|
- ``comments_dj/`` :mod:`django_comments.urls`
|
||||||
"""
|
"""
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
@ -59,9 +58,6 @@ urlpatterns = [
|
||||||
# treenode (ma vlastni podadresare)
|
# treenode (ma vlastni podadresare)
|
||||||
path('', include('treenode.urls')),
|
path('', include('treenode.urls')),
|
||||||
|
|
||||||
# Aesop (ma vlastni podadresare)
|
|
||||||
path('', include('aesop.urls')),
|
|
||||||
|
|
||||||
# Comments (interni i verejne)
|
# Comments (interni i verejne)
|
||||||
path('comments_dj/', include('django_comments.urls')),
|
path('comments_dj/', include('django_comments.urls')),
|
||||||
|
|
||||||
|
|
|
@ -115,14 +115,10 @@ class Osoba(SeminarModelBase):
|
||||||
u.save()
|
u.save()
|
||||||
super().save()
|
super().save()
|
||||||
|
|
||||||
#
|
|
||||||
# Mělo by být částečně vytaženo z Aesopa
|
|
||||||
# viz https://ovvp.mff.cuni.cz/wiki/aesop/export-skol.
|
|
||||||
#
|
|
||||||
|
|
||||||
@reversion.register(ignore_duplicates=True)
|
@reversion.register(ignore_duplicates=True)
|
||||||
class Skola(SeminarModelBase):
|
class Skola(SeminarModelBase):
|
||||||
|
# Mělo by být částečně vytaženo z Aesopa
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'seminar_skoly'
|
db_table = 'seminar_skoly'
|
||||||
verbose_name = 'Škola'
|
verbose_name = 'Škola'
|
||||||
|
@ -243,30 +239,6 @@ class Resitel(SeminarModelBase):
|
||||||
poznamka = models.TextField('neveřejná poznámka', blank=True,
|
poznamka = models.TextField('neveřejná poznámka', blank=True,
|
||||||
help_text='Neveřejná poznámka k řešiteli (plain text)')
|
help_text='Neveřejná poznámka k řešiteli (plain text)')
|
||||||
|
|
||||||
|
|
||||||
def export_row(self):
|
|
||||||
"Slovnik pro pouziti v AESOP exportu"
|
|
||||||
return {
|
|
||||||
'id': self.id,
|
|
||||||
'name': self.osoba.jmeno,
|
|
||||||
'surname': self.osoba.prijmeni,
|
|
||||||
'gender': 'M' if self.osoba.pohlavi_muz else 'F',
|
|
||||||
'born': self.osoba.datum_narozeni.isoformat() if self.osoba.datum_narozeni else '',
|
|
||||||
'email': self.osoba.email,
|
|
||||||
'end-year': self.rok_maturity or '',
|
|
||||||
|
|
||||||
'street': self.osoba.ulice,
|
|
||||||
'town': self.osoba.mesto,
|
|
||||||
'postcode': self.osoba.psc,
|
|
||||||
'country': self.osoba.stat,
|
|
||||||
|
|
||||||
'spam-flag': 'Y' if self.osoba.datum_souhlasu_zasilani else '',
|
|
||||||
'spam-date': self.osoba.datum_souhlasu_zasilani.isoformat() if self.osoba.datum_souhlasu_zasilani else '',
|
|
||||||
|
|
||||||
'school': self.skola.aesop_id if self.skola else '',
|
|
||||||
'school-name': str(self.skola) if self.skola else 'Skola neni znama',
|
|
||||||
}
|
|
||||||
|
|
||||||
def rocnik(self, rocnik):
|
def rocnik(self, rocnik):
|
||||||
"""Vrati skolni rocnik resitele pro zadany Rocnik.
|
"""Vrati skolni rocnik resitele pro zadany Rocnik.
|
||||||
Vraci '' pro neznamy rok maturity resitele, Z* pro ekvivalent ZŠ."""
|
Vraci '' pro neznamy rok maturity resitele, Z* pro ekvivalent ZŠ."""
|
||||||
|
|
|
@ -32,13 +32,6 @@ server {
|
||||||
location /media/ {
|
location /media/ {
|
||||||
root /akce/mam/www/mamweb-test/;
|
root /akce/mam/www/mamweb-test/;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /aesop-export/ {
|
|
||||||
auth_basic "AESOP API";
|
|
||||||
auth_basic_user_file /akce/mam/www/mamweb-test/.htpasswd-aesop;
|
|
||||||
try_files $uri @mamweb_test;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
location / { try_files $uri @mamweb_test; }
|
location / { try_files $uri @mamweb_test; }
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,6 @@ server {
|
||||||
|
|
||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
|
|
||||||
location /aesop-export/ {
|
|
||||||
auth_basic "AESOP API";
|
|
||||||
auth_basic_user_file /akce/mam/www/mamweb-prod/.htpasswd-aesop;
|
|
||||||
try_files $uri @mamweb_prod;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /static/ {
|
location /static/ {
|
||||||
root /akce/mam/www/mamweb-prod/;
|
root /akce/mam/www/mamweb-prod/;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue