From 394ada93e592aede772fd5875dc8efa3c6c6a931 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Mon, 20 Nov 2017 04:41:29 +0100 Subject: [PATCH 1/3] Ajoute le support des membres et admin clubs --- users/forms.py | 12 ++++ users/migrations/0060_auto_20171120_0317.py | 25 +++++++ users/models.py | 17 ++++- users/templates/users/profil.html | 46 ++++++++++++- users/templates/users/user.html | 2 +- users/urls.py | 5 ++ users/views.py | 74 ++++++++++++++++++--- 7 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 users/migrations/0060_auto_20171120_0317.py diff --git a/users/forms.py b/users/forms.py index 8aa2ffe7..a47c1436 100644 --- a/users/forms.py +++ b/users/forms.py @@ -379,6 +379,18 @@ class FullClubForm(ClubForm): ] +class ClubAdminandMembersForm(ModelForm): + """Permet d'éditer la liste des membres et des administrateurs + d'un club""" + class Meta: + model = Club + fields = ['administrators', 'members'] + + def __init__(self, *args, **kwargs): + prefix = kwargs.pop('prefix', self.Meta.model.__name__) + super(ClubAdminandMembersForm, self).__init__(*args, prefix=prefix, **kwargs) + + class PasswordForm(ModelForm): """ Formulaire de changement brut de mot de passe. Ne pas utiliser sans traitement""" diff --git a/users/migrations/0060_auto_20171120_0317.py b/users/migrations/0060_auto_20171120_0317.py new file mode 100644 index 00000000..a77b24db --- /dev/null +++ b/users/migrations/0060_auto_20171120_0317.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-11-20 02:17 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0059_auto_20171025_1854'), + ] + + operations = [ + migrations.AddField( + model_name='club', + name='administrators', + field=models.ManyToManyField(blank=True, related_name='club_administrator', to='users.Adherent'), + ), + migrations.AddField( + model_name='club', + name='members', + field=models.ManyToManyField(blank=True, related_name='club_members', to='users.Adherent'), + ), + ] diff --git a/users/models.py b/users/models.py index 54500f4e..fae011d6 100644 --- a/users/models.py +++ b/users/models.py @@ -60,7 +60,10 @@ 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 +from django.contrib.auth.models import ( + AbstractBaseUser, + BaseUserManager +) from django.core.validators import RegexValidator from reversion import revisions as reversion @@ -771,6 +774,7 @@ class Adherent(User): pass + class Club(User): PRETTY_NAME = "Clubs" room = models.ForeignKey( @@ -779,6 +783,17 @@ class Club(User): blank=True, null=True ) + administrators = models.ManyToManyField( + blank=True, + to='users.Adherent', + related_name='club_administrator' + ) + members = models.ManyToManyField( + blank=True, + to='users.Adherent', + related_name='club_members' + ) + pass diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index 253ab86d..fb9e37d9 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -141,21 +141,61 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ user.shell }} {% endif %} -

Machines :

+ {% if user.is_class_club %} + + + Gérer admin et membres + +

Administrateurs du club

+ + + + + + + + + {% for admin in user.club.administrators.all %} + + + + + + {% endfor %} +
NomPrenomPseudo
{{ admin.surname }}{{ admin.name }}{{ admin.pseudo }}
+

Membres

+ + + + + + + + + {% for admin in user.club.members.all %} + + + + + + {% endfor %} +
NomPrenomPseudo
{{ admin.surname }}{{ admin.name }}{{ admin.pseudo }}
+ {% endif %} +

Machines

Ajouter une machine

{% if machines_list %} {% include "machines/aff_machines.html" with machines_list=machines_list %} {% else %}

Aucune machine

{% endif %} -

Cotisations :

+

Cotisations

{% if is_cableur %}

Ajouter une cotisation {% if user_solde %} Modifier le solde{% endif%}

{% endif%} {% if facture_list %} {% include "cotisations/aff_cotisations.html" with facture_list=facture_list %} {% else %}

Aucune facture

{% endif %} -

Bannissements :

+

Bannissements

{% if is_bofh %}

Ajouter un bannissement

{% endif %} {% if ban_list %} {% include "users/aff_bans.html" with ban_list=ban_list %} diff --git a/users/templates/users/user.html b/users/templates/users/user.html index ad6ddb64..bf1bef0f 100644 --- a/users/templates/users/user.html +++ b/users/templates/users/user.html @@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% csrf_token %} - {% massive_bootstrap_form userform 'room,school' %} + {% massive_bootstrap_form userform 'room,school,administrators,members' %} {% bootstrap_button "Créer ou modifier" button_type="submit" icon="star" %}

diff --git a/users/urls.py b/users/urls.py index e351dcca..e669a0d9 100644 --- a/users/urls.py +++ b/users/urls.py @@ -33,6 +33,11 @@ urlpatterns = [ url(r'^new_user/$', views.new_user, name='new-user'), url(r'^new_club/$', views.new_club, name='new-club'), url(r'^edit_info/(?P[0-9]+)$', views.edit_info, name='edit-info'), + url( + r'^edit_club_admin_members/(?P[0-9]+)$', + views.edit_club_admin_members, + name='edit-club-admin-members' + ), url(r'^state/(?P[0-9]+)$', views.state, name='state'), url(r'^password/(?P[0-9]+)$', views.password, name='password'), url(r'^new_serviceuser/$', views.new_serviceuser, name='new-serviceuser'), diff --git a/users/views.py b/users/views.py index 5cbe462e..9aa51b5e 100644 --- a/users/views.py +++ b/users/views.py @@ -53,14 +53,40 @@ from rest_framework.renderers import JSONRenderer from reversion.models import Version from reversion import revisions as reversion from users.serializers import MailSerializer -from users.models import User, Right, Ban, Whitelist, School, ListRight -from users.models import Request, ServiceUser, Adherent, Club -from users.forms import DelRightForm, BanForm, WhitelistForm, DelSchoolForm -from users.forms import DelListRightForm, NewListRightForm, FullAdherentForm -from users.forms import StateForm, FullClubForm -from users.forms import RightForm, SchoolForm, EditServiceUserForm -from users.forms import ServiceUserForm, ListRightForm, AdherentForm, ClubForm -from users.forms import MassArchiveForm, PassForm, ResetPasswordForm +from users.models import ( + User, + Right, + Ban, + Whitelist, + School, + ListRight, + Request, + ServiceUser, + Adherent, + Club +) +from users.forms import ( + DelRightForm, + BanForm, + WhitelistForm, + DelSchoolForm, + DelListRightForm, + NewListRightForm, + FullAdherentForm, + StateForm, + FullClubForm, + RightForm, + SchoolForm, + EditServiceUserForm, + ServiceUserForm, + ListRightForm, + AdherentForm, + ClubForm, + MassArchiveForm, + PassForm, + ResetPasswordForm, + ClubAdminandMembersForm +) from cotisations.models import Facture from machines.models import Machine from preferences.models import OptionalUser, GeneralOption @@ -128,6 +154,38 @@ def new_club(request): return form({'userform': club}, 'users/user.html', request) +@login_required +def edit_club_admin_members(request, clubid): + """Vue d'edition de la liste des users administrateurs et + membres d'un club""" + try: + club_instance = Club.objects.get(pk=clubid) + except Club.DoesNotExist: + messages.error(request, "Club inexistant") + return redirect(reverse('users:index')) + if not request.user.has_perms(('cableur',))\ + and not request.user in club_instance.administrators.all(): + messages.error(request, "Vous ne pouvez pas accéder à ce menu") + return redirect(reverse( + 'users:profil', + kwargs={'userid':str(request.user.id)} + )) + club = ClubAdminandMembersForm(request.POST or None, instance=club_instance) + if club.is_valid(): + with transaction.atomic(), reversion.create_revision(): + club.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join( + field for field in club.changed_data + )) + messages.success(request, "Le club a bien été modifié") + return redirect(reverse( + 'users:profil', + kwargs={'userid':str(club_instance.id)} + )) + return form({'userform': club}, 'users/user.html', request) + + def select_user_edit_form(request, user): """Fonction de choix du bon formulaire, en fonction de: - droit From 772fdcaa1be24bd583fb9457a660e32b8bef18fc Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 21 Nov 2017 05:24:39 +0100 Subject: [PATCH 2/3] =?UTF-8?q?Acl=20g=C3=A9r=C3=A9es=20cot=C3=A9e=20model?= =?UTF-8?q?s,=20can=5Fedit=20et=20can=5Fview=20(vers=20les=20acl=20django.?= =?UTF-8?q?..)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- users/models.py | 15 +++++++++++++ users/templates/users/sidebar.html | 13 +++++++----- users/views.py | 34 ++++++++++++++---------------- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/users/models.py b/users/models.py index fae011d6..110531d3 100644 --- a/users/models.py +++ b/users/models.py @@ -758,6 +758,21 @@ class User(AbstractBaseUser): num += 1 return composed_pseudo(num) + def can_edit(self, user): + if self.is_class_club and user.is_class_adherent: + return self == user or user.has_perms(('cableur',))or\ + user.adherent in self.club.administrators.all() + else: + return self == user or user.has_perms(('cableur',)) + + def can_view(self, user): + if self.is_class_club and user.is_class_adherent: + return self == user or user.has_perms(('cableur',))or\ + user.adherent in self.club.administrators.all() or\ + user.adherent in self.club.members.all() + else: + return self == user or user.has_perms(('cableur',)) + def __str__(self): return self.pseudo diff --git a/users/templates/users/sidebar.html b/users/templates/users/sidebar.html index 9a4312ff..7c5f05f5 100644 --- a/users/templates/users/sidebar.html +++ b/users/templates/users/sidebar.html @@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block sidebar %} - {% if is_cableur %} + {% if is_cableur %} Créer un adhérent @@ -34,14 +34,17 @@ with this program; if not, write to the Free Software Foundation, Inc., Créer un club/association + {% endif %} + {% if is_cableur %} + + + Clubs et assos + + Adherents - - - Clubs - Bannissements diff --git a/users/views.py b/users/views.py index 9aa51b5e..6250db75 100644 --- a/users/views.py +++ b/users/views.py @@ -40,7 +40,7 @@ from django.shortcuts import get_object_or_404, render, redirect from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required -from django.db.models import ProtectedError +from django.db.models import ProtectedError, Q from django.db import IntegrityError from django.utils import timezone from django.db import transaction @@ -163,8 +163,7 @@ def edit_club_admin_members(request, clubid): except Club.DoesNotExist: messages.error(request, "Club inexistant") return redirect(reverse('users:index')) - if not request.user.has_perms(('cableur',))\ - and not request.user in club_instance.administrators.all(): + if not club_instance.can_edit(request.user): messages.error(request, "Vous ne pouvez pas accéder à ce menu") return redirect(reverse( 'users:profil', @@ -214,9 +213,8 @@ def edit_info(request, userid): except User.DoesNotExist: messages.error(request, "Utilisateur inexistant") return redirect(reverse('users:index')) - if not request.user.has_perms(('cableur',)) and user != request.user: - messages.error(request, "Vous ne pouvez pas modifier un autre\ - user que vous sans droit cableur") + if not user.can_edit(request.user): + messages.error(request, "Vous ne pouvez pas accéder à ce menu") return redirect(reverse( 'users:profil', kwargs={'userid':str(request.user.id)} @@ -279,9 +277,8 @@ def password(request, userid): except User.DoesNotExist: messages.error(request, "Utilisateur inexistant") return redirect(reverse('users')) - if not request.user.has_perms(('cableur',)) and user != request.user: - messages.error(request, "Vous ne pouvez pas modifier un\ - autre user que vous sans droit cableur") + if not user.can_edit(request.user): + messages.error(request, "Vous ne pouvez pas accéder à ce menu") return redirect(reverse( 'users:profil', kwargs={'userid':str(request.user.id)} @@ -722,12 +719,16 @@ def index(request): @login_required -@permission_required('cableur') def index_clubs(request): """ Affiche l'ensemble des clubs, need droit cableur """ options, _created = GeneralOption.objects.get_or_create() pagination_number = options.pagination_number - clubs_list = Club.objects.select_related('room') + if not request.user.has_perms(('cableur',)): + clubs_list = Club.objects.filter( + Q(administrators=request.user.adherent) | Q(members=request.user.adherent) + ).distinct().select_related('room') + else: + clubs_list = Club.objects.select_related('room') clubs_list = SortTable.sort( clubs_list, request.GET.get('col'), @@ -853,10 +854,8 @@ def history(request, object_name, object_id): except User.DoesNotExist: messages.error(request, "Utilisateur inexistant") return redirect(reverse('users:index')) - if not request.user.has_perms(('cableur',)) and\ - object_instance != request.user: - messages.error(request, "Vous ne pouvez pas afficher\ - l'historique d'un autre user que vous sans droit cableur") + if not object_instance.can_view(request.user): + messages.error(request, "Vous ne pouvez pas afficher ce menu") return redirect(reverse( 'users:profil', kwargs={'userid':str(request.user.id)} @@ -947,9 +946,8 @@ def profil(request, userid): except User.DoesNotExist: messages.error(request, "Utilisateur inexistant") return redirect(reverse('users:index')) - if not request.user.has_perms(('cableur',)) and users != request.user: - messages.error(request, "Vous ne pouvez pas afficher un autre user\ - que vous sans droit cableur") + if not users.can_view(request.user): + messages.error(request, "Vous ne pouvez pas accéder à ce menu") return redirect(reverse( 'users:profil', kwargs={'userid':str(request.user.id)} From 57f74f380a5738be689081fa0841376e8cc20145 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 21 Nov 2017 05:47:05 +0100 Subject: [PATCH 3/3] Fonction can_create sur un user --- .../0024_optionaluser_all_can_create.py | 20 +++++++++++++++++++ preferences/models.py | 4 ++++ .../preferences/display_preferences.html | 4 ++++ users/models.py | 11 ++++++++-- users/templates/users/sidebar.html | 11 +++++----- users/views.py | 7 ++++++- 6 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 preferences/migrations/0024_optionaluser_all_can_create.py diff --git a/preferences/migrations/0024_optionaluser_all_can_create.py b/preferences/migrations/0024_optionaluser_all_can_create.py new file mode 100644 index 00000000..3f7cf56e --- /dev/null +++ b/preferences/migrations/0024_optionaluser_all_can_create.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-11-21 04:42 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0023_auto_20171015_2033'), + ] + + operations = [ + migrations.AddField( + model_name='optionaluser', + name='all_can_create', + field=models.BooleanField(default=False, help_text="Tous les users peuvent en créer d'autres"), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index dc1412e7..6a793a24 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -42,6 +42,10 @@ class OptionalUser(models.Model): default=0 ) gpg_fingerprint = models.BooleanField(default=True) + all_can_create = models.BooleanField( + default=False, + help_text="Tous les users peuvent en créer d'autres", + ) def clean(self): """Creation du mode de paiement par solde""" diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index 9a2abe08..4858e414 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -52,6 +52,10 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ useroptions.solde_negatif }} {% endif %} + + Creations d'users par tous + {{ useroptions.all_can_create }} +

Préférences machines

{% if is_bureau %} diff --git a/users/models.py b/users/models.py index 110531d3..ac767bd3 100644 --- a/users/models.py +++ b/users/models.py @@ -758,16 +758,23 @@ class User(AbstractBaseUser): num += 1 return composed_pseudo(num) + def can_create(user): + options, _created = OptionalUser.objects.get_or_create() + if options.all_can_create: + return True + else: + return user.has_perms(('cableur',)) + def can_edit(self, user): if self.is_class_club and user.is_class_adherent: - return self == user or user.has_perms(('cableur',))or\ + return self == user or user.has_perms(('cableur',)) or\ user.adherent in self.club.administrators.all() else: return self == user or user.has_perms(('cableur',)) def can_view(self, user): if self.is_class_club and user.is_class_adherent: - return self == user or user.has_perms(('cableur',))or\ + return self == user or user.has_perms(('cableur',)) or\ user.adherent in self.club.administrators.all() or\ user.adherent in self.club.members.all() else: diff --git a/users/templates/users/sidebar.html b/users/templates/users/sidebar.html index 7c5f05f5..d6b31acd 100644 --- a/users/templates/users/sidebar.html +++ b/users/templates/users/sidebar.html @@ -26,21 +26,20 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block sidebar %} {% if is_cableur %} -
- - Créer un adhérent - Créer un club/association {% endif %} - {% if is_cableur %} + + + Créer un adhérent + Clubs et assos - + {% if is_cableur %} Adherents diff --git a/users/views.py b/users/views.py index 6250db75..e0c71157 100644 --- a/users/views.py +++ b/users/views.py @@ -111,10 +111,15 @@ def password_change_action(u_form, user, request, req=False): @login_required -@permission_required('cableur') def new_user(request): """ Vue de création d'un nouvel utilisateur, envoie un mail pour le mot de passe""" + if not User.can_create(request.user): + messages.error(request, "Vous ne pouvez pas accéder à ce menu") + return redirect(reverse( + 'users:profil', + kwargs={'userid':str(request.user.id)} + )) user = AdherentForm(request.POST or None) if user.is_valid(): user = user.save(commit=False)