diff --git a/CHANGELOG.md b/CHANGELOG.md index f390ba09..5ec2da1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,3 +128,11 @@ You need to ensure that your database character set is utf-8. ```sql ALTER DATABASE re2o CHARACTER SET utf8; ``` + +## MR 247: Fix des comptes mails + +Fix several issues with email accounts, you need to collect the static files. + +```bash +./manage.py collectstatic +``` diff --git a/static/js/email_address.js b/static/js/email_address.js new file mode 100644 index 00000000..10c1f544 --- /dev/null +++ b/static/js/email_address.js @@ -0,0 +1,17 @@ +/** To enable the redirection has no meaning if the local email adress is not + * enabled. Thus this function enable the checkbox if needed and changes its + * state. + */ +function enable_redirection_chkbox() { + var redirect = document.getElementById('id_User-local_email_redirect'); + var enabled = document.getElementById('id_User-local_email_enabled').checked; + if(!enabled) + { + redirect.checked = false; + } + redirect.disabled = !enabled; +} + +var enabled_chkbox = document.getElementById('id_User-local_email_enabled'); +enabled_chkbox.onclick = enable_redirection_chkbox; +enable_redirection_chkbox(); diff --git a/users/forms.py b/users/forms.py index 49135266..dac86d71 100644 --- a/users/forms.py +++ b/users/forms.py @@ -138,6 +138,12 @@ class UserCreationForm(FormRevMixin, forms.ModelForm): 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 fields = ('pseudo', 'surname', 'email') @@ -308,6 +314,12 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): self.fields['room'].empty_label = "Pas de chambre" self.fields['school'].empty_label = "Séléctionner un établissement" + 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 = [ @@ -323,6 +335,7 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): 'gpg_fingerprint' ] + def clean_telephone(self): """Verifie que le tel est présent si 'option est validée dans preferences""" @@ -608,6 +621,9 @@ class EMailAddressForm(FormRevMixin, ModelForm): 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: model = EMailAddress exclude = ['user'] @@ -618,19 +634,18 @@ class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(EmailSettingsForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['email'].label = "Contact email address" + self.fields['email'].label = "Main email address" if 'local_email_redirect' in self.fields: self.fields['local_email_redirect'].label = "Redirect local emails" - self.fields['local_email_redirect'].help_text = ( - "Enable the automated redirection of the local email address " - "to the contact email address" - ) if 'local_email_enabled' in self.fields: self.fields['local_email_enabled'].label = "Use local emails" - self.fields['local_email_enabled'].help_text = ( - "Enable the use of the local email account" - ) + + 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 = User - fields = ['email', 'local_email_redirect', 'local_email_enabled'] + fields = ['email','local_email_enabled', 'local_email_redirect'] diff --git a/users/migrations/0074_auto_20180814_1059.py b/users/migrations/0074_auto_20180814_1059.py new file mode 100644 index 00000000..e3e8527f --- /dev/null +++ b/users/migrations/0074_auto_20180814_1059.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-08-14 08:59 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0073_auto_20180629_1614'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='email', + field=models.EmailField(blank=True, null=True, help_text='External email address allowing us to contact you.', max_length=254), + ), + migrations.AlterField( + model_name='user', + name='local_email_enabled', + field=models.BooleanField(default=False, help_text='Enable the local email account.'), + ), + migrations.AlterField( + model_name='user', + name='local_email_redirect', + field=models.BooleanField(default=False, help_text='Enable redirection of the local email messages to the main email.'), + ), + ] diff --git a/users/models.py b/users/models.py index 01de431c..0fe2cd62 100755 --- a/users/models.py +++ b/users/models.py @@ -53,6 +53,7 @@ import sys from django.db import models from django.db.models import Q from django import forms +from django.forms import ValidationError from django.db.models.signals import post_save, post_delete, m2m_changed from django.dispatch import receiver from django.utils.functional import cached_property @@ -131,6 +132,7 @@ def get_fresh_gid(): class UserManager(BaseUserManager): """User manager basique de django""" + def _create_user( self, pseudo, @@ -195,14 +197,18 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, help_text="Doit contenir uniquement des lettres, chiffres, ou tirets", validators=[linux_user_validator] ) - email = models.EmailField() + email = models.EmailField( + blank=True, + null=True, + help_text="External email address allowing us to contact you." + ) local_email_redirect = models.BooleanField( default=False, - help_text="Whether or not to redirect the local email messages to the main email." + help_text="Enable redirection of the local email messages to the main email." ) local_email_enabled = models.BooleanField( default=False, - help_text="Wether or not to enable the local email account." + help_text="Enable the local email account." ) school = models.ForeignKey( 'School', @@ -286,7 +292,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, if not OptionalUser.get_cached_value('local_email_accounts_enabled') or not self.local_email_enabled or self.local_email_redirect: return str(self.email) else: - return str(self.emailaddress_set.get(local_part=self.pseudo)) + return str(self.emailaddress_set.get(local_part=self.pseudo.lower())) @cached_property def class_name(self): @@ -560,13 +566,15 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, user_ldap.gid = LDAP['user_gid'] if '{SSHA}' in self.password or '{SMD5}' in self.password: # We remove the extra $ added at import from ldap - user_ldap.user_password = self.password[:6] + self.password[7:] + user_ldap.user_password = self.password[:6] + \ + self.password[7:] elif '{crypt}' in self.password: # depending on the length, we need to remove or not a $ - if len(self.password)==41: + if len(self.password) == 41: user_ldap.user_password = self.password - else: - user_ldap.user_password = self.password[:7] + self.password[8:] + else: + user_ldap.user_password = self.password[:7] + \ + self.password[8:] user_ldap.sambat_nt_password = self.pwd_ntlm.upper() if self.get_shell: @@ -611,7 +619,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, send_mail( 'Bienvenue au %(name)s / Welcome to %(name)s' % { 'name': AssoOption.get_cached_value('name') - }, + }, '', GeneralOption.get_cached_value('email_from'), [self.email], @@ -654,8 +662,8 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, une machine inconnue sur le compte de l'user""" all_interfaces = self.user_interfaces(active=False) if all_interfaces.count() > OptionalMachine.get_cached_value( - 'max_lambdauser_interfaces' - ): + 'max_lambdauser_interfaces' + ): return False, "Maximum de machines enregistrees atteinte" if not nas_type: return False, "Re2o ne sait pas à quel machinetype affecter cette\ @@ -958,7 +966,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, 'force': self.can_change_force, 'selfpasswd': self.check_selfpasswd, 'local_email_redirect': self.can_change_local_email_redirect, - 'local_email_enabled' : self.can_change_local_email_enabled, + 'local_email_enabled': self.can_change_local_email_enabled, } self.__original_state = self.state @@ -966,9 +974,22 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, """Check if this pseudo is already used by any mailalias. Better than raising an error in post-save and catching it""" if (EMailAddress.objects - .filter(local_part=self.pseudo) - .exclude(user=self)): + .filter(local_part=self.pseudo.lower()).exclude(user_id=self.id) + ): raise ValidationError("This pseudo is already in use.") + if not self.local_email_enabled and not self.email: + raise ValidationError( + {'email': ( + 'There is neither a local email address nor an external' + ' email address for this user.' + ), } + ) + if self.local_email_redirect and not self.email: + raise ValidationError( + {'local_email_redirect': ( + 'You cannot redirect your local email if no external email ' + 'has been set.'), } + ) def __str__(self): return self.pseudo @@ -1106,7 +1127,8 @@ def user_post_save(**kwargs): Synchronise le ldap""" is_created = kwargs['created'] user = kwargs['instance'] - EMailAddress.objects.get_or_create(local_part=user.pseudo, user=user) + EMailAddress.objects.get_or_create( + local_part=user.pseudo.lower(), user=user) if is_created: user.notif_inscription() user.state_sync() @@ -1129,6 +1151,7 @@ def user_group_relation_changed(**kwargs): mac_refresh=False, group_refresh=True) + @receiver(post_delete, sender=Adherent) @receiver(post_delete, sender=Club) @receiver(post_delete, sender=User) @@ -1517,7 +1540,7 @@ class Request(models.Model): hours=GeneralOption.get_cached_value( 'req_expire_hrs' ) - )) + )) if not self.token: self.token = str(uuid.uuid4()).replace('-', '') # remove hyphens super(Request, self).save() @@ -1768,10 +1791,10 @@ class EMailAddress(RevMixin, AclMixin, models.Model): a message and a boolean which is True if the user can delete the local email account. """ - if self.local_part == self.user.pseudo: + if self.local_part == self.user.pseudo.lower(): return False, ("You cannot delete a local email account whose " "local part is the same as the username.") - if user_request.has_perm('users.delete_emailaddress'): + if user_request.has_perm('users.delete_emailaddress'): return True, None if not OptionalUser.get_cached_value('local_email_accounts_enabled'): return False, "The local email accounts are not enabled." @@ -1790,7 +1813,7 @@ class EMailAddress(RevMixin, AclMixin, models.Model): a message and a boolean which is True if the user can edit the local email account. """ - if self.local_part == self.user.pseudo: + if self.local_part == self.user.pseudo.lower(): return False, ("You cannot edit a local email account whose " "local part is the same as the username.") if user_request.has_perm('users.change_emailaddress'): @@ -1803,7 +1826,7 @@ class EMailAddress(RevMixin, AclMixin, models.Model): "local email account") def clean(self, *args, **kwargs): + self.local_part = self.local_part.lower() if "@" in self.local_part: raise ValidationError("The local part cannot contain a @") super(EMailAddress, self).clean(*args, **kwargs) - diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index c2053612..f573941b 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -27,15 +27,16 @@ with this program; if not, write to the Free Software Foundation, Inc., {% load acl %} {% load logs_extra %} {% load design %} +{% load i18n %} {% block title %}Profil{% endblock %} {% block content %}
{% if user == users %} -

Welcome {{ users.name }} {{ users.surname }}

+

Welcome {{ users.name }} {{ users.surname }}

{% else %} -

Profil de {{ users.name }} {{ users.surname }}

+

Profil de {{ users.name }} {{ users.surname }}

{% endif %}
@@ -74,7 +75,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- {{ users.solde }} + {{ users.solde }}
diff --git a/users/templates/users/user.html b/users/templates/users/user.html index edd57ea1..5e4048a3 100644 --- a/users/templates/users/user.html +++ b/users/templates/users/user.html @@ -36,6 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc., {% massive_bootstrap_form userform 'room,school,administrators,members' %} {% bootstrap_button action_name button_type="submit" icon="star" %} +{% if load_js_file %} + +{% endif %}
{% if showCGU %}

En cliquant sur Créer ou modifier, l'utilisateur s'engage à respecter les règles d'utilisation du réseau.

diff --git a/users/views.py b/users/views.py index ca7438df..5279dbb0 100644 --- a/users/views.py +++ b/users/views.py @@ -541,7 +541,8 @@ def edit_emailaddress(request, emailaddress_instance, **_kwargs): return form( {'userform': emailaddress, 'showCGU': False, - 'action_name': 'Edit a local email account'}, + 'action_name': 'Edit a local email account', + }, 'users/user.html', request ) @@ -585,6 +586,7 @@ def edit_email_settings(request, user_instance, **_kwargs): return form( {'userform': email_settings, 'showCGU': False, + 'load_js_file': '/static/js/email_address.js', 'action_name': 'Edit the email settings'}, 'users/user.html', request @@ -1017,7 +1019,7 @@ def profil(request, users, **_kwargs): 'emailaddress_list': users.email_address, 'local_email_accounts_enabled': ( OptionalUser.objects.first().local_email_accounts_enabled - ) + ) } )