Commit 371f6ed1 authored by lhark's avatar lhark

Introduce custom user model, pep8 code cleaning

parent b23e1eeb
......@@ -28,6 +28,8 @@ PASSWORD_HASHERS = (
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
)
AUTH_USER_MODEL = 'users.User'
# Application definition
......
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import User, School, Right, ListRight, Ban, Whitelist
from .forms import UserChangeForm, UserCreationForm
class UserAdmin(admin.ModelAdmin):
list_display = ('name','surname','pseudo','room','email', 'school', 'state')
list_display = (
'name',
'surname',
'pseudo',
'room',
'email',
'school',
'state'
)
class SchoolAdmin(admin.ModelAdmin):
list_display = ('name',)
class ListRightAdmin(admin.ModelAdmin):
list_display = ('listright',)
class RightAdmin(admin.ModelAdmin):
list_display = ('user', 'right')
class BanAdmin(admin.ModelAdmin):
list_display = ('user', 'raison', 'date_start', 'date_end')
class WhitelistAdmin(admin.ModelAdmin):
list_display = ('user', 'raison', 'date_start', 'date_end')
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('pseudo', 'name', 'surname', 'email', 'school', 'is_admin')
list_filter = ()
fieldsets = (
(None, {'fields': ('pseudo', 'password')}),
('Personal info', {'fields': ('name', 'surname', 'email', 'school')}),
('Permissions', {'fields': ('is_admin', )}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('pseudo', 'name', 'surname', 'email', 'school', 'is_admin', 'password1', 'password2')}
),
)
search_fields = ('pseudo',)
ordering = ('pseudo',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
admin.site.register(School, SchoolAdmin)
admin.site.register(Right, RightAdmin)
admin.site.register(ListRight, ListRightAdmin)
admin.site.register(Ban, BanAdmin)
admin.site.register(Whitelist, WhitelistAdmin)
# Now register the new UserAdmin...
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
......@@ -2,8 +2,71 @@
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User, get_admin_right
class PassForm(forms.Form):
passwd1 = forms.CharField(label=u'Nouveau mot de passe', max_length=255, widget=forms.PasswordInput)
passwd2 = forms.CharField(label=u'Saisir à nouveau le mot de passe', max_length=255, widget=forms.PasswordInput)
class UserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
is_admin = forms.BooleanField(label='is admin')
class Meta:
model = User
fields = ('pseudo', 'name', 'surname', 'email')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.save()
user.is_admin = self.cleaned_data.get("is_admin")
return user
class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
is_admin = forms.BooleanField(label='is admin', required=False)
class Meta:
model = User
fields = ('pseudo', 'password', 'name', 'surname', 'email')
def __init__(self, *args, **kwargs):
super(UserChangeForm, self).__init__(*args, **kwargs)
print("User is admin : %s" % kwargs['instance'].is_admin)
self.initial['is_admin'] = kwargs['instance'].is_admin
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserChangeForm, self).save(commit=False)
user.is_admin = self.cleaned_data.get("is_admin")
if commit:
user.save()
return user
......@@ -4,9 +4,11 @@ from django import forms
import re
from django.utils import timezone
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from topologie.models import Room
def remove_user_room(room):
""" Déménage de force l'ancien locataire de la chambre """
try:
......@@ -16,16 +18,67 @@ def remove_user_room(room):
user.room = None
user.save()
def linux_user_validator(login):
def linux_user_check(login):
""" Validation du pseudo pour respecter les contraintes unix"""
UNIX_LOGIN_PATTERN = re.compile("^[a-z_][a-z0-9_-]*[$]?$")
if not UNIX_LOGIN_PATTERN.match(login):
return UNIX_LOGIN_PATTERN.match(login)
def linux_user_validator(login):
if not linux_user_check(login):
raise forms.ValidationError(
", ce pseudo ('%(label)s') contient des carractères interdits",
params={'label': login},
)
class User(models.Model):
def get_admin_right():
try:
admin_right = ListRight.objects.get(listright="admin")
except ListRight.DoesNotExist:
admin_right = ListRight(listright="admin")
admin_right.save()
return admin_right
class UserManager(BaseUserManager):
def _create_user(self, pseudo, name, surname, email, password=None, su=False):
if not pseudo:
raise ValueError('Users must have an username')
if not linux_user_check(pseudo):
raise ValueError('Username shall only contain [a-z0-9_-]')
user = self.model(
pseudo=pseudo,
name=name,
surname=surname,
email=self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
if su:
user.make_admin()
return user
def create_user(self, pseudo, name, surname, email, password=None):
"""
Creates and saves a User with the given pseudo, name, surname, email,
and password.
"""
return self._create_user(pseudo, name, surname, email, password, False)
def create_superuser(self, pseudo, name, surname, email, password):
"""
Creates and saves a superuser with the given pseudo, name, surname,
email, and password.
"""
return self._create_user(pseudo, name, surname, email, password, True)
class User(AbstractBaseUser):
STATE_ACTIVE = 0
STATE_DEACTIVATED = 1
STATE_ARCHIVED = 2
......@@ -42,45 +95,103 @@ class User(models.Model):
school = models.ForeignKey('School', on_delete=models.PROTECT, null=False, blank=False)
comment = models.CharField(help_text="Commentaire, promo", max_length=255, blank=True)
room = models.OneToOneField('topologie.Room', on_delete=models.PROTECT, blank=True, null=True)
pwd_ssha = models.CharField(max_length=255)
pwd_ntlm = models.CharField(max_length=255)
state = models.IntegerField(choices=STATES, default=STATE_ACTIVE)
registered = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'pseudo'
REQUIRED_FIELDS = ['name', 'surname', 'email']
objects = UserManager()
@property
def is_active(self):
return self.state == self.STATE_ACTIVE
@property
def is_staff(self):
return self.is_admin
@property
def is_admin(self):
try:
Right.objects.get(user=self, right__listright='admin')
except Right.DoesNotExist:
return False
return True
@is_admin.setter
def is_admin(self, value):
if value and not self.is_admin:
self.make_admin()
elif not value and self.is_admin:
self.un_admin()
def get_full_name(self):
return '%s %s' % (self.name, self.surname)
def get_short_name(self):
return self.name
def has_perm(self, perm, obj=None):
# Simplest version
return True
def has_module_perms(self, app_label):
# Simplest version again
return True
def make_admin(self):
""" Make User admin """
user_admin_right = Right(user=self, right=get_admin_right())
user_admin_right.save()
def un_admin(self):
try:
user_right = Right.objects.get(user=self,right=get_admin_right())
except Right.DoesNotExist:
return
user_right.delete()
def __str__(self):
return self.pseudo
class Right(models.Model):
user = models.ForeignKey('User', on_delete=models.PROTECT)
user = models.ForeignKey('User', on_delete=models.PROTECT)
right = models.ForeignKey('ListRight', on_delete=models.PROTECT)
class Meta:
unique_together = ("user", "right")
def __str__(self):
return str(self.user) + " - " + str(self.right)
class School(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class ListRight(models.Model):
listright = models.CharField(max_length=255)
listright = models.CharField(max_length=255, unique=True)
def __str__(self):
return self.listright
class Ban(models.Model):
user = models.ForeignKey('User', on_delete=models.PROTECT)
raison = models.CharField(max_length=255)
date_start = models.DateTimeField(auto_now_add=True)
date_end = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S')
date_end = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S')
def __str__(self):
return str(self.user) + ' ' + str(self.raison)
class Whitelist(models.Model):
user = models.ForeignKey('User', on_delete=models.PROTECT)
raison = models.CharField(max_length=255)
......@@ -90,6 +201,7 @@ class Whitelist(models.Model):
def __str__(self):
return str(self.user) + ' ' + str(self.raison)
class InfoForm(ModelForm):
force = forms.BooleanField(label="Forcer le déménagement ?", initial=False, required=False)
......@@ -110,22 +222,34 @@ class InfoForm(ModelForm):
class Meta:
model = User
fields = ['name','surname','pseudo','email', 'school', 'comment', 'room']
fields = [
'name',
'surname',
'pseudo',
'email',
'school',
'comment',
'room',
]
class UserForm(InfoForm):
class Meta(InfoForm.Meta):
fields = '__all__'
class PasswordForm(ModelForm):
class Meta:
model = User
fields = ['pwd_ssha','pwd_ntlm']
fields = ['password', 'pwd_ntlm']
class StateForm(ModelForm):
class Meta:
model = User
fields = ['state']
class SchoolForm(ModelForm):
class Meta:
model = School
......@@ -135,6 +259,7 @@ class SchoolForm(ModelForm):
super(SchoolForm, self).__init__(*args, **kwargs)
self.fields['name'].label = 'Établissement à ajouter'
class DelSchoolForm(ModelForm):
schools = forms.ModelMultipleChoiceField(queryset=School.objects.all(), label="Etablissements actuels", widget=forms.CheckboxSelectMultiple)
......@@ -142,6 +267,7 @@ class DelSchoolForm(ModelForm):
exclude = ['name']
model = School
class RightForm(ModelForm):
def __init__(self, *args, **kwargs):
super(RightForm, self).__init__(*args, **kwargs)
......@@ -152,6 +278,7 @@ class RightForm(ModelForm):
model = Right
fields = ['right']
class DelRightForm(ModelForm):
rights = forms.ModelMultipleChoiceField(queryset=Right.objects.all(), label="Droits actuels", widget=forms.CheckboxSelectMultiple)
......@@ -159,6 +286,7 @@ class DelRightForm(ModelForm):
model = Right
exclude = ['user', 'right']
class BanForm(ModelForm):
def __init__(self, *args, **kwargs):
super(BanForm, self).__init__(*args, **kwargs)
......@@ -174,6 +302,7 @@ class BanForm(ModelForm):
raise forms.ValidationError("Triple buse, la date de fin ne peut pas être avant maintenant... Re2o ne voyage pas dans le temps")
return date_end
class WhitelistForm(ModelForm):
def __init__(self, *args, **kwargs):
super(WhitelistForm, self).__init__(*args, **kwargs)
......@@ -189,5 +318,6 @@ class WhitelistForm(ModelForm):
raise forms.ValidationError("Triple buse, la date de fin ne peut pas être avant maintenant... Re2o ne voyage pas dans le temps")
return date_end
class ProfilForm(Form):
user =forms.CharField(label ='Ok', max_length=100)
user = forms.CharField(label='Ok', max_length=100)
# App de gestion des users pour re2o
# Goulven Kermarec, Gabriel Détraz
# Gplv2
from django.shortcuts import render, redirect
from django.shortcuts import render_to_response, get_object_or_404
from django.shortcuts import render_to_response, render, redirect
from django.core.context_processors import csrf
from django.template import Context, RequestContext, loader
from django.template import RequestContext
from django.contrib import messages
from django.db.models import Max, ProtectedError
from django.db import IntegrityError
from django.utils import timezone
from users.models import User, Right, Ban, DelRightForm, UserForm, InfoForm, PasswordForm, StateForm, RightForm, BanForm, ProfilForm, Whitelist, WhitelistForm, DelSchoolForm, SchoolForm
from users.models import User, Right, Ban, Whitelist
from users.models import DelRightForm, BanForm, WhitelistForm, DelSchoolForm
from users.models import InfoForm, StateForm, RightForm, SchoolForm
from cotisations.models import Facture
from machines.models import Machine, Interface
from users.forms import PassForm
from search.models import SearchForm
from users.forms import PassForm
from cotisations.views import is_adherent, end_adhesion
from machines.views import unassign_ips, assign_ips
from re2o.login import makeSecret, hashNT
from re2o.login import hashNT
def archive(user):
""" Archive un utilisateur """
unassign_ips(user)
return
def unarchive(user):
""" Triger actions au desarchivage d'un user """
assign_ips(user)
return
def end_ban(user):
""" Renvoie la date de fin de ban d'un user, False sinon """
date_max = Ban.objects.all().filter(user=user).aggregate(Max('date_end'))['date_end__max']
date_max = Ban.objects.all().filter(
user=user).aggregate(Max('date_end'))['date_end__max']
return date_max
def end_whitelist(user):
""" Renvoie la date de fin de ban d'un user, False sinon """
date_max = Whitelist.objects.all().filter(user=user).aggregate(Max('date_end'))['date_end__max']
date_max = Whitelist.objects.all().filter(
user=user).aggregate(Max('date_end'))['date_end__max']
return date_max
def is_ban(user):
""" Renvoie si un user est banni ou non """
end = end_ban(user)
......@@ -48,7 +55,8 @@ def is_ban(user):
elif end < timezone.now():
return False
else:
return True
return True
def is_whitelisted(user):
""" Renvoie si un user est whitelisté ou non """
......@@ -60,9 +68,12 @@ def is_whitelisted(user):
else:
return True
def has_access(user):
""" Renvoie si un utilisateur a accès à internet"""
return user.state == User.STATE_ACTIVE and not is_ban(user) and ( is_adherent(user) or is_whitelisted(user))
""" Renvoie si un utilisateur a accès à internet """
return user.state == User.STATE_ACTIVE \
and not is_ban(user) and (is_adherent(user) or is_whitelisted(user))
def is_active(interface):
""" Renvoie si une interface doit avoir accès ou non """
......@@ -70,10 +81,16 @@ def is_active(interface):
user = machine.user
return machine.active and has_access(user)
def form(ctx, template, request):
c = ctx
c.update(csrf(request))
return render_to_response(template, c, context_instance=RequestContext(request))
return render_to_response(
template,
c,
context_instance=RequestContext(request)
)
def new_user(request):
user = InfoForm(request.POST or None)
......@@ -83,11 +100,12 @@ def new_user(request):
return redirect("/users/")
return form({'userform': user}, 'users/user.html', request)
def edit_info(request, userid):
try:
user = User.objects.get(pk=userid)
except User.DoesNotExist:
messages.error(request, u"Utilisateur inexistant" )
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
user = InfoForm(request.POST or None, instance=user)
if user.is_valid():
......@@ -96,11 +114,12 @@ def edit_info(request, userid):
return redirect("/users/")
return form({'userform': user}, 'users/user.html', request)
def state(request, userid):
try:
user = User.objects.get(pk=userid)
except User.DoesNotExist:
messages.error(request, u"Utilisateur inexistant" )
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
state = StateForm(request.POST or None, instance=user)
if state.is_valid():
......@@ -114,29 +133,31 @@ def state(request, userid):
return redirect("/users/")
return form({'userform': state}, 'users/user.html', request)
def password(request, userid):
try:
user = User.objects.get(pk=userid)
except User.DoesNotExist:
messages.error(request, u"Utilisateur inexistant" )
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
user_form = PassForm(request.POST or None)
if user_form.is_valid():
if user_form.cleaned_data['passwd1'] != user_form.cleaned_data['passwd2']:
messages.error(request, u"Les 2 mots de passe différent" )
return form({'userform': user_form}, 'users/user.html', request)
user.pwd_ssha = makeSecret(user_form.cleaned_data['passwd1'])
user.pwd_ntlm = hashNT(user_form.cleaned_data['passwd1'])
u_form = PassForm(request.POST or None)
if u_form.is_valid():
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é")
return redirect("/users/")
return form({'userform': user_form}, 'users/user.html', request)
return form({'userform': u_form}, 'users/user.html', request)
def add_right(request, userid):
try:
user = User.objects.get(pk=userid)
except User.DoesNotExist:
messages.error(request, u"Utilisateur inexistant" )
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
right = RightForm(request.POST or None)
if right.is_valid():
......@@ -150,6 +171,7 @@ def add_right(request, userid):
return redirect("/users/")
return form({'userform': right}, 'users/user.html', request)
def del_right(request):
right = DelRightForm(request.POST or None)
if right.is_valid():
......@@ -159,11 +181,12 @@ def del_right(request):
return redirect("/users/")
return form({'userform': right}, 'users/user.html', request)
def add_ban(request, userid):
try:
user = User.objects.get(pk=userid)
except User.DoesNotExist:
messages.error(request, u"Utilisateur inexistant" )
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
ban_instance = Ban(user=user)
ban = BanForm(request.POST or None, instance=ban_instance)
......@@ -172,14 +195,18 @@ def add_ban(request, userid):
messages.success(request, "Bannissement ajouté")
return redirect("/users/")
if is_ban(user):
messages.error(request, u"Attention, cet utilisateur a deja un bannissement actif" )
messages.error(
request,
"Attention, cet utilisateur a deja un bannissement actif"
)
return form({'userform': ban}, 'users/user.html', request)
def edit_ban(request, banid):
try:
ban_instance = Ban.objects.get(pk=banid)
except Ban.