8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-12-23 15:33:45 +00:00
re2o/users/forms.py

652 lines
22 KiB
Python
Raw Normal View History

# -*- mode: python; coding: utf-8 -*-
2017-01-15 23:01:18 +00:00
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017 Gabriel Détraz
# Copyright © 2017 Goulven Kermarec
# Copyright © 2017 Augustin Lemesle
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2017-10-14 18:18:12 +00:00
"""
Definition des forms pour l'application users.
2017-01-15 23:01:18 +00:00
2017-10-14 18:18:12 +00:00
Modification, creation de :
- un user (informations personnelles)
- un bannissement
- le mot de passe d'un user
- une whiteliste
- un user de service
"""
from __future__ import unicode_literals
from django import forms
from django.forms import ModelForm, Form
from django.contrib.auth.forms import ReadOnlyPasswordHashField
2016-11-21 19:14:25 +00:00
from django.core.validators import MinLengthValidator
from django.utils import timezone
2017-12-31 16:11:19 +00:00
from django.contrib.auth.models import Group, Permission
2017-10-14 18:18:12 +00:00
from preferences.models import OptionalUser
from re2o.utils import remove_user_room, get_input_formats_help_text
2018-04-14 23:16:49 +00:00
from re2o.mixins import FormRevMixin
from re2o.field_permissions import FieldPermissionFormMixin
2018-05-05 15:58:13 +00:00
from .widgets import DateTimePicker
from .models import (
User,
ServiceUser,
School,
ListRight,
Whitelist,
2018-08-01 11:06:25 +00:00
EMailAddress,
ListShell,
Ban,
Adherent,
Club
)
class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm):
2017-10-14 18:18:12 +00:00
"""Formulaire de changement de mot de passe. Verifie que les 2
nouveaux mots de passe renseignés sont identiques et respectent
une norme"""
selfpasswd = forms.CharField(
label=u'Saisir le mot de passe existant',
max_length=255,
widget=forms.PasswordInput
)
2017-10-14 18:18:12 +00:00
passwd1 = forms.CharField(
label=u'Nouveau mot de passe',
max_length=255,
validators=[MinLengthValidator(8)],
widget=forms.PasswordInput
)
passwd2 = forms.CharField(
label=u'Saisir à nouveau le mot de passe',
max_length=255,
validators=[MinLengthValidator(8)],
widget=forms.PasswordInput
)
class Meta:
model = User
fields = []
def clean_passwd2(self):
2017-10-14 18:18:12 +00:00
"""Verifie que passwd1 et 2 sont identiques"""
# Check that the two password entries match
password1 = self.cleaned_data.get("passwd1")
password2 = self.cleaned_data.get("passwd2")
if password1 and password2 and password1 != password2:
2018-04-14 01:25:05 +00:00
raise forms.ValidationError(
"Les 2 nouveaux mots de passe sont différents"
)
return password2
def clean_selfpasswd(self):
"""Verifie si il y a lieu que le mdp self est correct"""
2018-04-14 01:25:05 +00:00
if not self.instance.check_password(
2018-04-14 23:16:49 +00:00
self.cleaned_data.get("selfpasswd")
):
raise forms.ValidationError("Le mot de passe actuel est incorrect")
return
def save(self, commit=True):
"""Changement du mot de passe"""
user = super(PassForm, self).save(commit=False)
user.set_password(self.cleaned_data.get("passwd1"))
user.save()
2017-10-14 18:18:12 +00:00
class UserCreationForm(FormRevMixin, forms.ModelForm):
"""A form for creating new users. Includes all the required
2017-10-14 18:18:12 +00:00
fields, plus a repeated password.
Formulaire pour la création d'un user. N'est utilisé que pour
l'admin, lors de la creation d'un user par admin. Inclu tous les
champs obligatoires"""
password1 = forms.CharField(
label='Password',
widget=forms.PasswordInput,
validators=[MinLengthValidator(8)],
max_length=255
)
password2 = forms.CharField(
label='Password confirmation',
widget=forms.PasswordInput,
validators=[MinLengthValidator(8)],
max_length=255
)
is_admin = forms.BooleanField(label='is admin')
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(UserCreationForm, self).__init__(*args, prefix=prefix, **kwargs)
def clean_email(self):
if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get('email'):
return self.cleaned_data.get('email').lower()
else:
raise forms.ValidationError("You can't use an internal address as your external address.")
class Meta:
model = Adherent
2018-07-30 15:00:41 +00:00
fields = ('pseudo', 'surname', 'email')
def clean_password2(self):
2017-10-14 18:18:12 +00:00
"""Verifie que password1 et 2 sont identiques"""
# 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("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.save()
user.is_admin = self.cleaned_data.get("is_admin")
return user
2017-10-14 18:18:12 +00:00
class ServiceUserCreationForm(FormRevMixin, forms.ModelForm):
2016-07-31 03:03:07 +00:00
"""A form for creating new users. Includes all the required
2017-10-14 18:18:12 +00:00
fields, plus a repeated password.
Formulaire pour la creation de nouveaux serviceusers.
Requiert seulement un mot de passe; et un pseudo"""
password1 = forms.CharField(
label='Password',
widget=forms.PasswordInput,
min_length=8,
max_length=255
)
password2 = forms.CharField(
label='Password confirmation',
widget=forms.PasswordInput,
min_length=8,
max_length=255
)
2016-07-31 03:03:07 +00:00
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
2017-10-14 18:18:12 +00:00
super(ServiceUserCreationForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
2016-07-31 03:03:07 +00:00
class Meta:
model = ServiceUser
fields = ('pseudo',)
def clean_password2(self):
2017-10-14 18:18:12 +00:00
"""Verifie que password1 et 2 sont indentiques"""
2016-07-31 03:03:07 +00:00
# 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("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(ServiceUserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.save()
return user
2017-10-14 18:18:12 +00:00
class UserChangeForm(FormRevMixin, forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
2017-10-14 18:18:12 +00:00
Formulaire pour la modification d'un user coté admin
"""
password = ReadOnlyPasswordHashField()
is_admin = forms.BooleanField(label='is admin', required=False)
class Meta:
model = Adherent
fields = ('pseudo', 'password', 'surname', 'email')
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(UserChangeForm, self).__init__(*args, prefix=prefix, **kwargs)
print("User is admin : %s" % kwargs['instance'].is_admin)
self.initial['is_admin'] = kwargs['instance'].is_admin
def clean_password(self):
2017-10-14 18:18:12 +00:00
"""Dummy fun"""
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserChangeForm, self).save(commit=False)
user.is_admin = self.cleaned_data.get("is_admin")
if commit:
user.save()
return user
2016-07-20 10:06:33 +00:00
2017-10-14 18:18:12 +00:00
class ServiceUserChangeForm(FormRevMixin, forms.ModelForm):
2016-07-31 03:03:07 +00:00
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
2017-10-14 18:18:12 +00:00
Formulaire pour l'edition des service users coté admin
2016-07-31 03:03:07 +00:00
"""
password = ReadOnlyPasswordHashField()
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
2017-10-14 18:18:12 +00:00
super(ServiceUserChangeForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
2016-07-31 03:03:07 +00:00
class Meta:
model = ServiceUser
fields = ('pseudo',)
def clean_password(self):
2017-10-14 18:18:12 +00:00
"""Dummy fun"""
2016-07-31 03:03:07 +00:00
return self.initial["password"]
2017-10-14 18:18:12 +00:00
2016-07-20 10:06:33 +00:00
class ResetPasswordForm(forms.Form):
2017-10-14 18:18:12 +00:00
"""Formulaire de demande de reinitialisation de mot de passe,
mdp oublié"""
2016-07-20 10:06:33 +00:00
pseudo = forms.CharField(label=u'Pseudo', max_length=255)
email = forms.EmailField(max_length=255)
2017-10-14 18:18:12 +00:00
class MassArchiveForm(forms.Form):
2017-10-14 18:18:12 +00:00
"""Formulaire d'archivage des users inactif. Prend en argument
du formulaire la date de depart avant laquelle archiver les
users"""
date = forms.DateTimeField(help_text='%d/%m/%y')
def clean(self):
2017-10-14 18:18:12 +00:00
cleaned_data = super(MassArchiveForm, self).clean()
date = cleaned_data.get("date")
if date:
if date > timezone.now():
2017-10-14 18:18:12 +00:00
raise forms.ValidationError("Impossible d'archiver des\
utilisateurs dont la fin d'accès se situe dans le futur !")
class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
2017-10-14 18:18:12 +00:00
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé
pour l'edition de self par self ou un cableur. On formate les champs
avec des label plus jolis"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(AdherentForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = 'Prénom'
self.fields['surname'].label = 'Nom'
2018-08-11 01:58:03 +00:00
self.fields['email'].label = 'Adresse mail'
self.fields['school'].label = 'Établissement'
self.fields['comment'].label = 'Commentaire'
self.fields['room'].label = 'Chambre'
self.fields['room'].empty_label = "Pas de chambre"
self.fields['school'].empty_label = "Séléctionner un établissement"
2018-07-30 15:00:41 +00:00
def clean_email(self):
if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get('email'):
return self.cleaned_data.get('email').lower()
else:
raise forms.ValidationError("Vous ne pouvez pas utiliser une addresse {}".format(OptionalUser.objects.first().local_email_domain))
class Meta:
model = Adherent
fields = [
'name',
'surname',
'pseudo',
'email',
'school',
'comment',
'room',
'shell',
'telephone',
2018-08-11 01:58:03 +00:00
'gpg_fingerprint'
]
def clean_telephone(self):
2017-10-14 18:18:12 +00:00
"""Verifie que le tel est présent si 'option est validée
dans preferences"""
telephone = self.cleaned_data['telephone']
if not telephone and OptionalUser.get_cached_value('is_tel_mandatory'):
2017-10-14 18:18:12 +00:00
raise forms.ValidationError(
"Un numéro de téléphone valide est requis"
)
return telephone
2018-08-11 01:58:03 +00:00
def clean_gpg_fingerprint(self):
"""Format the GPG fingerprint"""
gpg_fingerprint = self.cleaned_data.get('gpg_fingerprint', None)
if gpg_fingerprint:
return gpg_fingerprint.replace(' ', '').upper()
force = forms.BooleanField(
label="Forcer le déménagement ?",
initial=False,
required=False
)
def clean_force(self):
"""On supprime l'ancien user de la chambre si et seulement si la
case est cochée"""
if self.cleaned_data.get('force', False):
remove_user_room(self.cleaned_data.get('room'))
return
2017-10-14 18:18:12 +00:00
class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé
pour l'edition de self par self ou un cableur. On formate les champs
avec des label plus jolis"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ClubForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['surname'].label = 'Nom'
self.fields['school'].label = 'Établissement'
self.fields['comment'].label = 'Commentaire'
self.fields['room'].label = 'Local'
self.fields['room'].empty_label = "Pas de chambre"
self.fields['school'].empty_label = "Séléctionner un établissement"
self.fields['mailing'].label = 'Utiliser une mailing'
class Meta:
model = Club
fields = [
'surname',
'pseudo',
'school',
'comment',
'room',
'telephone',
'shell',
'mailing'
]
def clean_telephone(self):
"""Verifie que le tel est présent si 'option est validée
dans preferences"""
telephone = self.cleaned_data['telephone']
if not telephone and OptionalUser.get_cached_value('is_tel_mandatory'):
raise forms.ValidationError(
"Un numéro de téléphone valide est requis"
)
return telephone
class ClubAdminandMembersForm(FormRevMixin, ModelForm):
"""Permet d'éditer la liste des membres et des administrateurs
d'un club"""
class Meta:
model = Club
fields = ['administrators', 'members']
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
2018-04-14 01:25:05 +00:00
super(ClubAdminandMembersForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
class PasswordForm(FormRevMixin, ModelForm):
2017-10-14 18:18:12 +00:00
""" Formulaire de changement brut de mot de passe.
Ne pas utiliser sans traitement"""
class Meta:
model = User
fields = ['password', 'pwd_ntlm']
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(PasswordForm, self).__init__(*args, prefix=prefix, **kwargs)
2017-10-14 18:18:12 +00:00
class ServiceUserForm(FormRevMixin, ModelForm):
2017-10-04 15:53:30 +00:00
""" Modification d'un service user"""
2017-10-14 18:18:12 +00:00
password = forms.CharField(
label=u'Nouveau mot de passe',
max_length=255,
validators=[MinLengthValidator(8)],
widget=forms.PasswordInput,
required=False
)
class Meta:
model = ServiceUser
fields = ('pseudo', 'access_group','comment')
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ServiceUserForm, self).__init__(*args, prefix=prefix, **kwargs)
def save(self, commit=True):
"""Changement du mot de passe"""
user = super(ServiceUserForm, self).save(commit=False)
if self.cleaned_data['password']:
user.set_password(self.cleaned_data.get("password"))
user.save()
2017-10-14 18:18:12 +00:00
class EditServiceUserForm(ServiceUserForm):
2017-10-14 18:18:12 +00:00
"""Formulaire d'edition de base d'un service user. Ne permet
d'editer que son group d'acl et son commentaire"""
class Meta(ServiceUserForm.Meta):
2017-10-14 18:18:12 +00:00
fields = ['access_group', 'comment']
class StateForm(FormRevMixin, ModelForm):
2017-10-04 15:53:30 +00:00
""" Changement de l'état d'un user"""
class Meta:
model = User
fields = ['state']
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(StateForm, self).__init__(*args, prefix=prefix, **kwargs)
2018-05-03 12:22:52 +00:00
class GroupForm(FieldPermissionFormMixin, FormRevMixin, ModelForm):
2017-12-31 16:11:19 +00:00
""" Gestion des groupes d'un user"""
groups = forms.ModelMultipleChoiceField(
Group.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=False
)
class Meta:
model = User
fields = ['is_superuser', 'groups']
2017-12-31 16:11:19 +00:00
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(GroupForm, self).__init__(*args, prefix=prefix, **kwargs)
2018-05-03 12:22:52 +00:00
if 'is_superuser' in self.fields:
self.fields['is_superuser'].label = "Superuser"
2017-12-31 16:11:19 +00:00
class SchoolForm(FormRevMixin, ModelForm):
2017-10-14 18:18:12 +00:00
"""Edition, creation d'un école"""
class Meta:
model = School
fields = ['name']
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(SchoolForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = 'Établissement'
2017-10-14 18:18:12 +00:00
class ShellForm(FormRevMixin, ModelForm):
"""Edition, creation d'un école"""
class Meta:
model = ListShell
fields = ['shell']
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ShellForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['shell'].label = 'Nom du shell'
class ListRightForm(FormRevMixin, ModelForm):
2017-10-14 18:18:12 +00:00
"""Edition, d'un groupe , équivalent à un droit
Ne permet pas d'editer le gid, car il sert de primary key"""
2017-12-31 16:11:19 +00:00
permissions = forms.ModelMultipleChoiceField(
Permission.objects.all().select_related('content_type'),
2017-12-31 16:11:19 +00:00
widget=forms.CheckboxSelectMultiple,
required=False
)
class Meta:
model = ListRight
fields = ('name', 'unix_name', 'critical', 'permissions', 'details')
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ListRightForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['unix_name'].label = 'Nom UNIX du groupe'
2017-10-14 18:18:12 +00:00
class NewListRightForm(ListRightForm):
2017-10-14 18:18:12 +00:00
"""Ajout d'un groupe/list de droit """
class Meta(ListRightForm.Meta):
fields = ('name', 'unix_name', 'gid', 'critical', 'permissions',
'details')
def __init__(self, *args, **kwargs):
super(NewListRightForm, self).__init__(*args, **kwargs)
self.fields['gid'].label = ("Gid, attention, cet attribut ne doit "
"pas être modifié après création")
2017-10-14 18:18:12 +00:00
class DelListRightForm(Form):
2017-10-14 18:18:12 +00:00
"""Suppression d'un ou plusieurs groupes"""
listrights = forms.ModelMultipleChoiceField(
2017-12-13 17:35:16 +00:00
queryset=ListRight.objects.none(),
2017-10-14 18:18:12 +00:00
label="Droits actuels",
widget=forms.CheckboxSelectMultiple
)
2017-12-13 17:35:16 +00:00
def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None)
super(DelListRightForm, self).__init__(*args, **kwargs)
if instances:
2017-12-31 16:11:19 +00:00
self.fields['listrights'].queryset = instances
2017-12-13 17:35:16 +00:00
else:
2017-12-31 16:11:19 +00:00
self.fields['listrights'].queryset = ListRight.objects.all()
2017-12-13 17:35:16 +00:00
class DelSchoolForm(Form):
2017-10-14 18:18:12 +00:00
"""Suppression d'une ou plusieurs écoles"""
schools = forms.ModelMultipleChoiceField(
2017-12-13 17:35:16 +00:00
queryset=School.objects.none(),
2017-10-14 18:18:12 +00:00
label="Etablissements actuels",
widget=forms.CheckboxSelectMultiple
)
2017-12-12 03:33:50 +00:00
def __init__(self, *args, **kwargs):
2017-12-13 17:35:16 +00:00
instances = kwargs.pop('instances', None)
2017-12-12 03:33:50 +00:00
super(DelSchoolForm, self).__init__(*args, **kwargs)
2017-12-13 17:35:16 +00:00
if instances:
self.fields['schools'].queryset = instances
else:
self.fields['schools'].queryset = School.objects.all()
2017-12-12 03:33:50 +00:00
class BanForm(FormRevMixin, ModelForm):
2017-10-14 18:18:12 +00:00
"""Creation, edition d'un objet bannissement"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(BanForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['date_end'].label = 'Date de fin'
self.fields['date_end'].localize = False
class Meta:
model = Ban
exclude = ['user']
widgets = {'date_end':DateTimePicker}
class WhitelistForm(FormRevMixin, ModelForm):
2017-10-14 18:18:12 +00:00
"""Creation, edition d'un objet whitelist"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(WhitelistForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['date_end'].label = 'Date de fin'
2018-05-05 15:58:13 +00:00
self.fields['date_end'].localize = False
class Meta:
model = Whitelist
exclude = ['user']
2018-05-05 15:58:13 +00:00
widgets = {'date_end':DateTimePicker}
2018-08-01 11:06:25 +00:00
class EMailAddressForm(FormRevMixin, ModelForm):
"""Create and edit a local email address"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
2018-08-01 11:06:25 +00:00
super(EMailAddressForm, self).__init__(*args, prefix=prefix, **kwargs)
2018-07-30 15:00:41 +00:00
self.fields['local_part'].label = "Local part of the email"
self.fields['local_part'].help_text = "Can't contain @"
def clean_local_part(self):
return self.cleaned_data.get('local_part').lower()
class Meta:
2018-08-01 11:06:25 +00:00
model = EMailAddress
2018-06-29 14:36:04 +00:00
exclude = ['user']
2018-07-30 15:00:41 +00:00
class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Edit email-related settings"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
2018-07-30 15:00:41 +00:00
super(EmailSettingsForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['email'].label = "Main email address"
2018-07-30 15:00:41 +00:00
if 'local_email_redirect' in self.fields:
self.fields['local_email_redirect'].label = "Redirect local emails"
if 'local_email_enabled' in self.fields:
self.fields['local_email_enabled'].label = "Use local emails"
def clean_email(self):
if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get('email'):
return self.cleaned_data.get('email').lower()
else:
raise forms.ValidationError("Vous ne pouvez pas utiliser une addresse {}".format(OptionalUser.objects.first().local_email_domain))
class Meta:
2018-06-29 14:36:04 +00:00
model = User
fields = ['email','local_email_enabled', 'local_email_redirect']