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" %}
+
+
+
+
+{% 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 %}
| |