8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-26 22:52:26 +00:00

Create STATE_SUSPENDED

This commit is contained in:
Jean-Romain Garnier 2020-04-17 16:51:58 +02:00 committed by Gabriel Detraz
parent ffdb32df90
commit 0dcd8b79e2
17 changed files with 59 additions and 32 deletions

View file

@ -513,8 +513,9 @@ class HomeCreationViewSet(viewsets.ReadOnlyModelViewSet):
queryset = users.User.objects.exclude( queryset = users.User.objects.exclude(
Q(state=users.User.STATE_DISABLED) Q(state=users.User.STATE_DISABLED)
| Q(state=users.User.STATE_NOT_YET_ACTIVE) | Q(state=users.User.STATE_NOT_YET_ACTIVE)
| Q(state=users.STATE_EMAIL_NOT_YET_CONFIRMED) | Q(state=users.User.STATE_EMAIL_NOT_YET_CONFIRMED)
| Q(state=users.User.STATE_FULL_ARCHIVE) | Q(state=users.User.STATE_FULL_ARCHIVE)
| Q(state=users.User.STATE_SUSPENDED)
) )
serializer_class = serializers.BasicUserSerializer serializer_class = serializers.BasicUserSerializer

View file

@ -247,6 +247,10 @@ msgstr "Utilisateurs pas encore actifs"
msgid "Waiting for email confirmation users" msgid "Waiting for email confirmation users"
msgstr "Utilisateurs en attente de confirmation d'email" msgstr "Utilisateurs en attente de confirmation d'email"
#: logs/views.py:273
msgid "Suspended users"
msgstr "Utilisateurs suspendus"
#: logs/views.py:273 #: logs/views.py:273
msgid "Contributing members" msgid "Contributing members"
msgstr "Adhérents cotisants" msgstr "Adhérents cotisants"

View file

@ -270,6 +270,16 @@ def stats_general(request):
), ),
Club.objects.filter(state=Club.STATE_EMAIL_NOT_YET_CONFIRMED).count(), Club.objects.filter(state=Club.STATE_EMAIL_NOT_YET_CONFIRMED).count(),
], ],
"suspended_users": [
_("Suspended users"),
User.objects.filter(state=User.STATE_SUSPENDED).count(),
(
Adherent.objects.filter(
state=Adherent.STATE_SUSPENDED
).count()
),
Club.objects.filter(state=Club.STATE_SUSPENDED).count(),
],
"adherent_users": [ "adherent_users": [
_("Contributing members"), _("Contributing members"),
_all_adherent.count(), _all_adherent.count(),

View file

@ -66,7 +66,7 @@ class EditOptionalUserForm(ModelForm):
self.fields["gpg_fingerprint"].label = _("GPG fingerprint") self.fields["gpg_fingerprint"].label = _("GPG fingerprint")
self.fields["all_can_create_club"].label = _("All can create a club") self.fields["all_can_create_club"].label = _("All can create a club")
self.fields["all_can_create_adherent"].label = _("All can create a member") self.fields["all_can_create_adherent"].label = _("All can create a member")
self.fields["disable_emailnotyetconfirmed"].label = _("Delay before disabling accounts without a verified email") self.fields["suspend_emailnotyetconfirmed"].label = _("Delay before suspending accounts without a verified email")
self.fields["self_adhesion"].label = _("Self registration") self.fields["self_adhesion"].label = _("Self registration")
self.fields["shell_default"].label = _("Default shell") self.fields["shell_default"].label = _("Default shell")
self.fields["allow_set_password_during_user_creation"].label = _("Allow directly setting a password during account creation") self.fields["allow_set_password_during_user_creation"].label = _("Allow directly setting a password during account creation")

View file

@ -287,11 +287,11 @@ msgstr ""
#: preferences/models.py:111 #: preferences/models.py:111
msgid "" msgid ""
"Users with an email address not yet confirmed will be disabled after" "Users with an email address not yet confirmed will be suspended after"
" this number of days." " this number of days."
msgstr "" msgstr ""
"Les utilisateurs n'ayant pas confirmé leur addresse mail seront" "Les utilisateurs n'ayant pas confirmé leur addresse mail seront"
" désactivés après ce nombre de jours" " suspendus après ce nombre de jours"
#: preferences/models.py:114 #: preferences/models.py:114
msgid "A new user can create their account on Re2o." msgid "A new user can create their account on Re2o."
@ -1083,8 +1083,8 @@ msgid "Allow directly entering a password during account creation"
msgstr "Permettre le choix d'un mot de passe directement lors de la création du compte" msgstr "Permettre le choix d'un mot de passe directement lors de la création du compte"
#: preferences/templates/preferences/display_preferences.html:136 #: preferences/templates/preferences/display_preferences.html:136
msgid "Delay before disabling accounts without a verified email" msgid "Delay before suspending accounts without a verified email"
msgstr "Délai avant la désactivation des comptes sans adresse mail confirmé" msgstr "Délai avant la suspension des comptes sans adresse mail confirmé"
#: preferences/templates/preferences/display_preferences.html:136 #: preferences/templates/preferences/display_preferences.html:136
msgid "Users general permissions" msgid "Users general permissions"

View file

@ -14,8 +14,8 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='optionaluser', model_name='optionaluser',
name='disable_emailnotyetconfirmed', name='suspend_emailnotyetconfirmed',
field=models.IntegerField(default=2, help_text='Users with an email address not yet confirmed will be disabled after this number of days.') field=models.IntegerField(default=2, help_text='Users with an email address not yet confirmed will be suspended after this number of days.')
), ),
] ]

View file

@ -107,10 +107,10 @@ class OptionalUser(AclMixin, PreferencesModel):
"Not yet active users will be deleted after this number of days." "Not yet active users will be deleted after this number of days."
), ),
) )
disable_emailnotyetconfirmed = models.IntegerField( suspend_emailnotyetconfirmed = models.IntegerField(
default=2, default=2,
help_text=_( help_text=_(
"Users with an email address not yet confirmed will be disabled after this number of days." "Users with an email address not yet confirmed will be suspended after this number of days."
), ),
) )
self_adhesion = models.BooleanField( self_adhesion = models.BooleanField(

View file

@ -131,8 +131,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th>{% trans "Allow directly entering a password during account creation" %}</th> <th>{% trans "Allow directly entering a password during account creation" %}</th>
<td>{{ useroptions.allow_set_password_during_user_creation|tick }}</td> <td>{{ useroptions.allow_set_password_during_user_creation|tick }}</td>
<th>{% trans "Delay before disabling accounts without a verified email" %}</th> <th>{% trans "Delay before suspending accounts without a verified email" %}</th>
<td>{% blocktrans with disable_emailnotyetconfirmed=useroptions.disable_emailnotyetconfirmed %}{{ disable_emailnotyetconfirmed }} days{% endblocktrans %}</td> <td>{% blocktrans with suspend_emailnotyetconfirmed=useroptions.suspend_emailnotyetconfirmed %}{{ suspend_emailnotyetconfirmed }} days{% endblocktrans %}</td>
</tr> </tr>
</table> </table>

View file

@ -36,6 +36,7 @@ CHOICES_USER = (
("3", _("Not yet active")), ("3", _("Not yet active")),
("4", _("Fully archived")), ("4", _("Fully archived")),
("5", _("Waiting for email confirmation")), ("5", _("Waiting for email confirmation")),
("6", _("Suspended")),
) )
CHOICES_AFF = ( CHOICES_AFF = (

View file

@ -54,6 +54,10 @@ msgstr "Complètement archivés"
msgid "Waiting for email confirmation" msgid "Waiting for email confirmation"
msgstr "En attente de confirmation d'email" msgstr "En attente de confirmation d'email"
#: search/forms.py:39
msgid "Suspended"
msgstr "Suspendu"
#: search/forms.py:41 #: search/forms.py:41
msgid "Users" msgid "Users"
msgstr "Utilisateurs" msgstr "Utilisateurs"

View file

@ -388,10 +388,14 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
if not self.is_anon and self.initial["email"] and user.email != self.initial["email"]: if not self.is_anon and self.initial["email"] and user.email != self.initial["email"]:
# Send a confirmation 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]: # Don't do this for archived or disabled users
user.state = User.STATE_EMAIL_NOT_YET_CONFIRMED if user.state not in [User.STATE_ARCHIVE, User.STATE_FULL_ARCHIVE, User.STATE_DISABLED]:
self.should_send_confirmation_email = True self.should_send_confirmation_email = True
# Suspend users stay suspended
if user.state == User.STATE_SUSPENDED:
user.state = User.STATE_EMAIL_NOT_YET_CONFIRMED
# Always keep the oldest change date # Always keep the oldest change date
if user.email_change_date is None: if user.email_change_date is None:
user.email_change_date = timezone.now() user.email_change_date = timezone.now()

View file

@ -28,13 +28,13 @@ from django.utils import timezone
class Command(BaseCommand): class Command(BaseCommand):
help = "Delete non members users (not yet active or disabled too long ago without an invoice)." help = "Delete non members users (not yet active or suspended too long ago without an invoice)."
def handle(self, *args, **options): def handle(self, *args, **options):
"""First deleting invalid invoices, and then deleting the users""" """First deleting invalid invoices, and then deleting the users"""
days = OptionalUser.get_cached_value("disable_emailnotyetconfirmed") days = OptionalUser.get_cached_value("delete_notyetactive")
users_to_delete = ( users_to_delete = (
User.objects.filter(Q(state=User.STATE_NOT_YET_ACTIVE) | Q(state=User.STATE_DISABLED)) User.objects.filter(Q(state=User.STATE_NOT_YET_ACTIVE) | Q(state=User.STATE_SUSPENDED))
.filter(registered__lte=timezone.now() - timedelta(days=days)) .filter(registered__lte=timezone.now() - timedelta(days=days))
.exclude(facture__valid=True) .exclude(facture__valid=True)
.distinct() .distinct()

View file

@ -25,19 +25,19 @@ from django.utils import timezone
class Command(BaseCommand): class Command(BaseCommand):
help = "Disable users who haven't confirmed their email." help = "Suspend users who haven't confirmed their email."
def handle(self, *args, **options): def handle(self, *args, **options):
"""First deleting invalid invoices, and then deleting the users""" """First deleting invalid invoices, and then deleting the users"""
days = OptionalUser.get_cached_value("disable_emailnotyetconfirmed") days = OptionalUser.get_cached_value("suspend_emailnotyetconfirmed")
users_to_disable = ( users_to_suspend = (
User.objects.filter(state=User.STATE_EMAIL_NOT_YET_CONFIRMED) User.objects.filter(state=User.STATE_EMAIL_NOT_YET_CONFIRMED)
.filter(email_change_date__lte=timezone.now() - timedelta(days=days)) .filter(email_change_date__lte=timezone.now() - timedelta(days=days))
.distinct() .distinct()
) )
print("Disabling " + str(users_to_disable.count()) + " users.") print("Suspending " + str(users_to_suspend.count()) + " users.")
for user in users_to_disable: for user in users_to_suspend:
user.state = User.STATE_DISABLED user.state = User.STATE_SUSPENDED
user.notif_disable() user.notif_suspension()
user.save() user.save()

View file

@ -174,12 +174,13 @@ class User(
Champs principaux : name, surnname, pseudo, email, room, password Champs principaux : name, surnname, pseudo, email, room, password
Herite du django BaseUser et du système d'auth django""" Herite du django BaseUser et du système d'auth django"""
STATE_ACTIVE = 0 STATE_ACTIVE = 0 # Can login and has Internet (if invoice is valid)
STATE_DISABLED = 1 STATE_DISABLED = 1 # Cannot login to Re2o and doesn't have Internet
STATE_ARCHIVE = 2 STATE_ARCHIVE = 2
STATE_NOT_YET_ACTIVE = 3 STATE_NOT_YET_ACTIVE = 3
STATE_FULL_ARCHIVE = 4 STATE_FULL_ARCHIVE = 4
STATE_EMAIL_NOT_YET_CONFIRMED = 5 STATE_EMAIL_NOT_YET_CONFIRMED = 5
STATE_SUSPENDED = 6 # Can login to Re2o but doesn't have Internet
STATES = ( STATES = (
(0, _("Active")), (0, _("Active")),
(1, _("Disabled")), (1, _("Disabled")),
@ -187,6 +188,7 @@ class User(
(3, _("Not yet active")), (3, _("Not yet active")),
(4, _("Fully archived")), (4, _("Fully archived")),
(5, _("Waiting for email confirmation")), (5, _("Waiting for email confirmation")),
(5, _("Suspended")),
) )
surname = models.CharField(max_length=255) surname = models.CharField(max_length=255)
@ -395,7 +397,7 @@ class User(
@cached_property @cached_property
def get_shadow_expire(self): def get_shadow_expire(self):
"""Return the shadow_expire value for the user""" """Return the shadow_expire value for the user"""
if self.state == self.STATE_DISABLED: if self.state == self.STATE_DISABLED or self.STATE_SUSPENDED:
return str(0) return str(0)
else: else:
return None return None
@ -690,6 +692,7 @@ class User(
or self.state == self.STATE_EMAIL_NOT_YET_CONFIRMED or self.state == self.STATE_EMAIL_NOT_YET_CONFIRMED
or self.state == self.STATE_ARCHIVE or self.state == self.STATE_ARCHIVE
or self.state == self.STATE_DISABLED or self.state == self.STATE_DISABLED
or self.state == self.STATE_SUSPENDED
): ):
self.refresh_from_db() self.refresh_from_db()
try: try:
@ -810,7 +813,7 @@ class User(
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.state != self.STATE_EMAIL_NOT_YET_CONFIRMED:
return None return None
days = OptionalUser.get_cached_value("disable_emailnotyetconfirmed") days = OptionalUser.get_cached_value("suspend_emailnotyetconfirmed")
return self.email_change_date + timedelta(days=days) return self.email_change_date + timedelta(days=days)
def confirm_email_address_mail(self, request): def confirm_email_address_mail(self, request):
@ -897,9 +900,9 @@ class User(
) )
return return
def notif_disable(self): def notif_suspension(self):
"""Envoi un mail de notification informant que l'adresse mail n'a pas été confirmée""" """Envoi un mail de notification informant que l'adresse mail n'a pas été confirmée"""
template = loader.get_template("users/email_disable_notif") template = loader.get_template("users/email_suspension_notif")
context = { context = {
"name": self.get_full_name(), "name": self.get_full_name(),
"asso_name": AssoOption.get_cached_value("name"), "asso_name": AssoOption.get_cached_value("name"),

View file

@ -50,7 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% blocktrans %}Didn't receive the email?{% endblocktrans %} {% blocktrans %}Didn't receive the email?{% endblocktrans %}
</a> </a>
</div> </div>
{% elif users.state == users.STATE_DISABLED %} {% elif users.state == users.STATE_SUSPENDED %}
<div class="alert alert-danger"> <div class="alert alert-danger">
{% blocktrans %}Your account has been suspended.{% endblocktrans %} {% blocktrans %}Your account has been suspended.{% endblocktrans %}
</div> </div>

View file

@ -981,7 +981,7 @@ def reset_password(request):
user = User.objects.get( user = User.objects.get(
pseudo=userform.cleaned_data["pseudo"], pseudo=userform.cleaned_data["pseudo"],
email=userform.cleaned_data["email"], 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, User.STATE_EMAIL_NOT_YET_CONFIRMED, User.STATE_SUSPENDED],
) )
except User.DoesNotExist: except User.DoesNotExist:
messages.error(request, _("The user doesn't exist.")) messages.error(request, _("The user doesn't exist."))