diff --git a/users/acl.py b/users/acl.py index cb3a16db..c650f054 100644 --- a/users/acl.py +++ b/users/acl.py @@ -27,6 +27,7 @@ Here are defined some functions to check acl on the application. """ from django.utils.translation import ugettext as _ + def can_view(user): """Check if an user can view the application. @@ -40,4 +41,3 @@ def can_view(user): can = user.has_module_perms('users') return can, None if can else _("You don't have the right to view this" " application.") - diff --git a/users/admin.py b/users/admin.py index e7dd3240..304b045e 100644 --- a/users/admin.py +++ b/users/admin.py @@ -28,10 +28,16 @@ où on fait appel à UserChange et ServiceUserChange, forms custom from __future__ import unicode_literals from django.contrib import admin -from django.contrib.auth.models import Group from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from django.contrib.auth.models import Group from reversion.admin import VersionAdmin +from .forms import ( + UserChangeForm, + UserCreationForm, + ServiceUserChangeForm, + ServiceUserCreationForm +) from .models import ( User, EMailAddress, @@ -49,12 +55,6 @@ from .models import ( LdapServiceUserGroup, LdapUserGroup ) -from .forms import ( - UserChangeForm, - UserCreationForm, - ServiceUserChangeForm, - ServiceUserCreationForm -) class LdapUserAdmin(admin.ModelAdmin): @@ -147,10 +147,10 @@ class UserAdmin(VersionAdmin, BaseUserAdmin): 'Personal info', { 'fields': - ('surname', 'email', 'school', 'shell', 'uid_number') + ('surname', 'email', 'school', 'shell', 'uid_number') } ), - ('Permissions', {'fields': ('is_admin', )}), + ('Permissions', {'fields': ('is_admin',)}), ) # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin # overrides get_fieldsets to use this attribute when creating a user. @@ -167,7 +167,7 @@ class UserAdmin(VersionAdmin, BaseUserAdmin): 'is_admin', 'password1', 'password2' - ) + ) } ), ) diff --git a/users/forms.py b/users/forms.py index 3dce8ecf..4511cc1a 100644 --- a/users/forms.py +++ b/users/forms.py @@ -34,25 +34,21 @@ Modification, creation de : from __future__ import unicode_literals from django import forms -from django.forms import ModelForm, Form from django.contrib.auth.forms import ReadOnlyPasswordHashField -from django.core.validators import MinLengthValidator -from django.utils import timezone from django.contrib.auth.models import Group, Permission -from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinLengthValidator +from django.forms import ModelForm, Form +from django.utils import timezone from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ -from machines.models import Interface, Machine, Nas -from topologie.models import Port -from preferences.models import OptionalUser -from re2o.utils import remove_user_room, get_input_formats_help_text -from re2o.mixins import FormRevMixin -from re2o.field_permissions import FieldPermissionFormMixin - +from machines.models import Interface, Nas from preferences.models import GeneralOption - -from .widgets import DateTimePicker - +from preferences.models import OptionalUser +from re2o.field_permissions import FieldPermissionFormMixin +from re2o.mixins import FormRevMixin +from re2o.utils import remove_user_room +from topologie.models import Port from .models import ( User, ServiceUser, @@ -65,6 +61,7 @@ from .models import ( Adherent, Club ) +from .widgets import DateTimePicker class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm): @@ -108,7 +105,7 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm): """Verifie si il y a lieu que le mdp self est correct""" if not self.instance.check_password( self.cleaned_data.get("selfpasswd") - ): + ): raise forms.ValidationError(_("The current password is incorrect.")) return @@ -310,6 +307,7 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Formulaire de base d'edition d'un user. Formulaire de base, utilisé pour l'edition de self par self ou un cableur. On formate les champs avec des label plus jolis""" + def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(AdherentForm, self).__init__(*args, prefix=prefix, **kwargs) @@ -328,8 +326,8 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): return self.cleaned_data.get('email').lower() else: raise forms.ValidationError( - _("You can't use a {} address.").format( - OptionalUser.objects.first().local_email_domain)) + _("You can't use a {} address.").format( + OptionalUser.objects.first().local_email_domain)) class Meta: model = Adherent @@ -344,7 +342,6 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): 'room', ] - def clean_telephone(self): """Verifie que le tel est présent si 'option est validée dans preferences""" @@ -368,16 +365,17 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): remove_user_room(self.cleaned_data.get('room')) return + class AdherentCreationForm(AdherentForm): """Formulaire de création d'un user. AdherentForm auquel on ajoute une checkbox afin d'éviter les doublons d'utilisateurs""" # Champ permettant d'éviter au maxium les doublons d'utilisateurs - former_user_check_info = _("If you already have an account, please use it. "\ - + "If your lost access to it, please consider "\ - + "using the forgotten password button on the "\ - + "login page or contacting support.") + former_user_check_info = _("If you already have an account, please use it. " + "If your lost access to it, please consider " + "using the forgotten password button on the " + "login page or contacting support.") former_user_check = forms.BooleanField(required=True, help_text=former_user_check_info) former_user_check.label = _("I certifie that I have not had an account before") @@ -389,14 +387,16 @@ class AdherentCreationForm(AdherentForm): def __init__(self, *args, **kwargs): super(AdherentCreationForm, self).__init__(*args, **kwargs) + class AdherentEditForm(AdherentForm): """Formulaire d'édition d'un user. AdherentForm incluant la modification des champs gpg et shell""" + def __init__(self, *args, **kwargs): - super(AdherentEditForm, self).__init__(*args, **kwargs) - self.fields['gpg_fingerprint'].widget.attrs['placeholder'] = _("Leave empty if you don't have any GPG key.") - if 'shell' in self.fields: - self.fields['shell'].empty_label = _("Default shell") + super(AdherentEditForm, self).__init__(*args, **kwargs) + self.fields['gpg_fingerprint'].widget.attrs['placeholder'] = _("Leave empty if you don't have any GPG key.") + if 'shell' in self.fields: + self.fields['shell'].empty_label = _("Default shell") def clean_gpg_fingerprint(self): """Format the GPG fingerprint""" @@ -419,10 +419,12 @@ class AdherentEditForm(AdherentForm): 'gpg_fingerprint' ] + class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Formulaire de base d'edition d'un user. Formulaire de base, utilisé pour l'edition de self par self ou un cableur. On formate les champs avec des label plus jolis""" + def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(ClubForm, self).__init__(*args, prefix=prefix, **kwargs) @@ -462,6 +464,7 @@ class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class ClubAdminandMembersForm(FormRevMixin, ModelForm): """Permet d'éditer la liste des membres et des administrateurs d'un club""" + class Meta: model = Club fields = ['administrators', 'members'] @@ -478,6 +481,7 @@ class ClubAdminandMembersForm(FormRevMixin, ModelForm): class PasswordForm(FormRevMixin, ModelForm): """ Formulaire de changement brut de mot de passe. Ne pas utiliser sans traitement""" + class Meta: model = User fields = ['password', 'pwd_ntlm'] @@ -499,7 +503,7 @@ class ServiceUserForm(FormRevMixin, ModelForm): class Meta: model = ServiceUser - fields = ('pseudo', 'access_group','comment') + fields = ('pseudo', 'access_group', 'comment') def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) @@ -516,12 +520,14 @@ class ServiceUserForm(FormRevMixin, ModelForm): class EditServiceUserForm(ServiceUserForm): """Formulaire d'edition de base d'un service user. Ne permet d'editer que son group d'acl et son commentaire""" + class Meta(ServiceUserForm.Meta): fields = ['access_group', 'comment'] class StateForm(FormRevMixin, ModelForm): """ Changement de l'état d'un user""" + class Meta: model = User fields = ['state'] @@ -552,6 +558,7 @@ class GroupForm(FieldPermissionFormMixin, FormRevMixin, ModelForm): class SchoolForm(FormRevMixin, ModelForm): """Edition, creation d'un école""" + class Meta: model = School fields = ['name'] @@ -564,6 +571,7 @@ class SchoolForm(FormRevMixin, ModelForm): class ShellForm(FormRevMixin, ModelForm): """Edition, creation d'un école""" + class Meta: model = ListShell fields = ['shell'] @@ -595,6 +603,7 @@ class ListRightForm(FormRevMixin, ModelForm): class NewListRightForm(ListRightForm): """Ajout d'un groupe/list de droit """ + class Meta(ListRightForm.Meta): fields = ('name', 'unix_name', 'gid', 'critical', 'permissions', 'details') @@ -641,6 +650,7 @@ class DelSchoolForm(Form): class BanForm(FormRevMixin, ModelForm): """Creation, edition d'un objet bannissement""" + def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(BanForm, self).__init__(*args, prefix=prefix, **kwargs) @@ -650,11 +660,12 @@ class BanForm(FormRevMixin, ModelForm): class Meta: model = Ban exclude = ['user'] - widgets = {'date_end':DateTimePicker} + widgets = {'date_end': DateTimePicker} class WhitelistForm(FormRevMixin, ModelForm): """Creation, edition d'un objet whitelist""" + def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(WhitelistForm, self).__init__(*args, prefix=prefix, **kwargs) @@ -664,11 +675,12 @@ class WhitelistForm(FormRevMixin, ModelForm): class Meta: model = Whitelist exclude = ['user'] - widgets = {'date_end':DateTimePicker} + widgets = {'date_end': DateTimePicker} class EMailAddressForm(FormRevMixin, ModelForm): """Create and edit a local email address""" + def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(EMailAddressForm, self).__init__(*args, prefix=prefix, **kwargs) @@ -685,6 +697,7 @@ class EMailAddressForm(FormRevMixin, ModelForm): class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Edit email-related settings""" + def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(EmailSettingsForm, self).__init__(*args, prefix=prefix, **kwargs) @@ -699,12 +712,12 @@ class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): return self.cleaned_data.get('email').lower() else: raise forms.ValidationError( - _("You can't use a {} address.").format( - OptionalUser.objects.first().local_email_domain)) + _("You can't use a {} address.").format( + OptionalUser.objects.first().local_email_domain)) class Meta: model = User - fields = ['email','local_email_enabled', 'local_email_redirect'] + fields = ['email', 'local_email_enabled', 'local_email_redirect'] class InitialRegisterForm(forms.Form): @@ -721,7 +734,9 @@ class InitialRegisterForm(forms.Form): port = Port.objects.filter(switch__interface__ipv4__ipv4=switch_ip, port=switch_port).first() # If a port exists, checking there is a room AND radius if port: - if port.get_port_profile.radius_type != 'NO' and port.get_port_profile.radius_mode == 'STRICT' and hasattr(port, 'room'): + if (port.get_port_profile.radius_type != 'NO' + and port.get_port_profile.radius_mode == 'STRICT' + and hasattr(port, 'room')): # Requesting user is not in this room ? if self.user.room != port.room: self.new_room = port.room diff --git a/users/models.py b/users/models.py index 928e771f..9e4b7229 100755 --- a/users/models.py +++ b/users/models.py @@ -42,50 +42,45 @@ models sql classiques. Seuls certains champs essentiels sont dupliqués. """ - from __future__ import unicode_literals -import re -import uuid import datetime +import re import sys +import traceback +import uuid -from django.db import models -from django.db.models import Q +import ldapdb.models.fields from django import forms -from django.forms import ValidationError -from django.db.models.signals import post_save, post_delete, m2m_changed -from django.dispatch import receiver -from django.utils.functional import cached_property -from django.template import Context, loader -from django.core.mail import send_mail -from django.core.urlresolvers import reverse -from django.db import transaction -from django.utils import timezone from django.contrib.auth.models import ( AbstractBaseUser, BaseUserManager, PermissionsMixin, Group ) +from django.core.mail import send_mail +from django.core.urlresolvers import reverse from django.core.validators import RegexValidator -import traceback +from django.db import models +from django.db import transaction +from django.db.models import Q +from django.db.models.signals import post_save, post_delete, m2m_changed +from django.dispatch import receiver +from django.forms import ValidationError +from django.template import Context, loader +from django.utils import timezone +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ - from reversion import revisions as reversion -import ldapdb.models -import ldapdb.models.fields - -from re2o.settings import LDAP, GID_RANGES, UID_RANGES -from re2o.login import hashNT -from re2o.field_permissions import FieldPermissionModelMixin -from re2o.mixins import AclMixin, RevMixin - from cotisations.models import Cotisation, Facture, Paiement, Vente from machines.models import Domain, Interface, Machine, regen from preferences.models import GeneralOption, AssoOption, OptionalUser from preferences.models import OptionalMachine, MailMessageOption +from re2o.field_permissions import FieldPermissionModelMixin +from re2o.login import hashNT +from re2o.mixins import AclMixin, RevMixin +from re2o.settings import LDAP, GID_RANGES, UID_RANGES # Utilitaires généraux @@ -93,8 +88,8 @@ from preferences.models import OptionalMachine, MailMessageOption def linux_user_check(login): """ Validation du pseudo pour respecter les contraintes unix""" - UNIX_LOGIN_PATTERN = re.compile("^[a-zA-Z][a-zA-Z0-9-]*[$]?$") - return UNIX_LOGIN_PATTERN.match(login) + unix_login_pattern = re.compile("^[a-zA-Z][a-zA-Z0-9-]*[$]?$") + return unix_login_pattern.match(login) def linux_user_validator(login): @@ -117,7 +112,7 @@ def get_fresh_user_uid(): used_uids = list(User.objects.values_list('uid_number', flat=True)) except: used_uids = [] - free_uids = [id for id in uids if id not in used_uids] + free_uids = [uid for uid in uids if uid not in used_uids] return min(free_uids) @@ -128,7 +123,7 @@ def get_fresh_gid(): int(max(GID_RANGES['posix'])) )) used_gids = list(ListRight.objects.values_list('gid', flat=True)) - free_gids = [id for id in gids if id not in used_gids] + free_gids = [gid for gid in gids if gid not in used_gids] return min(free_gids) @@ -296,7 +291,8 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, @cached_property def get_mail(self): """Return the mail address choosen by the user""" - if not OptionalUser.get_cached_value('local_email_accounts_enabled') or not self.local_email_enabled or self.local_email_redirect: + if (not OptionalUser.get_cached_value('local_email_accounts_enabled') + or not self.local_email_enabled or self.local_email_redirect): return str(self.email) else: return str(self.emailaddress_set.get(local_part=self.pseudo.lower())) @@ -336,7 +332,8 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def set_active(self): """Enable this user if he subscribed successfully one time before""" if self.state == self.STATE_NOT_YET_ACTIVE: - if self.facture_set.filter(valid=True).filter(Q(vente__type_cotisation='All') | Q(vente__type_cotisation='Adhesion')).exists(): + if self.facture_set.filter(valid=True).filter( + Q(vente__type_cotisation='All') | Q(vente__type_cotisation='Adhesion')).exists(): self.state = self.STATE_ACTIVE self.save() @@ -502,7 +499,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, ) ).aggregate( total=models.Sum( - models.F('prix')*models.F('number'), + models.F('prix') * models.F('number'), output_field=models.DecimalField() ) )['total'] or 0 @@ -511,7 +508,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, name="solde" ).aggregate( total=models.Sum( - models.F('prix')*models.F('number'), + models.F('prix') * models.F('number'), output_field=models.DecimalField() ) )['total'] or 0 @@ -587,20 +584,20 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, user_ldap.dialupAccess = str(self.has_access()) user_ldap.home_directory = self.home_directory user_ldap.mail = self.get_mail - user_ldap.given_name = self.surname.lower() + '_'\ - + self.name.lower()[:3] + user_ldap.given_name = self.surname.lower() + '_' \ + + self.name.lower()[:3] user_ldap.gid = LDAP['user_gid'] if '{SSHA}' in self.password or '{SMD5}' in self.password: # We remove the extra $ added at import from ldap user_ldap.user_password = self.password[:6] + \ - self.password[7:] + self.password[7:] elif '{crypt}' in self.password: # depending on the length, we need to remove or not a $ if len(self.password) == 41: user_ldap.user_password = self.password else: user_ldap.user_password = self.password[:7] + \ - self.password[8:] + self.password[8:] user_ldap.sambat_nt_password = self.pwd_ntlm.upper() if self.get_shell: @@ -632,7 +629,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def notif_inscription(self): """ Prend en argument un objet user, envoie un mail de bienvenue """ template = loader.get_template('users/email_welcome') - mailmessageoptions, _created = MailMessageOption\ + mailmessageoptions, _created = MailMessageOption \ .objects.get_or_create() context = Context({ 'nom': self.get_full_name(), @@ -688,7 +685,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, une machine inconnue sur le compte de l'user""" all_interfaces = self.user_interfaces(active=False) if all_interfaces.count() > OptionalMachine.get_cached_value( - 'max_lambdauser_interfaces' + 'max_lambdauser_interfaces' ): return False, _("Maximum number of registered machines reached.") if not nas_type: @@ -714,7 +711,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, domain.save() self.notif_auto_newmachine(interface_cible) except Exception as error: - return False, traceback.format_exc() + return False, traceback.format_exc() return interface_cible, "Ok" def notif_auto_newmachine(self, interface): @@ -741,7 +738,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def set_password(self, password): """ A utiliser de préférence, set le password en hash courrant et dans la version ntlm""" - super().set_password(password) + super(User).set_password(password) self.pwd_ntlm = hashNT(password) return @@ -853,7 +850,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, the right to change a state """ if not ((self.pk == user_request.pk and OptionalUser.get_cached_value('self_change_room')) - or user_request.has_perm('users.change_user')): + or user_request.has_perm('users.change_user')): return False, _("Permission required to change the room.") else: return True, None @@ -879,16 +876,15 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, the right to change a shell """ if not ((self.pk == user_request.pk and OptionalUser.get_cached_value('self_change_shell')) - or user_request.has_perm('users.change_user_shell')): + or user_request.has_perm('users.change_user_shell')): return False, _("Permission required to change the shell.") else: return True, None @staticmethod - def can_change_local_email_redirect(user_request, *_args, **_kwargs): + def can_change_local_email_redirect(*_args, **_kwargs): """ Check if a user can change local_email_redirect. - :param user_request: The user who request :returns: a message and a boolean which is True if the user has the right to change a redirection """ @@ -898,7 +894,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, ) @staticmethod - def can_change_local_email_enabled(user_request, *_args, **_kwargs): + def can_change_local_email_enabled(*_args, **_kwargs): """ Check if a user can change internal address. :param user_request: The user who request @@ -1014,8 +1010,8 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, """Check if this pseudo is already used by any mailalias. Better than raising an error in post-save and catching it""" if (EMailAddress.objects - .filter(local_part=self.pseudo.lower()).exclude(user_id=self.id) - ): + .filter(local_part=self.pseudo.lower()).exclude(user_id=self.id) + ): raise ValidationError("This pseudo is already in use.") if not self.local_email_enabled and not self.email: raise ValidationError( @@ -1027,8 +1023,8 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, if self.local_email_redirect and not self.email: raise ValidationError( {'local_email_redirect': ( - _("You can't redirect your local emails if no external email" - " address has been set.")), } + _("You can't redirect your local emails if no external email" + " address has been set.")), } ) def __str__(self): @@ -1399,7 +1395,6 @@ class ListShell(RevMixin, AclMixin, models.Model): verbose_name = _("shell") verbose_name_plural = _("shells") - def get_pretty_name(self): """Return the canonical name of the shell""" return self.shell.split("/")[-1] @@ -1586,14 +1581,14 @@ class Request(models.Model): created_at = models.DateTimeField(auto_now_add=True, editable=False) expires_at = models.DateTimeField() - def save(self): + def save(self, **kwargs): if not self.expires_at: self.expires_at = (timezone.now() + datetime.timedelta( hours=GeneralOption.get_cached_value( 'req_expire_hrs' ) - )) + )) if not self.token: self.token = str(uuid.uuid4()).replace('-', '') # remove hyphens super(Request, self).save() @@ -1682,7 +1677,7 @@ class LdapUser(ldapdb.models.Model): self.sn = self.name self.uid = self.name self.sambaSID = self.uidNumber - super(LdapUser, self).save(*args, **kwargs) + super(LdapUser, self).save() class LdapUserGroup(ldapdb.models.Model): @@ -1856,7 +1851,7 @@ class EMailAddress(RevMixin, AclMixin, models.Model): if user_request == self.user: return True, None return False, _("You don't have the right to delete another user's" - " local email account") + " local email account") def can_edit(self, user_request, *_args, **_kwargs): """Check if a user can edit the alias @@ -1885,4 +1880,3 @@ class EMailAddress(RevMixin, AclMixin, models.Model): if "@" in self.local_part: raise ValidationError(_("The local part must not contain @.")) super(EMailAddress, self).clean(*args, **kwargs) - diff --git a/users/serializers.py b/users/serializers.py index be925881..219cd44a 100644 --- a/users/serializers.py +++ b/users/serializers.py @@ -27,6 +27,7 @@ Serializers for the User app """ from rest_framework import serializers + from users.models import Club, Adherent diff --git a/users/tests.py b/users/tests.py index 6b2bfb41..1843171e 100644 --- a/users/tests.py +++ b/users/tests.py @@ -23,13 +23,9 @@ The tests for the Users module. """ -import os.path - from django.test import TestCase -from django.conf import settings -from . import models -import volatildap +from . import models class SchoolTestCase(TestCase): @@ -84,4 +80,3 @@ class LdapServiceUserTestCase(TestCase): user_password="{SSHA}AbCdEfGhIjKlMnOpQrStUvWxYz987654" ) self.assertEqual(g.name, 'users_test_ldapserviceuser') - diff --git a/users/views.py b/users/views.py index e3060105..7f3f2d3f 100644 --- a/users/views.py +++ b/users/views.py @@ -36,30 +36,24 @@ des whitelist, des services users et des écoles from __future__ import unicode_literals -from django.urls import reverse -from django.shortcuts import get_object_or_404, render, redirect from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required -from django.db.models import ProtectedError, Count, Max -from django.utils import timezone from django.db import transaction +from django.db.models import ProtectedError, Count, Max from django.http import HttpResponse from django.http import HttpResponseRedirect -from django.views.decorators.csrf import csrf_exempt +from django.shortcuts import get_object_or_404, render, redirect +from django.urls import reverse +from django.utils import timezone from django.utils.translation import ugettext as _ - +from django.views.decorators.csrf import csrf_exempt from rest_framework.renderers import JSONRenderer from reversion import revisions as reversion from cotisations.models import Facture, Paiement +from cotisations.utils import find_payment_method from machines.models import Machine from preferences.models import OptionalUser, GeneralOption, AssoOption -from re2o.views import form -from re2o.utils import ( - all_has_access, - SortTable, - re2o_paginator -) from re2o.acl import ( can_create, can_edit, @@ -69,22 +63,13 @@ from re2o.acl import ( can_view_all, can_change ) -from cotisations.utils import find_payment_method -from topologie.models import Port -from .serializers import MailingSerializer, MailingMemberSerializer -from .models import ( - User, - Ban, - Whitelist, - School, - ListRight, - Request, - ServiceUser, - Adherent, - Club, - ListShell, - EMailAddress, +from re2o.utils import ( + all_has_access, + SortTable, + re2o_paginator ) +from re2o.views import form +from topologie.models import Port from .forms import ( BanForm, WhitelistForm, @@ -109,6 +94,20 @@ from .forms import ( GroupForm, InitialRegisterForm ) +from .models import ( + User, + Ban, + Whitelist, + School, + ListRight, + Request, + ServiceUser, + Adherent, + Club, + ListShell, + EMailAddress, +) +from .serializers import MailingSerializer, MailingMemberSerializer @can_create(Adherent) @@ -116,8 +115,8 @@ def new_user(request): """ Vue de création d'un nouvel utilisateur, envoie un mail pour le mot de passe""" user = AdherentCreationForm(request.POST or None, user=request.user) - GTU_sum_up = GeneralOption.get_cached_value('GTU_sum_up') - GTU = GeneralOption.get_cached_value('GTU') + gtu_sum_up = GeneralOption.get_cached_value('GTU_sum_up') + gtu = GeneralOption.get_cached_value('GTU') if user.is_valid(): user = user.save() user.reset_passwd_mail(request) @@ -130,8 +129,8 @@ def new_user(request): return form( { 'userform': user, - 'GTU_sum_up': GTU_sum_up, - 'GTU': GTU, + 'GTU_sum_up': gtu_sum_up, + 'GTU': gtu, 'showCGU': True, 'action_name': _("Commit") }, @@ -560,7 +559,7 @@ def del_emailaddress(request, emailaddress, **_kwargs): return redirect(reverse( 'users:profil', kwargs={'userid': str(emailaddress.user.id)} - )) + )) return form( {'objet': emailaddress, 'objet_name': 'emailaddress'}, 'users/delete.html', @@ -584,7 +583,7 @@ def edit_email_settings(request, user_instance, **_kwargs): return redirect(reverse( 'users:profil', kwargs={'userid': str(user_instance.id)} - )) + )) return form( {'userform': email_settings, 'showCGU': False, @@ -909,28 +908,28 @@ def index_listright(request): """ Affiche l'ensemble des droits""" rights = {} for right in (ListRight.objects - .order_by('name') - .prefetch_related('permissions') - .prefetch_related('user_set') - .prefetch_related('user_set__facture_set__vente_set__cotisation') - ): + .order_by('name') + .prefetch_related('permissions') + .prefetch_related('user_set') + .prefetch_related('user_set__facture_set__vente_set__cotisation') + ): rights[right] = (right.user_set .annotate(action_number=Count('revision'), last_seen=Max('revision__date_created'), end_adhesion=Max('facture__vente__cotisation__date_end')) - ) + ) superusers = (User.objects .filter(is_superuser=True) .annotate(action_number=Count('revision'), last_seen=Max('revision__date_created'), end_adhesion=Max('facture__vente__cotisation__date_end')) - ) + ) return render( request, 'users/index_listright.html', { 'rights': rights, - 'superusers' : superusers, + 'superusers': superusers, } ) @@ -960,10 +959,10 @@ def mon_profil(request): @can_view(User) def profil(request, users, **_kwargs): """ Affiche un profil, self or cableur, prend un userid en argument """ - machines = Machine.objects.filter(user=users).select_related('user')\ - .prefetch_related('interface_set__domain__extension')\ - .prefetch_related('interface_set__ipv4__ip_type__extension')\ - .prefetch_related('interface_set__type')\ + machines = Machine.objects.filter(user=users).select_related('user') \ + .prefetch_related('interface_set__domain__extension') \ + .prefetch_related('interface_set__ipv4__ip_type__extension') \ + .prefetch_related('interface_set__type') \ .prefetch_related('interface_set__domain__related_domain__extension') machines = SortTable.sort( machines, @@ -1003,8 +1002,8 @@ def profil(request, users, **_kwargs): user_solde = False else: user_solde = ( - balance is not None - and balance.can_credit_balance(request.user) + balance is not None + and balance.can_credit_balance(request.user) ) return render( request, @@ -1083,18 +1082,21 @@ def process_passwd(request, req): request ) + @login_required def initial_register(request): switch_ip = request.GET.get('switch_ip', None) switch_port = request.GET.get('switch_port', None) client_mac = request.GET.get('client_mac', None) - u_form = InitialRegisterForm(request.POST or None, user=request.user, switch_ip=switch_ip, switch_port=switch_port, client_mac=client_mac) + u_form = InitialRegisterForm(request.POST or None, user=request.user, switch_ip=switch_ip, switch_port=switch_port, + client_mac=client_mac) if not u_form.fields: messages.error(request, _("Incorrect URL, or already registered device")) return redirect(reverse( 'users:profil', kwargs={'userid': str(request.user.id)} )) + port = None # TODO: local variable initialized only if condition succeed if switch_ip and switch_port: port = Port.objects.filter(switch__interface__ipv4__ipv4=switch_ip, port=switch_port).first() if u_form.is_valid(): @@ -1184,9 +1186,8 @@ def ml_club_members(request, ml_name): messages.error(request, _("The mailing list doesn't exist.")) return redirect(reverse('index')) members = ( - club.administrators.all().values('email').distinct() | - club.members.all().values('email').distinct() + club.administrators.all().values('email').distinct() | + club.members.all().values('email').distinct() ) seria = MailingMemberSerializer(members, many=True) return JSONResponse(seria.data) - diff --git a/users/widgets.py b/users/widgets.py index b423d2e0..261d74d3 100644 --- a/users/widgets.py +++ b/users/widgets.py @@ -1,18 +1,17 @@ -from django.forms.widgets import Input -from django.forms.utils import flatatt -from django.utils.safestring import mark_safe -from django.template import Context, Template -from django.template.loader import get_template -from django.conf import settings -from django.utils.translation import ugettext_lazy as _, get_language_bidi -from django.utils.dates import ( - WEEKDAYS, - WEEKDAYS_ABBR, - MONTHS, - MONTHS_3, - MONTHS_AP, - MONTHS_ALT +from django.conf import settings +from django.forms.utils import flatatt +from django.forms.widgets import Input +from django.template import Context +from django.template.loader import get_template +from django.utils.dates import ( + WEEKDAYS, + WEEKDAYS_ABBR, + MONTHS, + MONTHS_3 ) +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _, get_language_bidi + def list2str(str_iterable): """ @@ -22,29 +21,30 @@ def list2str(str_iterable): :returns: A representation of the iterable as a list (e.g '["a", "b"]') """ return '["' + '", "'.join(str_iterable) + '"]' - + + class DateTimePicker(Input): is_localized = False - def render(self, name, value, attrs=None): - super().render(name, value, attrs) + + def render(self, name, value, attrs=None, **kwargs): + super(DateTimePicker).render(name, value, attrs) flat_attrs = flatatt(attrs) context = Context({ 'name': name, - 'attrs': flat_attrs, - 'id': attrs['id'], - 'closeText': _("Close"), + 'attrs': flat_attrs, + 'id': attrs['id'], + 'closeText': _("Close"), 'currentText': _("Today"), 'dayNames': mark_safe(list2str((str(item[1]) for item in WEEKDAYS.items()))), - 'dayNamesMin': mark_safe(list2str((str(item[1]) for item in WEEKDAYS_ABBR.items()))), - 'dayNamesShort': mark_safe(list2str((str(item[1]) for item in WEEKDAYS_ABBR.items()))), - 'firstDay': mark_safe('"' + str(WEEKDAYS[settings.FIRST_DAY_OF_WEEK]) + '"'), - 'isRTL': str(get_language_bidi()).lower(), + 'dayNamesMin': mark_safe(list2str((str(item[1]) for item in WEEKDAYS_ABBR.items()))), + 'dayNamesShort': mark_safe(list2str((str(item[1]) for item in WEEKDAYS_ABBR.items()))), + 'firstDay': mark_safe('"' + str(WEEKDAYS[settings.FIRST_DAY_OF_WEEK]) + '"'), + 'isRTL': str(get_language_bidi()).lower(), 'monthNames': mark_safe(list2str((str(item[1]) for item in MONTHS.items()))), - 'monthNamesShort': mark_safe(list2str((str(item[1]) for item in MONTHS_3.items()))), - 'nextText': mark_safe('"' + str(_('Next')) + '"'), - 'prevText': mark_safe('"' + str(_('Previous')) + '"'), - 'weekHeader': mark_safe('"' + str(_('Wk')) + '"' ), - }) + 'monthNamesShort': mark_safe(list2str((str(item[1]) for item in MONTHS_3.items()))), + 'nextText': mark_safe('"' + str(_('Next')) + '"'), + 'prevText': mark_safe('"' + str(_('Previous')) + '"'), + 'weekHeader': mark_safe('"' + str(_('Wk')) + '"'), + }) template = get_template('users/datetimepicker.html') - return template.render(context) - + return template.render(context)