Merge pull request 'ruzne exporty resitelu - zatím určitě ne merge xd spíš potřebuji zpětnou vazbu...' (!89) from export_resitelskych_dat into master
Reviewed-on: #89
This commit is contained in:
commit
ff7d36a965
5 changed files with 236 additions and 1 deletions
88
personalni/templates/personalni/profil/export_lidi.html
Normal file
88
personalni/templates/personalni/profil/export_lidi.html
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h2><strong>Export lidí</strong></h2>
|
||||||
|
|
||||||
|
<select name="select-one" id="select-one">
|
||||||
|
<option value="0">---</option>
|
||||||
|
<option value="1">Řešitelé čísla</option>
|
||||||
|
<option value="2">Řešitelé ročníku</option>
|
||||||
|
<option value="3">Všichni řešitelé, kteří ještě neodmaturovali</option>
|
||||||
|
<option value="4">Organizátoři soustředění</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select name="select-two" id="select-two">
|
||||||
|
<!-- will be filled with ajax -->
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button id="download-button">Stáhnout</button>
|
||||||
|
|
||||||
|
<script defer>
|
||||||
|
const select_one = document.getElementById("select-one")
|
||||||
|
const select_two = document.getElementById("select-two")
|
||||||
|
const download_button = document.getElementById("download-button")
|
||||||
|
|
||||||
|
download_button.style.display = 'none'
|
||||||
|
select_two.style.display = 'none'
|
||||||
|
|
||||||
|
const fetch_dict_string = '{{ typy_exportu|safe }}'
|
||||||
|
const fetch_dict = JSON.parse(fetch_dict_string)
|
||||||
|
|
||||||
|
|
||||||
|
select_one.addEventListener('change', (e) => {
|
||||||
|
value = e.target.value
|
||||||
|
select_two.style.display = 'none'
|
||||||
|
select_two.innerHTML = ''
|
||||||
|
// puvodni stav
|
||||||
|
if (value == 0) {
|
||||||
|
download_button.style.display = 'none'
|
||||||
|
select_two.style.display = 'none'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// v tomto pripade muzeme rovnou stahnout
|
||||||
|
if (!(value in fetch_dict)) {
|
||||||
|
download_button.style.display = 'block'
|
||||||
|
select_two.style.display = 'none'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
download_button.style.display = 'none'
|
||||||
|
fetch("/profil/exporty_lidi/get/" + value)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const option = document.createElement('option')
|
||||||
|
option.value = 0
|
||||||
|
option.text = '---'
|
||||||
|
select_two.appendChild(option)
|
||||||
|
for (const [key, value] of Object.entries(data)) {
|
||||||
|
const option = document.createElement('option')
|
||||||
|
option.value = value["id"]
|
||||||
|
option.text = value["display"]
|
||||||
|
select_two.appendChild(option)
|
||||||
|
}
|
||||||
|
select_two.style.display = 'block'
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
select_two.addEventListener('change', (e) => {
|
||||||
|
value = e.target.value
|
||||||
|
if (value == 0) {
|
||||||
|
download_button.style.display = 'none'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
download_button.style.display = 'block'
|
||||||
|
})
|
||||||
|
|
||||||
|
download_button.addEventListener('click', (e) => {
|
||||||
|
if (select_two.innerHTML == '') {
|
||||||
|
window.location.href = "/profil/exporty_lidi/get_csv_only_one_step/" + select_one.value
|
||||||
|
} else {
|
||||||
|
window.location.href = "/profil/exporty_lidi/get_csv/" + select_one.value + "/" + select_two.value
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -107,6 +107,13 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<h2><strong>Exporty dat lidí v semináří</strong></h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="{% url 'exporty_lidi' %}">dostupné exporty</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
<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>
|
<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 %}
|
||||||
|
|
|
@ -38,6 +38,28 @@ urlpatterns = [
|
||||||
'org/propagace/jak-se-dozvedeli/',
|
'org/propagace/jak-se-dozvedeli/',
|
||||||
org_required(views.JakSeDozvedeliView.as_view()),
|
org_required(views.JakSeDozvedeliView.as_view()),
|
||||||
name='jak_se_dozvedeli'
|
name='jak_se_dozvedeli'
|
||||||
|
),
|
||||||
|
|
||||||
|
# export dat o řešitelích
|
||||||
|
path(
|
||||||
|
'profil/exporty_lidi',
|
||||||
|
org_required(views.ExportLidiView.as_view()),
|
||||||
|
name='exporty_lidi',
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'profil/exporty_lidi/get/<int:type>',
|
||||||
|
org_required(views.get_export_options),
|
||||||
|
name='exporty_lidi_options',
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'profil/exporty_lidi/get_csv_only_one_step/<int:type>',
|
||||||
|
org_required(views.download_export_csv_only_first_step),
|
||||||
|
name='exporty_lidi_data',
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'profil/exporty_lidi/get_csv/<int:type>/<int:id>',
|
||||||
|
org_required(views.download_export_csv),
|
||||||
|
name='exporty_lidi_download',
|
||||||
)
|
)
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -20,13 +20,16 @@ from django.utils import timezone
|
||||||
import personalni.models as m
|
import personalni.models as m
|
||||||
from soustredeni.models import Soustredeni
|
from soustredeni.models import Soustredeni
|
||||||
from odevzdavatko.models import Hodnoceni
|
from odevzdavatko.models import Hodnoceni
|
||||||
from tvorba.models import Clanek, Uloha, Tema
|
from tvorba.models import Clanek, Uloha, Tema, Cislo, Rocnik
|
||||||
|
import tvorba.utils as tvorba_utils
|
||||||
from various.models import Nastaveni
|
from various.models import Nastaveni
|
||||||
from .forms import PrihlaskaForm, ProfileEditForm, PoMaturiteProfileEditForm
|
from .forms import PrihlaskaForm, ProfileEditForm, PoMaturiteProfileEditForm
|
||||||
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
import logging
|
import logging
|
||||||
import csv
|
import csv
|
||||||
|
from enum import Enum
|
||||||
|
import json
|
||||||
|
|
||||||
from various.views.pomocne import formularOKView
|
from various.views.pomocne import formularOKView
|
||||||
from various.autentizace.views import LoginView
|
from various.autentizace.views import LoginView
|
||||||
|
@ -140,7 +143,55 @@ class OrgoRozcestnikView(TemplateView):
|
||||||
|
|
||||||
#content_type = 'text/plain; charset=UTF8'
|
#content_type = 'text/plain; charset=UTF8'
|
||||||
#XXX
|
#XXX
|
||||||
|
|
||||||
|
class PrvniTypExportu(Enum):
|
||||||
|
CISLA = 1
|
||||||
|
ROCNIKU = 2
|
||||||
|
SOUSTREDENI = 4
|
||||||
|
|
||||||
|
class ExportLidiView(TemplateView):
|
||||||
|
template_name = 'personalni/profil/export_lidi.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['typy_exportu'] = json.dumps({member.value: member.name.lower().capitalize() for member in PrvniTypExportu})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
def get_export_options(request, type):
|
||||||
|
if type == PrvniTypExportu.CISLA.value:
|
||||||
|
data = [{"id": c.id, "display": str(c)} for c in Cislo.objects.all()]
|
||||||
|
if type == PrvniTypExportu.ROCNIKU.value:
|
||||||
|
data = [{"id": r.id, "display": str(r)} for r in Rocnik.objects.all()]
|
||||||
|
if type == PrvniTypExportu.SOUSTREDENI.value:
|
||||||
|
data = [{"id": s.id, "display": str(s)} for s in Soustredeni.objects.all()]
|
||||||
|
return HttpResponse(json.dumps(data), content_type='application/json')
|
||||||
|
|
||||||
|
def download_export_csv_only_first_step(request, type):
|
||||||
|
if type == 3:
|
||||||
|
response = dataResiteluCsvResponse(tvorba_utils.resitele_co_neodmaturovali())
|
||||||
|
response['Content-Disposition'] = 'attachment; filename="resitele_co_neodmaturovali.csv"'
|
||||||
|
return response
|
||||||
|
|
||||||
|
def download_export_csv(request, type, id):
|
||||||
|
if type == PrvniTypExportu.CISLA.value:
|
||||||
|
response = dataResiteluCsvResponse(tvorba_utils.resi_cislo(Cislo.objects.get(id=id)))
|
||||||
|
name = str(Cislo.objects.get(id=id)).replace(" ", "_") + "_resitele_cisla.csv"
|
||||||
|
response['Content-Disposition'] = 'attachment; filename="' + name + '"'
|
||||||
|
return response
|
||||||
|
if type == PrvniTypExportu.ROCNIKU.value:
|
||||||
|
response = dataResiteluCsvResponse(tvorba_utils.resi_v_rocniku(Rocnik.objects.get(id=id)))
|
||||||
|
name = str(Rocnik.objects.get(id=id)).replace(" ", "_") + "_resitele_rocniku.csv"
|
||||||
|
response['Content-Disposition'] = 'attachment; filename="' + name + '"'
|
||||||
|
return response
|
||||||
|
if type == PrvniTypExportu.SOUSTREDENI.value:
|
||||||
|
soustredeni = Soustredeni.objects.get(id=id)
|
||||||
|
organizatori = soustredeni.organizatori.all()
|
||||||
|
organizatoriOsoby = Osoba.objects.filter(org__in=organizatori)
|
||||||
|
response = dataOsobCsvResponse(organizatoriOsoby, columns=("jmeno", "prijmeni", "email", "telefon",))
|
||||||
|
name = str(soustredeni).replace(" ", "_") + "_organizatori_soustredeni.csv"
|
||||||
|
response['Content-Disposition'] = 'attachment; filename="' + name + '"'
|
||||||
|
return response
|
||||||
|
|
||||||
class ResitelView(LoginRequiredMixin,generic.DetailView):
|
class ResitelView(LoginRequiredMixin,generic.DetailView):
|
||||||
model = m.Resitel
|
model = m.Resitel
|
||||||
|
@ -470,3 +521,46 @@ def dataResiteluCsvResponse(queryset, columns=None, with_header=True):
|
||||||
writer.writerows(queryset_list)
|
writer.writerows(queryset_list)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def dataOsobCsvResponse(queryset, columns=None, with_header=True):
|
||||||
|
"""Pomocná funkce pro vracení dat osob jako CSV. Musí dostat správný QuerySet, který dává Ososby"""
|
||||||
|
|
||||||
|
default_columns = (
|
||||||
|
'id',
|
||||||
|
'jmeno',
|
||||||
|
'prijmeni',
|
||||||
|
'prezdivka',
|
||||||
|
'email',
|
||||||
|
'telefon',
|
||||||
|
'datum_narozeni',
|
||||||
|
'osloveni',
|
||||||
|
'ulice',
|
||||||
|
'mesto',
|
||||||
|
'psc',
|
||||||
|
'stat',
|
||||||
|
'jak_se_dozvedeli',
|
||||||
|
'poznamka',
|
||||||
|
'datum_registrace',
|
||||||
|
'datum_souhlasu_udaje',
|
||||||
|
'datum_souhlasu_zasilani',
|
||||||
|
)
|
||||||
|
|
||||||
|
if columns is None: columns = default_columns
|
||||||
|
|
||||||
|
def get_field_name(column_name):
|
||||||
|
return column_name
|
||||||
|
|
||||||
|
response = HttpResponse(content_type='text/csv')
|
||||||
|
writer = csv.writer(response)
|
||||||
|
|
||||||
|
# První řádek je záhlaví
|
||||||
|
if with_header:
|
||||||
|
writer.writerow(map(get_field_name, columns))
|
||||||
|
|
||||||
|
# Data:
|
||||||
|
queryset_list = queryset.values_list(*columns)
|
||||||
|
writer.writerows(queryset_list)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,30 @@ def resi_v_rocniku(rocnik, cislo=None):
|
||||||
reseni__hodnoceni__deadline_body__cislo__rocnik=rocnik,
|
reseni__hodnoceni__deadline_body__cislo__rocnik=rocnik,
|
||||||
reseni__hodnoceni__deadline_body__cislo__poradi__lte=cislo.poradi
|
reseni__hodnoceni__deadline_body__cislo__poradi__lte=cislo.poradi
|
||||||
).distinct()
|
).distinct()
|
||||||
|
|
||||||
|
def resi_cislo(cislo):
|
||||||
|
""" Vrátí seznam řešitelů, co vyřešili nějaký problém v daném čísle.
|
||||||
|
Parametry:
|
||||||
|
cislo (typu Cislo) číslo, ve kterém chci řešitele, co něco odevzdali
|
||||||
|
Výstup:
|
||||||
|
QuerySet objektů typu Resitel
|
||||||
|
"""
|
||||||
|
|
||||||
|
return personalni.models.Resitel.objects.filter(
|
||||||
|
reseni__hodnoceni__deadline_body__cislo=cislo
|
||||||
|
).distinct()
|
||||||
|
|
||||||
|
def resitele_co_neodmaturovali():
|
||||||
|
""" Vrátí seznam řešitelů, co ještě neodmaturovali.
|
||||||
|
Pokud ještě není srpen, tak zahrnuje i ty, kteří odmaturovali letos.
|
||||||
|
|
||||||
|
Výstup:
|
||||||
|
QuerySet objektů typu Resitel """
|
||||||
|
from datetime import datetime
|
||||||
|
current_year = datetime.now().year
|
||||||
|
if datetime.now().month < 8:
|
||||||
|
current_year -= 1
|
||||||
|
return personalni.models.Resitel.objects.filter(rok_maturity__gte=current_year)
|
||||||
|
|
||||||
|
|
||||||
def aktivniResitele(cislo, pouze_letosni=False):
|
def aktivniResitele(cislo, pouze_letosni=False):
|
||||||
|
|
Loading…
Reference in a new issue