8
0
Fork 0
mirror of https://gitlab.federez.net/re2o/re2o synced 2024-05-19 09:02:35 +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 Gabriel Detraz
parent 19261400d1
commit 64626335d2
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),
)
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 (
sw_name,
room,

View file

@ -260,6 +260,16 @@ def stats_general(request):
),
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": [
_("Contributing members"),
_all_adherent.count(),

View file

@ -116,7 +116,7 @@ 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_ACTIVE) | Q(state=User.STATE_EMAIL_NOT_YET_CONFIRMED))
& ~Q(
ban__in=Ban.objects.filter(
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()
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):
"""A form for creating new users. Includes all the required
fields, plus a repeated password.

View file

@ -77,6 +77,7 @@ 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:

View file

@ -176,12 +176,14 @@ 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")),
)
surname = models.CharField(max_length=255)
@ -326,6 +328,7 @@ 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)
@ -480,7 +483,7 @@ class User(
def has_access(self):
""" Renvoie si un utilisateur a accès à internet """
return (
self.state == User.STATE_ACTIVE
self.state in [User.STATE_ACTIVE, User.STATE_EMAIL_NOT_YET_CONFIRMED]
and not self.is_ban()
and (self.is_connected() or self.is_whitelisted())
) 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"""
if sys.version_info[0] >= 3 and (
self.state == self.STATE_ACTIVE
or self.state == STATE_EMAIL_NOT_YET_CONFIRMED
or self.state == self.STATE_ARCHIVE
or self.state == self.STATE_DISABLED
):
@ -783,6 +787,34 @@ class User(
)
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):
""" Fonction appellée par freeradius. Enregistre la mac pour
une machine inconnue sur le compte de l'user"""
@ -845,6 +877,12 @@ class User(
self.pwd_ntlm = hashNT(password)
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
def email_address(self):
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,
MassArchiveForm,
PassForm,
ConfirmMailForm,
ResetPasswordForm,
ClubAdminandMembersForm,
GroupForm,
@ -126,6 +127,7 @@ def new_user(request):
# 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:
user.confirm_email_address_mail(request)
messages.success(
request,
_("The user %s was created.")
@ -737,6 +739,7 @@ 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)
@ -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
def initial_register(request):
switch_ip = request.GET.get("switch_ip", None)