diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index 17b9513d..c20764e9 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -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) diff --git a/logs/views.py b/logs/views.py index b3af50e9..6ab48706 100644 --- a/logs/views.py +++ b/logs/views.py @@ -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}) diff --git a/re2o/templatetags/acl.py b/re2o/templatetags/acl.py index c2d3ba24..d749b299 100644 --- a/re2o/templatetags/acl.py +++ b/re2o/templatetags/acl.py @@ -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, diff --git a/re2o/utils.py b/re2o/utils.py index d577ba70..32be2432 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -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'], diff --git a/re2o/views.py b/re2o/views.py index c0fbb8ef..9a987e5a 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -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, diff --git a/search/views.py b/search/views.py index 601f4eeb..21279bfa 100644 --- a/search/views.py +++ b/search/views.py @@ -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( diff --git a/topologie/admin.py b/topologie/admin.py index f7021148..6c64aec7 100644 --- a/topologie/admin.py +++ b/topologie/admin.py @@ -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) diff --git a/topologie/forms.py b/topologie/forms.py index 6e37bb0c..7b8f0955 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -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): diff --git a/topologie/migrations/0041_transferportsw.py b/topologie/migrations/0041_transferportsw.py index a629c7e6..9e1d979a 100644 --- a/topologie/migrations/0041_transferportsw.py +++ b/topologie/migrations/0041_transferportsw.py @@ -12,6 +12,10 @@ class Migration(migrations.Migration): ] operations = [ + migrations.AlterUniqueTogether( + name='port', + unique_together=set([]), + ), migrations.RemoveField( model_name='port', name='switch', diff --git a/topologie/migrations/0044_auto_20180326_0002.py b/topologie/migrations/0044_auto_20180326_0002.py new file mode 100644 index 00000000..f18b4ed9 --- /dev/null +++ b/topologie/migrations/0044_auto_20180326_0002.py @@ -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'),)}, + ), + ] diff --git a/topologie/migrations/0045_auto_20180326_0123.py b/topologie/migrations/0045_auto_20180326_0123.py new file mode 100644 index 00000000..cf621967 --- /dev/null +++ b/topologie/migrations/0045_auto_20180326_0123.py @@ -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'), + ), + ] diff --git a/topologie/migrations/0046_auto_20180326_0129.py b/topologie/migrations/0046_auto_20180326_0129.py new file mode 100644 index 00000000..dc5e849e --- /dev/null +++ b/topologie/migrations/0046_auto_20180326_0129.py @@ -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')]), + ), + ] diff --git a/topologie/migrations/0047_ap_machine.py b/topologie/migrations/0047_ap_machine.py new file mode 100644 index 00000000..f09ca318 --- /dev/null +++ b/topologie/migrations/0047_ap_machine.py @@ -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',), + ), + ] diff --git a/topologie/migrations/0048_ap_machine.py b/topologie/migrations/0048_ap_machine.py new file mode 100644 index 00000000..ed1aa2fd --- /dev/null +++ b/topologie/migrations/0048_ap_machine.py @@ -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', + ), + ] diff --git a/topologie/migrations/0049_switchs_machine.py b/topologie/migrations/0049_switchs_machine.py new file mode 100644 index 00000000..040ab599 --- /dev/null +++ b/topologie/migrations/0049_switchs_machine.py @@ -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',), + ), + ] diff --git a/topologie/migrations/0050_port_new_switch.py b/topologie/migrations/0050_port_new_switch.py new file mode 100644 index 00000000..b03a8ee5 --- /dev/null +++ b/topologie/migrations/0050_port_new_switch.py @@ -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'), + ), + ] diff --git a/topologie/migrations/0051_switchs_machine.py b/topologie/migrations/0051_switchs_machine.py new file mode 100644 index 00000000..d7f1da86 --- /dev/null +++ b/topologie/migrations/0051_switchs_machine.py @@ -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), + ] diff --git a/topologie/migrations/0052_transferports.py b/topologie/migrations/0052_transferports.py new file mode 100644 index 00000000..88badbe6 --- /dev/null +++ b/topologie/migrations/0052_transferports.py @@ -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') + ] diff --git a/topologie/migrations/0053_finalsw.py b/topologie/migrations/0053_finalsw.py new file mode 100644 index 00000000..2ed7e2ac --- /dev/null +++ b/topologie/migrations/0053_finalsw.py @@ -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', + ), + ] diff --git a/topologie/migrations/0054_auto_20180326_1742.py b/topologie/migrations/0054_auto_20180326_1742.py new file mode 100644 index 00000000..cfaff01b --- /dev/null +++ b/topologie/migrations/0054_auto_20180326_1742.py @@ -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')]), + ), + ] diff --git a/topologie/models.py b/topologie/models.py index e0891f18..3cf0d5b2 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -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): diff --git a/topologie/templates/topologie/aff_ap.html b/topologie/templates/topologie/aff_ap.html new file mode 100644 index 00000000..192e5026 --- /dev/null +++ b/topologie/templates/topologie/aff_ap.html @@ -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 %} + +
+ {% if ap_list.paginator %} + {% include "pagination.html" with list=ap_list %} + {% endif %} + + + + + + + + + + + + + + {% for ap in ap_list %} + + + + + + + + + {% endfor %} +
{% include "buttons/sort.html" with prefix='ap' col='name' text='Borne' %}{% include "buttons/sort.html" with prefix='ap' col='mac' text='Addresse mac' %}{% include "buttons/sort.html" with prefix='ap' col='ip' text='Ipv4' %}CommentaireLocalisation
{{ap.interface_set.first}}{{ap.interface_set.first.mac_address}}{{ap.interface_set.first.ipv4}}{{ap.interface_set.first.details}}{{ap.location}} + + + + {% can_edit ap %} + + + + {% acl_end %} + {% can_delete ap %} + + + + {% acl_end %} +
+ + + {% if ap_list.paginator %} +{% include "pagination.html" with list=ap_list %} +{% endif %} +
diff --git a/topologie/templates/topologie/aff_borne.html b/topologie/templates/topologie/aff_borne.html deleted file mode 100644 index 8080aaaf..00000000 --- a/topologie/templates/topologie/aff_borne.html +++ /dev/null @@ -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 %} - -
-{% if borne_list.paginator %} -{% include "pagination.html" with list=borne_list %} -{% endif %} - - - - - - - - - - - - - - {% for borne in borne_list %} - - - - - - - - - {% endfor %} -
{% include "buttons/sort.html" with prefix='borne' col='name' text='Borne' %}{% include "buttons/sort.html" with prefix='borne' col='mac' text='Addresse mac' %}{% include "buttons/sort.html" with prefix='borne' col='ip' text='Ipv4' %}CommentaireLocalisation
{{borne}}{{borne.mac_address}}{{borne.ipv4}}{{borne.details}}{{borne.location}} - - - - {% can_edit borne %} - - - - {% acl_end %} - {% can_delete borne %} - - - - {% acl_end %} -
- - -{% if borne_list.paginator %} -{% include "pagination.html" with list=borne_list %} -{% endif %} -
diff --git a/topologie/templates/topologie/aff_switch.html b/topologie/templates/topologie/aff_switch.html index c8c9e6e0..bcbe5204 100644 --- a/topologie/templates/topologie/aff_switch.html +++ b/topologie/templates/topologie/aff_switch.html @@ -46,23 +46,23 @@ with this program; if not, write to the Free Software Foundation, Inc., - {{switch}} + {{switch}} - {{switch.ipv4}} + {{switch.interface_set.first.ipv4}} {{switch.location}} {{switch.number}} {{switch.stack.name}} {{switch.stack_member_id}} {{switch.model}} - {{switch.details}} + {{switch.interface_set.first.details}} {% 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'%} diff --git a/topologie/templates/topologie/index_borne.html b/topologie/templates/topologie/index_ap.html similarity index 88% rename from topologie/templates/topologie/index_borne.html rename to topologie/templates/topologie/index_ap.html index e6d20dfb..19499998 100644 --- a/topologie/templates/topologie/index_borne.html +++ b/topologie/templates/topologie/index_ap.html @@ -30,11 +30,11 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block content %}

Points d'accès WiFi

-{% can_create Room %} - Ajouter une borne +{% can_create AccessPoint %} + Ajouter une borne
{% acl_end %} - {% include "topologie/aff_borne.html" with borne_list=borne_list %} + {% include "topologie/aff_ap.html" with ap_list=ap_list %}


diff --git a/topologie/templates/topologie/sidebar.html b/topologie/templates/topologie/sidebar.html index 6351ffd0..bdbcf7fc 100644 --- a/topologie/templates/topologie/sidebar.html +++ b/topologie/templates/topologie/sidebar.html @@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., Switchs - + Bornes WiFi diff --git a/topologie/urls.py b/topologie/urls.py index 19b87947..1f2968b7 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -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[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[0-9]+)$', + views.edit_ap, + name='edit-ap'), url(r'^create_ports/(?P[0-9]+)$', views.create_ports, name='create-ports'), diff --git a/topologie/views.py b/topologie/views.py index 97091a83..bc53c77b 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -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', diff --git a/users/views.py b/users/views.py index a6a28ed0..a0d46fe8 100644 --- a/users/views.py +++ b/users/views.py @@ -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():