Commit 7d7a4500 authored by Chirac's avatar Chirac

Merge branch 'faster_ipform' into 'master'

Faster ipform

See merge request rezo/re2o!13
parents c9658205 25ddaa70
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # 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 # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
...@@ -5,6 +6,7 @@ ...@@ -5,6 +6,7 @@
# Copyright © 2017 Gabriel Détraz # Copyright © 2017 Gabriel Détraz
# Copyright © 2017 Goulven Kermarec # Copyright © 2017 Goulven Kermarec
# Copyright © 2017 Augustin Lemesle # Copyright © 2017 Augustin Lemesle
# Copyright © 2017 Maël Kervella
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
...@@ -27,7 +29,7 @@ import re ...@@ -27,7 +29,7 @@ import re
from django.forms import ModelForm, Form, ValidationError from django.forms import ModelForm, Form, ValidationError
from django import forms from django import forms
from .models import Domain, Machine, Interface, IpList, MachineType, Extension, Mx, Text, Ns, Service, Vlan, Nas, IpType, OuverturePortList, OuverturePort from .models import Domain, Machine, Interface, IpList, MachineType, Extension, Mx, Text, Ns, Service, Vlan, Nas, IpType, OuverturePortList, OuverturePort
from django.db.models import Q from django.db.models import Q, F
from django.core.validators import validate_email from django.core.validators import validate_email
from users.models import User from users.models import User
...@@ -52,8 +54,7 @@ class BaseEditMachineForm(EditMachineForm): ...@@ -52,8 +54,7 @@ class BaseEditMachineForm(EditMachineForm):
class EditInterfaceForm(ModelForm): class EditInterfaceForm(ModelForm):
class Meta: class Meta:
model = Interface model = Interface
# fields = '__all__' fields = ['machine', 'type', 'ipv4', 'mac_address', 'details']
exclude = ['port_lists']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(EditInterfaceForm, self).__init__(*args, **kwargs) super(EditInterfaceForm, self).__init__(*args, **kwargs)
...@@ -62,13 +63,15 @@ class EditInterfaceForm(ModelForm): ...@@ -62,13 +63,15 @@ class EditInterfaceForm(ModelForm):
self.fields['type'].empty_label = "Séléctionner un type de machine" self.fields['type'].empty_label = "Séléctionner un type de machine"
if "ipv4" in self.fields: if "ipv4" in self.fields:
self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4" self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4"
self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True) self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).annotate(mtype_id=F('ip_type__machinetype__id'))
# Add it's own address
self.fields['ipv4'].queryset |= IpList.objects.filter(interface=self.instance).annotate(mtype_id=F('ip_type__machinetype__id'))
if "machine" in self.fields: if "machine" in self.fields:
self.fields['machine'].queryset = Machine.objects.all().select_related('user') self.fields['machine'].queryset = Machine.objects.all().select_related('user')
class AddInterfaceForm(EditInterfaceForm): class AddInterfaceForm(EditInterfaceForm):
class Meta(EditInterfaceForm.Meta): class Meta(EditInterfaceForm.Meta):
fields = ['ipv4','mac_address','type','details'] fields = ['type','ipv4','mac_address','details']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
infra = kwargs.pop('infra') infra = kwargs.pop('infra')
...@@ -76,17 +79,17 @@ class AddInterfaceForm(EditInterfaceForm): ...@@ -76,17 +79,17 @@ class AddInterfaceForm(EditInterfaceForm):
self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4" self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4"
if not infra: if not infra:
self.fields['type'].queryset = MachineType.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False)) self.fields['type'].queryset = MachineType.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False))
self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).filter(ip_type__in=IpType.objects.filter(need_infra=False)) self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).filter(ip_type__in=IpType.objects.filter(need_infra=False)).annotate(mtype_id=F('ip_type__machinetype__id'))
else: else:
self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True) self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).annotate(mtype_id=F('ip_type__machinetype__id'))
class NewInterfaceForm(EditInterfaceForm): class NewInterfaceForm(EditInterfaceForm):
class Meta(EditInterfaceForm.Meta): class Meta(EditInterfaceForm.Meta):
fields = ['mac_address','type','details'] fields = ['type','mac_address','details']
class BaseEditInterfaceForm(EditInterfaceForm): class BaseEditInterfaceForm(EditInterfaceForm):
class Meta(EditInterfaceForm.Meta): class Meta(EditInterfaceForm.Meta):
fields = ['ipv4','mac_address','type','details'] fields = ['type','ipv4','mac_address','details']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
infra = kwargs.pop('infra') infra = kwargs.pop('infra')
...@@ -94,9 +97,12 @@ class BaseEditInterfaceForm(EditInterfaceForm): ...@@ -94,9 +97,12 @@ class BaseEditInterfaceForm(EditInterfaceForm):
self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4" self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4"
if not infra: if not infra:
self.fields['type'].queryset = MachineType.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False)) self.fields['type'].queryset = MachineType.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False))
self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).filter(ip_type__in=IpType.objects.filter(need_infra=False)) self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).filter(ip_type__in=IpType.objects.filter(need_infra=False)).annotate(mtype_id=F('ip_type__machinetype__id'))
# Add it's own address
self.fields['ipv4'].queryset |= IpList.objects.filter(interface=self.instance).annotate(mtype_id=F('ip_type__machinetype__id'))
else: else:
self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True) self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).annotate(mtype_id=F('ip_type__machinetype__id'))
self.fields['ipv4'].queryset |= IpList.objects.filter(interface=self.instance).annotate(mtype_id=F('ip_type__machinetype__id'))
class AliasForm(ModelForm): class AliasForm(ModelForm):
class Meta: class Meta:
......
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # 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 # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
......
...@@ -7,6 +7,7 @@ quelques clics. ...@@ -7,6 +7,7 @@ quelques clics.
Copyright © 2017 Gabriel Détraz Copyright © 2017 Gabriel Détraz
Copyright © 2017 Goulven Kermarec Copyright © 2017 Goulven Kermarec
Copyright © 2017 Augustin Lemesle Copyright © 2017 Augustin Lemesle
Copyright © 2017 Maël Kervella
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -24,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -24,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %} {% endcomment %}
{% load bootstrap3 %} {% load bootstrap3 %}
{% load bootstrap_form_typeahead %}
{% block title %}Création et modification de machines{% endblock %} {% block title %}Création et modification de machines{% endblock %}
...@@ -38,16 +40,22 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -38,16 +40,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% bootstrap_form_errors domainform %} {% bootstrap_form_errors domainform %}
{% endif %} {% endif %}
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
{% if machineform %} {% if machineform %}
<h3>Machine</h3>
{% bootstrap_form machineform %} {% bootstrap_form machineform %}
{% endif %} {% endif %}
{% if interfaceform %} {% if interfaceform %}
{% bootstrap_form interfaceform %} <h3>Interface</h3>
{% if i_bft_param %}
{% bootstrap_form_typeahead interfaceform 'ipv4' bft_param=i_bft_param %}
{% else %}
{% bootstrap_form_typeahead interfaceform 'ipv4' %}
{% endif %}
{% endif %} {% endif %}
{% if domainform %} {% if domainform %}
<h3>Domaine</h3>
{% bootstrap_form domainform %} {% bootstrap_form domainform %}
{% endif %} {% endif %}
{% bootstrap_button "Créer ou modifier" button_type="submit" icon="star" %} {% bootstrap_button "Créer ou modifier" button_type="submit" icon="star" %}
......
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017 Maël Kervella
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
This diff is collapsed.
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # 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 # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
......
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # 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 # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
......
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # 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 # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
...@@ -5,6 +6,7 @@ ...@@ -5,6 +6,7 @@
# Copyright © 2017 Gabriel Détraz # Copyright © 2017 Gabriel Détraz
# Copyright © 2017 Goulven Kermarec # Copyright © 2017 Goulven Kermarec
# Copyright © 2017 Augustin Lemesle # Copyright © 2017 Augustin Lemesle
# Copyright © 2017 Maël Kervella
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
...@@ -53,6 +55,7 @@ from .models import IpType, Machine, Interface, IpList, MachineType, Extension, ...@@ -53,6 +55,7 @@ from .models import IpType, Machine, Interface, IpList, MachineType, Extension,
from users.models import User from users.models import User
from users.models import all_has_access from users.models import all_has_access
from preferences.models import GeneralOption, OptionalMachine from preferences.models import GeneralOption, OptionalMachine
from .templatetags.bootstrap_form_typeahead import hidden_id, input_id
def all_active_interfaces(): def all_active_interfaces():
"""Renvoie l'ensemble des machines autorisées à sortir sur internet """ """Renvoie l'ensemble des machines autorisées à sortir sur internet """
...@@ -75,6 +78,81 @@ def form(ctx, template, request): ...@@ -75,6 +78,81 @@ def form(ctx, template, request):
c.update(csrf(request)) c.update(csrf(request))
return render(request, template, c) return render(request, template, c)
def f_type_id( is_type_tt ):
""" The id that will be used in HTML to store the value of the field
type. Depends on the fact that type is generate using typeahead or not
"""
return hidden_id('type') if is_type_tt else input_id('type')
def generate_ipv4_choices( form ) :
""" Generate the parameter choices for the bootstrap_form_typeahead tag
"""
f_ipv4 = form.fields['ipv4']
used_mtype_id = []
choices = '{ "": [{key: "", value: "Choisissez d\'abord un type de machine"},'
mtype_id = -1
for ip in f_ipv4.queryset.order_by('mtype_id', 'id') :
if mtype_id != ip.mtype_id :
mtype_id = ip.mtype_id
used_mtype_id.append(mtype_id)
choices += '], "'+str(mtype_id)+'": ['
choices += '{key: "", value: "' + str(f_ipv4.empty_label) + '"},'
choices += '{key: ' + str(ip.id) + ', value: "' + str(ip.ipv4) + '"},'
for t in form.fields['type'].queryset.exclude(id__in=used_mtype_id) :
choices += '], "'+str(t.id)+'": ['
choices += '{key: "", value: "' + str(f_ipv4.empty_label) + '"},'
choices += ']}'
return choices
def generate_ipv4_engine( is_type_tt ) :
""" Generate the parameter engine for the bootstrap_form_typeahead tag
"""
return 'new Bloodhound({ ' \
'datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"), ' \
'queryTokenizer: Bloodhound.tokenizers.whitespace, ' \
'local: choices_ipv4[$("#'+f_type_id(is_type_tt)+'").val()], ' \
'identify: function(obj) { return obj.key; } ' \
'})'
def generate_ipv4_match_func( is_type_tt ) :
""" Generate the parameter match_func for the bootstrap_form_typeahead tag
"""
return 'function(q, sync) {' \
'if (q === "") {' \
'var nb = 10;' \
'var first = [] ;' \
'for(' \
'var i=0 ;' \
'i<nb && i<choices_ipv4[' \
'$("#'+f_type_id(is_type_tt)+'").val()' \
'].length ;' \
'i++' \
') { first.push(' \
'choices_ipv4[$("#'+f_type_id(is_type_tt)+'").val()][i].key' \
'); }' \
'sync(engine_ipv4.get(first));' \
'} else {' \
'engine_ipv4.search(q, sync);' \
'}' \
'}'
def generate_ipv4_bft_param( form, is_type_tt ):
""" Generate all the parameters to use with the bootstrap_form_typeahead
tag """
i_choices = { 'ipv4': generate_ipv4_choices( form ) }
i_engine = { 'ipv4': generate_ipv4_engine( is_type_tt ) }
i_match_func = { 'ipv4': generate_ipv4_match_func( is_type_tt ) }
i_update_on = { 'ipv4': [f_type_id( is_type_tt )] }
i_bft_param = {
'choices': i_choices,
'engine': i_engine,
'match_func': i_match_func,
'update_on': i_update_on
}
return i_bft_param
@login_required @login_required
def new_machine(request, userid): def new_machine(request, userid):
try: try:
...@@ -118,7 +196,8 @@ def new_machine(request, userid): ...@@ -118,7 +196,8 @@ def new_machine(request, userid):
reversion.set_comment("Création") reversion.set_comment("Création")
messages.success(request, "La machine a été créée") messages.success(request, "La machine a été créée")
return redirect("/users/profil/" + str(user.id)) return redirect("/users/profil/" + str(user.id))
return form({'machineform': machine, 'interfaceform': interface, 'domainform': domain}, 'machines/machine.html', request) i_bft_param = generate_ipv4_bft_param( interface, False )
return form({'machineform': machine, 'interfaceform': interface, 'domainform': domain, 'i_bft_param': i_bft_param}, 'machines/machine.html', request)
@login_required @login_required
def edit_interface(request, interfaceid): def edit_interface(request, interfaceid):
...@@ -155,7 +234,8 @@ def edit_interface(request, interfaceid): ...@@ -155,7 +234,8 @@ def edit_interface(request, interfaceid):
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in domain_form.changed_data)) reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in domain_form.changed_data))
messages.success(request, "La machine a été modifiée") messages.success(request, "La machine a été modifiée")
return redirect("/users/profil/" + str(interface.machine.user.id)) return redirect("/users/profil/" + str(interface.machine.user.id))
return form({'machineform': machine_form, 'interfaceform': interface_form, 'domainform': domain_form}, 'machines/machine.html', request) i_bft_param = generate_ipv4_bft_param( interface_form, False )
return form({'machineform': machine_form, 'interfaceform': interface_form, 'domainform': domain_form, 'i_bft_param': i_bft_param}, 'machines/machine.html', request)
@login_required @login_required
def del_machine(request, machineid): def del_machine(request, machineid):
...@@ -211,7 +291,8 @@ def new_interface(request, machineid): ...@@ -211,7 +291,8 @@ def new_interface(request, machineid):
reversion.set_comment("Création") reversion.set_comment("Création")
messages.success(request, "L'interface a été ajoutée") messages.success(request, "L'interface a été ajoutée")
return redirect("/users/profil/" + str(machine.user.id)) return redirect("/users/profil/" + str(machine.user.id))
return form({'interfaceform': interface_form, 'domainform': domain_form}, 'machines/machine.html', request) i_bft_param = generate_ipv4_bft_param( interface_form, False )
return form({'interfaceform': interface_form, 'domainform': domain_form, 'i_bft_param': i_bft_param}, 'machines/machine.html', request)
@login_required @login_required
def del_interface(request, interfaceid): def del_interface(request, interfaceid):
......
span.twitter-typeahead .tt-menu,
span.twitter-typeahead .tt-dropdown-menu {
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
display: none;
float: left;
min-width: 160px;
padding: 5px 0;
margin: 2px 0 0;
list-style: none;
font-size: 14px;
text-align: left;
background-color: #ffffff;
border: 1px solid #cccccc;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
background-clip: padding-box;
}
span.twitter-typeahead .tt-suggestion {
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: 1.42857143;
color: #333333;
white-space: nowrap;
}
span.twitter-typeahead .tt-suggestion.tt-cursor,
span.twitter-typeahead .tt-suggestion:hover,
span.twitter-typeahead .tt-suggestion:focus {
color: #ffffff;
text-decoration: none;
outline: 0;
background-color: #337ab7;
}
.input-group.input-group-lg span.twitter-typeahead .form-control {
height: 46px;
padding: 10px 16px;
font-size: 18px;
line-height: 1.3333333;
border-radius: 6px;
}
.input-group.input-group-sm span.twitter-typeahead .form-control {
height: 30px;
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
span.twitter-typeahead {
width: 100%;
}
.input-group span.twitter-typeahead {
display: block !important;
height: 34px;
}
.input-group span.twitter-typeahead .tt-menu,
.input-group span.twitter-typeahead .tt-dropdown-menu {
top: 32px !important;
}
.input-group span.twitter-typeahead:not(:first-child):not(:last-child) .form-control {
border-radius: 0;
}
.input-group span.twitter-typeahead:first-child .form-control {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group span.twitter-typeahead:last-child .form-control {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.input-group.input-group-sm span.twitter-typeahead {
height: 30px;
}
.input-group.input-group-sm span.twitter-typeahead .tt-menu,
.input-group.input-group-sm span.twitter-typeahead .tt-dropdown-menu {
top: 30px !important;
}
.input-group.input-group-lg span.twitter-typeahead {
height: 46px;
}
.input-group.input-group-lg span.twitter-typeahead .tt-menu,
.input-group.input-group-lg span.twitter-typeahead .tt-dropdown-menu {
top: 46px !important;
}
This diff is collapsed.
This diff is collapsed.
...@@ -32,8 +32,11 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -32,8 +32,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<head> <head>
{# Load CSS and JavaScript #} {# Load CSS and JavaScript #}
{% bootstrap_css %} {% bootstrap_css %}
<link href="/static/css/typeaheadjs.css" rel="stylesheet">
{% bootstrap_javascript %} {% bootstrap_javascript %}
<script src="/static/js/typeahead.js"></script>
<script src="/static/js/handlebars.js"></script>
<link rel="stylesheet" href="{% static "/css/base.css" %}"> <link rel="stylesheet" href="{% static "/css/base.css" %}">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ site_name }} : {% block title %}Accueil{% endblock %}</title> <title>{{ site_name }} : {% block title %}Accueil{% endblock %}</title>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment