8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-23 11:53:12 +00:00

Merge branch 'new_upstream' into 'master'

New upstream

See merge request nounous/re2o!13
This commit is contained in:
Gabriel Detraz 2018-03-27 01:30:18 +02:00
commit 835525a877
29 changed files with 578 additions and 231 deletions

View file

@ -192,19 +192,21 @@ def post_auth(data):
mac = data.get('Calling-Station-Id', None)
# Switch et bornes héritent de machine et peuvent avoir plusieurs interfaces filles
nas_machine = nas_instance.machine
# Si il s'agit d'un switch
if hasattr(nas_instance, 'switch'):
if hasattr(nas_machine, 'switch'):
port = data.get('NAS-Port-Id', data.get('NAS-Port', None))
#Pour les infrastructures possédant des switchs Juniper :
#On vérifie si le switch fait partie d'un stack Juniper
instance_stack = nas_instance.switch.stack
instance_stack = nas_machine.switch.stack
if instance_stack:
# Si c'est le cas, on resélectionne le bon switch dans la stack
id_stack_member = port.split("-")[1].split('/')[0]
nas_instance = Interface.objects.filter(switch__in=Switch.objects.filter(stack=instance_stack).filter(stack_member_id=id_stack_member)).select_related('domain__extension').first()
nas_machine = Switch.objects.filter(stack=instance_stack).filter(stack_member_id=id_stack_member).prefetch_related('interface_set__domain__extension').first()
# On récupère le numéro du port sur l'output de freeradius. La ligne suivante fonctionne pour cisco, HP et Juniper
port = port.split(".")[0].split('/')[-1][-2:]
out = decide_vlan_and_register_switch(nas_instance, nas_type, port, mac)
out = decide_vlan_and_register_switch(nas_machine, nas_type, port, mac)
sw_name, room, reason, vlan_id = out
log_message = '(fil) %s -> %s [%s%s]' % \
@ -271,7 +273,7 @@ def check_user_machine_and_register(nas_type, username, mac_address):
return (False, u"Machine inconnue", '')
def decide_vlan_and_register_switch(nas, nas_type, port_number, mac_address):
def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, mac_address):
"""Fonction de placement vlan pour un switch en radius filaire auth par mac.
Plusieurs modes :
- nas inconnu, port inconnu : on place sur le vlan par defaut VLAN_OK
@ -296,12 +298,12 @@ def decide_vlan_and_register_switch(nas, nas_type, port_number, mac_address):
# Get port from switch and port number
extra_log = ""
# Si le NAS est inconnu, on place sur le vlan defaut
if not nas:
if not nas_machine:
return ('?', u'Chambre inconnue', u'Nas inconnu', VLAN_OK)
sw_name = str(nas)
sw_name = str(nas_machine)
port = Port.objects.filter(switch=Switch.objects.filter(interface_ptr=nas), port=port_number).first()
port = Port.objects.filter(switch=Switch.objects.filter(machine_ptr=nas_machine), port=port_number).first()
#Si le port est inconnu, on place sur le vlan defaut
if not port:
return (sw_name, "Chambre inconnue", u'Port inconnu', VLAN_OK)

View file

@ -42,8 +42,7 @@ 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
from django.db.models import Count
from django.db.models import Max
from django.db.models import Count, Max
from reversion.models import Revision
from reversion.models import Version, ContentType
@ -457,7 +456,7 @@ def stats_droits(request):
depart=time()
stats_list={}
for droit in ListRight.objects.all().select_related('group_ptr'):#.prefetch_related('group_ptr__user_set__revision_set'):
for droit in ListRight.objects.all().select_related('group_ptr'):
stats_list[droit]=droit.user_set.all().annotate(num=Count('revision'),last=Max('revision__date_created'))
return render(request, 'logs/stats_droits.html', {'stats_list': stats_list})

View file

@ -122,6 +122,7 @@ MODEL_NAME = {
# topologie
'Stack' : topologie.models.Stack,
'Switch' : topologie.models.Switch,
'AccessPoint' : topologie.models.AccessPoint,
'ModelSwitch' : topologie.models.ModelSwitch,
'ConstructorSwitch' : topologie.models.ConstructorSwitch,
'Port' : topologie.models.Port,

View file

@ -213,8 +213,8 @@ class SortTable:
'default': ['-date']
}
TOPOLOGIE_INDEX = {
'switch_dns': ['switch_interface__domain__name'],
'switch_ip': ['switch_interface__ipv4__ipv4'],
'switch_dns': ['interface__domain__name'],
'switch_ip': ['interface__ipv4__ipv4'],
'switch_loc': ['location'],
'switch_ports': ['number'],
'switch_stack': ['stack__name'],
@ -234,10 +234,10 @@ class SortTable:
'default': ['name']
}
TOPOLOGIE_INDEX_BORNE = {
'borne_name': ['domain__name'],
'borne_ip': ['ipv4__ipv4'],
'borne_mac': ['mac_address'],
'default': ['domain__name']
'ap_name': ['interface__domain__name'],
'ap_ip': ['interface__ipv4__ipv4'],
'ap_mac': ['interface__mac_address'],
'default': ['interface__domain__name']
}
TOPOLOGIE_INDEX_STACK = {
'stack_name': ['name'],

View file

@ -83,7 +83,7 @@ HISTORY_BIND = {
'stack' : topologie.models.Stack,
'model_switch' : topologie.models.ModelSwitch,
'constructor_switch' : topologie.models.ConstructorSwitch,
'borne' : topologie.models.Borne,
'ap' : topologie.models.AccessPoint,
},
'machines' : {
'machine' : machines.models.Machine,

View file

@ -260,7 +260,7 @@ def search_single_word(word, filters, user,
) | Q(
machine_interface__domain__name__icontains=word
) | Q(
related__switch__switch_interface__domain__name__icontains=word
related__switch__domain__name__icontains=word
) | Q(
radius__icontains=word
) | Q(
@ -277,9 +277,9 @@ def search_single_word(word, filters, user,
# Switches
if '7' in aff and Switch.can_view_all(user):
filter_switches = Q(
switch_interface__domain__name__icontains=word
domain__name__icontains=word
) | Q(
switch_interface__ipv4__ipv4__icontains=word
ipv4__ipv4__icontains=word
) | Q(
location__icontains=word
) | Q(

View file

@ -36,7 +36,7 @@ from .models import (
Stack,
ModelSwitch,
ConstructorSwitch,
Borne
AccessPoint
)
@ -55,7 +55,7 @@ class PortAdmin(VersionAdmin):
pass
class BorneAdmin(VersionAdmin):
class AccessPointAdmin(VersionAdmin):
"""Administration d'une borne"""
pass
@ -76,7 +76,7 @@ class ConstructorSwitchAdmin(VersionAdmin):
admin.site.register(Port, PortAdmin)
admin.site.register(Borne, BorneAdmin)
admin.site.register(AccessPoint, AccessPointAdmin)
admin.site.register(Room, RoomAdmin)
admin.site.register(Switch, SwitchAdmin)
admin.site.register(Stack, StackAdmin)

View file

@ -33,9 +33,14 @@ NewSwitchForm)
from __future__ import unicode_literals
from machines.models import Interface
from machines.forms import EditInterfaceForm
from machines.forms import (
EditInterfaceForm,
EditMachineForm,
NewMachineForm
)
from django import forms
from django.forms import ModelForm, Form
from django.db.models import Prefetch
from .models import (
Port,
Switch,
@ -43,7 +48,7 @@ from .models import (
Stack,
ModelSwitch,
ConstructorSwitch,
Borne
AccessPoint
)
@ -76,10 +81,12 @@ class EditPortForm(ModelForm):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditPortForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['machine_interface'].queryset = Interface.objects.all()\
.select_related('domain__extension')
.select_related('domain__extension')
self.fields['related'].queryset = Port.objects.all()\
.select_related('switch__domain__extension')\
.order_by('switch', 'port')
.prefetch_related(Prefetch(
'switch__interface_set',
queryset=Interface.objects.select_related('ipv4__ip_type__extension').select_related('domain__extension')
))
class AddPortForm(ModelForm):
@ -93,10 +100,12 @@ class AddPortForm(ModelForm):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(AddPortForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['machine_interface'].queryset = Interface.objects.all()\
.select_related('domain__extension')
.select_related('domain__extension')
self.fields['related'].queryset = Port.objects.all()\
.select_related('switch__domain__extension')\
.order_by('switch', 'port')
.prefetch_related(Prefetch(
'switch__interface_set',
queryset=Interface.objects.select_related('ipv4__ip_type__extension').select_related('domain__extension')
))
class StackForm(ModelForm):
@ -111,33 +120,33 @@ class StackForm(ModelForm):
super(StackForm, self).__init__(*args, prefix=prefix, **kwargs)
class AddBorneForm(EditInterfaceForm):
class AddAccessPointForm(NewMachineForm):
"""Formulaire pour la création d'une borne
Relié directement au modèle borne"""
class Meta:
model = Borne
fields = ['mac_address', 'type', 'ipv4', 'details', 'location']
model = AccessPoint
fields = ['location', 'name']
class EditBorneForm(EditInterfaceForm):
"""Edition d'une interface. Edition complète"""
class EditAccessPointForm(EditMachineForm):
"""Edition d'une borne. Edition complète"""
class Meta:
model = Borne
fields = ['machine', 'type', 'ipv4', 'mac_address', 'details', 'location']
model = AccessPoint
fields = '__all__'
class EditSwitchForm(EditInterfaceForm):
class EditSwitchForm(EditMachineForm):
"""Permet d'éditer un switch : nom et nombre de ports"""
class Meta:
model = Switch
fields = ['machine', 'type', 'ipv4', 'mac_address', 'details', 'location', 'number', 'stack', 'stack_member_id']
fields = '__all__'
class NewSwitchForm(EditInterfaceForm):
class NewSwitchForm(NewMachineForm):
"""Permet de créer un switch : emplacement, paramètres machine,
membre d'un stack (option), nombre de ports (number)"""
class Meta(EditSwitchForm.Meta):
fields = ['type', 'ipv4', 'mac_address', 'details', 'location', 'number', 'stack', 'stack_member_id']
fields = ['name', 'location', 'number', 'stack', 'stack_member_id']
class EditRoomForm(ModelForm):

View file

@ -12,6 +12,10 @@ class Migration(migrations.Migration):
]
operations = [
migrations.AlterUniqueTogether(
name='port',
unique_together=set([]),
),
migrations.RemoveField(
model_name='port',
name='switch',

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-25 22:02
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0043_renamenewswitch'),
]
operations = [
migrations.RenameModel(
old_name='Borne',
new_name='AccessPoint',
),
migrations.AlterModelOptions(
name='accesspoint',
options={'permissions': (('view_ap', 'Peut voir une borne'),)},
),
migrations.AlterModelOptions(
name='switch',
options={'permissions': (('view_switch', 'Peut voir un objet switch'),)},
),
]

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-25 23:23
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0044_auto_20180326_0002'),
]
operations = [
migrations.AlterField(
model_name='port',
name='switch',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ports', to='topologie.Switch'),
),
]

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-25 23:29
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('topologie', '0045_auto_20180326_0123'),
]
operations = [
migrations.AlterUniqueTogether(
name='port',
unique_together=set([('switch', 'port')]),
),
]

View file

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-23 01:18
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0046_auto_20180326_0129'),
]
operations = [
migrations.CreateModel(
name='NewAccessPoint',
fields=[
('machine_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='machines.Machine')),
('location', models.CharField(help_text="Détails sur la localisation de l'AP", max_length=255, null=True, blank=True)),
],
bases=('machines.machine',),
),
]

View file

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-23 01:18
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0047_ap_machine'),
]
def transfer_ap(apps, schema_editor):
db_alias = schema_editor.connection.alias
ap = apps.get_model("topologie", "AccessPoint")
new_ap = apps.get_model("topologie", "NewAccessPoint")
ap_list = ap.objects.using(db_alias).all()
for borne in ap_list:
new_borne = new_ap()
new_borne.machine_ptr_id = borne.machine.pk
new_borne.__dict__.update(borne.machine.__dict__)
new_borne.location = borne.location
new_borne.save()
def untransfer_ap(apps, schema_editor):
return
operations = [
migrations.RunPython(transfer_ap, untransfer_ap),
migrations.DeleteModel(
name='AccessPoint',
),
migrations.RenameModel(
old_name='NewAccessPoint',
new_name='AccessPoint',
),
]

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-23 01:18
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0048_ap_machine'),
]
operations = [
migrations.CreateModel(
name='NewSw',
fields=[
('machine_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='machines.Machine')),
('location', models.CharField(max_length=255)),
('number', models.PositiveIntegerField()),
('stack_member_id', models.PositiveIntegerField(blank=True, null=True)),
('model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.ModelSwitch')),
('stack', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.Stack')),
],
bases=('machines.machine',),
),
]

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-25 00:52
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0049_switchs_machine'),
]
operations = [
migrations.AddField(
model_name='port',
name='new_sw',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ports', to='topologie.NewSw'),
),
]

View file

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-23 01:18
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0050_port_new_switch'),
]
def transfer_sw(apps, schema_editor):
db_alias = schema_editor.connection.alias
newswitch = apps.get_model("topologie", "NewSw")
switch = apps.get_model("topologie", "Switch")
machine = apps.get_model("machines", "Machine")
sw_list = switch.objects.using(db_alias).all()
for sw in sw_list:
new_sw = newswitch()
new_sw.location = sw.location
new_sw.number = sw.number
new_sw.details = sw.details
new_sw.stack = sw.stack
new_sw.stack_member_id = sw.stack_member_id
new_sw.model = sw.model
new_sw.machine_ptr_id = sw.interface_ptr.machine.pk
new_sw.__dict__.update(sw.interface_ptr.machine.__dict__)
new_sw.save()
def untransfer_sw(apps, schema_editor):
return
operations = [
migrations.RunPython(transfer_sw, untransfer_sw),
]

View file

@ -0,0 +1,37 @@
# -*- 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 = [
('topologie', '0051_switchs_machine'),
]
def transfer_port(apps, schema_editor):
db_alias = schema_editor.connection.alias
port = apps.get_model("topologie", "Port")
switch = apps.get_model("topologie", "NewSw")
port_list = port.objects.using(db_alias).all()
for p in port_list:
p.new_sw = switch.objects.filter(machine_ptr=p.switch.machine).first()
p.save()
def untransfer_port(apps, schema_editor):
return
operations = [
migrations.AlterUniqueTogether(
name='port',
unique_together=set([]),
),
migrations.RunPython(transfer_port, untransfer_port),
migrations.RemoveField(
model_name='port',
name='switch',
),
migrations.RenameField('Port', 'new_sw', 'switch')
]

View file

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-23 01:18
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0052_transferports'),
]
operations = [
migrations.DeleteModel(
name='Switch',
),
migrations.RenameModel(
old_name='NewSw',
new_name='Switch',
),
]

View file

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-03-26 15:42
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('topologie', '0053_finalsw'),
]
operations = [
migrations.AlterModelOptions(
name='accesspoint',
options={'permissions': (('view_ap', 'Peut voir une borne'),)},
),
migrations.AlterModelOptions(
name='switch',
options={'permissions': (('view_switch', 'Peut voir un objet switch'),)},
),
migrations.AlterField(
model_name='port',
name='switch',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ports', to='topologie.Switch'),
preserve_default=False,
),
migrations.AlterUniqueTogether(
name='port',
unique_together=set([('switch', 'port')]),
),
migrations.AlterUniqueTogether(
name='switch',
unique_together=set([('stack', 'stack_member_id')]),
),
]

View file

@ -47,7 +47,7 @@ from django.db import IntegrityError
from django.db import transaction
from reversion import revisions as reversion
from machines.models import Interface
from machines.models import Machine, Interface
class Stack(models.Model):
"""Un objet stack. Regrouppe des switchs en foreign key
@ -109,7 +109,7 @@ class Stack(models.Model):
inférieure à l'id minimale"})
class Borne(Interface):
class AccessPoint(Machine):
"""Define a wireless AP. Inherit from machines.interfaces
Definition pour une borne wifi , hérite de machines.interfaces
@ -125,38 +125,38 @@ class Borne(Interface):
class Meta:
permissions = (
("view_borne", "Peut voir une borne"),
("view_ap", "Peut voir une borne"),
)
def get_instance(borne_id, *args, **kwargs):
return Borne.objects.get(pk=borne_id)
def get_instance(ap_id, *args, **kwargs):
return AccessPoint.objects.get(pk=ap_id)
def can_create(user_request, *args, **kwargs):
return user_request.has_perm('topologie.add_borne') , u"Vous n'avez pas le droit\
return user_request.has_perm('topologie.add_ap') , u"Vous n'avez pas le droit\
de créer une borne"
def can_edit(self, user_request, *args, **kwargs):
if not user_request.has_perm('topologie.change_borne'):
if not user_request.has_perm('topologie.change_ap'):
return False, u"Vous n'avez pas le droit d'éditer des bornes"
return True, None
def can_delete(self, user_request, *args, **kwargs):
if not user_request.has_perm('topologie.delete_borne'):
if not user_request.has_perm('topologie.delete_ap'):
return False, u"Vous n'avez pas le droit de supprimer une borne"
return True, None
def can_view_all(user_request, *args, **kwargs):
if not user_request.has_perm('topologie.view_borne'):
if not user_request.has_perm('topologie.view_ap'):
return False, u"Vous n'avez pas le droit de voir les bornes"
return True, None
def can_view(self, user_request, *args, **kwargs):
if not user_request.has_perm('topologie.view_borne'):
if not user_request.has_perm('topologie.view_ap'):
return False, u"Vous n'avez pas le droit de voir les bornes"
return True, None
class Switch(Interface):
class Switch(Machine):
""" Definition d'un switch. Contient un nombre de ports (number),
un emplacement (location), un stack parent (optionnel, stack)
et un id de membre dans le stack (stack_member_id)
@ -263,6 +263,9 @@ class Switch(Interface):
except IntegrityError:
ValidationError("Création d'un port existant.")
def __str__(self):
return str(self.interface_set.first())
class ModelSwitch(models.Model):
"""Un modèle (au sens constructeur) de switch"""
@ -416,11 +419,11 @@ class Port(models.Model):
def get_instance(port_id, *args, **kwargs):
return Port.objects\
.select_related('switch__domain__extension')\
.select_related('machine_interface__domain__extension')\
.select_related('machine_interface__switch')\
.select_related('machine_interface__machine__switch')\
.select_related('room')\
.select_related('related')\
.prefetch_related('switch__interface_set__domain__extension')\
.get(pk=port_id)
def can_create(user_request, *args, **kwargs):

View file

@ -0,0 +1,74 @@
{% 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 %}
<div class="table-responsive">
{% if ap_list.paginator %}
{% include "pagination.html" with list=ap_list %}
{% endif %}
<table class="table table-striped">
<thead>
<tr>
<th>{% include "buttons/sort.html" with prefix='ap' col='name' text='Borne' %}</th>
<th>{% include "buttons/sort.html" with prefix='ap' col='mac' text='Addresse mac' %}</th>
<th>{% include "buttons/sort.html" with prefix='ap' col='ip' text='Ipv4' %}</th>
<th>Commentaire</th>
<th>Localisation</th>
<th></th>
</tr>
</thead>
{% for ap in ap_list %}
<tr>
<td>{{ap.interface_set.first}}</td>
<td>{{ap.interface_set.first.mac_address}}</td>
<td>{{ap.interface_set.first.ipv4}}</td>
<td>{{ap.interface_set.first.details}}</td>
<td>{{ap.location}}</td>
<td class="text-right">
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'topologie:history' 'ap' ap.pk %}">
<i class="fa fa-history"></i>
</a>
{% can_edit ap %}
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'topologie:edit-ap' ap.id %}">
<i class="fa fa-edit"></i>
</a>
{% acl_end %}
{% can_delete ap %}
<a class="btn btn-danger btn-sm" role="button" title="Supprimer" href="{% url 'machines:del-machine' ap.id %}">
<i class="fa fa-trash"></i>
</a>
{% acl_end %}
</td>
</tr>
{% endfor %}
</table>
{% if ap_list.paginator %}
{% include "pagination.html" with list=ap_list %}
{% endif %}
</div>

View file

@ -1,74 +0,0 @@
{% 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 %}
<div class="table-responsive">
{% if borne_list.paginator %}
{% include "pagination.html" with list=borne_list %}
{% endif %}
<table class="table table-striped">
<thead>
<tr>
<th>{% include "buttons/sort.html" with prefix='borne' col='name' text='Borne' %}</th>
<th>{% include "buttons/sort.html" with prefix='borne' col='mac' text='Addresse mac' %}</th>
<th>{% include "buttons/sort.html" with prefix='borne' col='ip' text='Ipv4' %}</th>
<th>Commentaire</th>
<th>Localisation</th>
<th></th>
</tr>
</thead>
{% for borne in borne_list %}
<tr>
<td>{{borne}}</td>
<td>{{borne.mac_address}}</td>
<td>{{borne.ipv4}}</td>
<td>{{borne.details}}</td>
<td>{{borne.location}}</td>
<td class="text-right">
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'topologie:history' 'borne' borne.pk %}">
<i class="fa fa-history"></i>
</a>
{% can_edit borne %}
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'topologie:edit-borne' borne.id %}">
<i class="fa fa-edit"></i>
</a>
{% acl_end %}
{% can_delete borne %}
<a class="btn btn-danger btn-sm" role="button" title="Supprimer" href="{% url 'machines:del-interface' borne.id %}">
<i class="fa fa-trash"></i>
</a>
{% acl_end %}
</td>
</tr>
{% endfor %}
</table>
{% if borne_list.paginator %}
{% include "pagination.html" with list=borne_list %}
{% endif %}
</div>

View file

@ -46,23 +46,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr>
<td>
<a title="Configuer" href="{% url 'topologie:index-port' switch.pk %}">
{{switch}}
{{switch}}
</a>
</td>
<td>{{switch.ipv4}}</td>
<td>{{switch.interface_set.first.ipv4}}</td>
<td>{{switch.location}}</td>
<td>{{switch.number}}</td>
<td>{{switch.stack.name}}</td>
<td>{{switch.stack_member_id}}</td>
<td>{{switch.model}}</td>
<td>{{switch.details}}</td>
<td>{{switch.interface_set.first.details}}</td>
<td class="text-right">
{% include 'buttons/history.html' with href='topologie:history' name='switch' id=switch.pk%}
{% can_edit switch %}
{% include 'buttons/edit.html' with href='topologie:edit-switch' id=switch.pk %}
{% acl_end %}
{% can_delete switch %}
{% include 'buttons/suppr.html' with href='machines:del-interface' id=switch.id %}
{% include 'buttons/suppr.html' with href='machines:del-machine' id=switch.id %}
{% acl_end %}
{% can_create Port %}
{% include 'buttons/add.html' with href='topologie:create-ports' id=switch.pk desc='Création de ports'%}

View file

@ -30,11 +30,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
<h2>Points d'accès WiFi</h2>
{% can_create Room %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:new-borne' %}"><i class="fa fa-plus"></i> Ajouter une borne</a>
{% can_create AccessPoint %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:new-ap' %}"><i class="fa fa-plus"></i> Ajouter une borne</a>
<hr>
{% acl_end %}
{% include "topologie/aff_borne.html" with borne_list=borne_list %}
{% include "topologie/aff_ap.html" with ap_list=ap_list %}
<br />
<br />
<br />

View file

@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<i class="fa fa-microchip"></i>
Switchs
</a>
<a class="list-group-item list-group-item-info" href="{% url "topologie:index-borne" %}">
<a class="list-group-item list-group-item-info" href="{% url "topologie:index-ap" %}">
<i class="fa fa-wifi"></i>
Bornes WiFi
</a>

View file

@ -35,11 +35,11 @@ from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^index_borne/$', views.index_borne, name='index-borne'),
url(r'^new_borne/$', views.new_borne, name='new-borne'),
url(r'^edit_borne/(?P<borne_id>[0-9]+)$',
views.edit_borne,
name='edit-borne'),
url(r'^index_ap/$', views.index_ap, name='index-ap'),
url(r'^new_ap/$', views.new_ap, name='new-ap'),
url(r'^edit_ap/(?P<ap_id>[0-9]+)$',
views.edit_ap,
name='edit-ap'),
url(r'^create_ports/(?P<switch_id>[0-9]+)$',
views.create_ports,
name='create-ports'),

View file

@ -41,7 +41,7 @@ from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.db import IntegrityError
from django.db import transaction
from django.db.models import ProtectedError
from django.db.models import ProtectedError, Prefetch
from django.core.exceptions import ValidationError
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from reversion import revisions as reversion
@ -54,7 +54,7 @@ from topologie.models import (
Stack,
ModelSwitch,
ConstructorSwitch,
Borne
AccessPoint
)
from topologie.forms import EditPortForm, NewSwitchForm, EditSwitchForm
from topologie.forms import (
@ -64,8 +64,8 @@ from topologie.forms import (
EditModelSwitchForm,
EditConstructorSwitchForm,
CreatePortsForm,
AddBorneForm,
EditBorneForm
AddAccessPointForm,
EditAccessPointForm
)
from users.views import form
from re2o.utils import SortTable
@ -84,6 +84,7 @@ from machines.forms import (
AddInterfaceForm
)
from machines.views import generate_ipv4_mbf_param
from machines.models import Interface
from preferences.models import AssoOption, GeneralOption
@ -92,9 +93,10 @@ from preferences.models import AssoOption, GeneralOption
def index(request):
""" Vue d'affichage de tous les swicthes"""
switch_list = Switch.objects\
.select_related('domain__extension')\
.select_related('ipv4')\
.select_related('domain')\
.prefetch_related(Prefetch(
'interface_set',
queryset=Interface.objects.select_related('ipv4__ip_type__extension').select_related('domain__extension')
))\
.select_related('stack')
switch_list = SortTable.sort(
switch_list,
@ -127,9 +129,11 @@ def index_port(request, switch, switch_id):
.select_related('room')\
.select_related('machine_interface__domain__extension')\
.select_related('machine_interface__machine__user')\
.select_related(
'related__switch__domain__extension'
)\
.select_related('related__switch')\
.prefetch_related(Prefetch(
'related__switch__interface_set',
queryset=Interface.objects.select_related('domain__extension')
))\
.select_related('switch')
port_list = SortTable.sort(
port_list,
@ -172,29 +176,33 @@ def index_room(request):
@login_required
@can_view_all(Borne)
def index_borne(request):
@can_view_all(AccessPoint)
def index_ap(request):
""" Affichage de l'ensemble des bornes"""
borne_list = Borne.objects
borne_list = SortTable.sort(
borne_list,
ap_list = AccessPoint.objects\
.prefetch_related(Prefetch(
'interface_set',
queryset=Interface.objects.select_related('ipv4__ip_type__extension').select_related('domain__extension')
))
ap_list = SortTable.sort(
ap_list,
request.GET.get('col'),
request.GET.get('order'),
SortTable.TOPOLOGIE_INDEX_BORNE
)
pagination_number = GeneralOption.get_cached_value('pagination_number')
paginator = Paginator(borne_list, pagination_number)
paginator = Paginator(ap_list, pagination_number)
page = request.GET.get('page')
try:
borne_list = paginator.page(page)
ap_list = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
borne_list = paginator.page(1)
ap_list = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
borne_list = paginator.page(paginator.num_pages)
return render(request, 'topologie/index_borne.html', {
'borne_list': borne_list
ap_list = paginator.page(paginator.num_pages)
return render(request, 'topologie/index_ap.html', {
'ap_list': ap_list
})
@ -385,45 +393,45 @@ def new_switch(request):
request.POST or None,
user=request.user
)
machine = NewMachineForm(
interface = AddInterfaceForm(
request.POST or None,
user=request.user
)
domain = DomainForm(
request.POST or None,
)
if switch.is_valid() and machine.is_valid():
if switch.is_valid() and interface.is_valid():
user = AssoOption.get_cached_value('utilisateur_asso')
if not user:
messages.error(request, "L'user association n'existe pas encore,\
veuillez le créer ou le linker dans preferences")
return redirect(reverse('topologie:index'))
new_machine = machine.save(commit=False)
new_machine.user = user
new_switch_instance = switch.save(commit=False)
domain.instance.interface_parent = new_switch_instance
new_switch = switch.save(commit=False)
new_switch.user = user
new_interface_instance = interface.save(commit=False)
domain.instance.interface_parent = new_interface_instance
if domain.is_valid():
new_domain_instance = domain.save(commit=False)
with transaction.atomic(), reversion.create_revision():
new_machine.save()
new_switch.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_switch_instance.machine = new_machine
new_interface_instance.machine = new_switch
with transaction.atomic(), reversion.create_revision():
new_switch_instance.save()
new_interface_instance.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_domain_instance.interface_parent = new_switch_instance
new_domain_instance.interface_parent = new_interface_instance
with transaction.atomic(), reversion.create_revision():
new_domain_instance.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Le switch a été créé")
return redirect(reverse('topologie:index'))
i_mbf_param = generate_ipv4_mbf_param(switch, False)
i_mbf_param = generate_ipv4_mbf_param(interface, False)
return form({
'topoform': switch,
'machineform': machine,
'topoform': interface,
'machineform': switch,
'domainform': domain,
'i_mbf_param': i_mbf_param,
'device' : 'switch',
@ -479,32 +487,32 @@ def edit_switch(request, switch, switch_id):
instance=switch,
user=request.user
)
machine_form = EditMachineForm(
interface_form = EditInterfaceForm(
request.POST or None,
instance=switch.machine,
instance=switch.interface_set.first(),
user=request.user
)
domain_form = DomainForm(
request.POST or None,
instance=switch.domain
instance=switch.interface_set.first().domain
)
if switch_form.is_valid() and machine_form.is_valid():
new_machine = machine_form.save(commit=False)
new_switch_instance = switch_form.save(commit=False)
if switch_form.is_valid() and interface_form.is_valid():
new_switch = switch_form.save(commit=False)
new_interface_instance = interface_form.save(commit=False)
new_domain = domain_form.save(commit=False)
with transaction.atomic(), reversion.create_revision():
new_machine.save()
new_switch.save()
reversion.set_user(request.user)
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in machine_form.changed_data
field for field in switch_form.changed_data
)
)
with transaction.atomic(), reversion.create_revision():
new_switch_instance.save()
new_interface_instance.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in switch_form.changed_data)
field for field in interface_form.changed_data)
)
with transaction.atomic(), reversion.create_revision():
new_domain.save()
@ -514,11 +522,11 @@ def edit_switch(request, switch, switch_id):
)
messages.success(request, "Le switch a bien été modifié")
return redirect(reverse('topologie:index'))
i_mbf_param = generate_ipv4_mbf_param(switch_form, False )
i_mbf_param = generate_ipv4_mbf_param(interface_form, False )
return form({
'id_switch': switch_id,
'topoform': switch_form,
'machineform': machine_form,
'topoform': interface_form,
'machineform': switch_form,
'domainform': domain_form,
'i_mbf_param': i_mbf_param,
'device' : 'switch',
@ -526,54 +534,54 @@ def edit_switch(request, switch, switch_id):
@login_required
@can_create(Borne)
def new_borne(request):
""" Creation d'une borne. Cree en meme temps l'interface et la machine
@can_create(AccessPoint)
def new_ap(request):
""" Creation d'une ap. Cree en meme temps l'interface et la machine
associée. Vue complexe. Appelle successivement les 3 models forms
adaptés : machine, interface, domain et switch"""
borne = AddBorneForm(
ap = AddAccessPointForm(
request.POST or None,
user=request.user
)
machine = NewMachineForm(
interface = AddInterfaceForm(
request.POST or None,
user=request.user
)
domain = DomainForm(
request.POST or None,
)
if borne.is_valid() and machine.is_valid():
if ap.is_valid() and interface.is_valid():
user = AssoOption.get_cached_value('utilisateur_asso')
if not user:
messages.error(request, "L'user association n'existe pas encore,\
veuillez le créer ou le linker dans preferences")
return redirect(reverse('topologie:index'))
new_machine = machine.save(commit=False)
new_machine.user = user
new_borne = borne.save(commit=False)
domain.instance.interface_parent = new_borne
new_ap = ap.save(commit=False)
new_ap.user = user
new_interface = interface.save(commit=False)
domain.instance.interface_parent = new_interface
if domain.is_valid():
new_domain_instance = domain.save(commit=False)
with transaction.atomic(), reversion.create_revision():
new_machine.save()
new_ap.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_borne.machine = new_machine
new_interface.machine = new_ap
with transaction.atomic(), reversion.create_revision():
new_borne.save()
new_interface.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_domain_instance.interface_parent = new_borne
new_domain_instance.interface_parent = new_interface
with transaction.atomic(), reversion.create_revision():
new_domain_instance.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "La borne a été créé")
return redirect(reverse('topologie:index-borne'))
i_mbf_param = generate_ipv4_mbf_param(borne, False)
return redirect(reverse('topologie:index-ap'))
i_mbf_param = generate_ipv4_mbf_param(interface, False)
return form({
'topoform': borne,
'machineform': machine,
'topoform': interface,
'machineform': ap,
'domainform': domain,
'i_mbf_param': i_mbf_param,
'device' : 'wifi ap',
@ -581,45 +589,45 @@ def new_borne(request):
@login_required
@can_edit(Borne)
def edit_borne(request, borne, borne_id):
@can_edit(AccessPoint)
def edit_ap(request, ap, ap_id):
""" Edition d'un switch. Permet de chambre nombre de ports,
place dans le stack, interface et machine associée"""
borne_form = EditBorneForm(
interface_form = EditInterfaceForm(
request.POST or None,
user=request.user,
instance=borne
instance=ap.interface_set.first()
)
machine_form = NewMachineForm(
ap_form = EditAccessPointForm(
request.POST or None,
user=request.user,
instance=borne.machine
instance=ap
)
domain_form = DomainForm(
request.POST or None,
instance=borne.domain
instance=ap.interface_set.first().domain
)
if borne_form.is_valid() and machine_form.is_valid():
if ap_form.is_valid() and interface_form.is_valid():
user = AssoOption.get_cached_value('utilisateur_asso')
if not user:
messages.error(request, "L'user association n'existe pas encore,\
veuillez le créer ou le linker dans preferences")
return redirect(reverse('topologie:index-borne'))
new_machine = machine_form.save(commit=False)
new_borne = borne_form.save(commit=False)
return redirect(reverse('topologie:index-ap'))
new_ap = ap_form.save(commit=False)
new_interface = interface_form.save(commit=False)
new_domain = domain_form.save(commit=False)
with transaction.atomic(), reversion.create_revision():
new_machine.save()
new_ap.save()
reversion.set_user(request.user)
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in machine_form.changed_data)
field for field in ap_form.changed_data)
)
with transaction.atomic(), reversion.create_revision():
new_borne.save()
new_interface.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in borne_form.changed_data)
field for field in interface_form.changed_data)
)
reversion.set_comment("Création")
with transaction.atomic(), reversion.create_revision():
@ -629,11 +637,11 @@ def edit_borne(request, borne, borne_id):
field for field in domain_form.changed_data)
)
messages.success(request, "La borne a été modifiée")
return redirect(reverse('topologie:index-borne'))
i_mbf_param = generate_ipv4_mbf_param(borne_form, False )
return redirect(reverse('topologie:index-ap'))
i_mbf_param = generate_ipv4_mbf_param(interface_form, False )
return form({
'topoform': borne_form,
'machineform': machine_form,
'topoform': interface_form,
'machineform': ap_form,
'domainform': domain_form,
'i_mbf_param': i_mbf_param,
'device' : 'wifi ap',

View file

@ -501,8 +501,7 @@ def del_school(request, instances):
@login_required
@can_create(ListShell)
def add_shell(request):
""" Ajouter un établissement d'enseignement à la base de donnée,
need cableur"""
""" Ajouter un shell à la base de donnée"""
shell = ShellForm(request.POST or None)
if shell.is_valid():
with transaction.atomic(), reversion.create_revision():
@ -517,8 +516,7 @@ def add_shell(request):
@login_required
@can_edit(ListShell)
def edit_shell(request, shell_instance, shellid):
""" Editer un établissement d'enseignement à partir du shellid dans
la base de donnée, need cableur"""
""" Editer un shell à partir du shellid"""
shell = ShellForm(request.POST or None, instance=shell_instance)
if shell.is_valid():
with transaction.atomic(), reversion.create_revision():