8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-26 06:32:26 +00:00

Suppression de right et utilisation du système django

This commit is contained in:
Gabriel Detraz 2017-12-31 13:24:18 +01:00 committed by root
parent 8ab23e2925
commit 90b55b6dc8
14 changed files with 139 additions and 224 deletions

View file

@ -35,5 +35,5 @@ def can_view(user):
A couple (allowed, msg) where allowed is a boolean which is True if A couple (allowed, msg) where allowed is a boolean which is True if
viewing is granted and msg is a message (can be None). viewing is granted and msg is a message (can be None).
""" """
can = user.has_perms(('cableur',)) can = user.has_perm('cotisation.view_app_cotisation')
return can, None if can else "Vous ne pouvez pas voir cette application." return can, None if can else "Vous ne pouvez pas voir cette application."

View file

@ -50,7 +50,6 @@ from reversion.models import Version, ContentType
from users.models import ( from users.models import (
User, User,
ServiceUser, ServiceUser,
Right,
School, School,
ListRight, ListRight,
ListShell, ListShell,
@ -325,7 +324,6 @@ def stats_models(request):
'clubs': [Club.PRETTY_NAME, Club.objects.count()], 'clubs': [Club.PRETTY_NAME, Club.objects.count()],
'serviceuser': [ServiceUser.PRETTY_NAME, 'serviceuser': [ServiceUser.PRETTY_NAME,
ServiceUser.objects.count()], ServiceUser.objects.count()],
'right': [Right.PRETTY_NAME, Right.objects.count()],
'school': [School.PRETTY_NAME, School.objects.count()], 'school': [School.PRETTY_NAME, School.objects.count()],
'listright': [ListRight.PRETTY_NAME, ListRight.objects.count()], 'listright': [ListRight.PRETTY_NAME, ListRight.objects.count()],
'listshell': [ListShell.PRETTY_NAME, ListShell.objects.count()], 'listshell': [ListShell.PRETTY_NAME, ListShell.objects.count()],

View file

@ -130,7 +130,6 @@ MODEL_NAME = {
'Adherent' : users.models.Adherent, 'Adherent' : users.models.Adherent,
'Club' : users.models.Club, 'Club' : users.models.Club,
'ServiceUser' : users.models.ServiceUser, 'ServiceUser' : users.models.ServiceUser,
'Right' : users.models.Right,
'School' : users.models.School, 'School' : users.models.School,
'ListRight' : users.models.ListRight, 'ListRight' : users.models.ListRight,
'Ban' : users.models.Ban, 'Ban' : users.models.Ban,

View file

@ -32,7 +32,7 @@ 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 reversion.admin import VersionAdmin from reversion.admin import VersionAdmin
from .models import User, ServiceUser, School, Right, ListRight, ListShell from .models import User, ServiceUser, School, ListRight, ListShell
from .models import Ban, Whitelist, Request, LdapUser, LdapServiceUser from .models import Ban, Whitelist, Request, LdapUser, LdapServiceUser
from .models import LdapServiceUserGroup, LdapUserGroup from .models import LdapServiceUserGroup, LdapUserGroup
from .forms import UserChangeForm, UserCreationForm from .forms import UserChangeForm, UserCreationForm
@ -86,7 +86,7 @@ class SchoolAdmin(VersionAdmin):
class ListRightAdmin(VersionAdmin): class ListRightAdmin(VersionAdmin):
"""Gestion de la liste des droits existants """Gestion de la liste des droits existants
Ne permet pas l'edition du gid (primarykey pour ldap)""" Ne permet pas l'edition du gid (primarykey pour ldap)"""
list_display = ('listright',) list_display = ('unix_name',)
class ListShellAdmin(VersionAdmin): class ListShellAdmin(VersionAdmin):
@ -94,11 +94,6 @@ class ListShellAdmin(VersionAdmin):
pass pass
class RightAdmin(VersionAdmin):
"""Gestion de la liste des droits affectés"""
pass
class RequestAdmin(admin.ModelAdmin): class RequestAdmin(admin.ModelAdmin):
"""Gestion des request objet, ticket pour lien de reinit mot de passe""" """Gestion des request objet, ticket pour lien de reinit mot de passe"""
list_display = ('user', 'type', 'created_at', 'expires_at') list_display = ('user', 'type', 'created_at', 'expires_at')
@ -206,7 +201,6 @@ admin.site.register(LdapUserGroup, LdapUserGroupAdmin)
admin.site.register(LdapServiceUser, LdapServiceUserAdmin) admin.site.register(LdapServiceUser, LdapServiceUserAdmin)
admin.site.register(LdapServiceUserGroup, LdapServiceUserGroupAdmin) admin.site.register(LdapServiceUserGroup, LdapServiceUserGroupAdmin)
admin.site.register(School, SchoolAdmin) admin.site.register(School, SchoolAdmin)
admin.site.register(Right, RightAdmin)
admin.site.register(ListRight, ListRightAdmin) admin.site.register(ListRight, ListRightAdmin)
admin.site.register(ListShell, ListShellAdmin) admin.site.register(ListShell, ListShellAdmin)
admin.site.register(Ban, BanAdmin) admin.site.register(Ban, BanAdmin)

View file

@ -40,7 +40,7 @@ from django.core.validators import MinLengthValidator
from django.utils import timezone from django.utils import timezone
from preferences.models import OptionalUser from preferences.models import OptionalUser
from .models import User, ServiceUser, Right, School, ListRight, Whitelist from .models import User, ServiceUser, School, ListRight, Whitelist
from .models import Ban, Adherent, Club from .models import Ban, Adherent, Club
from re2o.utils import remove_user_room from re2o.utils import remove_user_room
@ -426,12 +426,12 @@ class ListRightForm(ModelForm):
Ne peremet pas d'editer le gid, car il sert de primary key""" Ne peremet pas d'editer le gid, car il sert de primary key"""
class Meta: class Meta:
model = ListRight model = ListRight
fields = ['listright', 'details'] fields = ['name', 'unix_name', 'permissions', 'details']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ListRightForm, self).__init__(*args, prefix=prefix, **kwargs) super(ListRightForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['listright'].label = 'Nom du droit/groupe' self.fields['unix_name'].label = 'Nom du droit/groupe'
class NewListRightForm(ListRightForm): class NewListRightForm(ListRightForm):
@ -457,9 +457,9 @@ class DelListRightForm(Form):
instances = kwargs.pop('instances', None) instances = kwargs.pop('instances', None)
super(DelListRightForm, self).__init__(*args, **kwargs) super(DelListRightForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['listrights'].queryset = instances self.fields['unix_name'].queryset = instances
else: else:
self.fields['listrights'].queryset = ListRight.objects.all() self.fields['unix_name'].queryset = ListRight.objects.all()
class DelSchoolForm(Form): class DelSchoolForm(Form):
@ -479,32 +479,6 @@ class DelSchoolForm(Form):
self.fields['schools'].queryset = School.objects.all() self.fields['schools'].queryset = School.objects.all()
class RightForm(ModelForm):
"""Assignation d'un droit à un user"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(RightForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['right'].label = 'Droit'
self.fields['right'].empty_label = "Choisir un nouveau droit"
class Meta:
model = Right
fields = ['right']
class DelRightForm(Form):
"""Suppression d'un droit d'un user"""
rights = forms.ModelMultipleChoiceField(
queryset=Right.objects.select_related('user'),
widget=forms.CheckboxSelectMultiple
)
def __init__(self, right, *args, **kwargs):
super(DelRightForm, self).__init__(*args, **kwargs)
self.fields['rights'].queryset = Right.objects.select_related('user')\
.select_related('right').filter(right=right)
class BanForm(ModelForm): class BanForm(ModelForm):
"""Creation, edition d'un objet bannissement""" """Creation, edition d'un objet bannissement"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View file

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-30 23:56
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('auth', '0008_alter_user_username_max_length'),
('users', '0061_auto_20171230_2033'),
]
def create_groups(apps, schema_editor):
group = apps.get_model("auth", "Group")
listrights = apps.get_model("users", "ListRight")
db_alias = schema_editor.connection.alias
for gr in listrights.objects.using(db_alias).all():
grp = group()
grp.name=gr.unix_name
grp.save()
gr.group_ptr=grp
gr.save()
def delete_groups(apps, schema_editor):
group = apps.get_model("auth", "Group")
db_alias = schema_editor.connection.alias
group.objects.using(db_alias).all().delete()
operations = [
migrations.RenameField(
model_name='listright',
old_name='listright',
new_name='unix_name',
),
migrations.AddField(
model_name='listright',
name='group_ptr',
field=models.OneToOneField(blank=True, null=True, auto_created=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='auth.Group'),
preserve_default=False,
),
migrations.RunPython(create_groups, delete_groups),
]

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-31 00:40
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0062_auto_20171231_0056'),
]
def transfer_right(apps, schema_editor):
rights = apps.get_model("users", "Right")
db_alias = schema_editor.connection.alias
for rg in rights.objects.using(db_alias).all():
group = rg.right
u=rg.user
u.groups.add(group.group_ptr)
u.save()
def untransfer_right(apps, schema_editor):
return
operations = [
migrations.RunPython(transfer_right, untransfer_right),
]

View file

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-31 00:50
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0063_auto_20171231_0140'),
]
operations = [
migrations.AlterUniqueTogether(
name='right',
unique_together=set([]),
),
migrations.RemoveField(
model_name='right',
name='right',
),
migrations.RemoveField(
model_name='right',
name='user',
),
migrations.DeleteModel(
name='Right',
),
migrations.RemoveField(
model_name='listright',
name='id',
),
migrations.AlterField(
model_name='listright',
name='group_ptr',
field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='auth.Group'),
),
]

View file

@ -63,7 +63,8 @@ from django.utils import timezone
from django.contrib.auth.models import ( from django.contrib.auth.models import (
AbstractBaseUser, AbstractBaseUser,
BaseUserManager, BaseUserManager,
PermissionsMixin PermissionsMixin,
Group
) )
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
@ -128,18 +129,6 @@ def get_fresh_gid():
return min(free_gids) return min(free_gids)
def get_admin_right():
""" Renvoie l'instance droit admin. La crée si elle n'existe pas
Lui attribue un gid libre"""
try:
admin_right = ListRight.objects.get(listright="admin")
except ListRight.DoesNotExist:
admin_right = ListRight(listright="admin")
admin_right.gid = get_fresh_gid()
admin_right.save()
return admin_right
class UserManager(BaseUserManager): class UserManager(BaseUserManager):
"""User manager basique de django""" """User manager basique de django"""
def _create_user( def _create_user(
@ -163,9 +152,9 @@ class UserManager(BaseUserManager):
) )
user.set_password(password) user.set_password(password)
user.save(using=self._db)
if su: if su:
user.make_admin() user.is_superuser=True
user.save(using=self._db)
return user return user
def create_user(self, pseudo, surname, email, password=None): def create_user(self, pseudo, surname, email, password=None):
@ -479,23 +468,6 @@ class User(FieldPermissionModelMixin, AbstractBaseUser, PermissionsMixin):
self.assign_ips() self.assign_ips()
self.state = User.STATE_ACTIVE self.state = User.STATE_ACTIVE
def has_module_perms(self, app_label):
"""True, a toutes les permissions de module"""
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):
"""Supprime les droits admin d'un user"""
try:
user_right = Right.objects.get(user=self, right=get_admin_right())
except Right.DoesNotExist:
return
user_right.delete()
def ldap_sync(self, base=True, access_refresh=True, mac_refresh=True, group_refresh=False): def ldap_sync(self, base=True, access_refresh=True, mac_refresh=True, group_refresh=False):
""" Synchronisation du ldap. Synchronise dans le ldap les attributs de """ Synchronisation du ldap. Synchronise dans le ldap les attributs de
self self
@ -538,8 +510,9 @@ class User(FieldPermissionModelMixin, AbstractBaseUser, PermissionsMixin):
machine__user=self machine__user=self
).values_list('mac_address', flat=True).distinct()] ).values_list('mac_address', flat=True).distinct()]
if group_refresh: if group_refresh:
for right in Right.objects.filter(user=self): for group in self.groups.all():
right.right.ldap_sync() if hasattr(group, 'listright'):
group.listright.ldap_sync()
user_ldap.save() user_ldap.save()
def ldap_del(self): def ldap_del(self):
@ -1032,88 +1005,6 @@ def service_user_post_delete(sender, **kwargs):
service_user.ldap_del() service_user.ldap_del()
class Right(models.Model):
""" Couple droit/user. Peut-être aurait-on mieux fait ici d'utiliser un
manytomany
Ceci dit le résultat aurait été le même avec une table intermediaire"""
PRETTY_NAME = "Droits affectés à des users"
user = models.ForeignKey('User', on_delete=models.PROTECT)
right = models.ForeignKey('ListRight', on_delete=models.PROTECT)
class Meta:
unique_together = ("user", "right")
def get_instance(rightid, *args, **kwargs):
return Right.objects.get(pk=rightid)
def can_create(user_request, *args, **kwargs):
"""Check if an user can create a Right object.
:param user_request: The user who wants to create an object.
:return: a message and a boolean which is True if the user can create.
"""
return user_request.has_perms(('bureau',)), u"Vous n'avez pas le droit de\
créer des droits"
def can_edit(self, user_request, *args, **kwargs):
"""Check if an user can edit a Right object.
:param self: The Right which is to be edited.
:param user_request: The user who requests to edit self.
:return: a message and a boolean which is True if edition is granted.
"""
return user_request.has_perms(('bureau',)), u"Vous n'avez pas le droit\
d'éditer des droits."
def can_delete(self, user_request, *args, **kwargs):
"""Check if an user can delete a Right object.
:param self: The Right which is to be deleted.
:param user_request: The user who requests deletion.
:return: True if deletion is granted, and a message.
"""
return user_request.has_perms(('bureau',)), u"Vous n'avez pas le droit de\
supprimer des droits"
def can_view_all(user_request, *args, **kwargs):
"""Check if an user can access to the list of every Right objects
:param user_request: The user who wants to view the list.
:return: True if the user can view the list and an explanation message.
"""
return user_request.has_perms(('cableur',)), u"Vous ne pouvez pas voir\
la liste des droits."
def can_view(self, user_request, *args, **kwargs):
"""Check if an user can view a Right object.
:param self: The targeted Right.
:param user_request: The user who ask for viewing the target.
:return: A boolean telling if the acces is granted and an explanation
text
"""
return user_request.has_perms(('cableur',)), u"Vous ne pouvez pas voir\
ce droit."
def __str__(self):
return str(self.user)
@receiver(post_save, sender=Right)
def right_post_save(sender, **kwargs):
""" Synchronise les users ldap groups avec les groupes de droits"""
right = kwargs['instance'].right
right.ldap_sync()
@receiver(post_delete, sender=Right)
def right_post_delete(sender, **kwargs):
""" Supprime l'user du groupe"""
right = kwargs['instance'].right
right.ldap_sync()
class School(models.Model): class School(models.Model):
""" Etablissement d'enseignement""" """ Etablissement d'enseignement"""
PRETTY_NAME = "Etablissements enregistrés" PRETTY_NAME = "Etablissements enregistrés"
@ -1176,7 +1067,7 @@ class School(models.Model):
return self.name return self.name
class ListRight(models.Model): class ListRight(Group):
""" Ensemble des droits existants. Chaque droit crée un groupe """ Ensemble des droits existants. Chaque droit crée un groupe
ldap synchronisé, avec gid. ldap synchronisé, avec gid.
Permet de gérer facilement les accès serveurs et autres Permet de gérer facilement les accès serveurs et autres
@ -1184,7 +1075,7 @@ class ListRight(models.Model):
il n'est plus modifiable après creation""" il n'est plus modifiable après creation"""
PRETTY_NAME = "Liste des droits existants" PRETTY_NAME = "Liste des droits existants"
listright = models.CharField( unix_name = models.CharField(
max_length=255, max_length=255,
unique=True, unique=True,
validators=[RegexValidator( validators=[RegexValidator(
@ -1253,7 +1144,7 @@ class ListRight(models.Model):
de voir les groupes de droits" de voir les groupes de droits"
def __str__(self): def __str__(self):
return self.listright return self.name
def ldap_sync(self): def ldap_sync(self):
"""Sychronise les groups ldap avec le model listright coté django""" """Sychronise les groups ldap avec le model listright coté django"""

View file

@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th>Droit</th> <th>Droit</th>
<th>Gid</th> <th>Gid</th>
<th>Permissions</th>
<th>Users</th>
<th>Details</th> <th>Details</th>
<th></th> <th></th>
<th></th> <th></th>
@ -34,8 +36,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</thead> </thead>
{% for listright in listright_list %} {% for listright in listright_list %}
<tr> <tr>
<td>{{ listright.listright }}</td> <td>{{ listright.name }}</td>
<td>{{ listright.gid }}</td> <td>{{ listright.gid }}</td>
<td>{{ listright.permissions.all }}</td>
<td>{{ listright.user_set.all }}</td>
<td>{{ listright.details }}</td> <td>{{ listright.details }}</td>
<td class="text-right"> <td class="text-right">
{% include 'buttons/edit.html' with href='users:edit-listright' id=listright.id %} {% include 'buttons/edit.html' with href='users:edit-listright' id=listright.id %}

View file

@ -42,10 +42,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<i class="glyphicon glyphicon-flash"></i> <i class="glyphicon glyphicon-flash"></i>
Changer le statut Changer le statut
</a> </a>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-right' users.id %}">
<i class="glyphicon glyphicon-ok"></i>
Ajouter un droit
</a>
<a class="btn btn-info btn-sm" role="button" href="{% url 'users:history' 'user' users.id %}"> <a class="btn btn-info btn-sm" role="button" href="{% url 'users:history' 'user' users.id %}">
<i class="glyphicon glyphicon-time"></i> <i class="glyphicon glyphicon-time"></i>
Historique Historique

View file

@ -77,10 +77,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Gérer les service users Gérer les service users
</a> </a>
{% acl_end %} {% acl_end %}
<a class="list-group-item list-group-item-danger" href="{% url "users:del-right" %}">
<i class="glyphicon glyphicon-trash"></i>
Retirer un droit
</a>
{% can_change User state %} {% can_change User state %}
<a class="list-group-item list-group-item-danger" href="{% url "users:mass-archive" %}"> <a class="list-group-item list-group-item-danger" href="{% url "users:mass-archive" %}">
<i class="glyphicon glyphicon-book"></i> <i class="glyphicon glyphicon-book"></i>

View file

@ -64,8 +64,6 @@ urlpatterns = [
views.edit_whitelist, views.edit_whitelist,
name='edit-whitelist' name='edit-whitelist'
), ),
url(r'^add_right/(?P<userid>[0-9]+)$', views.add_right, name='add-right'),
url(r'^del_right/$', views.del_right, name='del-right'),
url(r'^add_school/$', views.add_school, name='add-school'), url(r'^add_school/$', views.add_school, name='add-school'),
url( url(
r'^edit_school/(?P<schoolid>[0-9]+)$', r'^edit_school/(?P<schoolid>[0-9]+)$',

View file

@ -55,7 +55,6 @@ from reversion import revisions as reversion
from users.serializers import MailSerializer from users.serializers import MailSerializer
from users.models import ( from users.models import (
User, User,
Right,
Ban, Ban,
Whitelist, Whitelist,
School, School,
@ -66,14 +65,12 @@ from users.models import (
Club, Club,
) )
from users.forms import ( from users.forms import (
DelRightForm,
BanForm, BanForm,
WhitelistForm, WhitelistForm,
DelSchoolForm, DelSchoolForm,
DelListRightForm, DelListRightForm,
NewListRightForm, NewListRightForm,
StateForm, StateForm,
RightForm,
SchoolForm, SchoolForm,
EditServiceUserForm, EditServiceUserForm,
ServiceUserForm, ServiceUserForm,
@ -313,51 +310,6 @@ def del_serviceuser(request, user, userid):
) )
@login_required
@can_create(Right)
@can_edit(User)
def add_right(request, user, userid):
""" Ajout d'un droit à un user, need droit bureau """
right = RightForm(request.POST or None)
if right.is_valid():
right = right.save(commit=False)
right.user = user
try:
with transaction.atomic(), reversion.create_revision():
reversion.set_user(request.user)
reversion.set_comment("Ajout du droit %s" % right.right)
right.save()
messages.success(request, "Droit ajouté")
except IntegrityError:
pass
return redirect(reverse(
'users:profil',
kwargs={'userid':str(userid)}
))
return form({'userform': right}, 'users/user.html', request)
@login_required
@permission_required('bureau')
def del_right(request):
""" Supprimer un droit à un user, need droit bureau """
user_right_list = dict()
for right in ListRight.objects.all():
user_right_list[right] = DelRightForm(right, request.POST or None)
for _keys, right_item in user_right_list.items():
if right_item.is_valid():
right_del = right_item.cleaned_data['rights']
with transaction.atomic(), reversion.create_revision():
reversion.set_user(request.user)
reversion.set_comment("Retrait des droit %s" % ','.join(
str(deleted_right) for deleted_right in right_del
))
right_del.delete()
messages.success(request, "Droit retiré avec succès")
return redirect(reverse('users:index'))
return form({'userform': user_right_list}, 'users/del_right.html', request)
@login_required @login_required
@can_create(Ban) @can_create(Ban)
@can_edit(User) @can_edit(User)
@ -731,7 +683,7 @@ def index_school(request):
@can_view_all(ListRight) @can_view_all(ListRight)
def index_listright(request): def index_listright(request):
""" Affiche l'ensemble des droits , need droit cableur """ """ Affiche l'ensemble des droits , need droit cableur """
listright_list = ListRight.objects.order_by('listright') listright_list = ListRight.objects.order_by('unix_name')
return render( return render(
request, request,
'users/index_listright.html', 'users/index_listright.html',
@ -796,7 +748,6 @@ def profil(request, users, userid):
request.GET.get('order'), request.GET.get('order'),
SortTable.USERS_INDEX_WHITE SortTable.USERS_INDEX_WHITE
) )
list_droits = Right.objects.filter(user=users)
options, _created = OptionalUser.objects.get_or_create() options, _created = OptionalUser.objects.get_or_create()
user_solde = options.user_solde user_solde = options.user_solde
return render( return render(
@ -808,7 +759,6 @@ def profil(request, users, userid):
'facture_list': factures, 'facture_list': factures,
'ban_list': bans, 'ban_list': bans,
'white_list': whitelists, 'white_list': whitelists,
'list_droits': list_droits,
'user_solde': user_solde, 'user_solde': user_solde,
} }
) )