diff --git a/api/views.py b/api/views.py index 58730754..4077eeeb 100644 --- a/api/views.py +++ b/api/views.py @@ -513,7 +513,6 @@ class HomeCreationViewSet(viewsets.ReadOnlyModelViewSet): queryset = users.User.objects.exclude( Q(state=users.User.STATE_DISABLED) | Q(state=users.User.STATE_NOT_YET_ACTIVE) - | Q(state=users.STATE_EMAIL_NOT_YET_CONFIRMED) | Q(state=users.User.STATE_FULL_ARCHIVE) ) serializer_class = serializers.BasicUserSerializer diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index daebf95d..966663b1 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -469,7 +469,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address): RadiusOption.get_attributes("non_member_attributes", attributes_kwargs), ) for user in room_user: - if user.is_ban() or user.state not in [User.STATE_ACTIVE, User.STATE_EMAIL_NOT_YET_CONFIRMED]: + if user.is_ban() or user.state != User.STATE_ACTIVE: return ( sw_name, room, @@ -480,6 +480,21 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address): RadiusOption.get_cached_value("banned") != RadiusOption.REJECT, RadiusOption.get_attributes("banned_attributes", attributes_kwargs), ) + elif user.email_state == User.EMAIL_STATE_UNVERIFIED: + return ( + sw_name, + room, + u"Utilisateur suspendu (mail non confirme)", + getattr( + RadiusOption.get_cached_value("non_member_vlan"), + "vlan_id", + None, + ), + RadiusOption.get_cached_value("non_member") != RadiusOption.REJECT, + RadiusOption.get_attributes( + "non_member_attributes", attributes_kwargs + ), + ) elif not (user.is_connected() or user.is_whitelisted()): return ( sw_name, diff --git a/logs/views.py b/logs/views.py index 615fb69b..7c509134 100644 --- a/logs/views.py +++ b/logs/views.py @@ -260,16 +260,6 @@ def stats_general(request): ), Club.objects.filter(state=Club.STATE_NOT_YET_ACTIVE).count(), ], - "email_not_confirmed_users": [ - _("Waiting for email confirmation users"), - User.objects.filter(state=User.STATE_EMAIL_NOT_YET_CONFIRMED).count(), - ( - Adherent.objects.filter( - state=Adherent.STATE_EMAIL_NOT_YET_CONFIRMED - ).count() - ), - Club.objects.filter(state=Club.STATE_EMAIL_NOT_YET_CONFIRMED).count(), - ], "adherent_users": [ _("Contributing members"), _all_adherent.count(), diff --git a/re2o/utils.py b/re2o/utils.py index 61c45c0c..348e5c55 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -116,7 +116,8 @@ def all_has_access(search_time=None, including_asso=True): if search_time is None: search_time = timezone.now() filter_user = ( - (Q(state=User.STATE_ACTIVE) | Q(state=User.STATE_EMAIL_NOT_YET_CONFIRMED)) + Q(state=User.STATE_ACTIVE) + & ~Q(email_state=User.EMAIL_STATE_UNVERIFIED) & ~Q( ban__in=Ban.objects.filter( Q(date_start__lt=search_time) & Q(date_end__gt=search_time) diff --git a/users/forms.py b/users/forms.py index ad5c3708..94002eeb 100644 --- a/users/forms.py +++ b/users/forms.py @@ -388,8 +388,8 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): if not self.is_anon and self.initial["email"] and user.email != self.initial["email"]: # Send a confirmation email - if user.state in [User.STATE_ACTIVE, User.STATE_DISABLED, User.STATE_NOT_YET_ACTIVE, User.STATE_EMAIL_NOT_YET_CONFIRMED]: - user.state = User.STATE_EMAIL_NOT_YET_CONFIRMED + if user.state in [User.STATE_ACTIVE, User.STATE_DISABLED, User.STATE_NOT_YET_ACTIVE]: + user.email_state = User.EMAIL_STATE_PENDING self.should_send_confirmation_email = True # Always keep the oldest change date @@ -682,7 +682,6 @@ class StateForm(FormRevMixin, ModelForm): user.state = self.cleaned_data.get("state") user.state_sync() - user.email_change_date_sync() user.save() diff --git a/users/locale/fr/LC_MESSAGES/django.po b/users/locale/fr/LC_MESSAGES/django.po index 1d6ec63b..922c2dbe 100644 --- a/users/locale/fr/LC_MESSAGES/django.po +++ b/users/locale/fr/LC_MESSAGES/django.po @@ -1008,8 +1008,8 @@ msgstr "Vous n'avez pas reçu le mail ?" #: users/templates/users/profil.html:53 #, python-format -msgid "Your account has been suspended." -msgstr "Votre compte a été suspendu." +msgid "Your account has been suspended, please confirm your email address." +msgstr "Votre compte a été suspendu, veuillez confirmer votre adresse mail." #: users/templates/users/profil.html:46 msgid "Your account has been banned." diff --git a/users/management/commands/archive.py b/users/management/commands/archive.py index d730cfcd..1e4601a0 100644 --- a/users/management/commands/archive.py +++ b/users/management/commands/archive.py @@ -77,7 +77,6 @@ class Command(BaseCommand): .exclude(id__in=all_has_access(search_time=date)) .exclude(state=User.STATE_NOT_YET_ACTIVE) .exclude(state=User.STATE_FULL_ARCHIVE) - .exclude(state=User.STATE_EMAIL_NOT_YET_CONFIRMED) ) if show: diff --git a/users/management/commands/disable_emailnotyetconfirmed.py b/users/management/commands/disable_emailnotyetconfirmed.py index 955234e5..85b12699 100644 --- a/users/management/commands/disable_emailnotyetconfirmed.py +++ b/users/management/commands/disable_emailnotyetconfirmed.py @@ -31,13 +31,13 @@ class Command(BaseCommand): """First deleting invalid invoices, and then deleting the users""" days = OptionalUser.get_cached_value("disable_emailnotyetconfirmed") users_to_disable = ( - User.objects.filter(state=User.STATE_EMAIL_NOT_YET_CONFIRMED) + User.objects.filter(email_state=User.EMAIL_STATE_PENDING) .filter(email_change_date__lte=timezone.now() - timedelta(days=days)) .distinct() ) print("Disabling " + str(users_to_disable.count()) + " users.") for user in users_to_disable: - user.state = User.STATE_DISABLED + user.email_state = User.EMAIL_STATE_UNVERIFIED user.notif_disable() user.save() diff --git a/users/migrations/0085_auto_20200417_0031.py b/users/migrations/0085_auto_20200417_0031.py index 3a2e4241..802ea721 100644 --- a/users/migrations/0085_auto_20200417_0031.py +++ b/users/migrations/0085_auto_20200417_0031.py @@ -11,10 +11,16 @@ class Migration(migrations.Migration): ('users', '0084_auto_20191120_0159'), ] + def flag_verified(apps, schema_editor): + db_alias = schema_editor.connection.alias + users = apps.get_model("users", "User") + users.objects.using(db_alias).all().update(email_state=0) + operations = [ - migrations.AlterField( + migrations.AddField( model_name='user', - name='state', - field=models.IntegerField(choices=[(0, 'Active'), (1, 'Disabled'), (2, 'Archived'), (3, 'Not yet active'), (4, 'Fully archived'), (5, 'Waiting for email confirmation')], default=3), + name='email_state', + field=models.IntegerField(choices=[(0, 'Verified'), (1, 'Unverified'), (2, 'Waiting for email confirmation')], default=2), ), + migrations.RunPython(flag_verified), ] diff --git a/users/migrations/0085_user_email_state.py b/users/migrations/0085_user_email_state.py new file mode 100644 index 00000000..9dfff9af --- /dev/null +++ b/users/migrations/0085_user_email_state.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.28 on 2020-04-16 22:31 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0084_auto_20191120_0159'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='email_state', + field=models.IntegerField(choices=[(0, 'Verified'), (1, 'Unverified'), (2, 'Waiting for email confirmation')], default=2), + ), + ] diff --git a/users/migrations/0086_user_email_change_date.py b/users/migrations/0086_user_email_change_date.py index b6f7075c..e8d9ea9d 100644 --- a/users/migrations/0086_user_email_change_date.py +++ b/users/migrations/0086_user_email_change_date.py @@ -8,7 +8,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('users', '0085_auto_20200417_0031'), + ('users', '0085_user_email_state'), ] operations = [ diff --git a/users/models.py b/users/models.py index 397dc7f3..b658e9ef 100755 --- a/users/models.py +++ b/users/models.py @@ -179,14 +179,21 @@ class User( STATE_ARCHIVE = 2 STATE_NOT_YET_ACTIVE = 3 STATE_FULL_ARCHIVE = 4 - STATE_EMAIL_NOT_YET_CONFIRMED = 5 STATES = ( (0, _("Active")), (1, _("Disabled")), (2, _("Archived")), (3, _("Not yet active")), (4, _("Fully archived")), - (5, _("Waiting for email confirmation")), + ) + + EMAIL_STATE_VERIFIED = 0 + EMAIL_STATE_UNVERIFIED = 1 + EMAIL_STATE_PENDING = 2 + EMAIL_STATES = ( + (0, _("Verified")), + (1, _("Unverified")), + (2, _("Waiting for email confirmation")), ) surname = models.CharField(max_length=255) @@ -222,6 +229,7 @@ class User( ) pwd_ntlm = models.CharField(max_length=255) state = models.IntegerField(choices=STATES, default=STATE_NOT_YET_ACTIVE) + email_state = models.IntegerField(choices=EMAIL_STATES, default=EMAIL_STATE_PENDING) registered = models.DateTimeField(auto_now_add=True) telephone = models.CharField(max_length=15, blank=True, null=True) uid_number = models.PositiveIntegerField(default=get_fresh_user_uid, unique=True) @@ -332,7 +340,6 @@ class User( return ( self.state == self.STATE_ACTIVE or self.state == self.STATE_NOT_YET_ACTIVE - or self.state == self.STATE_EMAIL_NOT_YET_CONFIRMED or ( allow_archived and self.state in (self.STATE_ARCHIVE, self.STATE_FULL_ARCHIVE) @@ -395,7 +402,7 @@ class User( @cached_property def get_shadow_expire(self): """Return the shadow_expire value for the user""" - if self.state == self.STATE_DISABLED: + if self.state == self.STATE_DISABLED or self.email_state == self.EMAIL_STATE_UNVERIFIED: return str(0) else: return None @@ -487,7 +494,8 @@ class User( def has_access(self): """ Renvoie si un utilisateur a accès à internet """ return ( - self.state in [User.STATE_ACTIVE, User.STATE_EMAIL_NOT_YET_CONFIRMED] + self.state == User.STATE_ACTIVE + and self.email_state != User.EMAIL_STATE_UNVERIFIED and not self.is_ban() and (self.is_connected() or self.is_whitelisted()) ) or self == AssoOption.get_cached_value("utilisateur_asso") @@ -658,21 +666,6 @@ class User( ): self.full_archive() - def email_change_date_sync(self): - """Update user's email_change_date based on state update""" - if ( - self.__original_state != self.STATE_ACTIVE - and self.state == self.STATE_ACTIVE - ): - self.email_change_date = None - self.save() - elif ( - self.__original_state != self.STATE_EMAIL_NOT_YET_CONFIRMED - and self.state == self.STATE_EMAIL_NOT_YET_CONFIRMED - ): - self.email_change_date = timezone.now() - self.save() - def ldap_sync( self, base=True, access_refresh=True, mac_refresh=True, group_refresh=False ): @@ -687,7 +680,6 @@ class User( Si l'instance n'existe pas, on crée le ldapuser correspondant""" if sys.version_info[0] >= 3 and ( self.state == self.STATE_ACTIVE - or self.state == self.STATE_EMAIL_NOT_YET_CONFIRMED or self.state == self.STATE_ARCHIVE or self.state == self.STATE_DISABLED ): @@ -807,7 +799,7 @@ class User( return def confirm_email_before_date(self): - if self.email_change_date is None or self.state != self.STATE_EMAIL_NOT_YET_CONFIRMED: + if self.email_change_date is None or self.email_state == self.EMAIL_STATE_VERIFIED: return None days = OptionalUser.get_cached_value("disable_emailnotyetconfirmed") diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index ed613537..c5347dcb 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -42,7 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc., -{% if users.state == users.STATE_EMAIL_NOT_YET_CONFIRMED %} +{% if users.email_state == users.EMAIL_STATE_PENDING %}
{% blocktrans with confirm_before_date=users.confirm_email_before_date|date:"DATE_FORMAT" %}Please confirm your email address before {{ confirm_before_date }}, or your account will be suspended.{% endblocktrans %}
@@ -50,9 +50,9 @@ with this program; if not, write to the Free Software Foundation, Inc., {% blocktrans %}Didn't receive the email?{% endblocktrans %}
-{% elif users.state == users.STATE_DISABLED %} +{% elif users.email_state == users.EMAIL_STATE_UNVERIFIED %}
- {% blocktrans %}Your account has been suspended.{% endblocktrans %} + {% blocktrans %}Your account has been suspended, please confirm your email address.{% endblocktrans %}
{% endif %} diff --git a/users/views.py b/users/views.py index fb5f8d73..db41c7d1 100644 --- a/users/views.py +++ b/users/views.py @@ -745,7 +745,6 @@ def mass_archive(request): .exclude(id__in=all_has_access(search_time=date)) .exclude(state=User.STATE_NOT_YET_ACTIVE) .exclude(state=User.STATE_FULL_ARCHIVE) - .exclude(state=User.STATE_EMAIL_NOT_YET_CONFIRMED) ) if not full_archive: to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE) @@ -981,7 +980,7 @@ def reset_password(request): user = User.objects.get( pseudo=userform.cleaned_data["pseudo"], email=userform.cleaned_data["email"], - state__in=[User.STATE_ACTIVE, User.STATE_NOT_YET_ACTIVE, User.STATE_EMAIL_NOT_YET_CONFIRMED], + state__in=[User.STATE_ACTIVE, User.STATE_NOT_YET_ACTIVE], ) except User.DoesNotExist: messages.error(request, _("The user doesn't exist.")) @@ -1060,7 +1059,7 @@ def resend_confirmation_email(request, logged_user, userid): try: user = User.objects.get( id=userid, - state__in=[User.STATE_EMAIL_NOT_YET_CONFIRMED], + email_state__in=[User.EMAIL_STATE_PENDING, User.EMAIL_STATE_UNVERIFIED], ) except User.DoesNotExist: messages.error(request, _("The user doesn't exist."))