diff --git a/src/dgsi/forms.py b/src/dgsi/forms.py new file mode 100644 index 0000000..2bc31a7 --- /dev/null +++ b/src/dgsi/forms.py @@ -0,0 +1,35 @@ +from asgiref.sync import async_to_sync +from django.core.exceptions import ValidationError +from django.forms import BooleanField, CharField, EmailField, forms +from django.utils.translation import gettext_lazy as _ + +from shared.kanidm import client + + +@async_to_sync +async def name_validator(value: str) -> None: + try: + await client.person_account_get(value) + except ValueError: + return + + raise ValidationError(_("Identifiant déjà présent dans la base de données.")) + + +class CreateKanidmAccountForm(forms.Form): + # TODO: Add a field for the clipper login information for the local mapping + name = CharField( + label=_("Identifiant"), + help_text=_("De préférence identique au login ENS de la personne concernée"), + validators=[name_validator], + ) + displayname = CharField(label=_("Nom d'usage")) + mail = EmailField( + label=_("Adresse e-mail"), + help_text=_("De préférence l'adresse '@ens.psl.eu'"), + ) + active = BooleanField( + label=_("Membre actif"), + help_text=_("Si selectionné, la personne sera ajoutée au groupe dgnum_members"), + required=False, + ) diff --git a/src/dgsi/urls.py b/src/dgsi/urls.py index 2555ae0..09cd361 100644 --- a/src/dgsi/urls.py +++ b/src/dgsi/urls.py @@ -6,7 +6,11 @@ app_name = "dgsi" urlpatterns = [ path("accounts/profile/", views.ProfileView.as_view(), name="dgn-profile"), - path("accounts/create/", views.CreateUserView.as_view(), name="dgn-create_user"), + path( + "accounts/create-kanidm/", + views.CreateKanidmAccountView.as_view(), + name="dgn-create_user", + ), path( "accounts/forbidden/", views.TemplateView.as_view(template_name="account/forbidden_category.html"), diff --git a/src/dgsi/views.py b/src/dgsi/views.py index cb3c4f7..f1e5d95 100644 --- a/src/dgsi/views.py +++ b/src/dgsi/views.py @@ -1,8 +1,12 @@ +from asgiref.sync import async_to_sync from django.contrib.auth.mixins import LoginRequiredMixin -from django.views.generic import CreateView, TemplateView +from django.urls import reverse_lazy +from django.views.generic import FormView, TemplateView +from dgsi.forms import CreateKanidmAccountForm from dgsi.mixins import StaffRequiredMixin from dgsi.models import User +from shared.kanidm import client class ProfileView(LoginRequiredMixin, TemplateView): @@ -18,5 +22,26 @@ class ProfileView(LoginRequiredMixin, TemplateView): ) -class CreateUserView(StaffRequiredMixin, CreateView): - model = User +class CreateKanidmAccountView(StaffRequiredMixin, FormView): + form_class = CreateKanidmAccountForm + template_name = "account/create_kanidm.html" + + success_url = reverse_lazy("dgsi:dgn-create_user") + + @async_to_sync + async def form_valid(self, form): + d = form.cleaned_data + + # Create the base account + await client.person_account_create(d["name"], d["displayname"]) + + # Update the information + await client.person_account_update(d["name"], mail=d["mail"]) + + # If necessary, add the user to the active members group + if d["active"]: + await client.group_add_members("dgnum_members", [d["name"]]) + + # TODO: Generate a reset token, and update it + + return super().form_valid(form) diff --git a/src/shared/templates/account/create_kanidm.html b/src/shared/templates/account/create_kanidm.html new file mode 100644 index 0000000..2ccb838 --- /dev/null +++ b/src/shared/templates/account/create_kanidm.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +

{% trans "Création de compte Kanidm" %}

+
+ +
+ {% csrf_token %} + {% include "bulma/form.html" with form=form %} + + +
+{% endblock content %} diff --git a/src/shared/templates/home.html b/src/shared/templates/home.html index 45f2c21..a0b0968 100644 --- a/src/shared/templates/home.html +++ b/src/shared/templates/home.html @@ -3,6 +3,9 @@ {% block content %} {% if user.is_authenticated %} - {% trans "Mon profil" %} + {% trans "Mon profil" %} + {% endif %} + {% if user.is_admin %} + {% trans "Créer un nouveau compte" %} {% endif %} {% endblock content %}