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 | ||||||
|  | @ -141,6 +144,54 @@ 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 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -28,6 +28,30 @@ def resi_v_rocniku(rocnik, cislo=None): | ||||||
| 			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): | ||||||
| 	""" Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali | 	""" Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue