Commit 23732800 authored by chirac's avatar chirac

Merge branch 'acl' into 'master'

Acl

See merge request federez/re2o!55
parents 09157a6a 2c6697a2
......@@ -21,3 +21,4 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from .acl import *
# -*- 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."
......@@ -43,6 +43,8 @@ from django.forms import ModelForm, Form
from django.core.validators import MinValueValidator
from .models import Article, Paiement, Facture, Banque
from re2o.field_permissions import FieldPermissionFormMixin
class NewFactureForm(ModelForm):
"""Creation d'une facture, moyen de paiement, banque et numero
......@@ -141,27 +143,18 @@ class NewFactureFormPdf(Form):
)
class EditFactureForm(NewFactureForm):
class EditFactureForm(FieldPermissionFormMixin, NewFactureForm):
"""Edition d'une facture : moyen de paiement, banque, user parent"""
class Meta(NewFactureForm.Meta):
fields = ['paiement', 'banque', 'cheque', 'user']
model = Facture
fields = '__all__'
def __init__(self, *args, **kwargs):
super(EditFactureForm, self).__init__(*args, **kwargs)
self.fields['user'].label = 'Adherent'
self.fields['user'].empty_label = "Séléctionner\
l'adhérent propriétaire"
class TrezEditFactureForm(EditFactureForm):
"""Vue pour édition controle trésorier"""
class Meta(EditFactureForm.Meta):
fields = '__all__'
def __init__(self, *args, **kwargs):
super(TrezEditFactureForm, self).__init__(*args, **kwargs)
self.fields['valid'].label = 'Validité de la facture'
self.fields['control'].label = 'Contrôle de la facture'
class ArticleForm(ModelForm):
......@@ -180,11 +173,19 @@ class DelArticleForm(Form):
"""Suppression d'un ou plusieurs articles en vente. Choix
parmis les modèles"""
articles = forms.ModelMultipleChoiceField(
queryset=Article.objects.all(),
queryset=Article.objects.none(),
label="Articles actuels",
widget=forms.CheckboxSelectMultiple
)
def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None)
super(DelArticleForm, self).__init__(*args, **kwargs)
if instances:
self.fields['articles'].queryset = instances
else:
self.fields['articles'].queryset = Article.objects.all()
class PaiementForm(ModelForm):
"""Creation d'un moyen de paiement, champ text moyen et type
......@@ -204,11 +205,19 @@ class DelPaiementForm(Form):
"""Suppression d'un ou plusieurs moyens de paiements, selection
parmis les models"""
paiements = forms.ModelMultipleChoiceField(
queryset=Paiement.objects.all(),
queryset=Paiement.objects.none(),
label="Moyens de paiement actuels",
widget=forms.CheckboxSelectMultiple
)
def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None)
super(DelPaiementForm, self).__init__(*args, **kwargs)
if instances:
self.fields['paiements'].queryset = instances
else:
self.fields['paiements'].queryset = Paiement.objects.all()
class BanqueForm(ModelForm):
"""Creation d'une banque, field name"""
......@@ -225,7 +234,15 @@ class BanqueForm(ModelForm):
class DelBanqueForm(Form):
"""Selection d'une ou plusieurs banques, pour suppression"""
banques = forms.ModelMultipleChoiceField(
queryset=Banque.objects.all(),
queryset=Banque.objects.none(),
label="Banques actuelles",
widget=forms.CheckboxSelectMultiple
)
def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None)
super(DelBanqueForm, self).__init__(*args, **kwargs)
if instances:
self.fields['banques'].queryset = instances
else:
self.fields['banques'].queryset = Banque.objects.all()
# -*- 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'))},
),
]
This diff is collapsed.
......@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load acl %}
<table class="table table-striped">
<thead>
<tr>
......@@ -41,11 +43,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<td>{{ article.duration }}</td>
<td>{{ article.type_user }}</td>
<td class="text-right">
{% if is_trez %}
{% can_edit article %}
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'cotisations:edit-article' article.id %}">
<i class="glyphicon glyphicon-edit"></i>
</a>
{% endif %}
{% acl_end %}
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'cotisations:history' 'article' article.id %}">
<i class="glyphicon glyphicon-time"></i>
</a>
......
......@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load acl %}
<table class="table table-striped">
<thead>
<tr>
......@@ -33,11 +35,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr>
<td>{{ banque.name }}</td>
<td class="text-right">
{% if is_trez %}
{% can_edit banque %}
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'cotisations:edit-banque' banque.id %}">
<i class="glyphicon glyphicon-edit"></i>
</a>
{% endif %}
{% acl_end %}
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'cotisations:history' 'banque' banque.id %}">
<i class="glyphicon glyphicon-time"></i>
</a>
......
......@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load acl %}
{% if facture_list.paginator %}
{% include "pagination.html" with list=facture_list %}
{% endif %}
......@@ -47,7 +49,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<td>{{ facture.paiement }}</td>
<td>{{ facture.date }}</td>
<td>{{ facture.id }}</td>
{% if is_cableur %}
<td>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="editionfacture" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
......@@ -55,17 +56,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="editionfacture">
{% if facture.valid and not facture.control or is_trez %}
{% can_edit facture %}
<li><a href="{% url 'cotisations:edit-facture' facture.id %}"><i class="glyphicon glyphicon-bitcoin"></i> Modifier</a></li>
{% acl_else %}
<li>Facture controlée</li>
{% acl_end %}
{% can_delete facture %}
<li><a href="{% url 'cotisations:del-facture' facture.id %}"><i class="glyphicon glyphicon-trash"></i> Supprimer</a></li>
{% acl_end %}
<li><a href="{% url 'cotisations:history' 'facture' facture.id %}"><i class="glyphicon glyphicon-time"></i> Historique</a></li>
{% else %}
<li>Facture controlée</li>
{% endif %}
</ul>
</div>
</td>
{% endif %}
<td>
{% if facture.valid %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:facture-pdf' facture.id %}">
......
......@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load acl %}
<table class="table table-striped">
<thead>
<tr>
......@@ -33,11 +35,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr>
<td>{{ paiement.moyen }}</td>
<td class="text-right">
{% if is_trez %}
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'cotisations:edit-paiement' paiement.id %}">
{% can_edit paiement %}
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'cotisations:edit-paiement' paiement.id %}">
<i class="glyphicon glyphicon-edit"></i>
</a>
{% endif %}
{% acl_end %}
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'cotisations:history' 'paiement' paiement.id %}">
<i class="glyphicon glyphicon-time"></i>
</a>
......
......@@ -24,15 +24,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% load bootstrap3 %}
{% load acl %}
{% block title %}Articles{% endblock %}
{% block content %}
<h2>Liste des types d'articles</h2>
{% if is_trez %}
{% can_create Article %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-article' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter un type d'articles</a>
{% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-article' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer un ou plusieurs types d'articles</a>
{% endif %}
{% include "cotisations/aff_article.html" with article_list=article_list %}
<br />
<br />
......
......@@ -24,15 +24,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% load bootstrap3 %}
{% load acl %}
{% block title %}Banques{% endblock %}
{% block content %}
<h2>Liste des banques</h2>
{% can_create Banque %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-banque' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter une banque</a>
{% if is_trez %}
{% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-banque' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer une ou plusieurs banques</a>
{% endif %}
{% include "cotisations/aff_banque.html" with banque_list=banque_list %}
<br />
<br />
......
......@@ -24,15 +24,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% load bootstrap3 %}
{% load acl %}
{% block title %}Paiements{% endblock %}
{% block content %}
<h2>Liste des types de paiements</h2>
{% if is_trez %}
{% can_create Paiement %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-paiement' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter un type de paiement</a>
{% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-paiement' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer un ou plusieurs types de paiements</a>
{% endif %}
{% include "cotisations/aff_paiement.html" with paiement_list=paiement_list %}
<br />
<br />
......
......@@ -23,9 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load acl %}
{% block sidebar %}
{% if is_trez %}
{% can_change Facture pdf %}
<a class="list-group-item list-group-item-success" href="{% url "cotisations:new-facture-pdf" %}">
<i class="glyphicon glyphicon-plus"></i>
Créer une facture
......@@ -34,21 +35,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<i class="glyphicon glyphicon-eye-open"></i>
Contrôler les factures
</a>
{% endif %}
{% acl_end %}
{% can_view_all Facture %}
<a class="list-group-item list-group-item-info" href="{% url "cotisations:index" %}">
<i class="glyphicon glyphicon-list"></i>
Factures
</a>
{% acl_end %}
{% can_view_all Article %}
<a class="list-group-item list-group-item-info" href="{% url "cotisations:index-article" %}">
<i class="glyphicon glyphicon-list"></i>
Articles en vente
</a>
{% acl_end %}
{% can_view_all Banque %}
<a class="list-group-item list-group-item-info" href="{% url "cotisations:index-banque" %}">
<i class="glyphicon glyphicon-list"></i>
Banques
</a>
{% acl_end %}
{% can_view_all Paiement %}
<a class="list-group-item list-group-item-info" href="{% url "cotisations:index-paiement" %}">
<i class="glyphicon glyphicon-list"></i>
Moyens de paiement
</a>
{% acl_end %}
{% endblock %}
......@@ -24,6 +24,7 @@ from __future__ import unicode_literals
from django.conf.urls import url
import re2o
from . import views
urlpatterns = [
......@@ -99,21 +100,12 @@ urlpatterns = [
views.index_paiement,
name='index-paiement'
),
url(r'^history/(?P<object_name>facture)/(?P<object_id>[0-9]+)$',
views.history,
name='history'
),
url(r'^history/(?P<object_name>article)/(?P<object_id>[0-9]+)$',
views.history,
name='history'
),
url(r'^history/(?P<object_name>paiement)/(?P<object_id>[0-9]+)$',
views.history,
name='history'),
url(r'^history/(?P<object_name>banque)/(?P<object_id>[0-9]+)$',
views.history,
name='history'
),
url(
r'history/(?P<object_name>\w+)/(?P<object_id>[0-9]+)$',
re2o.views.history,
name='history',
kwargs={'application':'cotisations'},
),
url(r'^control/$',
views.control,
name='control'
......
This diff is collapsed.
......@@ -21,3 +21,4 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from .acl import *
# -*- 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."
......@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endif %}
{% load logs_extra %}
{% load acl %}
<table class="table table-striped">
<thead>
......@@ -47,19 +48,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<td>{{ revision.user }}</td>
<td>{{ revision.date_created }}</td>
<td>{{ revision.comment }}</td>
{% if is_bureau %}
{% can_edit_history %}
<td>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'logs:revert-action' revision.id %}">
<i class="glyphicon glyphicon-remove"></i>
Annuler
</a>
</td>
{% endif %}
{% acl_end %}
</tr>
{% endfor %}
{% endfor %}
</table>
{% if revisions_list.paginator %}
{% include "pagination.html" with list=revisions_list %}
{% endif %}
......@@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endif %}
{% load logs_extra %}
{% load acl %}
<table class="table table-striped">
<thead>
<tr>
......@@ -51,14 +51,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endif %}
</i>)
</td>
{% if is_bureau %}
{% can_edit_history %}
<td>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'logs:revert-action' v.rev_id %}">
<i class="glyphicon glyphicon-remove"></i>
Annuler
</a>
</td>
{% endif %}
{% acl_end %}
</tr>
{% elif v.version.content_type.model == 'whitelist' %}
<tr class="success">
......@@ -74,14 +74,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endif %}
</i>)
</td>
{% if is_bureau %}
{% can_edit_history%}
<td>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'logs:revert-action' v.rev_id %}">
<i class="glyphicon glyphicon-remove"></i>
Annuler
</a>
</td>
{% endif %}
{% acl_end %}
</tr>
{% elif v.version.content_type.model == 'user' %}
<tr>
......@@ -93,14 +93,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
(<i>{{ v.comment }}</i>)
{% endif %}
</td>
{% if is_bureau %}
{% can_edit_history %}
<td>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'logs:revert-action' v.rev_id %}">
<i class="glyphicon glyphicon-remove"></i>
Annuler
</a>
</td>
{% endif %}
{% acl_end %}
</tr>
{% elif v.version.content_type.model == 'vente' %}
<tr>
......@@ -112,14 +112,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
(<i>+{{ v.version.object.duration }} mois</i>)
{% endif %}
</td>
{% if is_bureau %}
{% can_edit_history %}
<td>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'logs:revert-action' v.rev_id %}">
<i class="glyphicon glyphicon-remove"></i>
Annuler
</a>
</td>
{% endif %}
{% acl_end %}
</tr>
{% elif v.version.content_type.model == 'interface' %}
<tr>
......@@ -131,14 +131,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
(<i>{{ v.comment }}</i>)
{% endif %}
</td>
{% if is_bureau %}
{% can_edit_history %}
<td>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'logs:revert-action' v.rev_id %}">
<i class="glyphicon glyphicon-remove"></i>
Annuler
</a>
</td>
{% endif %}
{% acl_end %}
</tr>
{% endif %}
{% endfor %}
......
......@@ -23,9 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load acl %}
{% block sidebar %}
{% if is_cableur %}
{% can_view_app logs %}
<a class="list-group-item list-group-item-info" href="{% url "logs:index" %}">
<i class="glyphicon glyphicon-stats"></i>
Résumé
......@@ -50,5 +51,5 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<i class="glyphicon glyphicon-stats"></i>
Utilisateurs
</a>
{% endif %}
{% acl_end %}
{% endblock %}
......@@ -41,7 +41,7 @@ from django.urls import reverse
from django.shortcuts import 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.contrib.auth.decorators import login_required
from django.db.models import Count
from reversion.models import Revision
......@@ -50,7 +50,6 @@ from reversion.models import Version, ContentType
from users.models import (
User,
ServiceUser,
Right,
School,
ListRight,
ListShell,
......@@ -93,7 +92,17 @@ from topologie.models import (
)
from preferences.models import GeneralOption
from re2o.views import form
from re2o.utils import all_whitelisted, all_baned, all_has_access, all_adherent
from re2o.utils import (
all_whitelisted,
all_baned,
all_has_access,
all_adherent,
)
from re2o.acl import (
can_view_all,
can_view_app,
can_edit_history,
)
from re2o.utils import all_active_assigned_interfaces_count
from re2o.utils import all_active_interfaces_count, SortTable
......@@ -108,7 +117,7 @@ STATS_DICT = {
@login_required
@permission_required('cableur')
@can_view_app('logs')
def index(request):
"""Affiche les logs affinés, date reformatées, selectionne
les event importants (ajout de droits, ajout de ban/whitelist)"""
......@@ -167,7 +176,7 @@ def index(request):
@login_required
@permission_required('cableur')
@can_view_all(GeneralOption)
def stats_logs(request):
"""Affiche l'ensemble des logs et des modifications sur les objets,
classés par date croissante, en vrac"""
......@@ -197,7 +206,7 @@ def stats_logs(request):
@login_required
@permission_required('bureau')
@can_edit_history
def revert_action(request, revision_id):
""" Annule l'action en question """
try:
......@@ -215,7 +224,9 @@ def revert_action(request, revision_id):
@login_required
@permission_required('cableur')
@can_view_all(IpList)
@can_view_all(Interface)
@can_view_all(User)
def stats_general(request):
"""Statistiques générales affinées sur les ip, activées, utilisées par
range, et les statistiques générales sur les users : users actifs,
......@@ -298,7 +309,10 @@ def stats_general(request):