592 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			592 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import tempfile
 | |
| import subprocess
 | |
| import shutil
 | |
| import http
 | |
| 
 | |
| from django.shortcuts import render
 | |
| from django.urls import reverse
 | |
| 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, AnonymousUser
 | |
| from django.contrib.auth.mixins import LoginRequiredMixin
 | |
| from django.contrib.staticfiles.finders import find
 | |
| from django.db import transaction
 | |
| from django.http import HttpResponse
 | |
| from django.utils import timezone
 | |
| 
 | |
| 
 | |
| import personalni.models as m
 | |
| from soustredeni.models import Soustredeni
 | |
| from odevzdavatko.models import Hodnoceni
 | |
| from tvorba.models import Clanek, Uloha, Tema, Cislo, Rocnik
 | |
| import tvorba.utils as tvorba_utils
 | |
| from various.models import Nastaveni
 | |
| from .forms import PrihlaskaForm, ProfileEditForm, PoMaturiteProfileEditForm
 | |
| 
 | |
| from datetime import date
 | |
| import logging
 | |
| import csv
 | |
| from enum import Enum
 | |
| import json
 | |
| 
 | |
| from various.views.pomocne import formularOKView
 | |
| from various.autentizace.views import LoginView
 | |
| from various.autentizace.utils import posli_reset_hesla
 | |
| 
 | |
| from django.forms.models import model_to_dict
 | |
| 
 | |
| from .models import Organizator, Osoba 
 | |
| 
 | |
| 
 | |
| def aktivniOrganizatori(datum=timezone.now()):
 | |
| 	return Organizator.objects.exclude(
 | |
| 		organizuje_do__isnull=False,
 | |
| 		organizuje_do__lt=datum
 | |
| 	).order_by('osoba__jmeno')
 | |
| 
 | |
| 
 | |
| class CojemamOrganizatoriView(generic.ListView):
 | |
| 	model = Organizator
 | |
| 	template_name = 'personalni/organizatori.html'
 | |
| 	queryset = aktivniOrganizatori()
 | |
| 
 | |
| 	def get_context_data(self, **kwargs):
 | |
| 		context = super(CojemamOrganizatoriView, self).get_context_data(**kwargs)
 | |
| 		context['aktivni'] = True
 | |
| 		return context
 | |
| 
 | |
| 
 | |
| class CojemamOrganizatoriStariView(generic.ListView):
 | |
| 	model = Organizator
 | |
| 	template_name = 'personalni/organizatori.html'
 | |
| 	queryset = Organizator.objects.exclude(
 | |
| 		id__in=aktivniOrganizatori()
 | |
| 	).order_by('-organizuje_do')
 | |
| 
 | |
| class JakSeDozvedeliView(generic.ListView):
 | |
| 	model = Osoba
 | |
| 	template_name = 'personalni/jak_se_dozvedeli.html'
 | |
| 	queryset = Osoba.objects.order_by('-datum_registrace')
 | |
| 
 | |
| 
 | |
| def obalkyView(request, resitele):
 | |
| 	if len(resitele) == 0:
 | |
| 		return HttpResponse(
 | |
| 			render(request, 'universal.html', {
 | |
| 				'title': 'Není pro koho vyrobit obálky.',
 | |
| 				'text': 'Právě ses pokusil/a vygenerovat obálky pro prázdnou množinu lidí. Můžeš to zkusit změnit, případně se zeptej webařů :-)',
 | |
| 			}),
 | |
| 			status=http.HTTPStatus.NOT_FOUND,
 | |
| 		)
 | |
| 
 | |
| 	tex = render(request, 'personalni/obalky.tex', {
 | |
| 		'resitele': resitele
 | |
| 	}).content
 | |
| 
 | |
| 	with tempfile.TemporaryDirectory() as tempdir:
 | |
| 		with open(tempdir+"/obalky.tex", "w") as texfile:
 | |
| 			texfile.write(tex.decode())
 | |
| 		shutil.copy(find('personalni/lisak.pdf'), tempdir)
 | |
| 		subprocess.call(["pdflatex", "obalky.tex"], cwd=tempdir)
 | |
| 
 | |
| 		with open(tempdir+"/obalky.pdf", "rb") as pdffile:
 | |
| 			response = HttpResponse(pdffile.read(), content_type='application/pdf')
 | |
| 	return response
 | |
| 
 | |
| 
 | |
| class OrgoRozcestnikView(TemplateView):
 | |
| 	""" Zobrazí organizátorský rozcestník."""
 | |
| 
 | |
| 	template_name = 'personalni/profil/orgorozcestnik.html'
 | |
| 
 | |
| 	def get_context_data(self, **kwargs):
 | |
| 		context = super().get_context_data(**kwargs)
 | |
| 		context['posledni_soustredeni'] = Soustredeni.objects.order_by('-datum_konce').first()
 | |
| 		nastaveni = Nastaveni.objects.first()
 | |
| 		aktualni_rocnik = nastaveni.aktualni_rocnik
 | |
| 		context['posledni_cislo_url'] = nastaveni.aktualni_cislo.verejne_url()
 | |
| 		# TODO možná chceme odkazovat na právě rozpracované číslo, a ne to poslední vydané
 | |
| 		# pokud nechceme haluzit kód (= poradi) dalšího čísla, bude asi potřeba jít
 | |
| 		# přes treenody (a dát si přitom pozor na MezicisloNode)
 | |
| 
 | |
| 		neobodovana_reseni = Hodnoceni.objects.filter(body__isnull=True)
 | |
| 		reseni_mimo_cislo = Hodnoceni.objects.filter(deadline_body__isnull=True)
 | |
| 		context['pocet_neobodovanych_reseni'] = neobodovana_reseni.count()
 | |
| 		context['pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.count()
 | |
| 
 | |
| 		u = self.request.user
 | |
| 		os = m.Osoba.objects.get(user=u)
 | |
| 		organizator = m.Organizator.objects.get(osoba=os)
 | |
| 
 | |
| 		context['muj_pocet_neobodovanych_reseni'] = neobodovana_reseni.filter(Q(problem__garant=organizator) | Q(problem__autor=organizator) | Q(problem__opravovatele__in=[organizator])).distinct().count()
 | |
| 		context['muj_pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.filter(Q(problem__garant=organizator) | Q(problem__autor=organizator) | Q(problem__opravovatele__in=[organizator])).count()
 | |
| 
 | |
| 		# Termínářský přehled
 | |
| 		pocty_neopravenych_reseni = neobodovana_reseni.select_related('problem').values('problem__nazev').annotate(cas=Min('reseni__cas_doruceni')).order_by('cas')
 | |
| 		context["pocty_neopravenych_reseni"] = [(it['problem__nazev'], it['cas'].date) for it in pocty_neopravenych_reseni.all()]
 | |
| 
 | |
| 		#FIXME: přidat stav='STAV_ZADANY'
 | |
| 		temata = Tema.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]),
 | |
| 			rocnik=aktualni_rocnik).distinct()
 | |
| 		ulohy = Uloha.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]),
 | |
| 			cislo_zadani__rocnik=aktualni_rocnik).distinct()
 | |
| 		clanky = Clanek.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]),
 | |
| 			cislo__rocnik=aktualni_rocnik).distinct()
 | |
| 
 | |
| 		context['temata'] = temata
 | |
| 		context['ulohy'] = ulohy
 | |
| 		context['clanky'] = clanky
 | |
| 		context['organizator'] = organizator
 | |
| 		return context
 | |
| 
 | |
| 		#content_type = 'text/plain; charset=UTF8'
 | |
| 	#XXX
 | |
| 	
 | |
| class PrvniTypExportu(Enum):
 | |
| 	CISLA = 1
 | |
| 	ROCNIKU = 2
 | |
| 	SOUSTREDENI_ORG = 4
 | |
| 	SOUSTREDENI_UCASTNICI = 5
 | |
| 
 | |
| 
 | |
| 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_ORG.value:
 | |
| 		data = [{"id": s.id, "display": str(s)} for s in Soustredeni.objects.all()]
 | |
| 	if type == PrvniTypExportu.SOUSTREDENI_UCASTNICI.value:
 | |
| 		data = [{"id": s.id, "display": str(s)} for s in Soustredeni.objects.all()]
 | |
| 	return HttpResponse(json.dumps(data), content_type='application/json')
 | |
| 
 | |
| def getFieldsForExport(request):
 | |
| 	if 'fields' not in request.GET or request.GET.get('fields') == '':
 | |
| 		return ["jmeno", "prijmeni", "email", "telefon"]
 | |
| 	fields = request.GET.get('fields').split(',')
 | |
| 	return fields
 | |
| 
 | |
| def download_export_csv_only_first_step(request, type):
 | |
| 	fields = getFieldsForExport(request)
 | |
| 	if type == 3:
 | |
| 		resitele = tvorba_utils.resitele_co_neodmaturovali()
 | |
| 		resiteleOsoby = Osoba.objects.filter(resitel__in=resitele)
 | |
| 		response = dataOsobCsvResponse(resiteleOsoby, columns=fields)
 | |
| 		response['Content-Disposition'] = 'attachment; filename="resitele_co_neodmaturovali.csv"'
 | |
| 		return response
 | |
| 
 | |
| def download_export_csv(request, type, id):
 | |
| 	fields = getFieldsForExport(request)
 | |
| 	if type == PrvniTypExportu.CISLA.value:
 | |
| 		resitele = tvorba_utils.resi_cislo(Cislo.objects.get(id=id))
 | |
| 		resiteleOsoby = Osoba.objects.filter(resitel__in=resitele)
 | |
| 		response = dataOsobCsvResponse(resiteleOsoby, columns=fields)
 | |
| 		name = str(Cislo.objects.get(id=id)).replace(" ", "_") + "_resitele_cisla.csv"
 | |
| 		response['Content-Disposition'] = 'attachment; filename="' + name + '"'
 | |
| 		return response
 | |
| 	if type == PrvniTypExportu.ROCNIKU.value:
 | |
| 		resitele = tvorba_utils.resi_v_rocniku(Rocnik.objects.get(id=id))
 | |
| 		resiteleOsoby = Osoba.objects.filter(resitel__in=resitele)
 | |
| 		response = dataOsobCsvResponse(resiteleOsoby, columns=fields)
 | |
| 		name = str(Rocnik.objects.get(id=id)).replace(" ", "_") + "_resitele_rocniku.csv"
 | |
| 		response['Content-Disposition'] = 'attachment; filename="' + name + '"'
 | |
| 		return response
 | |
| 	if type == PrvniTypExportu.SOUSTREDENI_ORG.value:
 | |
| 		soustredeni = Soustredeni.objects.get(id=id)
 | |
| 		organizatori = soustredeni.organizatori.all()
 | |
| 		organizatoriOsoby = Osoba.objects.filter(org__in=organizatori)
 | |
| 		response = dataOsobCsvResponse(organizatoriOsoby, columns=fields)
 | |
| 		name = str(soustredeni).replace(" ", "_") + "_organizatori_soustredeni.csv"
 | |
| 		response['Content-Disposition'] = 'attachment; filename="' + name + '"'
 | |
| 		return response
 | |
| 	if type == PrvniTypExportu.SOUSTREDENI_UCASTNICI.value:
 | |
| 		soustredeni = Soustredeni.objects.get(id=id)
 | |
| 		ucastnici = soustredeni.ucastnici.all()
 | |
| 		ucastniciOsoby = Osoba.objects.filter(resitel__in=ucastnici)
 | |
| 		response = dataOsobCsvResponse(ucastniciOsoby, columns=fields)
 | |
| 		name = str(soustredeni).replace(" ", "_") + "_ucastnici_soustredeni.csv"
 | |
| 		response['Content-Disposition'] = 'attachment; filename="' + name + '"'
 | |
| 		return response
 | |
| 
 | |
| class ResitelView(LoginRequiredMixin,generic.DetailView):
 | |
| 	model = m.Resitel
 | |
| 	template_name = 'personalni/profil/resitel.html'
 | |
| 
 | |
| 	def get_object(self, queryset=None):
 | |
| 		print(self.request.user)
 | |
| 		return m.Resitel.objects.get(osoba__user=self.request.user)
 | |
| 
 | |
| ### Formulare
 | |
| 
 | |
| # 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
 | |
| 
 | |
| def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data):
 | |
| 	msg = "{}, form_hash:{}".format(msg,hash(frozenset(form_data.items)))
 | |
| 	logger.warn(msg)
 | |
| 	gdpr_logger.warn(msg+", form:{}".format(form_data))
 | |
| 
 | |
| 
 | |
| @sensitive_post_parameters('jmeno', 'prijmeni', 'email', 'telefon', 'datum_narozeni', 'ulice', 'mesto', 'psc', 'skola')
 | |
| def resitelEditView(request):
 | |
| 	err_logger = logging.getLogger('personalni.prihlaska.problem')
 | |
| 	## Načtení objektů Osoba a Resitel patřících k aktuálně přihlášenému uživateli
 | |
| 	u = request.user
 | |
| 	osoba_edit = m.Osoba.objects.get(user=u)
 | |
| 	if hasattr(osoba_edit,'resitel'):
 | |
| 		resitel_edit = osoba_edit.resitel
 | |
| 	else:
 | |
| 		resitel_edit = None
 | |
| 	user_edit = osoba_edit.user
 | |
| 	## Vytvoření slovníku, kterým předvyplním formulář 
 | |
| 	prefill_1=model_to_dict(user_edit)
 | |
| 	if resitel_edit:
 | |
| 		prefill_2=model_to_dict(resitel_edit)
 | |
| 		prefill_1.update(prefill_2)
 | |
| 	prefill_3=model_to_dict(osoba_edit)
 | |
| 	prefill_1.update(prefill_3)
 | |
| 	if 'datum_narozeni' in prefill_1:
 | |
| 		prefill_1['datum_narozeni'] = str(prefill_1['datum_narozeni'])
 | |
| 	if 'datum_souhlasu_udaje' in prefill_1:
 | |
| 		prefill_1['spam'] = bool(prefill_1['datum_souhlasu_zasilani'])
 | |
| 	if 'rok_maturity' not in prefill_1 or prefill_1['rok_maturity'] < date.today().year:
 | |
| 		form = PoMaturiteProfileEditForm(initial=prefill_1)
 | |
| 	else:
 | |
| 		form = ProfileEditForm(initial=prefill_1)
 | |
| 	## Změna údajů a jejich uložení
 | |
| 	if request.method == 'POST':
 | |
| 		POST = request.POST.copy()
 | |
| 		POST["username"] = osoba_edit.user.username
 | |
| 
 | |
| 		if 'rok_maturity' not in prefill_1 or prefill_1['rok_maturity'] < date.today().year:
 | |
| 			form = PoMaturiteProfileEditForm(POST)
 | |
| 		else:
 | |
| 			form = ProfileEditForm(POST)
 | |
| 		form.username = user_edit.username
 | |
| 		if form.is_valid():
 | |
| 			## Změny v osobě
 | |
| 			fcd = form.cleaned_data
 | |
| 			form_hash = hash(frozenset(fcd.items()))
 | |
| 			form_logger = logging.getLogger('personalni.prihlaska.form')
 | |
| 			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.osloveni = fcd['osloveni']
 | |
| 			osoba_edit.email = fcd['email']
 | |
| 			osoba_edit.telefon = fcd['telefon']
 | |
| 			osoba_edit.ulice = fcd['ulice']
 | |
| 			osoba_edit.mesto = fcd['mesto']
 | |
| 			osoba_edit.psc = fcd['psc']
 | |
| 			osoba_edit.datum_narozeni = fcd['datum_narozeni']
 | |
| 			## Změny v osobě s podmínkami
 | |
| 			if fcd.get('spam',False):
 | |
| 				if not osoba_edit.datum_souhlasu_zasilani:
 | |
| 					osoba_edit.datum_souhlasu_zasilani = date.today()
 | |
| 			else:
 | |
| 				osoba_edit.datum_souhlasu_zasilani = None
 | |
| 			if fcd.get('stat','') in ('CZ','SK'):
 | |
| 				osoba_edit.stat = fcd['stat']
 | |
| 			else:
 | |
| 				## Neznámá země
 | |
| 				msg = "Unknown country {}".format(fcd['stat_text'])
 | |
| 
 | |
| 			if resitel_edit:
 | |
| 				## Změny v řešiteli
 | |
| 				resitel_edit.prezdivka_resitele = fcd['prezdivka_resitele'] if fcd['prezdivka_resitele'] != '' else None
 | |
| 				resitel_edit.skola = fcd['skola']
 | |
| 				resitel_edit.rok_maturity = fcd['rok_maturity']
 | |
| 				resitel_edit.zasilat = fcd['zasilat']
 | |
| 				resitel_edit.zasilat_cislo_emailem = fcd['zasilat_cislo_emailem']
 | |
| 				resitel_edit.zasilat_cislo_papirove = fcd['zasilat_cislo_papirove']
 | |
| 				resitel_edit.upozornovat_na_opravy_reseni = fcd['upozornovat_na_opravy_reseni']
 | |
| 				if fcd.get('skola'):
 | |
| 					resitel_edit.skola = fcd['skola']
 | |
| 				else:
 | |
| 					# Unknown school - log it
 | |
| 					msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa'])
 | |
| 				resitel_edit.save()
 | |
| 			osoba_edit.save()
 | |
| 			return formularOKView(
 | |
| 				request,
 | |
| 				text='Údaje byly úspěšně uloženy.',
 | |
| 				dalsi_odkazy=[("Vrátit se zpět na profil", reverse("profil"))],
 | |
| 			)
 | |
| 
 | |
| 	return render(request, 'personalni/udaje/edit.html', {'form': form})
 | |
| 
 | |
| 
 | |
| @sensitive_post_parameters('jmeno', 'prijmeni', 'email', 'telefon', 'datum_narozeni', 'ulice', 'mesto', 'psc', 'skola', 'jak_se_dozvedeli')
 | |
| def prihlaskaView(request):
 | |
| 	generic_logger = logging.getLogger('personalni.prihlaska')
 | |
| 	err_logger = logging.getLogger('personalni.prihlaska.problem')
 | |
| 	form_logger = logging.getLogger('personalni.prihlaska.form')
 | |
| 	if request.method == 'POST':
 | |
| 		form = PrihlaskaForm(request.POST)
 | |
| 		# TODO vyresit, co se bude v jakych situacich zobrazovat
 | |
| 		if form.is_valid():
 | |
| 			generic_logger.info("Form valid")
 | |
| 			fcd = form.cleaned_data
 | |
| 			form_hash = hash(frozenset(fcd.items()))
 | |
| 			form_logger.info(str(fcd) + str(form_hash))  # TODO možná logovat jinak
 | |
| 
 | |
| 			with transaction.atomic():
 | |
| 				u = User.objects.create_user(
 | |
| 					username=fcd['username'],
 | |
| 					email = fcd['email'])
 | |
| 				u.save()
 | |
| 				resitel_perm = Permission.objects.filter(codename__exact='resitel').first()
 | |
| 				u.user_permissions.add(resitel_perm)
 | |
| 				resitel_grp = Group.objects.filter(name__exact='resitel').first()
 | |
| 				u.groups.add(resitel_grp)
 | |
| 
 | |
| 				o = m.Osoba(
 | |
| 					jmeno = fcd['jmeno'],
 | |
| 					prijmeni = fcd['prijmeni'],
 | |
| 					osloveni = fcd['osloveni'],
 | |
| 					email = fcd['email'],
 | |
| 					telefon = fcd.get('telefon',''),
 | |
| 					datum_narozeni = fcd.get('datum_narozeni',None),
 | |
| 					datum_souhlasu_udaje = date.today(),
 | |
| 					datum_registrace = date.today(),
 | |
| 					ulice = fcd.get('ulice',''),
 | |
| 					mesto = fcd.get('mesto',''),
 | |
| 					psc = fcd.get('psc',''),
 | |
| 					jak_se_dozvedeli = fcd.get('jak_se_dozvedeli',''),
 | |
| 					poznamka = str(fcd)
 | |
| 					)
 | |
| 
 | |
| 				if fcd.get('spam',False):
 | |
| 					o.datum_souhlasu_zasilani = date.today()
 | |
| 				if fcd.get('stat','') in ('CZ','SK'):
 | |
| 					o.stat = fcd['stat']
 | |
| 				else:
 | |
| 					# Unknown country - log it
 | |
| 					msg = "Unknown country {}".format(fcd['stat_text'])
 | |
| 					err_logger.warn(msg + str(form_hash))
 | |
| 
 | |
| 				
 | |
| 				# Dovolujeme doregistraci uživatele pro existující mail, takže naopak chceme doplnit/aktualizovat údaje do stávajícího objektu
 | |
| 				try:
 | |
| 					orig_osoba = m.Osoba.objects.get(email=fcd['email'])
 | |
| 					orig_osoba.poznamka += '\nDOREGISTRACE K EXISTUJÍCÍMU E-MAILU, diff níže.'
 | |
| 				except m.Osoba.DoesNotExist:
 | |
| 					# Trik: Budeme aktualizovat údaje nové osoby, takže se asi nic nezmění, ale fungovat to bude.
 | |
| 					orig_osoba = o
 | |
| 
 | |
| 				# Porovnání údajů
 | |
| 				assert orig_osoba.user is None, "Právě-registrující-se osoba už má Uživatele!"
 | |
| 				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)
 | |
| 					old = getattr(orig_osoba, attr)
 | |
| 					if new != old:
 | |
| 						orig_osoba.poznamka += f'\nRozdíl v {attr}: Původní {old}, nový {new}'
 | |
| 						diffattrs.append(f'Osoba.{attr}')
 | |
| 						setattr(orig_osoba, attr, new)
 | |
| 				# Datum registrace chceme původní / nižší:
 | |
| 				orig_osoba.datum_registrace = min(orig_osoba.datum_registrace, o.datum_registrace)
 | |
| 
 | |
| 				# Od této chvíle dál je správná osoba ta "původní", novou podle formuláře si ale zachováme
 | |
| 				o, o_form = orig_osoba, o
 | |
| 
 | |
| 
 | |
| 
 | |
| 				o.save()
 | |
| 				o.user = u
 | |
| 				o.save()
 | |
| 
 | |
| 				# Jednoduchá kvazi-kontrola duplicitních Osob
 | |
| 				kolize = m.Osoba.objects.filter(jmeno=o.jmeno, prijmeni=o.prijmeni)
 | |
| 				if kolize.count() > 1:	# Jednu z nich jsme právě uložili
 | |
| 					err_logger.warning(f'Zaregistrovala se osoba s kolizním jménem. ID osob: {[o.id for o in kolize]}')
 | |
| 
 | |
| 				r = m.Resitel(
 | |
| 					prezdivka_resitele=fcd['prezdivka_resitele'] if fcd['prezdivka_resitele'] != "" else None,
 | |
| 					rok_maturity = fcd['rok_maturity'],
 | |
| 					zasilat = fcd['zasilat'],
 | |
| 					zasilat_cislo_emailem = fcd['zasilat_cislo_emailem'],
 | |
| 					zasilat_cislo_papirove = fcd['zasilat_cislo_papirove'],
 | |
| 					)
 | |
| 
 | |
| 				if fcd.get('skola'):
 | |
| 					r.skola = fcd['skola']
 | |
| 				else:
 | |
| 					# Unknown school - log it
 | |
| 					msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa'])
 | |
| 					err_logger.warn(msg + str(form_hash))
 | |
| 
 | |
| 				# Porovnání údajů u řešitele
 | |
| 				try:
 | |
| 					orig_resitel = o.resitel
 | |
| 					orig_resitel.poznamka += '\nDOREGISTRACE ŘEŠITELE, diff:'
 | |
| 				except m.Resitel.DoesNotExist:
 | |
| 					# Stejný trik:
 | |
| 					orig_resitel = r
 | |
| 				resitel_attrs = ['skola', 'rok_maturity', 'zasilat', 'zasilat_cislo_emailem', 'zasilat_cislo_papirove']
 | |
| 				for attr in resitel_attrs:
 | |
| 					new = getattr(r, attr)
 | |
| 					old = getattr(orig_resitel, attr)
 | |
| 					if new != old:
 | |
| 						orig_resitel.poznamka += f'\nRozdíl v {attr}: Původní {old}, nový {new}'
 | |
| 						diffattrs.append(f'Resitel.{attr}')
 | |
| 						setattr(orig_resitel, attr, new)
 | |
| 				r, r_form = orig_resitel, r
 | |
| 
 | |
| 				r.osoba = o	# Tohle by mělo být bezpečné…
 | |
| 				r.save()
 | |
| 
 | |
| 				if diffattrs: err_logger.warning(f'Different fields when matching Řešitel id {r.id} or Osoba id {o.id}: {diffattrs}')
 | |
| 
 | |
| 			posli_reset_hesla(u, request)
 | |
| 			return formularOKView(request, text='Na tvůj e-mail jsme právě poslali odkaz pro nastavení hesla.')
 | |
| 
 | |
| 	# if a GET (or any other method) we'll create a blank form
 | |
| 	else:
 | |
| 		form = PrihlaskaForm()
 | |
| 
 | |
| 	return render(request, 'personalni/udaje/prihlaska.html', {'form': form})
 | |
| 
 | |
| 
 | |
| # 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'):
 | |
| 		return ResitelView.as_view()(request)
 | |
| 	else:
 | |
| 		return LoginView.as_view()(request)
 | |
| 
 | |
| def dataResiteluCsvResponse(queryset, columns=None, with_header=True):
 | |
| 	"""Pomocná funkce pro vracení dat řešitelů jako CSV. Musí dostat správný QuerySet, který dává Řešitele"""
 | |
| 	# TODO: Možná nějak zobecnit i na Osoby?
 | |
| 	# TODO: Nemá to spíš být class-based? Tohle je efektivně metoda "get", které ale chybí "get_queryset"…
 | |
| 	
 | |
| 	default_columns = (
 | |
| 		'id',
 | |
| 		'osoba__jmeno',
 | |
| 		'osoba__prijmeni',
 | |
| 		'osoba__prezdivka',
 | |
| 		'osoba__email',
 | |
| 		'osoba__telefon',
 | |
| 		'osoba__user__username',
 | |
| 		'osoba__datum_narozeni',
 | |
| 		'osoba__osloveni',
 | |
| 		'osoba__ulice',
 | |
| 		'osoba__mesto',
 | |
| 		'osoba__psc',
 | |
| 		'osoba__stat',
 | |
| 		'skola',	#FIXME: dává jen ID
 | |
| 		'osoba__jak_se_dozvedeli',
 | |
| 		'poznamka',
 | |
| 		'osoba__poznamka',
 | |
| 		'rok_maturity',
 | |
| 		'zasilat',
 | |
| 		'zasilat_cislo_emailem',
 | |
| 		'zasilat_cislo_papirove',
 | |
| 		'osoba__datum_registrace',
 | |
| 		'osoba__datum_souhlasu_udaje',
 | |
| 		'osoba__datum_souhlasu_zasilani',
 | |
| 		)
 | |
| 	if columns is None: columns = default_columns
 | |
| 
 | |
| 	field_name_overrides = {
 | |
| 		# Zrušení prefixu "osoba__"
 | |
| 		'osoba__jmeno':                  'jmeno',
 | |
| 		'osoba__prijmeni':               'prijmeni',
 | |
| 		'osoba__prezdivka':              'prezdivka',
 | |
| 		'osoba__email':                  'email',
 | |
| 		'osoba__telefon':                'telefon',
 | |
| 		'osoba__user__username':         'user',
 | |
| 		'osoba__datum_narozeni':         'datum_narozeni',
 | |
| 		'osoba__osloveni':               'osloveni',
 | |
| 		'osoba__ulice':                  'ulice',
 | |
| 		'osoba__mesto':                  'mesto',
 | |
| 		'osoba__psc':                    'psc',
 | |
| 		'osoba__stat':                   'stat',
 | |
| 		'osoba__datum_registrace':       'datum_registrace',
 | |
| 		'osoba__datum_souhlasu_udaje':   'datum_souhlasu_udaje',
 | |
| 		'osoba__datum_souhlasu_zasilani':'datum_souhlasu_zasilani',
 | |
| 		}
 | |
| 	
 | |
| 	def get_field_name(column_name):
 | |
| 		if column_name in field_name_overrides:
 | |
| 			return field_name_overrides[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
 | |
| 
 | |
| 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
 | |
| 
 | |
| 
 |