mirror of https://gitlab.federez.net/re2o/re2o
117 changed files with 5504 additions and 1910 deletions
@ -0,0 +1,40 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Gabriel Détraz |
|||
# Copyright © 2017 Goulven Kermarec |
|||
# Copyright © 2017 Augustin Lemesle |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
"""cotisations.acl |
|||
|
|||
Here are defined some functions to check acl on the application. |
|||
""" |
|||
|
|||
def can_view(user): |
|||
"""Check if an user can view the application. |
|||
|
|||
Args: |
|||
user: The user who wants to view the application. |
|||
|
|||
Returns: |
|||
A couple (allowed, msg) where allowed is a boolean which is True if |
|||
viewing is granted and msg is a message (can be None). |
|||
""" |
|||
can = user.has_module_perms('cotisations') |
|||
return can, None if can else "Vous ne pouvez pas voir cette application." |
|||
@ -0,0 +1,39 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.10.7 on 2017-12-30 23:07 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('cotisations', '0027_auto_20171029_1156'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='article', |
|||
options={'permissions': (('view_article', 'Peut voir un objet article'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='banque', |
|||
options={'permissions': (('view_banque', 'Peut voir un objet banque'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='cotisation', |
|||
options={'permissions': (('view_cotisation', 'Peut voir un objet cotisation'), ('change_all_cotisation', 'Superdroit, peut modifier toutes les cotisations'))}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='facture', |
|||
options={'permissions': (('change_facture_control', "Peut changer l'etat de controle"), ('change_facture_pdf', 'Peut éditer une facture pdf'), ('view_facture', 'Peut voir un objet facture'), ('change_all_facture', 'Superdroit, peut modifier toutes les factures'))}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='paiement', |
|||
options={'permissions': (('view_paiement', 'Peut voir un objet paiement'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='vente', |
|||
options={'permissions': (('view_vente', 'Peut voir un objet vente'), ('change_all_vente', 'Superdroit, peut modifier toutes les ventes'))}, |
|||
), |
|||
] |
|||
@ -0,0 +1,40 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Gabriel Détraz |
|||
# Copyright © 2017 Goulven Kermarec |
|||
# Copyright © 2017 Augustin Lemesle |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
"""logs.acl |
|||
|
|||
Here are defined some functions to check acl on the application. |
|||
""" |
|||
|
|||
def can_view(user): |
|||
"""Check if an user can view the application. |
|||
|
|||
Args: |
|||
user: The user who wants to view the application. |
|||
|
|||
Returns: |
|||
A couple (allowed, msg) where allowed is a boolean which is True if |
|||
viewing is granted and msg is a message (can be None). |
|||
""" |
|||
can = user.has_module_perms('admin') |
|||
return can, None if can else "Vous ne pouvez pas voir cette application." |
|||
@ -0,0 +1,40 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Gabriel Détraz |
|||
# Copyright © 2017 Goulven Kermarec |
|||
# Copyright © 2017 Augustin Lemesle |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
"""machines.acl |
|||
|
|||
Here are defined some functions to check acl on the application. |
|||
""" |
|||
|
|||
def can_view(user): |
|||
"""Check if an user can view the application. |
|||
|
|||
Args: |
|||
user: The user who wants to view the application. |
|||
|
|||
Returns: |
|||
A couple (allowed, msg) where allowed is a boolean which is True if |
|||
viewing is granted and msg is a message (can be None). |
|||
""" |
|||
can = user.has_module_perms('machines') |
|||
return can, None if can else "Vous ne pouvez pas voir cette application." |
|||
@ -0,0 +1,79 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.10.7 on 2017-12-31 18:47 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('machines', '0069_auto_20171116_0822'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='domain', |
|||
options={'permissions': (('view_domain', 'Peut voir un objet domain'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='extension', |
|||
options={'permissions': (('view_extension', 'Peut voir un objet extension'), ('use_all_extension', 'Peut utiliser toutes les extension'))}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='interface', |
|||
options={'permissions': (('view_interface', 'Peut voir un objet interface'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='iplist', |
|||
options={'permissions': (('view_iplist', 'Peut voir un objet iplist'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='iptype', |
|||
options={'permissions': (('view_iptype', 'Peut voir un objet iptype'), ('use_all_iptype', 'Peut utiliser tous les iptype'))}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='machine', |
|||
options={'permissions': (('view_machine', 'Peut voir un objet machine quelquonque'), ('change_machine_user', "Peut changer le propriétaire d'une machine"))}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='machinetype', |
|||
options={'permissions': (('view_machinetype', 'Peut voir un objet machinetype'), ('use_all_machinetype', "Peut utiliser n'importe quel type de machine"))}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='mx', |
|||
options={'permissions': (('view_mx', 'Peut voir un objet mx'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='nas', |
|||
options={'permissions': (('view_nas', 'Peut voir un objet Nas'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='ns', |
|||
options={'permissions': (('view_nx', 'Peut voir un objet nx'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='ouvertureportlist', |
|||
options={'permissions': (('view_ouvertureportlist', 'Peut voir un objet ouvertureport'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='service', |
|||
options={'permissions': (('view_service', 'Peut voir un objet service'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='soa', |
|||
options={'permissions': (('view_soa', 'Peut voir un objet soa'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='srv', |
|||
options={'permissions': (('view_soa', 'Peut voir un objet soa'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='txt', |
|||
options={'permissions': (('view_txt', 'Peut voir un objet txt'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='vlan', |
|||
options={'permissions': (('view_vlan', 'Peut voir un objet vlan'),)}, |
|||
), |
|||
] |
|||
@ -0,0 +1,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.10.7 on 2017-12-31 20:00 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('machines', '0070_auto_20171231_1947'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='ns', |
|||
options={'permissions': (('view_ns', 'Peut voir un objet ns'),)}, |
|||
), |
|||
] |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,2 @@ |
|||
|
|||
from .acl import * |
|||
@ -0,0 +1,40 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Gabriel Détraz |
|||
# Copyright © 2017 Goulven Kermarec |
|||
# Copyright © 2017 Augustin Lemesle |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
"""preferences.acl |
|||
|
|||
Here are defined some functions to check acl on the application. |
|||
""" |
|||
|
|||
def can_view(user): |
|||
"""Check if an user can view the application. |
|||
|
|||
Args: |
|||
user: The user who wants to view the application. |
|||
|
|||
Returns: |
|||
A couple (allowed, msg) where allowed is a boolean which is True if |
|||
viewing is granted and msg is a message (can be None). |
|||
""" |
|||
can = user.has_module_perms('preferences') |
|||
return can, None if can else "Vous ne pouvez pas voir cette application." |
|||
@ -0,0 +1,43 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.10.7 on 2017-12-31 20:42 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('preferences', '0024_optionaluser_all_can_create'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='assooption', |
|||
options={'permissions': (('view_assooption', "Peut voir les options de l'asso"),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='generaloption', |
|||
options={'permissions': (('view_generaloption', 'Peut voir les options générales'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='mailmessageoption', |
|||
options={'permissions': (('view_mailmessageoption', 'Peut voir les options de mail'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='optionalmachine', |
|||
options={'permissions': (('view_optionalmachine', 'Peut voir les options de machine'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='optionaltopologie', |
|||
options={'permissions': (('view_optionaltopologie', 'Peut voir les options de topologie'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='optionaluser', |
|||
options={'permissions': (('view_optionaluser', "Peut voir les options de l'user"),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='service', |
|||
options={'permissions': (('view_service', 'Peut voir les options de service'),)}, |
|||
), |
|||
] |
|||
@ -0,0 +1,16 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.10.7 on 2018-01-06 19:19 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('preferences', '0025_auto_20171231_2142'), |
|||
('preferences', '0026_auto_20171216_0401'), |
|||
] |
|||
|
|||
operations = [ |
|||
] |
|||
@ -0,0 +1,235 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Gabriel Détraz |
|||
# Copyright © 2017 Goulven Kermarec |
|||
# Copyright © 2017 Augustin Lemesle |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
"""Handles ACL for re2o. |
|||
|
|||
Here are defined some decorators that can be used in views to handle ACL. |
|||
""" |
|||
from __future__ import unicode_literals |
|||
|
|||
import sys |
|||
|
|||
from django.contrib import messages |
|||
from django.shortcuts import redirect |
|||
from django.urls import reverse |
|||
|
|||
import cotisations, logs, machines, preferences, search, topologie, users |
|||
|
|||
|
|||
def can_create(model): |
|||
"""Decorator to check if an user can create a model. |
|||
It assumes that a valid user exists in the request and that the model has a |
|||
method can_create(user) which returns true if the user can create this kind |
|||
of models. |
|||
""" |
|||
def decorator(view): |
|||
def wrapper(request, *args, **kwargs): |
|||
can, msg = model.can_create(request.user, *args, **kwargs) |
|||
if not can: |
|||
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return view(request, *args, **kwargs) |
|||
return wrapper |
|||
return decorator |
|||
|
|||
|
|||
def can_edit(model, *field_list): |
|||
"""Decorator to check if an user can edit a model. |
|||
It tries to get an instance of the model, using |
|||
`model.get_instance(*args, **kwargs)` and assumes that the model has a |
|||
method `can_edit(user)` which returns `true` if the user can edit this |
|||
kind of models. |
|||
""" |
|||
def decorator(view): |
|||
def wrapper(request, *args, **kwargs): |
|||
try: |
|||
instance = model.get_instance(*args, **kwargs) |
|||
except model.DoesNotExist: |
|||
messages.error(request, u"Entrée inexistante") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
can, msg = instance.can_edit(request.user) |
|||
if not can: |
|||
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
for field in field_list: |
|||
can_change = getattr(instance, 'can_change_' + field) |
|||
can, msg = can_change(request.user, *args, **kwargs) |
|||
if not can: |
|||
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return view(request, instance, *args, **kwargs) |
|||
return wrapper |
|||
return decorator |
|||
|
|||
|
|||
def can_change(model, *field_list): |
|||
"""Decorator to check if an user can edit a field of a model class. |
|||
Difference with can_edit : take a class and not an instance |
|||
""" |
|||
def decorator(view): |
|||
def wrapper(request, *args, **kwargs): |
|||
for field in field_list: |
|||
can_change = getattr(model, 'can_change_' + field) |
|||
can, msg = can_change(request.user, *args, **kwargs) |
|||
if not can: |
|||
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return view(request, *args, **kwargs) |
|||
return wrapper |
|||
return decorator |
|||
|
|||
|
|||
def can_delete(model): |
|||
"""Decorator to check if an user can delete a model. |
|||
It tries to get an instance of the model, using |
|||
`model.get_instance(*args, **kwargs)` and assumes that the model has a |
|||
method `can_delete(user)` which returns `true` if the user can delete this |
|||
kind of models. |
|||
""" |
|||
def decorator(view): |
|||
def wrapper(request, *args, **kwargs): |
|||
try: |
|||
instance = model.get_instance(*args, **kwargs) |
|||
except model.DoesNotExist: |
|||
messages.error(request, u"Entrée inexistante") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
can, msg = instance.can_delete(request.user) |
|||
if not can: |
|||
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return view(request, instance, *args, **kwargs) |
|||
return wrapper |
|||
return decorator |
|||
|
|||
|
|||
def can_delete_set(model): |
|||
"""Decorator which returns a list of detable models by request user. |
|||
If none of them, return an error""" |
|||
def decorator(view): |
|||
def wrapper(request, *args, **kwargs): |
|||
all_objects = model.objects.all() |
|||
instances_id = [] |
|||
for instance in all_objects: |
|||
can, msg = instance.can_delete(request.user) |
|||
if can: |
|||
instances_id.append(instance.id) |
|||
instances = model.objects.filter(id__in=instances_id) |
|||
if not instances: |
|||
messages.error(request, "Vous ne pouvez pas accéder à ce menu") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return view(request, instances, *args, **kwargs) |
|||
return wrapper |
|||
return decorator |
|||
|
|||
|
|||
def can_view(model): |
|||
"""Decorator to check if an user can view a model. |
|||
It tries to get an instance of the model, using |
|||
`model.get_instance(*args, **kwargs)` and assumes that the model has a |
|||
method `can_view(user)` which returns `true` if the user can view this |
|||
kind of models. |
|||
""" |
|||
def decorator(view): |
|||
def wrapper(request, *args, **kwargs): |
|||
try: |
|||
instance = model.get_instance(*args, **kwargs) |
|||
except model.DoesNotExist: |
|||
messages.error(request, u"Entrée inexistante") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
can, msg = instance.can_view(request.user) |
|||
if not can: |
|||
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return view(request, instance, *args, **kwargs) |
|||
return wrapper |
|||
return decorator |
|||
|
|||
|
|||
def can_view_all(model): |
|||
"""Decorator to check if an user can view a class of model. |
|||
""" |
|||
def decorator(view): |
|||
def wrapper(request, *args, **kwargs): |
|||
can, msg = model.can_view_all(request.user) |
|||
if not can: |
|||
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu") |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return view(request, *args, **kwargs) |
|||
return wrapper |
|||
return decorator |
|||
|
|||
|
|||
def can_view_app(app_name): |
|||
"""Decorator to check if an user can view an application. |
|||
""" |
|||
assert app_name in sys.modules.keys() |
|||
def decorator(view): |
|||
def wrapper(request, *args, **kwargs): |
|||
app = sys.modules[app_name] |
|||
can,msg = app.can_view(request.user) |
|||
if can: |
|||
return view(request, *args, **kwargs) |
|||
messages.error(request, msg) |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return wrapper |
|||
return decorator |
|||
|
|||
|
|||
def can_edit_history(view): |
|||
"""Decorator to check if an user can edit history.""" |
|||
def wrapper(request, *args, **kwargs): |
|||
if request.user.has_perm('admin.change_logentry'): |
|||
return view(request, *args, **kwargs) |
|||
messages.error( |
|||
request, |
|||
"Vous ne pouvez pas éditer l'historique." |
|||
) |
|||
return redirect(reverse('users:profil', |
|||
kwargs={'userid':str(request.user.id)} |
|||
)) |
|||
return wrapper |
|||
|
|||
@ -0,0 +1,79 @@ |
|||
from django.db import models |
|||
from django import forms |
|||
from functools import partial |
|||
|
|||
|
|||
class FieldPermissionModelMixin: |
|||
field_permissions = {} # {'field_name': callable} |
|||
FIELD_PERM_CODENAME = 'can_change_{model}_{name}' |
|||
FIELD_PERMISSION_GETTER = 'can_change_{name}' |
|||
FIELD_PERMISSION_MISSING_DEFAULT = True |
|||
|
|||
def has_field_perm(self, user, field): |
|||
if field in self.field_permissions: |
|||
checks = self.field_permissions[field] |
|||
if not isinstance(checks, (list, tuple)): |
|||
checks = [checks] |
|||
|
|||
else: |
|||
checks = [] |
|||
|
|||
# Consult the optional field-specific hook. |
|||
getter_name = self.FIELD_PERMISSION_GETTER.format(name=field) |
|||
if hasattr(self, getter_name): |
|||
checks.append(getattr(self, getter_name)) |
|||
|
|||
# Try to find a static permission for the field |
|||
else: |
|||
perm_label = self.FIELD_PERM_CODENAME.format(**{ |
|||
'model': self._meta.model_name, |
|||
'name': field, |
|||
}) |
|||
if perm_label in dict(self._meta.permissions): |
|||
checks.append(perm_label) |
|||
|
|||
# No requirements means no restrictions. |
|||
if not len(checks): |
|||
return self.FIELD_PERMISSION_MISSING_DEFAULT |
|||
|
|||
# Try to find a user setting that qualifies them for permission. |
|||
for perm in checks: |
|||
if callable(perm): |
|||
result, reason = perm(user_request=user) |
|||
if result is not None: |
|||
return result |
|||
else: |
|||
result = user.has_perm(perm) # Don't supply 'obj', or else infinite recursion. |
|||
if result: |
|||
return True |
|||
|
|||
# If no requirement can be met, then permission is denied. |
|||
return False |
|||
|
|||
class FieldPermissionModel(FieldPermissionModelMixin, models.Model): |
|||
class Meta: |
|||
abstract = True |
|||
|
|||
|
|||
class FieldPermissionFormMixin: |
|||
""" |
|||
Construit le formulaire et retire les champs interdits |
|||
""" |
|||
def __init__(self, *args, **kwargs): |
|||
user = kwargs.pop('user') |
|||
|
|||
super(FieldPermissionFormMixin, self).__init__(*args, **kwargs) |
|||
to_be_deleted = [] |
|||
for name in self.fields: |
|||
if not self.instance.has_field_perm(user, field=name): |
|||
to_be_deleted.append(name) |
|||
for name in to_be_deleted: |
|||
self.remove_unauthorized_field(name) |
|||
|
|||
def remove_unauthorized_field(self, name): |
|||
del self.fields[name] |
|||
|
|||
|
|||
class FieldPermissionForm(FieldPermissionFormMixin, forms.ModelForm): |
|||
pass |
|||
|
|||
@ -0,0 +1,410 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Maël Kervella |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
""" |
|||
Set of templatetags for using acl in templates: |
|||
- can_create (model) |
|||
- cannot_create (model) |
|||
- can_edit (instance) |
|||
- cannot_edit (instance) |
|||
|
|||
Some templatetags require a model to calculate the acl while others are need |
|||
an instance of a model (either Model.can_xxx or instance.can_xxx) |
|||
|
|||
**Parameters**: |
|||
model_name or instance - Either the model_name (if templatetag is based on |
|||
model) or an instantiated object (if templatetag is base on instance) |
|||
that needs to be checked for the current user |
|||
args - Any other argument that is interpreted as a python object and passed |
|||
to the acl function (can_xxx) |
|||
|
|||
**Usage**: |
|||
{% <acl_name> <obj> [arg1 [arg2 [...]]]%} |
|||
<template stuff> |
|||
[{% acl_else %} |
|||
<template stuff>] |
|||
{% acl_end %} |
|||
|
|||
where <acl_name> is one of the templatetag names available |
|||
(can_xxx or cannot_xxx) |
|||
|
|||
**Example**: |
|||
{% can_create Machine targeted_user %} |
|||
<p>I'm authorized to create new machines.models.for this guy \\o/</p> |
|||
{% acl_else %} |
|||
<p>Why can't I create a little machine for this guy ? :(</p> |
|||
{% acl_end %} |
|||
|
|||
{% can_edit user %} |
|||
<p>Oh I can edit myself oO</p> |
|||
{% acl_else %} |
|||
<p>Sniff can't edit my own infos ...</p> |
|||
{% acl_end %} |
|||
|
|||
**How to modify**: |
|||
To add a new acl function (can_xxx or cannot_xxx), |
|||
- if it's based on a model (like can_create), add an entry in |
|||
'get_callback' and register your tag with the other ones juste before |
|||
'acl_model_generic' definition |
|||
- if it's bases on an instance (like can_edit), just register yout tag with |
|||
the other ones juste before 'acl_instance_generic' definition |
|||
To add support for a new model, add an entry in 'get_model' and be sure |
|||
the acl function exists in the model definition |
|||
|
|||
""" |
|||
import sys |
|||
|
|||
from django import template |
|||
from django.template.base import Node, NodeList |
|||
|
|||
import cotisations |
|||
import machines |
|||
import preferences |
|||
import topologie |
|||
import users |
|||
|
|||
register = template.Library() |
|||
|
|||
MODEL_NAME = { |
|||
# cotisations |
|||
'Facture' : cotisations.models.Facture, |
|||
'Vente' : cotisations.models.Vente, |
|||
'Article' : cotisations.models.Article, |
|||
'Banque' : cotisations.models.Banque, |
|||
'Paiement' : cotisations.models.Paiement, |
|||
'Cotisation' : cotisations.models.Cotisation, |
|||
# machines |
|||
'Machine' : machines.models.Machine, |
|||
'MachineType' : machines.models.MachineType, |
|||
'IpType' : machines.models.IpType, |
|||
'Vlan' : machines.models.Vlan, |
|||
'Nas' : machines.models.Nas, |
|||
'SOA' : machines.models.SOA, |
|||
'Extension' : machines.models.Extension, |
|||
'Mx' : machines.models.Mx, |
|||
'Ns' : machines.models.Ns, |
|||
'Txt' : machines.models.Txt, |
|||
'Srv' : machines.models.Srv, |
|||
'Interface' : machines.models.Interface, |
|||
'Domain' : machines.models.Domain, |
|||
'IpList' : machines.models.IpList, |
|||
'Service' : machines.models.Service, |
|||
'Service_link' : machines.models.Service_link, |
|||
'OuverturePortList' : machines.models.OuverturePortList, |
|||
'OuverturePort' : machines.models.OuverturePort, |
|||
# preferences |
|||
'OptionalUser': preferences.models.OptionalUser, |
|||
'OptionalMachine': preferences.models.OptionalMachine, |
|||
'OptionalTopologie': preferences.models.OptionalTopologie, |
|||
'GeneralOption': preferences.models.GeneralOption, |
|||
'Service': preferences.models.Service, |
|||
'AssoOption': preferences.models.AssoOption, |
|||
'MailMessageOption': preferences.models.MailMessageOption, |
|||
# topologie |
|||
'Stack' : topologie.models.Stack, |
|||
'Switch' : topologie.models.Switch, |
|||
'ModelSwitch' : topologie.models.ModelSwitch, |
|||
'ConstructorSwitch' : topologie.models.ConstructorSwitch, |
|||
'Port' : topologie.models.Port, |
|||
'Room' : topologie.models.Room, |
|||
# users |
|||
'User' : users.models.User, |
|||
'Adherent' : users.models.Adherent, |
|||
'Club' : users.models.Club, |
|||
'ServiceUser' : users.models.ServiceUser, |
|||
'School' : users.models.School, |
|||
'ListRight' : users.models.ListRight, |
|||
'Ban' : users.models.Ban, |
|||
'Whitelist' : users.models.Whitelist, |
|||
} |
|||
|
|||
|
|||
def get_model(model_name): |
|||
"""Retrieve the model object from its name""" |
|||
try: |
|||
return MODEL_NAME[model_name] |
|||
except KeyError: |
|||
raise template.TemplateSyntaxError( |
|||
"%r is not a valid model for an acl tag" % model_name |
|||
) |
|||
|
|||
|
|||
def get_callback(tag_name, obj=None): |
|||
"""Return the right function to call back to check for acl""" |
|||
|
|||
if tag_name == 'can_create': |
|||
return acl_fct(obj.can_create, False) |
|||
if tag_name == 'cannot_create': |
|||
return acl_fct(obj.can_create, True) |
|||
if tag_name == 'can_edit': |
|||
return acl_fct(obj.can_edit, False) |
|||
if tag_name == 'cannot_edit': |
|||
return acl_fct(obj.can_edit, True) |
|||
if tag_name == 'can_edit_all': |
|||
return acl_fct(obj.can_edit_all, False) |
|||
if tag_name == 'cannot_edit_all': |
|||
return acl_fct(obj.can_edit_all, True) |
|||
if tag_name == 'can_delete': |
|||
return acl_fct(obj.can_delete, False) |
|||
if tag_name == 'cannot_delete': |
|||
return acl_fct(obj.can_delete, True) |
|||
if tag_name == 'can_delete_all': |
|||
return acl_fct(obj.can_delete_all, False) |
|||
if tag_name == 'cannot_delete_all': |
|||
return acl_fct(obj.can_delete_all, True) |
|||
if tag_name == 'can_view': |
|||
return acl_fct(obj.can_view, False) |
|||
if tag_name == 'cannot_view': |
|||
return acl_fct(obj.can_view, True) |
|||
if tag_name == 'can_view_all': |
|||
return acl_fct(obj.can_view_all, False) |
|||
if tag_name == 'cannot_view_all': |
|||
return acl_fct(obj.can_view_all, True) |
|||
if tag_name == 'can_view_app': |
|||
return acl_fct(sys.modules[obj].can_view, False) |
|||
if tag_name == 'cannot_view_app': |
|||
return acl_fct(sys.modules[obj].can_view, True) |
|||
if tag_name == 'can_edit_history': |
|||
return acl_fct(lambda user:(user.has_perm('admin.change_logentry'),None),False) |
|||
if tag_name == 'cannot_edit_history': |
|||
return acl_fct(lambda user:(user.has_perm('admin.change_logentry'),None),True) |
|||
|
|||
raise template.TemplateSyntaxError( |
|||
"%r tag is not a valid can_xxx tag" % tag_name |
|||
) |
|||
|
|||
|
|||
def acl_fct(callback, reverse): |
|||
"""Build a function to use as an acl checker""" |
|||
|
|||
def acl_fct_normal(user, *args, **kwargs): |
|||
"""The can_xxx checker callback""" |
|||
return callback(user, *args, **kwargs) |
|||
|
|||
def acl_fct_reverse(user, *args, **kwargs): |
|||
"""The cannot_xxx checker callback""" |
|||
can, msg = callback(user, *args, **kwargs) |
|||
return not can, msg |
|||
|
|||
return acl_fct_reverse if reverse else acl_fct_normal |
|||
|
|||
|
|||
@register.tag('can_edit_history') |
|||
@register.tag('cannot_edit_history') |
|||
def acl_history_filter(parser, token): |
|||
"""Templatetag for acl checking on history.""" |
|||
tag_name, = token.split_contents() |
|||
|
|||
callback = get_callback(tag_name) |
|||
oknodes = parser.parse(('acl_else', 'acl_end')) |
|||
token = parser.next_token() |
|||
if token.contents == 'acl_else': |
|||
konodes = parser.parse(('acl_end')) |
|||
token = parser.next_token() |
|||
else: |
|||
konodes = NodeList() |
|||
|
|||
assert token.contents == 'acl_end' |
|||
|
|||
return AclNode(callback, oknodes, konodes) |
|||
|
|||
|
|||
@register.tag('can_view_app') |
|||
@register.tag('cannot_view_app') |
|||
def acl_app_filter(parser, token): |
|||
"""Templatetag for acl checking on applications.""" |
|||
try: |
|||
tag_name, app_name = token.split_contents() |
|||
except ValueError: |
|||
raise template.TemplateSyntaxError( |
|||
"%r tag require 1 argument : the application" |
|||
% token.contents.split()[0] |
|||
) |
|||
if not app_name in sys.modules.keys(): |
|||
raise template.TemplateSyntaxError( |
|||
"%r is not a registered application for acl." |
|||
% app_name |
|||
) |
|||
|
|||
callback = get_callback(tag_name, app_name) |
|||
|
|||
oknodes = parser.parse(('acl_else', 'acl_end')) |
|||
token = parser.next_token() |
|||
if token.contents == 'acl_else': |
|||
konodes = parser.parse(('acl_end')) |
|||
token = parser.next_token() |
|||
else: |
|||
konodes = NodeList() |
|||
|
|||
assert token.contents == 'acl_end' |
|||
|
|||
return AclNode(callback, oknodes, konodes) |
|||
|
|||
@register.tag('can_change') |
|||
@register.tag('cannot_change') |
|||
def acl_change_filter(parser, token): |
|||
"""Templatetag for acl checking a can_change_xxx function""" |
|||
|
|||
try: |
|||
tag_content = token.split_contents() |
|||
tag_name = tag_content[0] |
|||
model_name = tag_content[1] |
|||
field_name = tag_content[2] |
|||
args = tag_content[3:] |
|||
except ValueError: |
|||
raise template.TemplateSyntaxError( |
|||
"%r tag require at least 2 argument : the model and the field" |
|||
% token.contents.split()[0] |
|||
) |
|||
|
|||
model = get_model(model_name) |
|||
callback = getattr(model, 'can_change_'+field_name) |
|||
|
|||
# {% can_create %} |
|||
oknodes = parser.parse(('acl_else', 'acl_end')) |
|||
token = parser.next_token() |
|||
|
|||
# {% can_create_else %} |
|||
if token.contents == 'acl_else': |
|||
konodes = parser.parse(('acl_end')) |
|||
token = parser.next_token() |
|||
else: |
|||
konodes = NodeList() |
|||
|
|||
# {% can_create_end %} |
|||
assert token.contents == 'acl_end' |
|||
|
|||
return AclNode(callback, oknodes, konodes, *args) |
|||
|
|||
@register.tag('can_create') |
|||
@register.tag('cannot_create') |
|||
@register.tag('can_edit_all') |
|||
@register.tag('cannot_edit_all') |
|||
@register.tag('can_delete_all') |
|||
@register.tag('cannot_delete_all') |
|||
@register.tag('can_view_all') |
|||
@register.tag('cannot_view_all') |
|||
def acl_model_filter(parser, token): |
|||
"""Generic definition of an acl templatetag for acl based on model""" |
|||
|
|||
try: |
|||
tag_content = token.split_contents() |
|||
tag_name = tag_content[0] |
|||
model_name = tag_content[1] |
|||
args = tag_content[2:] |
|||
except ValueError: |
|||
raise template.TemplateSyntaxError( |
|||
"%r tag require at least 1 argument : the model" |
|||
% token.contents.split()[0] |
|||
) |
|||
|
|||
model = get_model(model_name) |
|||
callback = get_callback(tag_name, model) |
|||
|
|||
# {% can_create %} |
|||
oknodes = parser.parse(('acl_else', 'acl_end')) |
|||
token = parser.next_token() |
|||
|
|||
# {% can_create_else %} |
|||
if token.contents == 'acl_else': |
|||
konodes = parser.parse(('acl_end')) |
|||
token = parser.next_token() |
|||
else: |
|||
konodes = NodeList() |
|||
|
|||
# {% can_create_end %} |
|||
assert token.contents == 'acl_end' |
|||
|
|||
return AclNode(callback, oknodes, konodes, *args) |
|||
|
|||
|
|||
@register.tag('can_edit') |
|||
@register.tag('cannot_edit') |
|||
@register.tag('can_delete') |
|||
@register.tag('cannot_delete') |
|||
@register.tag('can_view') |
|||
@register.tag('cannot_view') |
|||
def acl_instance_filter(parser, token): |
|||
"""Generic definition of an acl templatetag for acl based on instance""" |
|||
|
|||
try: |
|||
tag_content = token.split_contents() |
|||
tag_name = tag_content[0] |
|||
instance_name = tag_content[1] |
|||
args = tag_content[2:] |
|||
except ValueError: |
|||
raise template.TemplateSyntaxError( |
|||
"%r tag require at least 1 argument : the instance" |
|||
% token.contents.split()[0] |
|||
) |
|||
|
|||
# {% can_create %} |
|||
oknodes = parser.parse(('acl_else', 'acl_end')) |
|||
token = parser.next_token() |
|||
|
|||
# {% can_create_else %} |
|||
if token.contents == 'acl_else': |
|||
konodes = parser.parse(('acl_end')) |
|||
token = parser.next_token() |
|||
else: |
|||
konodes = NodeList() |
|||
|
|||
# {% can_create_end %} |
|||
assert token.contents == 'acl_end' |
|||
|
|||
return AclInstanceNode(tag_name, instance_name, oknodes, konodes, *args) |
|||
|
|||
|
|||
class AclNode(Node): |
|||
"""A node for the compiled ACL block when acl callback doesn't require |
|||
context.""" |
|||
|
|||
def __init__(self, callback, oknodes, konodes, *args): |
|||
self.callback = callback |
|||
self.oknodes = oknodes |
|||
self.konodes = konodes |
|||
self.args = [template.Variable(arg) for arg in args] |
|||
|
|||
def render(self, context): |
|||
resolved_args = [arg.resolve(context) for arg in self.args] |
|||
can, _ = self.callback(context['user'], *(resolved_args)) |
|||
if can: |
|||
return self.oknodes.render(context) |
|||
return self.konodes.render(context) |
|||
|
|||
|
|||
class AclInstanceNode(Node): |
|||
"""A node for the compiled ACL block when acl is based on instance""" |
|||
|
|||
def __init__(self, tag_name, instance_name, oknodes, konodes, *args): |
|||
self.tag_name = tag_name |
|||
self.instance = template.Variable(instance_name) |
|||
self.oknodes = oknodes |
|||
self.konodes = konodes |
|||
self.args = [template.Variable(arg) for arg in args] |
|||
|
|||
def render(self, context): |
|||
callback = get_callback(self.tag_name, self.instance.resolve(context)) |
|||
resolved_args = [arg.resolve(context) for arg in self.args] |
|||
can, _ = callback(context['user'], *(resolved_args)) |
|||
if can: |
|||
return self.oknodes.render(context) |
|||
return self.konodes.render(context) |
|||
@ -0,0 +1,39 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Gabriel Détraz |
|||
# Copyright © 2017 Goulven Kermarec |
|||
# Copyright © 2017 Augustin Lemesle |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
"""search.acl |
|||
|
|||
Here are defined some functions to check acl on the application. |
|||
""" |
|||
|
|||
def can_view(user): |
|||
"""Check if an user can view the application. |
|||
|
|||
Args: |
|||
user: The user who wants to view the application. |
|||
|
|||
Returns: |
|||
A couple (allowed, msg) where allowed is a boolean which is True if |
|||
viewing is granted and msg is a message (can be None). |
|||
""" |
|||
return True, None |
|||
@ -0,0 +1,40 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Gabriel Détraz |
|||
# Copyright © 2017 Goulven Kermarec |
|||
# Copyright © 2017 Augustin Lemesle |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
"""topologie.acl |
|||
|
|||
Here are defined some functions to check acl on the application. |
|||
""" |
|||
|
|||
def can_view(user): |
|||
"""Check if an user can view the application. |
|||
|
|||
Args: |
|||
user: The user who wants to view the application. |
|||
|
|||
Returns: |
|||
A couple (allowed, msg) where allowed is a boolean which is True if |
|||
viewing is granted and msg is a message (can be None). |
|||
""" |
|||
can = user.has_module_perms('topologie') |
|||
return can, None if can else "Vous ne pouvez pas voir cette application." |
|||
@ -0,0 +1,39 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.10.7 on 2017-12-31 16:43 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('topologie', '0032_auto_20171026_0338'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='constructorswitch', |
|||
options={'permissions': (('view_constructorswitch', 'Peut voir un objet constructorswitch'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='modelswitch', |
|||
options={'permissions': (('view_modelswitch', 'Peut voir un objet modelswitch'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='port', |
|||
options={'permissions': (('view_port', 'Peut voir un objet port'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='room', |
|||
options={'ordering': ['name'], 'permissions': (('view_room', 'Peut voir un objet chambre'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='stack', |
|||
options={'permissions': (('view_stack', 'Peut voir un objet stack'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='switch', |
|||
options={'permissions': (('view_switch', 'Peut voir un objet switch'),)}, |
|||
), |
|||
] |
|||
@ -0,0 +1,40 @@ |
|||
# -*- mode: python; coding: utf-8 -*- |
|||
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
|||
# se veut agnostique au réseau considéré, de manière à être installable en |
|||
# quelques clics. |
|||
# |
|||
# Copyright © 2017 Gabriel Détraz |
|||
# Copyright © 2017 Goulven Kermarec |
|||
# Copyright © 2017 Augustin Lemesle |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program; if not, write to the Free Software Foundation, Inc., |
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|||
|
|||
"""users.acl |
|||
|
|||
Here are defined some functions to check acl on the application. |
|||
""" |
|||
|
|||
def can_view(user): |
|||
"""Check if an user can view the application. |
|||
|
|||
Args: |
|||
user: The user who wants to view the application. |
|||
|
|||
Returns: |
|||
A couple (allowed, msg) where allowed is a boolean which is True if |
|||
viewing is granted and msg is a message (can be None). |
|||
""" |
|||
can = user.has_module_perms('users') |
|||
return can, None if can else "Vous ne pouvez pas voir cette application." |
|||
@ -0,0 +1,32 @@ |
|||
from django.core.management.base import BaseCommand, CommandError |
|||
|
|||
from datetime import datetime, timedelta |
|||
from pytz |
|||
|
|||
from users.models import User |
|||
|
|||
UTC = pytz.timezone('UTC') |
|||
|
|||
class Command(BaseCommand): |
|||
commands = ['email_remainder',] |
|||
args = '[command]' |
|||
help = 'Send email remainders' |
|||
|
|||
def handle(self, *args, **options): |
|||
''' |
|||
Sends an email before the end of a user's subscription |
|||
''' |
|||
users = User.objects.filter(state="STATE_ACTIVE") |
|||
|
|||
for user in users: |
|||
remaining = user.end_adhesion() - datetime.today(tz=UTC) |
|||
if (timedelta(weeks=4) - remaining).days == 1: |
|||
4_weeks_reminder() |
|||
elif (timedelta(weeks=1) - remaining).days == 1: |
|||
week_reminder() |
|||
elif remaining.days == 1: |
|||
last_day_reminder() |
|||
|
|||
def month_reminder(): |
|||
pass |
|||
|
|||
@ -0,0 +1,31 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.10.7 on 2017-12-30 19:33 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('auth', '0008_alter_user_username_max_length'), |
|||
('users', '0060_auto_20171120_0317'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AddField( |
|||
model_name='user', |
|||
name='groups', |
|||
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'), |
|||
), |
|||
migrations.AddField( |
|||
model_name='user', |
|||
name='is_superuser', |
|||
field=models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status'), |
|||
), |
|||
migrations.AddField( |
|||
model_name='user', |
|||
name='user_permissions', |
|||
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'), |
|||
), |
|||
] |
|||
@ -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), |
|||
] |
|||
@ -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), |
|||
] |
|||
@ -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'), |
|||
), |
|||
|
|||
] |
|||
@ -0,0 +1,39 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.10.7 on 2017-12-31 19:53 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('users', '0064_auto_20171231_0150'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='ban', |
|||
options={'permissions': (('view_ban', "Peut voir un objet ban quelqu'il soit"),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='listright', |
|||
options={'permissions': (('view_listright', 'Peut voir un objet Group/ListRight'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='school', |
|||
options={'permissions': (('view_school', 'Peut voir un objet school'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='serviceuser', |
|||
options={'permissions': (('view_serviceuser', 'Peut voir un objet serviceuser'),)}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='user', |
|||
options={'permissions': (('change_user_password', "Peut changer le mot de passe d'un user"), ('change_user_state', "Peut éditer l'etat d'un user"), ('change_user_force', 'Peut forcer un déménagement'), ('change_user_shell', "Peut éditer le shell d'un user"), ('change_user_groups', "Peut éditer les groupes d'un user ! Permission critique"), ('view_user', 'Peut voir un objet user quelquonque'))}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='whitelist', |
|||
options={'permissions': (('view_whitelist', 'Peut voir un objet whitelist'),)}, |
|||
), |
|||
] |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue