From 07acce2e90e4bef523a8849dbb3024b7346d9baf Mon Sep 17 00:00:00 2001 From: Jean-Romain Garnier Date: Thu, 16 Apr 2020 16:58:20 +0000 Subject: [PATCH] Add optional fields to select password during user creation --- static/js/toggle_password_fields.js | 24 +++++++++++ users/forms.py | 64 ++++++++++++++++++++++++++++- users/views.py | 40 +++++++++++++++--- 3 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 static/js/toggle_password_fields.js diff --git a/static/js/toggle_password_fields.js b/static/js/toggle_password_fields.js new file mode 100644 index 00000000..3c1f436f --- /dev/null +++ b/static/js/toggle_password_fields.js @@ -0,0 +1,24 @@ +/** This makes an checkbox toggle the appeareance of the + * password and password confirmations fields. + */ +function toggle_show_password_chkbox() { + var password1 = document.getElementById('id_Adherent-password1'); + var password2 = document.getElementById('id_Adherent-password2'); + + if (show_password_chkbox.checked) { + password1.parentElement.style.display = 'none'; + password2.parentElement.style.display = 'none'; + password1.required = false; + password2.required = false; + } else { + password1.parentElement.style.display = 'block'; + password2.parentElement.style.display = 'block'; + password1.required = true; + password2.required = true; + } +} + +var show_password_chkbox = document.getElementById('id_Adherent-init_password_by_mail'); +show_password_chkbox.onclick = toggle_show_password_chkbox; +toggle_show_password_chkbox(); + diff --git a/users/forms.py b/users/forms.py index cef1e43a..c5200fc2 100644 --- a/users/forms.py +++ b/users/forms.py @@ -380,7 +380,28 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class AdherentCreationForm(AdherentForm): """Formulaire de création d'un user. AdherentForm auquel on ajoute une checkbox afin d'éviter les - doublons d'utilisateurs""" + doublons d'utilisateurs et, optionnellement, + un champ mot de passe""" + # Champ pour choisir si un lien est envoyé par mail pour le mot de passe + init_password_by_mail = forms.BooleanField(required=False, initial=True) + init_password_by_mail.label = _("Send password reset link by email.") + + # Champs pour initialiser le mot de passe + # Validators are handled manually since theses fields aren't always required + password1 = forms.CharField( + required=False, + label=_("Password"), + widget=forms.PasswordInput, + # validators=[MinLengthValidator(8)], + max_length=255, + ) + password2 = forms.CharField( + required=False, + label=_("Password confirmation"), + widget=forms.PasswordInput, + # validators=[MinLengthValidator(8)], + max_length=255, + ) # Champ permettant d'éviter au maxium les doublons d'utilisateurs former_user_check_info = _( @@ -422,6 +443,47 @@ class AdherentCreationForm(AdherentForm): ) ) + def clean_password1(self): + """Ignore ce champs si la case init_password_by_mail est décochée""" + send_email = self.cleaned_data.get("init_password_by_mail") + if send_email: + return None + + password1 = self.cleaned_data.get("password1") + if len(password1) < 8: + raise forms.ValidationError(_("Password must contain at least 8 characters.")) + + return password1 + + def clean_password2(self): + """Verifie que password1 et 2 sont identiques (si nécessaire)""" + send_email = self.cleaned_data.get("init_password_by_mail") + if send_email: + return None + + # Check that the two password entries match + password1 = self.cleaned_data.get("password1") + password2 = self.cleaned_data.get("password2") + if password1 and password2 and password1 != password2: + raise forms.ValidationError(_("The passwords don't match.")) + + return password2 + + def save(self, commit=True): + """Set the user's password, if entered + Returns the user and a bool indicating whether + an email to init the password should be sent""" + # Save the provided password in hashed format + user = super(AdherentForm, self).save(commit=False) + + send_email = self.cleaned_data.get("init_password_by_mail") + if not send_email: + user.set_password(self.cleaned_data["password1"]) + + user.should_send_password_reset_email = send_email + user.save() + return user + class AdherentEditForm(AdherentForm): """Formulaire d'édition d'un user. diff --git a/users/views.py b/users/views.py index 3fb4d472..f14cb295 100644 --- a/users/views.py +++ b/users/views.py @@ -119,15 +119,42 @@ def new_user(request): user = AdherentCreationForm(request.POST or None, user=request.user) GTU_sum_up = GeneralOption.get_cached_value("GTU_sum_up") GTU = GeneralOption.get_cached_value("GTU") + if user.is_valid(): user = user.save() - user.reset_passwd_mail(request) - messages.success( - request, - _("The user %s was created, an email to set the password was sent.") - % user.pseudo, - ) + + # Use "is False" so that if None, the email is sent + if user.should_send_password_reset_email is False: + messages.success( + request, + _("The user %s was created.") + % user.pseudo, + ) + else: + user.reset_passwd_mail(request) + messages.success( + request, + _("The user %s was created, an email to set the password was sent.") + % user.pseudo, + ) + return redirect(reverse("users:profil", kwargs={"userid": str(user.id)})) + + # Anonymous users are allowed to create new accounts + # but they should be treated differently + params = { + "userform": user, + "GTU_sum_up": GTU_sum_up, + "GTU": GTU, + "showCGU": True, + "action_name": _("Commit"), + } + + if request.user.is_anonymous: + params["load_js_file"] = "/static/js/toggle_password_fields.js" + + return form(params, "users/user.html", request) + """ return form( { "userform": user, @@ -139,6 +166,7 @@ def new_user(request): "users/user.html", request, ) + """ @login_required