mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-23 20:03:11 +00:00
L'initialisation du mdp se fait par mail
This commit is contained in:
parent
8e5464a192
commit
60fae5af7a
7 changed files with 133 additions and 18 deletions
|
@ -12,7 +12,7 @@ https://docs.djangoproject.com/en/1.8/ref/settings/
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
import os
|
import os
|
||||||
from .settings_local import SECRET_KEY, DATABASES, DEBUG, ALLOWED_HOSTS, ASSO_NAME, ASSO_ADDRESS_LINE1, ASSO_ADDRESS_LINE2, ASSO_SIRET, ASSO_EMAIL, ASSO_PHONE, LOGO_PATH, services_urls
|
from .settings_local import SECRET_KEY, DATABASES, DEBUG, ALLOWED_HOSTS, ASSO_NAME, ASSO_ADDRESS_LINE1, ASSO_ADDRESS_LINE2, ASSO_SIRET, ASSO_EMAIL, ASSO_PHONE, LOGO_PATH, services_urls, REQ_EXPIRE_HRS, REQ_EXPIRE_STR, EMAIL_FROM, SITE_NAME
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ from django.contrib import admin
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
|
|
||||||
from .models import User, School, Right, ListRight, Ban, Whitelist
|
from .models import User, School, Right, ListRight, Ban, Whitelist, Request
|
||||||
from .forms import UserChangeForm, UserCreationForm
|
from .forms import UserChangeForm, UserCreationForm
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ class ListRightAdmin(admin.ModelAdmin):
|
||||||
class RightAdmin(admin.ModelAdmin):
|
class RightAdmin(admin.ModelAdmin):
|
||||||
list_display = ('user', 'right')
|
list_display = ('user', 'right')
|
||||||
|
|
||||||
|
class RequestAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('user', 'type', 'created_at', 'expires_at')
|
||||||
|
|
||||||
class BanAdmin(admin.ModelAdmin):
|
class BanAdmin(admin.ModelAdmin):
|
||||||
list_display = ('user', 'raison', 'date_start', 'date_end')
|
list_display = ('user', 'raison', 'date_start', 'date_end')
|
||||||
|
@ -71,6 +73,7 @@ admin.site.register(Right, RightAdmin)
|
||||||
admin.site.register(ListRight, ListRightAdmin)
|
admin.site.register(ListRight, ListRightAdmin)
|
||||||
admin.site.register(Ban, BanAdmin)
|
admin.site.register(Ban, BanAdmin)
|
||||||
admin.site.register(Whitelist, WhitelistAdmin)
|
admin.site.register(Whitelist, WhitelistAdmin)
|
||||||
|
admin.site.register(Request, RequestAdmin)
|
||||||
# Now register the new UserAdmin...
|
# Now register the new UserAdmin...
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(User)
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
|
|
27
users/migrations/0020_request.py
Normal file
27
users/migrations/0020_request.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0019_auto_20160708_1633'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Request',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
|
||||||
|
('type', models.CharField(choices=[('PW', 'Mot de passe'), ('EM', 'Email')], max_length=2)),
|
||||||
|
('token', models.CharField(max_length=32)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('expires_at', models.DateTimeField()),
|
||||||
|
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.PROTECT)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
|
@ -3,8 +3,9 @@ from django.db.models import Q
|
||||||
from django.forms import ModelForm, Form
|
from django.forms import ModelForm, Form
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from re2o.settings import RIGHTS_LINK
|
from re2o.settings import RIGHTS_LINK, REQ_EXPIRE_HRS
|
||||||
import re
|
import re, uuid
|
||||||
|
import datetime
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
|
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
|
||||||
|
@ -265,6 +266,27 @@ class Whitelist(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.user) + ' ' + str(self.raison)
|
return str(self.user) + ' ' + str(self.raison)
|
||||||
|
|
||||||
|
class Request(models.Model):
|
||||||
|
PASSWD = 'PW'
|
||||||
|
EMAIL = 'EM'
|
||||||
|
TYPE_CHOICES = (
|
||||||
|
(PASSWD, 'Mot de passe'),
|
||||||
|
(EMAIL, 'Email'),
|
||||||
|
)
|
||||||
|
type = models.CharField(max_length=2, choices=TYPE_CHOICES)
|
||||||
|
token = models.CharField(max_length=32)
|
||||||
|
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True, editable=False)
|
||||||
|
expires_at = models.DateTimeField()
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
if not self.expires_at:
|
||||||
|
self.expires_at = timezone.now() \
|
||||||
|
+ datetime.timedelta(hours=REQ_EXPIRE_HRS)
|
||||||
|
if not self.token:
|
||||||
|
self.token = str(uuid.uuid4()).replace('-', '') # remove hyphens
|
||||||
|
super(Request, self).save()
|
||||||
|
|
||||||
class BaseInfoForm(ModelForm):
|
class BaseInfoForm(ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(BaseInfoForm, self).__init__(*args, **kwargs)
|
super(BaseInfoForm, self).__init__(*args, **kwargs)
|
||||||
|
|
15
users/templates/users/email_passwd_request
Normal file
15
users/templates/users/email_passwd_request
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Bonjour {{ name }},
|
||||||
|
|
||||||
|
Vous trouverez ci-dessous une url permetant d'initialiser ou de reinitialiser votre
|
||||||
|
compte {{ site_name }}. Celui-ci vous permet de gérer l'ensemble de vos équipements
|
||||||
|
connectés, 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 }}.
|
||||||
|
|
||||||
|
Cordialement,
|
||||||
|
|
||||||
|
L'équipe de {{ asso }} {{ asso_mail }}.
|
|
@ -21,6 +21,7 @@ urlpatterns = [
|
||||||
url(r'^index_white/$', views.index_white, name='index-white'),
|
url(r'^index_white/$', views.index_white, name='index-white'),
|
||||||
url(r'^index_school/$', views.index_school, name='index-school'),
|
url(r'^index_school/$', views.index_school, name='index-school'),
|
||||||
url(r'^mon_profil/$', views.mon_profil, name='mon-profil'),
|
url(r'^mon_profil/$', views.mon_profil, name='mon-profil'),
|
||||||
|
url(r'^process/(?P<token>[a-z0-9]{32})/$', views.process, name='process'),
|
||||||
url(r'^$', views.index, name='index'),
|
url(r'^$', views.index, name='index'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
# App de gestion des users pour re2o
|
# App de gestion des users pour re2o
|
||||||
# Goulven Kermarec, Gabriel Détraz
|
# Goulven Kermarec, Gabriel Détraz
|
||||||
# Gplv2
|
# Gplv2
|
||||||
from django.shortcuts import render_to_response, render, redirect
|
from django.shortcuts import render_to_response, get_object_or_404, render, redirect
|
||||||
from django.core.context_processors import csrf
|
from django.core.context_processors import csrf
|
||||||
from django.template import RequestContext
|
from django.template import Context, RequestContext, loader
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.db.models import Max, ProtectedError
|
from django.db.models import Max, ProtectedError
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
|
from django.core.mail import send_mail
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
from users.models import User, Right, Ban, Whitelist, School
|
from users.models import User, Right, Ban, Whitelist, School, Request
|
||||||
from users.models import DelRightForm, BanForm, WhitelistForm, DelSchoolForm
|
from users.models import DelRightForm, BanForm, WhitelistForm, DelSchoolForm
|
||||||
from users.models import InfoForm, BaseInfoForm, StateForm, RightForm, SchoolForm
|
from users.models import InfoForm, BaseInfoForm, StateForm, RightForm, SchoolForm
|
||||||
from cotisations.models import Facture
|
from cotisations.models import Facture
|
||||||
|
@ -19,7 +21,7 @@ from users.forms import PassForm
|
||||||
from machines.views import unassign_ips, assign_ips
|
from machines.views import unassign_ips, assign_ips
|
||||||
|
|
||||||
from re2o.login import hashNT
|
from re2o.login import hashNT
|
||||||
|
from re2o.settings import REQ_EXPIRE_STR, EMAIL_FROM, ASSO_NAME, ASSO_EMAIL, SITE_NAME
|
||||||
|
|
||||||
def archive(user):
|
def archive(user):
|
||||||
""" Archive un utilisateur """
|
""" Archive un utilisateur """
|
||||||
|
@ -41,14 +43,49 @@ def form(ctx, template, request):
|
||||||
context_instance=RequestContext(request)
|
context_instance=RequestContext(request)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def password_change_action(u_form, user, request, req=False):
|
||||||
|
""" Fonction qui effectue le changeemnt de mdp bdd"""
|
||||||
|
if u_form.cleaned_data['passwd1'] != u_form.cleaned_data['passwd2']:
|
||||||
|
messages.error(request, "Les 2 mots de passe différent")
|
||||||
|
return form({'userform': u_form}, 'users/user.html', request)
|
||||||
|
user.set_password(u_form.cleaned_data['passwd1'])
|
||||||
|
user.pwd_ntlm = hashNT(u_form.cleaned_data['passwd1'])
|
||||||
|
user.save()
|
||||||
|
messages.success(request, "Le mot de passe a changé")
|
||||||
|
if req:
|
||||||
|
req.delete()
|
||||||
|
return redirect("/")
|
||||||
|
return redirect("/users/profil/" + str(user.id))
|
||||||
|
|
||||||
|
def reset_passwd_mail(req, request):
|
||||||
|
t = loader.get_template('users/email_passwd_request')
|
||||||
|
c = Context({
|
||||||
|
'name': str(req.user.name) + ' ' + str(req.user.surname),
|
||||||
|
'asso': ASSO_NAME,
|
||||||
|
'asso_mail': ASSO_EMAIL,
|
||||||
|
'site_name': SITE_NAME,
|
||||||
|
'url': request.build_absolute_uri(
|
||||||
|
reverse('users:process', kwargs={'token': req.token})),
|
||||||
|
'expire_in': REQ_EXPIRE_STR,
|
||||||
|
})
|
||||||
|
send_mail('Changement de mot de passe', t.render(c),
|
||||||
|
EMAIL_FROM, [req.user.email], fail_silently=False)
|
||||||
|
return
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def new_user(request):
|
def new_user(request):
|
||||||
user = InfoForm(request.POST or None)
|
user = InfoForm(request.POST or None)
|
||||||
if user.is_valid():
|
if user.is_valid():
|
||||||
|
user = user.save(commit=False)
|
||||||
user.save()
|
user.save()
|
||||||
messages.success(request, "L'utilisateur a été crée")
|
req = Request()
|
||||||
return redirect("/users/")
|
req.type = Request.PASSWD
|
||||||
|
req.user = user
|
||||||
|
req.save()
|
||||||
|
reset_passwd_mail(req, request)
|
||||||
|
messages.success(request, "L'utilisateur %s a été crée, un mail pour l'initialisation du mot de passe a été envoyé" % user.pseudo)
|
||||||
|
redirect("/users/profil/" + user.id)
|
||||||
return form({'userform': user}, 'users/user.html', request)
|
return form({'userform': user}, 'users/user.html', request)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -106,14 +143,7 @@ def password(request, userid):
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
u_form = PassForm(request.POST or None)
|
u_form = PassForm(request.POST or None)
|
||||||
if u_form.is_valid():
|
if u_form.is_valid():
|
||||||
if u_form.cleaned_data['passwd1'] != u_form.cleaned_data['passwd2']:
|
return password_change_action(u_form, user, request)
|
||||||
messages.error(request, "Les 2 mots de passe différent")
|
|
||||||
return form({'userform': u_form}, 'users/user.html', request)
|
|
||||||
user.set_password(u_form.cleaned_data['passwd1'])
|
|
||||||
user.pwd_ntlm = hashNT(u_form.cleaned_data['passwd1'])
|
|
||||||
user.save()
|
|
||||||
messages.success(request, "Le mot de passe a changé")
|
|
||||||
return redirect("/users/profil/" + userid)
|
|
||||||
return form({'userform': u_form}, 'users/user.html', request)
|
return form({'userform': u_form}, 'users/user.html', request)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -322,3 +352,20 @@ def profil(request, userid):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def process(request, token):
|
||||||
|
valid_reqs = Request.objects.filter(expires_at__gt=timezone.now())
|
||||||
|
req = get_object_or_404(valid_reqs, token=token)
|
||||||
|
|
||||||
|
if req.type == Request.PASSWD:
|
||||||
|
return process_passwd(request, req)
|
||||||
|
elif req.type == Request.EMAIL:
|
||||||
|
return process_email(request, req=req)
|
||||||
|
else:
|
||||||
|
return error(request, 'Entrée incorrecte, contactez un admin')
|
||||||
|
|
||||||
|
def process_passwd(request, req):
|
||||||
|
u_form = PassForm(request.POST or None)
|
||||||
|
user = req.user
|
||||||
|
if u_form.is_valid():
|
||||||
|
return password_change_action(u_form, user, request, req=req)
|
||||||
|
return form({'userform': u_form}, 'users/user.html', request)
|
||||||
|
|
Loading…
Reference in a new issue