From c97f57912bd0a1e4780876d49b53108a602f32df Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Mon, 26 Apr 2021 17:54:07 +0200 Subject: [PATCH] =?UTF-8?q?Rajoute=20une=20page=20pour=20cr=C3=A9er=20plus?= =?UTF-8?q?=20facilement=20des=20comptes=20avec=20mdp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elections/forms.py | 2 +- elections/models.py | 3 +- .../templates/elections/election_voters.html | 4 +-- .../templates/elections/upload_voters.html | 2 +- elections/utils.py | 15 ++------- shared/auth/forms.py | 21 +++++++++++++ shared/auth/urls.py | 1 + shared/auth/utils.py | 15 +++++++++ shared/auth/views.py | 31 ++++++++++++++++++- shared/templates/auth/create-user.html | 31 +++++++++++++++++++ shared/templates/base.html | 2 +- 11 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 shared/auth/utils.py create mode 100644 shared/templates/auth/create-user.html diff --git a/elections/forms.py b/elections/forms.py index 0004b53..e9da67e 100644 --- a/elections/forms.py +++ b/elections/forms.py @@ -94,7 +94,7 @@ class DeleteVoteForm(forms.Form): super().__init__(**kwargs) if voter is not None: self.fields["delete"].label = _("Supprimer le vote de {} ({}) ?").format( - voter.full_name, voter.get_username() + voter.full_name, voter.base_username ) delete = forms.ChoiceField( diff --git a/elections/models.py b/elections/models.py index 430d225..85a69eb 100644 --- a/elections/models.py +++ b/elections/models.py @@ -208,7 +208,8 @@ class User(AbstractUser): ) full_name = models.CharField(_("Nom et Prénom"), max_length=150, blank=True) - def get_username(self): + @property + def base_username(self): return "__".join(self.username.split("__")[1:]) def can_vote(self, request, election): diff --git a/elections/templates/elections/election_voters.html b/elections/templates/elections/election_voters.html index ddf553d..9a9fc94 100644 --- a/elections/templates/elections/election_voters.html +++ b/elections/templates/elections/election_voters.html @@ -62,7 +62,7 @@ {% if election.restricted %} {% for v in election.registered_voters.all %} - {{ v.full_name }} ({{ v.get_username }}) + {{ v.full_name }} ({{ v.base_username }}) {% if v in voters %} @@ -77,7 +77,7 @@ {% else %} {% for v in voters %} - {{ v.full_name }} ({{ v.get_username }}) + {{ v.full_name }} ({{ v.base_username }}) diff --git a/elections/templates/elections/upload_voters.html b/elections/templates/elections/upload_voters.html index 4a992b3..c0ccdad 100644 --- a/elections/templates/elections/upload_voters.html +++ b/elections/templates/elections/upload_voters.html @@ -110,7 +110,7 @@ {% for v in voters %} - {{ v.get_username }} + {{ v.base_username }} {{ v.full_name }} {{ v.email }} diff --git a/elections/utils.py b/elections/utils.py index a77e637..267f5af 100644 --- a/elections/utils.py +++ b/elections/utils.py @@ -1,6 +1,5 @@ import csv import io -import random import networkx as nx import numpy as np @@ -14,6 +13,8 @@ from django.template.loader import render_to_string from django.urls import reverse from django.utils.translation import gettext_lazy as _ +from shared.auth.utils import generate_password + # ############################################################################# # Fonctions universelles # ############################################################################# @@ -389,16 +390,6 @@ def check_csv(csv_file): return errors -def generate_password(): - random.seed() - alphabet = "abcdefghjkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789" - password = "" - for i in range(15): - password += random.choice(alphabet) - - return password - - def send_mail(election, mail_form): """Envoie le mail d'annonce de l'élection avec identifiants et mot de passe aux votant·e·s, le mdp est généré en même temps que le mail est envoyé. @@ -418,7 +409,7 @@ def send_mail(election, mail_form): body=mail_form.cleaned_data["message"].format( full_name=v.full_name, election_url=url, - username=v.get_username(), + username=v.base_username, password=password, ), to=[v.email], diff --git a/shared/auth/forms.py b/shared/auth/forms.py index a36e046..0b11156 100644 --- a/shared/auth/forms.py +++ b/shared/auth/forms.py @@ -2,6 +2,7 @@ from django import forms from django.contrib.auth import authenticate from django.contrib.auth import forms as auth_forms from django.contrib.auth import get_user_model +from django.core.validators import validate_email from django.utils.translation import gettext_lazy as _ UserModel = get_user_model() @@ -61,3 +62,23 @@ class PwdResetForm(auth_forms.PasswordResetForm): def get_users(self, email): users = super().get_users(email) return (u for u in users if u.username.split("__")[0] == "pwd") + + +class PwdUserForm(forms.ModelForm): + """ + Allows for the creation of a Password Account given the email, base username and full name. + """ + + email = forms.EmailField( + label=_("Email"), required=True, validators=[validate_email] + ) + + def clean(self): + # On rajoute le préfixe signifiant qu'on crée un compte avec mot de passe + cleaned_data = super().clean() + cleaned_data["username"] = "pwd__" + cleaned_data["username"] + return cleaned_data + + class Meta: + model = UserModel + fields = ["username", "full_name", "email"] diff --git a/shared/auth/urls.py b/shared/auth/urls.py index a5c8cce..d110dc9 100644 --- a/shared/auth/urls.py +++ b/shared/auth/urls.py @@ -8,4 +8,5 @@ urlpatterns = [ views.ElectionLoginView.as_view(), name="auth.election", ), + path("pwd-create", views.CreatePwdAccount.as_view(), name="auth.create-account"), ] diff --git a/shared/auth/utils.py b/shared/auth/utils.py new file mode 100644 index 0000000..77b3fd8 --- /dev/null +++ b/shared/auth/utils.py @@ -0,0 +1,15 @@ +import random + +# ############################################################################# +# Fonctions universelles +# ############################################################################# + + +def generate_password(size=15): + random.seed() + alphabet = "abcdefghjkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789" + password = "" + for i in range(size): + password += random.choice(alphabet) + + return password diff --git a/shared/auth/views.py b/shared/auth/views.py index b9694a6..5cee235 100644 --- a/shared/auth/views.py +++ b/shared/auth/views.py @@ -1,6 +1,15 @@ +from django.contrib.admin.views.decorators import staff_member_required +from django.contrib.auth import get_user_model from django.contrib.auth import views as auth_views +from django.contrib.auth.hashers import make_password +from django.urls import reverse_lazy +from django.utils.decorators import method_decorator +from django.views.generic.edit import CreateView -from .forms import ElectionAuthForm +from .forms import ElectionAuthForm, PwdUserForm +from .utils import generate_password + +User = get_user_model() # ############################################################################# # Election Specific Login @@ -17,3 +26,23 @@ class ElectionLoginView(auth_views.LoginView): def get_context_data(self, **kwargs): kwargs.update({"election_id": self.kwargs.get("election_id")}) return super().get_context_data(**kwargs) + + +# ############################################################################# +# Creation of Password Accounts +# ############################################################################# + + +@method_decorator(staff_member_required, name="dispatch") +class CreatePwdAccount(CreateView): + model = User + form_class = PwdUserForm + template_name = "auth/create-user.html" + success_url = reverse_lazy("auth.create-account") + + def form_valid(self, form): + # On enregistre un mot de passe aléatoire + form.instance.password = make_password(generate_password(32)) + + # On envoie un mail pour réinitialiser le mot de passe + return super().form_valid(form) diff --git a/shared/templates/auth/create-user.html b/shared/templates/auth/create-user.html new file mode 100644 index 0000000..cbdce87 --- /dev/null +++ b/shared/templates/auth/create-user.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} +{% load i18n %} + + +{% block content %} + +

{% trans "Créer un compte avec mot de passe" %}

+
+ +
+
+
+ {% csrf_token %} + + {% include "forms/form.html" with errors=True %} + +
+
+ +
+
+
+
+
+ +{% endblock %} diff --git a/shared/templates/base.html b/shared/templates/base.html index 22780cc..0d92901 100644 --- a/shared/templates/base.html +++ b/shared/templates/base.html @@ -122,7 +122,7 @@
- {% blocktrans with name=user.get_username connection=user.connection_method %}Connecté·e en tant que {{ name }} par {{ connection }}{% endblocktrans %} + {% blocktrans with name=user.base_username connection=user.connection_method %}Connecté·e en tant que {{ name }} par {{ connection }}{% endblocktrans %}