Add Generování hesla v registraci.
This commit is contained in:
		
							parent
							
								
									9a90648f29
								
							
						
					
					
						commit
						8572264845
					
				
					 3 changed files with 49 additions and 49 deletions
				
			
		|  | @ -1,5 +1,6 @@ | |||
| from django import forms | ||||
| from dal import autocomplete | ||||
| from django.contrib.auth.forms import PasswordResetForm | ||||
| from django.core.exceptions import ObjectDoesNotExist | ||||
| from django.contrib.auth.models import User | ||||
| from django.forms import formset_factory | ||||
|  | @ -37,21 +38,11 @@ class LoginForm(forms.Form): | |||
| 			widget=forms.PasswordInput()) | ||||
| 
 | ||||
| 
 | ||||
| class PrihlaskaForm(forms.Form): | ||||
| class PrihlaskaForm(PasswordResetForm): | ||||
| 	username = forms.CharField(label='Přihlašovací jméno',  | ||||
| 			max_length=256,  | ||||
| 			required=True, | ||||
| 			help_text='Tímto jménem se následně budeš přihlašovat pro odevzdání řešení a další činnosti v semináři') | ||||
| 	password = forms.CharField( | ||||
| 			label='Heslo', | ||||
| 			max_length=256, | ||||
| 			required=True, | ||||
| 			widget=forms.PasswordInput()) | ||||
| 	password_check = forms.CharField( | ||||
| 			label='Ověření hesla', | ||||
| 			max_length=256, | ||||
| 			required=True, | ||||
| 			widget=forms.PasswordInput()) | ||||
| 
 | ||||
| 	jmeno = forms.CharField(label='Jméno', max_length=256, required=True) | ||||
| 	prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) | ||||
|  |  | |||
|  | @ -33,8 +33,8 @@ | |||
|          </h4> | ||||
|          <table class="form"> | ||||
|            {% include "seminar/profil/prihlaska_field.html" with field=form.username %} | ||||
|            {% include "seminar/profil/prihlaska_field.html" with field=form.password %} | ||||
|            {% include "seminar/profil/prihlaska_field.html" with field=form.password_check %} | ||||
| {#           {% include "seminar/profil/prihlaska_field.html" with field=form.password %}#} | ||||
| {#           {% include "seminar/profil/prihlaska_field.html" with field=form.password_check %}#} | ||||
|          </table> | ||||
| 
 | ||||
| <hr> | ||||
|  |  | |||
|  | @ -1,10 +1,12 @@ | |||
| 
 | ||||
| 
 | ||||
| from django.contrib.auth.tokens import PasswordResetTokenGenerator | ||||
| from django.contrib.sites.shortcuts import get_current_site | ||||
| from django.shortcuts import get_object_or_404, render, redirect | ||||
| from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse | ||||
| from django.urls import reverse,reverse_lazy | ||||
| from django.core.exceptions import PermissionDenied, ObjectDoesNotExist | ||||
| from django.core.mail import send_mail | ||||
| from django.utils.encoding import force_bytes | ||||
| from django.utils.http import urlsafe_base64_encode | ||||
| from django.views import generic | ||||
| from django.utils.translation import ugettext as _ | ||||
| from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect | ||||
|  | @ -79,7 +81,7 @@ class ObalkovaniView(generic.ListView): | |||
| 	def get_context_data(self, **kwargs): | ||||
| 		context = super(ObalkovaniView, self).get_context_data(**kwargs) | ||||
| 		print(self.cislo) | ||||
| 		context['cislo'] = self.cislo  | ||||
| 		context['cislo'] = self.cislo | ||||
| 		return context | ||||
| 
 | ||||
| class TNLData(object): | ||||
|  | @ -97,7 +99,7 @@ class TNLData(object): | |||
| 			self.tema_in_path = True | ||||
| 
 | ||||
| 	def add_edit_options(self): | ||||
| 		self.deletable = tnltt.deletable(self)  | ||||
| 		self.deletable = tnltt.deletable(self) | ||||
| 		self.editable_siblings = tnltt.editableSiblings(self) | ||||
| 		self.editable_children = tnltt.editableChildren(self) | ||||
| 		self.text_only_subtree = tnltt.textOnlySubtree(self) | ||||
|  | @ -117,7 +119,7 @@ class TNLData(object): | |||
| 		while True: | ||||
| 			rocnik = isinstance(parent, s.RocnikNode) | ||||
| 			cislo = isinstance(parent, s.CisloNode) | ||||
| 			uloha = (isinstance(parent, s.UlohaVzorakNode) or  | ||||
| 			uloha = (isinstance(parent, s.UlohaVzorakNode) or | ||||
| 				isinstance(parent, s.UlohaZadaniNode)) | ||||
| 			tema = isinstance(parent, s.TemaVCisleNode) | ||||
| 
 | ||||
|  | @ -137,7 +139,7 @@ class TNLData(object): | |||
| 			print("Existuje TreeNode, který není pod číslem, ročníkem, úlohou" | ||||
| 			"ani tématem. {}".format(anode)) | ||||
| 			return False | ||||
| 	 | ||||
| 
 | ||||
| 	@classmethod | ||||
| 	def all_public_children(cls, anode): | ||||
| 		for ch in treelib.all_children(anode): | ||||
|  | @ -156,14 +158,14 @@ class TNLData(object): | |||
| 		if user.has_perm('auth.org'): | ||||
| 			enum_children = enumerate(treelib.all_children(anode)) | ||||
| 		else: | ||||
| 			enum_children = enumerate(TNLData.all_public_children(anode))	 | ||||
| 	 | ||||
| 			enum_children = enumerate(TNLData.all_public_children(anode)) | ||||
| 
 | ||||
| 		for (idx,ch) in enum_children: | ||||
| 			outitem = cls.from_treenode(ch, user, out,  idx) | ||||
| 			out.children.append(outitem) | ||||
| 		out.add_edit_options() | ||||
| 		return out | ||||
| 	 | ||||
| 
 | ||||
| 	@classmethod | ||||
| 	def from_tnldata_list(cls, tnllist): | ||||
| 		"""Vyrobíme virtuální TNL, který nemá obsah, ale má za potomky všechna zadaná TNLData""" | ||||
|  | @ -192,7 +194,7 @@ class TNLData(object): | |||
| 				for tnl in result: | ||||
| 					found.append(tnl) | ||||
| 			return found | ||||
| 	 | ||||
| 
 | ||||
| 	def to_json(self): | ||||
| 		#self.node = anode | ||||
| 		#self.children = [] | ||||
|  | @ -264,7 +266,7 @@ class TreeNodePridatView(generic.View): | |||
| 
 | ||||
| 		if kam not in ('pred','syn','za'): | ||||
| 			raise ValidationError('Přidat lze pouze před nebo za node nebo jako syna') | ||||
| 		 | ||||
| 
 | ||||
| 		if co == m.TextNode: | ||||
| 			new_obj = m.Text() | ||||
| 			new_obj.save() | ||||
|  | @ -303,7 +305,7 @@ class TreeNodePridatView(generic.View): | |||
| 				node = treelib.create_node_after(node,typ) | ||||
| 
 | ||||
| 		return redirect(node.get_admin_url()) | ||||
| 		 | ||||
| 
 | ||||
| 
 | ||||
| class TreeNodeSmazatView(generic.base.View): | ||||
| 	def post(self, request, *args, **kwargs): | ||||
|  | @ -343,7 +345,7 @@ class TreeNodeProhoditView(generic.base.View): | |||
| class SirotcinecView(generic.ListView): | ||||
| 	model = s.TreeNode | ||||
| 	template_name = 'seminar/orphanage.html' | ||||
| 	 | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		return s.TreeNode.objects.not_instance_of(s.RocnikNode).filter(root=None,prev=None,succ=None,father_of_first=None) | ||||
| 
 | ||||
|  | @ -548,7 +550,7 @@ class TitulniStranaView(generic.ListView): | |||
| 	def get_context_data(self, **kwargs): | ||||
| 		context = super(TitulniStranaView, self).get_context_data(**kwargs) | ||||
| 		nastaveni = get_object_or_404(Nastaveni) | ||||
| 		 | ||||
| 
 | ||||
| 		deadline_soustredeni = (nastaveni.aktualni_cislo.datum_deadline_soustredeni, "soustredeni") | ||||
| 		preddeadline = (nastaveni.aktualni_cislo.datum_preddeadline, "preddeadline") | ||||
| 		deadline = (nastaveni.aktualni_cislo.datum_deadline, "deadline") | ||||
|  | @ -564,7 +566,7 @@ class TitulniStranaView(generic.ListView): | |||
| 			context['nejblizsi_deadline'] = datetime.combine(nejblizsi_deadline[0], datetime.max.time()) | ||||
| 		else: | ||||
| 			context['nejblizsi_deadline'] = None | ||||
| 		 | ||||
| 
 | ||||
| 		context['typ_deadline'] = nejblizsi_deadline[1] | ||||
| 
 | ||||
| 		# Aktuální témata | ||||
|  | @ -637,10 +639,10 @@ class ArchivView(generic.ListView): | |||
| 				urls[c.rocnik] = c.titulka_nahled.url | ||||
| 
 | ||||
| 		context["object_list"] = urls | ||||
| 		 | ||||
| 
 | ||||
| 		return context | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -762,7 +764,7 @@ class OdmenyView(generic.TemplateView): | |||
| 				outlist.append({'jmeno': resitel.osoba.plne_jmeno(), 'ftitul': ftitul, 'ttitul': ttitul}) | ||||
| 		context['zmeny'] = outlist | ||||
| 		return context | ||||
| 		 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -852,7 +854,7 @@ class OrgoRozcestnikView(TemplateView): | |||
| 		os = s.Osoba.objects.get(user=u) | ||||
| 		organizator = s.Organizator.objects.get(osoba=os) | ||||
| 		#FIXME: přidat stav='STAV_ZADANY' | ||||
| 		temata = s.Tema.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]),  | ||||
| 		temata = s.Tema.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]), | ||||
| 			rocnik=aktualni_rocnik).distinct() | ||||
| 		ulohy = s.Uloha.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]), | ||||
| 			cislo_zadani__rocnik=aktualni_rocnik).distinct() | ||||
|  | @ -877,7 +879,7 @@ def TitulyView(request, rocnik, cislo): | |||
| 	cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, poradi = cislo) | ||||
| 
 | ||||
| 	asciijmena = [] | ||||
| 	jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka),  | ||||
| 	jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka), | ||||
| 		# pokud ano, vrátí se jako true | ||||
| 	slovnik_s_body = body_resitelu(resitele, rocnik_obj) | ||||
| 
 | ||||
|  | @ -893,7 +895,7 @@ def TitulyView(request, rocnik, cislo): | |||
| 			asciijmena.append(resitel.ascii) | ||||
| 		else: | ||||
| 			jmenovci = True | ||||
| 	 | ||||
| 
 | ||||
| 	return render(request, 'seminar/archiv/tituly.tex', | ||||
| 		{'resitele': resitele,'jmenovci':jmenovci},content_type="text/plain") | ||||
| 
 | ||||
|  | @ -966,7 +968,7 @@ def group_by_rocnik(clanky): | |||
| 			rocnik = clanek.cislo.rocnik.rocnik | ||||
| 	skupiny_clanku.append(skupina) | ||||
| 	return skupiny_clanku | ||||
| 	 | ||||
| 
 | ||||
| 
 | ||||
| # FIXME: clanky jsou vsechny, pokud budou i neresitelske, tak se take zobrazi | ||||
| # FIXME: Původně tu byl kód přímo v těle třídy, což rozbíjelo migrace. Opravil jsem, ale vůbec nevím, jestli to funguje. | ||||
|  | @ -1055,9 +1057,9 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | |||
| 	def get_context_data(self,**kwargs): | ||||
| 		data = super().get_context_data(**kwargs) | ||||
| 		if self.request.POST: | ||||
| 			data['prilohy'] = f.ReseniSPrilohamiFormSet(self.request.POST,self.request.FILES)  | ||||
| 			data['prilohy'] = f.ReseniSPrilohamiFormSet(self.request.POST,self.request.FILES) | ||||
| 		else: | ||||
| 			data['prilohy'] = f.ReseniSPrilohamiFormSet()  | ||||
| 			data['prilohy'] = f.ReseniSPrilohamiFormSet() | ||||
| 		return data | ||||
| 
 | ||||
| 	# FIXME prepsat tak, aby form_valid se volalo jen tehdy, kdyz je form i formset validni | ||||
|  | @ -1070,13 +1072,13 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | |||
| 		with transaction.atomic(): | ||||
| 			self.object = form.save() | ||||
| 			self.object.resitele.add(Resitel.objects.get(osoba__user = self.request.user)) | ||||
| 			self.object.cas_doruceni = timezone.now()  | ||||
| 			self.object.cas_doruceni = timezone.now() | ||||
| 			self.object.forma = s.Reseni.FORMA_UPLOAD | ||||
| 			self.object.save() | ||||
| 
 | ||||
| 			prilohy.instance = self.object | ||||
| 			prilohy.save() | ||||
| 		 | ||||
| 
 | ||||
| 		# Pošleme mail opravovatelům a garantovi | ||||
| 		# FIXME: Nechat spočítat databázi? Je to pár dotazů (pravděpodobně), takže to za to možná nestojí | ||||
| 		prijemci = set() | ||||
|  | @ -1099,7 +1101,7 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | |||
| 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))		 | ||||
| 	gdpr_logger.warn(msg+", form:{}".format(form_data)) | ||||
| 
 | ||||
| from django.forms.models import model_to_dict | ||||
| def resitelEditView(request): | ||||
|  | @ -1185,11 +1187,10 @@ def prihlaskaView(request): | |||
| 			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'], | ||||
| 					password=fcd['password'], | ||||
| 					email = fcd['email']) | ||||
| 				u.save() | ||||
| 				resitel_perm = Permission.objects.filter(codename__exact='resitel').first() | ||||
|  | @ -1229,7 +1230,7 @@ def prihlaskaView(request): | |||
| 					zasilat = fcd['zasilat'], | ||||
| 					zasilat_cislo_emailem = fcd['zasilat_cislo_emailem'] | ||||
| 					) | ||||
| 				 | ||||
| 
 | ||||
| 				r.save() | ||||
| 				r.osoba = o | ||||
| 				if fcd.get('skola'): | ||||
|  | @ -1240,11 +1241,19 @@ def prihlaskaView(request): | |||
| 					err_logger.warn(msg + str(form_hash)) | ||||
| 				r.save() | ||||
| 
 | ||||
| 			send_mail( | ||||
| 			uid = urlsafe_base64_encode(force_bytes(u.pk)) | ||||
| 			token = PasswordResetTokenGenerator().make_token(u) | ||||
| 			url = "https://%s%s" % ( | ||||
| 				str(get_current_site(request)), | ||||
| 				str(reverse_lazy("password_reset_confirm", args=[uid, token])) | ||||
| 			) | ||||
| 
 | ||||
| 			u.email_user( | ||||
| 				subject="Registrace na M&M", | ||||
| 				message=f"Tento e-mail byl právě zaregistrován na mam.matfyz.cz.", # TODO: Dovymyslet text. | ||||
| 				message=f"Tento e-mail byl právě zaregistrován na mam.matfyz.cz. Nové heslo si nastavíš na: " + url, | ||||
| 				# TODO: templates/seminar/registrace a django/contrib/auth/forms.py říkají, jak na to lépe | ||||
| 				# TODO: Dovymyslet text. | ||||
| 				from_email="registrace@mam.mff.cuni.cz",  # FIXME: Chceme to mít radši tady, nebo v nastavení? | ||||
| 				recipient_list=list([fcd['email']]), | ||||
| 			) | ||||
| 
 | ||||
| 			return formularOKView(request) | ||||
|  | @ -1319,7 +1328,7 @@ class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView): | |||
| 
 | ||||
| 		return JsonResponse({"url":self.object.na_web.url}) | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
| 
 | ||||
| # Jen hloupé rozhazovátko | ||||
| def profilView(request): | ||||
|  | @ -1345,10 +1354,10 @@ def formularOKView(request): | |||
| 	return render(request, template_name, context) | ||||
| 
 | ||||
| #------------------ Jak řešit - možná má být udělané úplně jinak | ||||
|      | ||||
| 
 | ||||
| class JakResitView(generic.ListView): | ||||
| 	template_name = 'seminar/jak-resit.html' | ||||
|      | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		return None | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Jonas Havelka
						Jonas Havelka