diff --git a/machines/admin.py b/machines/admin.py
index 26d7a6a3..0c83e9ab 100644
--- a/machines/admin.py
+++ b/machines/admin.py
@@ -42,6 +42,7 @@ from .models import (
SshFp,
Nas,
Service,
+ Role,
OuverturePort,
Ipv6List,
OuverturePortList,
@@ -146,6 +147,11 @@ class ServiceAdmin(VersionAdmin):
""" Admin view of a ServiceAdmin object """
list_display = ('service_type', 'min_time_regen', 'regular_time_regen')
+class RoleAdmin(VersionAdmin):
+ """ Admin view of a RoleAdmin object """
+ list_display = ('role_type')
+
+
admin.site.register(Machine, MachineAdmin)
admin.site.register(MachineType, MachineTypeAdmin)
@@ -162,6 +168,7 @@ admin.site.register(IpList, IpListAdmin)
admin.site.register(Interface, InterfaceAdmin)
admin.site.register(Domain, DomainAdmin)
admin.site.register(Service, ServiceAdmin)
+admin.site.register(Role, RoleAdmin)
admin.site.register(Vlan, VlanAdmin)
admin.site.register(Ipv6List, Ipv6ListAdmin)
admin.site.register(Nas, NasAdmin)
diff --git a/machines/forms.py b/machines/forms.py
index 23c2aa39..c8584d30 100644
--- a/machines/forms.py
+++ b/machines/forms.py
@@ -53,6 +53,7 @@ from .models import (
Txt,
DName,
Ns,
+ Role,
Service,
Vlan,
Srv,
@@ -497,6 +498,40 @@ class DelNasForm(FormRevMixin, Form):
self.fields['nas'].queryset = Nas.objects.all()
+class RoleForm(FormRevMixin, ModelForm):
+ """Ajout et edition d'un role"""
+ class Meta:
+ model = Role
+ fields = '__all__'
+
+ def __init__(self, *args, **kwargs):
+ prefix = kwargs.pop('prefix', self.Meta.model.__name__)
+ super(RoleForm, self).__init__(*args, prefix=prefix, **kwargs)
+ self.fields['servers'].queryset = (Interface.objects.all()
+ .select_related(
+ 'domain__extension'
+ ))
+
+
+class DelRoleForm(FormRevMixin, Form):
+ """Suppression d'un ou plusieurs service"""
+ role = forms.ModelMultipleChoiceField(
+ queryset=Role.objects.none(),
+ label="Roles actuels",
+ widget=forms.CheckboxSelectMultiple
+ )
+
+ def __init__(self, *args, **kwargs):
+ instances = kwargs.pop('instances', None)
+ super(DelRoleForm, self).__init__(*args, **kwargs)
+ if instances:
+ self.fields['role'].queryset = instances
+ else:
+ self.fields['role'].queryset = role.objects.all()
+
+
+
+
class ServiceForm(FormRevMixin, ModelForm):
"""Ajout et edition d'une classe de service : dns, dhcp, etc"""
class Meta:
diff --git a/machines/models.py b/machines/models.py
index 7be76e74..4b3ee891 100644
--- a/machines/models.py
+++ b/machines/models.py
@@ -1441,6 +1441,26 @@ class IpList(RevMixin, AclMixin, models.Model):
return self.ipv4
+
+class Role(RevMixin, AclMixin, models.Model):
+ """ Definition d'un role (routeur principal, routeur de backkup)"""
+ """ Sert à la génération automatique de la conf des serveurs"""
+ PRETTY_NAME = "Roles des serveurs"
+
+ role_type = models.CharField(max_length=255, unique=True)
+ servers = models.ManyToManyField('Interface')
+
+ class Meta:
+ permissions = (
+ ("view_role", "Peut voir un objet service"),
+ )
+
+ def save(self, *args, **kwargs):
+ super(Role, self).save(*args, **kwargs)
+
+ def __str__(self):
+ return str(self.role_type)
+
class Service(RevMixin, AclMixin, models.Model):
""" Definition d'un service (dhcp, dns, etc)"""
PRETTY_NAME = "Services à générer (dhcp, dns, etc)"
diff --git a/machines/templates/machines/aff_role.html b/machines/templates/machines/aff_role.html
new file mode 100644
index 00000000..f914cd24
--- /dev/null
+++ b/machines/templates/machines/aff_role.html
@@ -0,0 +1,49 @@
+{% comment %}
+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.
+{% endcomment %}
+
+{% load acl %}
+
+
+
+
+ Nom du role |
+ Serveurs inclus |
+ |
+ |
+
+
+ {% for role in role_list %}
+
+ {{ role.role_type }} |
+ {% for serv in role.servers.all %}{{ serv }}, {% endfor %} |
+
+ {% can_edit role %}
+ {% include 'buttons/edit.html' with href='machines:edit-role' id=role.id %}
+ {% acl_end %}
+ {% include 'buttons/history.html' with href='machines:history' name='role' id=role.id %}
+ |
+
+ {% endfor %}
+
+
diff --git a/machines/templates/machines/index_role.html b/machines/templates/machines/index_role.html
new file mode 100644
index 00000000..93a99577
--- /dev/null
+++ b/machines/templates/machines/index_role.html
@@ -0,0 +1,41 @@
+{% extends "machines/sidebar.html" %}
+{% comment %}
+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.
+{% endcomment %}
+
+{% load bootstrap3 %}
+{% load acl %}
+
+{% block title %}Machines{% endblock %}
+
+{% block content %}
+ Liste des roles
+ {% can_create Role %}
+ Ajouter un role
+ {% acl_end %}
+ Supprimer un ou plusieurs role
+ {% include "machines/aff_role.html" with role_list=role_list %}
+
+
+{% endblock %}
+
diff --git a/machines/templates/machines/machine.html b/machines/templates/machines/machine.html
index 7ec4212a..cd00ba0c 100644
--- a/machines/templates/machines/machine.html
+++ b/machines/templates/machines/machine.html
@@ -71,6 +71,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endif %}
{% if sshfpform %}
{% bootstrap_form_errors sshfpform %}
+{% if roleform %}
+ {% bootstrap_form_errors roleform %}
{% endif %}
{% if vlanform %}
{% bootstrap_form_errors vlanform %}
@@ -148,6 +150,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Service
{% massive_bootstrap_form serviceform 'servers' %}
{% endif %}
+ {% if roleform %}
+ Role
+ {% massive_bootstrap_form roleform 'servers' %}
+ {% endif %}
{% if vlanform %}
Vlan
{% bootstrap_form vlanform %}
diff --git a/machines/templates/machines/sidebar.html b/machines/templates/machines/sidebar.html
index 5a0f975d..68031f29 100644
--- a/machines/templates/machines/sidebar.html
+++ b/machines/templates/machines/sidebar.html
@@ -68,6 +68,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Services (dhcp, dns...)
{% acl_end %}
+ {% can_view_all Role %}
+
+
+ Roles des serveurs
+
+ {% acl_end %}
{% can_view_all OuverturePortList %}
diff --git a/machines/urls.py b/machines/urls.py
index ce0a7a78..8c670308 100644
--- a/machines/urls.py
+++ b/machines/urls.py
@@ -21,7 +21,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""machines.urls
-The defined URLs for the Cotisations app
+The defined URLs for the Machines app
"""
from __future__ import unicode_literals
@@ -125,6 +125,12 @@ urlpatterns = [
name='edit-service'),
url(r'^del_service/$', views.del_service, name='del-service'),
url(r'^index_service/$', views.index_service, name='index-service'),
+ url(r'^add_role/$', views.add_role, name='add-role'),
+ url(r'^edit_role/(?P[0-9]+)$',
+ views.edit_role,
+ name='edit-role'),
+ url(r'^del_role/$', views.del_role, name='del-role'),
+ url(r'^index_role/$', views.index_role, name='index-role'),
url(r'^add_vlan/$', views.add_vlan, name='add-vlan'),
url(r'^edit_vlan/(?P[0-9]+)$', views.edit_vlan, name='edit-vlan'),
url(r'^del_vlan/$', views.del_vlan, name='del-vlan'),
diff --git a/machines/views.py b/machines/views.py
index 398b9250..134560ba 100644
--- a/machines/views.py
+++ b/machines/views.py
@@ -101,6 +101,8 @@ from .forms import (
DelMxForm,
VlanForm,
DelVlanForm,
+ RoleForm,
+ DelRoleForm,
ServiceForm,
DelServiceForm,
SshFpForm,
@@ -122,6 +124,7 @@ from .models import (
Mx,
Ns,
Domain,
+ Role,
Service,
Service_link,
Vlan,
@@ -1141,6 +1144,65 @@ def del_alias(request, interface, interfaceid):
)
+@login_required
+@can_create(Role)
+def add_role(request):
+ """ View used to add a Role object """
+ role = RoleForm(request.POST or None)
+ if role.is_valid():
+ role.save()
+ messages.success(request, "Cet enregistrement role a été ajouté")
+ return redirect(reverse('machines:index-role'))
+ return form(
+ {'roleform': role, 'action_name': 'Créer'},
+ 'machines/machine.html',
+ request
+ )
+
+
+@login_required
+@can_edit(Role)
+def edit_role(request, role_instance, **_kwargs):
+ """ View used to edit a Role object """
+ role = RoleForm(request.POST or None, instance=role_instance)
+ if role.is_valid():
+ if role.changed_data:
+ role.save()
+ messages.success(request, "Role modifié")
+ return redirect(reverse('machines:index-role'))
+ return form(
+ {'roleform': role, 'action_name': 'Editer'},
+ 'machines/machine.html',
+ request
+ )
+
+
+@login_required
+@can_delete_set(Role)
+def del_role(request, instances):
+ """ View used to delete a Service object """
+ role = DelRoleForm(request.POST or None, instances=instances)
+ if role.is_valid():
+ role_dels = role.cleaned_data['role']
+ for role_del in role_dels:
+ try:
+ role_del.delete()
+ messages.success(request, "Le role a été supprimée")
+ except ProtectedError:
+ messages.error(
+ request,
+ ("Erreur le role suivant %s ne peut être supprimé"
+ % role_del)
+ )
+ return redirect(reverse('machines:index-role'))
+ return form(
+ {'roleform': role, 'action_name': 'Supprimer'},
+ 'machines/machine.html',
+ request
+ )
+
+
+
@login_required
@can_create(Service)
def add_service(request):
@@ -1481,6 +1543,21 @@ def index_ipv6(request, interface, interfaceid):
)
+@login_required
+@can_view_all(Role)
+def index_role(request):
+ """ View used to display the list of existing roles """
+ role_list = (Role.objects
+ .prefetch_related(
+ 'servers__domain__extension'
+ ).all())
+ return render(
+ request,
+ 'machines/index_role.html',
+ {'role_list': role_list}
+ )
+
+
@login_required
@can_view_all(Service)
def index_service(request):
diff --git a/re2o/templatetags/acl.py b/re2o/templatetags/acl.py
index 9a439f88..fe13c5ac 100644
--- a/re2o/templatetags/acl.py
+++ b/re2o/templatetags/acl.py
@@ -79,6 +79,7 @@ from django.contrib.contenttypes.models import ContentType
register = template.Library()
+
def get_model(model_name):
"""Retrieve the model object from its name"""
splitted = model_name.split('.')