8
0
Fork 0
mirror of https://gitlab.federez.net/re2o/re2o synced 2024-07-02 20:24:07 +00:00

Create EMAIL_NOT_YET_CONFIRMED state

This commit is contained in:
Jean-Romain Garnier 2020-04-16 22:06:14 +02:00 committed by Jean-Romain Garnier
parent e57ec2ccd1
commit 8728bc69f5
8 changed files with 134 additions and 3 deletions

View file

@ -469,7 +469,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address):
RadiusOption.get_attributes("non_member_attributes", attributes_kwargs), RadiusOption.get_attributes("non_member_attributes", attributes_kwargs),
) )
for user in room_user: for user in room_user:
if user.is_ban() or user.state != User.STATE_ACTIVE: if user.is_ban() or user.state not in [User.STATE_ACTIVE, User.STATE_EMAIL_NOT_YET_CONFIRMED]:
return ( return (
sw_name, sw_name,
room, room,

View file

@ -260,6 +260,16 @@ def stats_general(request):
), ),
Club.objects.filter(state=Club.STATE_NOT_YET_ACTIVE).count(), Club.objects.filter(state=Club.STATE_NOT_YET_ACTIVE).count(),
], ],
"email_not_confirmed_users": [
_("Email not yet confirmed 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": [ "adherent_users": [
_("Contributing members"), _("Contributing members"),
_all_adherent.count(), _all_adherent.count(),

View file

@ -116,7 +116,7 @@ def all_has_access(search_time=None, including_asso=True):
if search_time is None: if search_time is None:
search_time = timezone.now() search_time = timezone.now()
filter_user = ( filter_user = (
Q(state=User.STATE_ACTIVE) (Q(state=User.STATE_ACTIVE) | Q(state=User.STATE_EMAIL_NOT_YET_CONFIRMED))
& ~Q( & ~Q(
ban__in=Ban.objects.filter( ban__in=Ban.objects.filter(
Q(date_start__lt=search_time) & Q(date_end__gt=search_time) Q(date_start__lt=search_time) & Q(date_end__gt=search_time)

View file

@ -117,6 +117,20 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm):
user.save() user.save()
class ConfirmMailForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm):
"""Formulaire de confirmation de l'email de l'utilisateur"""
class Meta:
model = User
fields = []
def save(self, commit=True):
"""Confirmation de l'email"""
user = super(ConfirmMailForm, self).save(commit=False)
user.confirm_mail()
user.set_active()
user.save()
class UserCreationForm(FormRevMixin, forms.ModelForm): class UserCreationForm(FormRevMixin, forms.ModelForm):
"""A form for creating new users. Includes all the required """A form for creating new users. Includes all the required
fields, plus a repeated password. fields, plus a repeated password.

View file

@ -77,6 +77,7 @@ class Command(BaseCommand):
.exclude(id__in=all_has_access(search_time=date)) .exclude(id__in=all_has_access(search_time=date))
.exclude(state=User.STATE_NOT_YET_ACTIVE) .exclude(state=User.STATE_NOT_YET_ACTIVE)
.exclude(state=User.STATE_FULL_ARCHIVE) .exclude(state=User.STATE_FULL_ARCHIVE)
.exclude(state=User.STATE_EMAIL_NOT_YET_CONFIRMED)
) )
if show: if show:

View file

@ -176,12 +176,14 @@ class User(
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
STATES = ( STATES = (
(0, _("Active")), (0, _("Active")),
(1, _("Disabled")), (1, _("Disabled")),
(2, _("Archived")), (2, _("Archived")),
(3, _("Not yet active")), (3, _("Not yet active")),
(4, _("Fully archived")), (4, _("Fully archived")),
(5, _("Waiting for email confirmation")),
) )
surname = models.CharField(max_length=255) surname = models.CharField(max_length=255)
@ -326,6 +328,7 @@ class User(
return ( return (
self.state == self.STATE_ACTIVE self.state == self.STATE_ACTIVE
or self.state == self.STATE_NOT_YET_ACTIVE or self.state == self.STATE_NOT_YET_ACTIVE
or self.state == self.STATE_EMAIL_NOT_YET_CONFIRMED
or ( or (
allow_archived allow_archived
and self.state in (self.STATE_ARCHIVE, self.STATE_FULL_ARCHIVE) and self.state in (self.STATE_ARCHIVE, self.STATE_FULL_ARCHIVE)
@ -480,7 +483,7 @@ class User(
def has_access(self): def has_access(self):
""" Renvoie si un utilisateur a accès à internet """ """ Renvoie si un utilisateur a accès à internet """
return ( return (
self.state == User.STATE_ACTIVE self.state in [User.STATE_ACTIVE, User.STATE_EMAIL_NOT_YET_CONFIRMED]
and not self.is_ban() and not self.is_ban()
and (self.is_connected() or self.is_whitelisted()) and (self.is_connected() or self.is_whitelisted())
) or self == AssoOption.get_cached_value("utilisateur_asso") ) or self == AssoOption.get_cached_value("utilisateur_asso")
@ -665,6 +668,7 @@ class User(
Si l'instance n'existe pas, on crée le ldapuser correspondant""" Si l'instance n'existe pas, on crée le ldapuser correspondant"""
if sys.version_info[0] >= 3 and ( if sys.version_info[0] >= 3 and (
self.state == self.STATE_ACTIVE self.state == self.STATE_ACTIVE
or self.state == 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
): ):
@ -783,6 +787,34 @@ class User(
) )
return return
def confirm_email_address_mail(self, request):
"""Prend en argument un request, envoie un mail pour
confirmer l'adresse"""
req = Request()
req.type = Request.EMAIL
req.user = self
req.save()
template = loader.get_template("users/email_confirmation_request")
context = {
"name": req.user.get_full_name(),
"asso": AssoOption.get_cached_value("name"),
"asso_mail": AssoOption.get_cached_value("contact"),
"site_name": GeneralOption.get_cached_value("site_name"),
"url": request.build_absolute_uri(
reverse("users:process", kwargs={"token": req.token})
),
"expire_in": str(GeneralOption.get_cached_value("req_expire_hrs")),
}
send_mail(
"Confirmation de l'email de %(name)s / Email confirmation for "
"%(name)s" % {"name": AssoOption.get_cached_value("name")},
template.render(context),
GeneralOption.get_cached_value("email_from"),
[req.user.email],
fail_silently=False,
)
return
def autoregister_machine(self, mac_address, nas_type): def autoregister_machine(self, mac_address, nas_type):
""" Fonction appellée par freeradius. Enregistre la mac pour """ Fonction appellée par freeradius. Enregistre la mac pour
une machine inconnue sur le compte de l'user""" une machine inconnue sur le compte de l'user"""
@ -845,6 +877,12 @@ class User(
self.pwd_ntlm = hashNT(password) self.pwd_ntlm = hashNT(password)
return return
def confirm_mail(self):
"""Marque l'email de l'utilisateur comme confirmé"""
# Let the "set_active" method handle
self.state = self.STATE_NOT_YET_ACTIVE
self.set_active()
@cached_property @cached_property
def email_address(self): def email_address(self):
if ( if (

View file

@ -0,0 +1,33 @@
Bonjour {{ name }},
Vous trouverez ci-dessous une URL permettant de confirmer votre
adresse mail pour votre compte {{ site_name }}. Celui-ci vous permet de gérer l'ensemble
de vos équipements, votre compte, vos factures, et tous les services proposés sur le réseau.
{{ url }}
Contactez les administrateurs si vous n'êtes pas à l'origine de cette requête.
Ce lien expirera dans {{ expire_in }} heures.
Respectueusement,
L'équipe de {{ asso }} (contact : {{ asso_mail }}).
---
Hello {{ name }},
You will find below an URL allowing you to confirm the email address of your account
on {{ site_name }}. It enables you to manage your devices, your account, your invoices, and all
the services offered on the network.
{{ url }}
Contact the administrators if you didn't request this.
This link will expire in {{ expire_in }} hours.
Regards,
The {{ asso }} team (contact: {{ asso_mail }}).

View file

@ -105,6 +105,7 @@ from .forms import (
ClubForm, ClubForm,
MassArchiveForm, MassArchiveForm,
PassForm, PassForm,
ConfirmMailForm,
ResetPasswordForm, ResetPasswordForm,
ClubAdminandMembersForm, ClubAdminandMembersForm,
GroupForm, GroupForm,
@ -126,6 +127,7 @@ def new_user(request):
# Use "is False" so that if None, the email is sent # Use "is False" so that if None, the email is sent
if is_set_password_allowed and user.should_send_password_reset_email is False: if is_set_password_allowed and user.should_send_password_reset_email is False:
user.confirm_email_address_mail(request)
messages.success( messages.success(
request, request,
_("The user %s was created.") _("The user %s was created.")
@ -737,6 +739,7 @@ def mass_archive(request):
.exclude(id__in=all_has_access(search_time=date)) .exclude(id__in=all_has_access(search_time=date))
.exclude(state=User.STATE_NOT_YET_ACTIVE) .exclude(state=User.STATE_NOT_YET_ACTIVE)
.exclude(state=User.STATE_FULL_ARCHIVE) .exclude(state=User.STATE_FULL_ARCHIVE)
.exclude(state=User.STATE_EMAIL_NOT_YET_CONFIRMED)
) )
if not full_archive: if not full_archive:
to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE) to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE)
@ -1020,6 +1023,38 @@ def process_passwd(request, req):
) )
def confirm_email(request, token):
"""Lien pour la confirmation de l'email"""
valid_reqs = Request.objects.filter(expires_at__gt=timezone.now())
req = get_object_or_404(valid_reqs, token=token)
if req.type == Request.EMAIL:
return process_email(request, req)
else:
messages.error(request, _("Error: please contact an admin."))
redirect(reverse("index"))
def process_email(request, req):
"""Process la confirmation de mail, renvoie le formulaire
de validation"""
user = req.user
u_form = ConfirmMailForm(request.POST or None, instance=user, user=request.user)
if u_form.is_valid():
with transaction.atomic(), reversion.create_revision():
u_form.save()
reversion.set_comment("Email confirmation")
req.delete()
messages.success(request, _("The email was confirmed."))
return redirect(reverse("index"))
return form(
{"userform": u_form, "action_name": _("Confirm the email")},
"users/user.html",
request,
)
@login_required @login_required
def initial_register(request): def initial_register(request):
switch_ip = request.GET.get("switch_ip", None) switch_ip = request.GET.get("switch_ip", None)