- {{ machine.name }}
+ {{ machine.name|default:'Pas de nom' }}
{{ machine.user }}
diff --git a/machines/views.py b/machines/views.py
index 69f41581..83cad204 100644
--- a/machines/views.py
+++ b/machines/views.py
@@ -117,7 +117,8 @@ from preferences.models import GeneralOption, OptionalMachine
from re2o.utils import (
all_active_assigned_interfaces,
all_has_access,
- filter_active_interfaces
+ filter_active_interfaces,
+ SortTable
)
from re2o.views import form
@@ -936,7 +937,13 @@ def del_nas(request):
def index(request):
options, created = GeneralOption.objects.get_or_create()
pagination_large_number = options.pagination_large_number
- machines_list = Machine.objects.select_related('user').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__ipv4__ip_type').prefetch_related('interface_set__type__ip_type__extension').prefetch_related('interface_set__domain__related_domain__extension').order_by('pk')
+ machines_list = Machine.objects.select_related('user').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__ipv4__ip_type').prefetch_related('interface_set__type__ip_type__extension').prefetch_related('interface_set__domain__related_domain__extension')
+ machines_list = SortTable.sort(
+ machines_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.MACHINES_INDEX
+ )
paginator = Paginator(machines_list, pagination_large_number)
page = request.GET.get('page')
try:
diff --git a/re2o/templatetags/url_insert_param.py b/re2o/templatetags/url_insert_param.py
new file mode 100644
index 00000000..7e37a71b
--- /dev/null
+++ b/re2o/templatetags/url_insert_param.py
@@ -0,0 +1,100 @@
+# -*- 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.
+
+"""
+Templatetag used to write a URL (specified or current one) and adding
+or inserting specific parameters into the query part without deleting
+the other parameters.
+"""
+
+from django import template
+
+register = template.Library()
+
+
+@register.simple_tag
+def url_insert_param(url="", **kwargs):
+ """
+ Return the URL with some specific parameters inserted into the query
+ part. If a URL has already some parameters, those requested will be
+ modified if already exisiting or will be added and the other parameters
+ will stay unmodified.
+
+ **Tag name**::
+
+ url_insert_param
+
+ **Parameters**:
+
+ url (optional)
+ The URL to use as a base. The parameters will be added to this URL.
+ If not specified, it will only return the query part of the URL
+ ("?a=foo&b=bar" for example).
+ Example : "https://example.com/bar?foo=0&thing=abc"
+
+ other arguments
+ Any other key-value argument will be used. The key is considered as
+ the name of the parameter to insert/modify and the value is the one
+ used.
+ Example : q="foo" search="bar" name="johnDoe"
+ will return as ?&q=foo&search=bar&name=johnDoe
+
+ **Usage**::
+
+ {% url_insert_param [URL] [param1=val1 [param2=val2 [...]]] %}
+
+ **Example**::
+
+ {% url_insert_param a=0 b="bar" %}
+ return "?a=0&b=bar"
+
+ {% url_insert_param "url.net/foo.html" a=0 b="bar" %}
+ return "url.net/foo.html?a=0&b=bar"
+
+ {% url_insert_param "url.net/foo.html?c=keep" a=0 b="bar" %}
+ return "url.net/foo.html?c=keep&a=0&b=bar"
+
+ {% url_insert_param "url.net/foo.html?a=del" a=0 b="bar" %}
+ return "url.net/foo.html?a=0&b=bar"
+
+ {% url_insert_param "url.net/foo.html?a=del&c=keep" a=0 b="bar" %}
+ return "url.net/foo.hmtl?a=0&c=keep&b=bar"
+ """
+
+ # Get existing parameters in the url
+ params = {}
+ if '?' in url:
+ url, params = url.split('?', maxsplit=1)
+ params = {
+ p[:p.find('=')]: p[p.find('=')+1:] for p in params.split('&')
+ }
+
+ # Add the request parameters to the list of parameters
+ for key, value in kwargs.items():
+ params[key] = value
+
+ # Write the url
+ url += '?'
+ for param, value in params.items():
+ url += str(param) + '=' + str(value) + '&'
+
+ # Remove the last '&' (or '?' if no parameters)
+ return url[:-1]
diff --git a/re2o/utils.py b/re2o/utils.py
index 8abee181..7ec29e87 100644
--- a/re2o/utils.py
+++ b/re2o/utils.py
@@ -139,3 +139,102 @@ def all_active_interfaces_count():
def all_active_assigned_interfaces_count():
""" Version light seulement pour compter"""
return all_active_interfaces_count().filter(ipv4__isnull=False)
+
+class SortTable:
+ """ Class gathering uselful stuff to sort the colums of a table, according
+ to the column and order requested. It's used with a dict of possible
+ values and associated model_fields """
+
+ # All the possible possible values
+ # The naming convention is based on the URL or the views function
+ # The syntax to describe the sort to apply is a dict where the keys are
+ # the url value and the values are a list of model field name to use to
+ # order the request. They are applied in the order they are given.
+ # A 'default' might be provided to specify what to do if the requested col
+ # doesn't match any keys.
+ USERS_INDEX = {
+ 'user_name': ['name'],
+ 'user_surname': ['surname'],
+ 'user_pseudo': ['pseudo'],
+ 'user_room': ['room'],
+ 'default': ['state', 'pseudo']
+ }
+ USERS_INDEX_BAN = {
+ 'ban_user': ['user__pseudo'],
+ 'ban_start': ['date_start'],
+ 'ban_end': ['date_end'],
+ 'default': ['-date_end']
+ }
+ USERS_INDEX_WHITE = {
+ 'white_user': ['user__pseudo'],
+ 'white_start': ['date_start'],
+ 'white_end': ['date_end'],
+ 'default': ['-date_end']
+ }
+ MACHINES_INDEX = {
+ 'machine_name': ['name'],
+ 'default': ['pk']
+ }
+ COTISATIONS_INDEX = {
+ 'cotis_user': ['user__pseudo'],
+ 'cotis_paiement': ['paiement__moyen'],
+ 'cotis_date': ['date'],
+ 'default': ['-date']
+ }
+ COTISATIONS_CONTROL = {
+ 'control_name': ['user__name'],
+ 'control_surname': ['user__surname'],
+ 'control_paiement': ['paiement'],
+ 'control_date': ['date'],
+ 'control_valid': ['valid'],
+ 'control_control': ['control'],
+ 'default': ['-date']
+ }
+ TOPOLOGIE_INDEX = {
+ 'switch_dns': ['switch_interface__domain__name'],
+ 'switch_ip': ['switch_interface__ipv4__ipv4'],
+ 'switch_loc': ['location'],
+ 'switch_ports': ['number'],
+ 'switch_stack': ['stack__name'],
+ 'default': ['location', 'stack', 'stack_member_id']
+ }
+ TOPOLOGIE_INDEX_PORT = {
+ 'port_port': ['port'],
+ 'port_room': ['room__name'],
+ 'port_interface': ['machine_interface__domain__name'],
+ 'port_related': ['related__switch__name'],
+ 'port_radius': ['radius'],
+ 'port_vlan': ['vlan_force__name'],
+ 'default': ['port']
+ }
+ TOPOLOGIE_INDEX_ROOM = {
+ 'room_name': ['name'],
+ 'default': ['name']
+ }
+ TOPOLOGIE_INDEX_STACK = {
+ 'stack_name': ['name'],
+ 'stack_id': ['stack_id'],
+ 'default': ['stack_id'],
+ }
+ LOGS_INDEX = {
+ 'sum_date': ['revision__date_created'],
+ 'default': ['-revision__date_created'],
+ }
+ LOGS_STATS_LOGS = {
+ 'logs_author': ['user__name'],
+ 'logs_date': ['date_created'],
+ 'default': ['-date_created']
+ }
+
+ @staticmethod
+ def sort(request, col, order, values):
+ """ Check if the given values are possible and add .order_by() and
+ a .reverse() as specified according to those values """
+ fields = values.get(col, None)
+ if not fields:
+ fields = values.get('default', [])
+ request = request.order_by(*fields)
+ if order == 'desc':
+ return request.reverse()
+ else:
+ return request
diff --git a/templates/buttons/sort.html b/templates/buttons/sort.html
new file mode 100644
index 00000000..e90fbd15
--- /dev/null
+++ b/templates/buttons/sort.html
@@ -0,0 +1,50 @@
+{% 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 url_insert_param %}
+
+{% spaceless %}
+
+ {{ text }}
+
+ {% if prefix %}
+ {% with prefix|add:'_'|add:col as colname %}
+
+
+
+
+
+
+ {% endwith %}
+ {% else %}
+
+
+
+
+
+
+ {% endif %}
+
+
+{% endspaceless %}
diff --git a/templates/pagination.html b/templates/pagination.html
index ba90fe13..7ebd26c1 100644
--- a/templates/pagination.html
+++ b/templates/pagination.html
@@ -22,20 +22,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
+{% load url_insert_param %}
+
diff --git a/topologie/templates/topologie/aff_chambres.html b/topologie/templates/topologie/aff_chambres.html
index d3393fc2..252ff808 100644
--- a/topologie/templates/topologie/aff_chambres.html
+++ b/topologie/templates/topologie/aff_chambres.html
@@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- Chambre |
+ {% include "buttons/sort.html" with prefix='room' col='name' text='Chambre' %} |
Commentaire |
|
diff --git a/topologie/templates/topologie/aff_port.html b/topologie/templates/topologie/aff_port.html
index 609d4349..6d1ca08e 100644
--- a/topologie/templates/topologie/aff_port.html
+++ b/topologie/templates/topologie/aff_port.html
@@ -25,12 +25,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- Port |
- Room |
- Interface machine |
- Related |
- Radius |
- Vlan forcé |
+ {% include "buttons/sort.html" with prefix='port' col='port' text='Port' %} |
+ {% include "buttons/sort.html" with prefix='port' col='room' text='Room' %} |
+ {% include "buttons/sort.html" with prefix='port' col='interface' text='Interface machine' %} |
+ {% include "buttons/sort.html" with prefix='port' col='related' text='Related' %} |
+ {% include "buttons/sort.html" with prefix='port' col='radius' text='Radius' %} |
+ {% include "buttons/sort.html" with prefix='port' col='vlan' text='Vlan forcé' %} |
Détails |
|
diff --git a/topologie/templates/topologie/aff_stacks.html b/topologie/templates/topologie/aff_stacks.html
index 586fd90a..1a9d316e 100644
--- a/topologie/templates/topologie/aff_stacks.html
+++ b/topologie/templates/topologie/aff_stacks.html
@@ -25,9 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- Stack |
- ID |
- Details |
+ {% include "buttons/sort.html" with prefix='stack' col='name' text='Stack' %} |
+ {% include "buttons/sort.html" with prefix='stack' col='id' text='ID' %} |
+ Détails |
Membres |
diff --git a/topologie/templates/topologie/aff_switch.html b/topologie/templates/topologie/aff_switch.html
index 611e6c39..f503798e 100644
--- a/topologie/templates/topologie/aff_switch.html
+++ b/topologie/templates/topologie/aff_switch.html
@@ -25,12 +25,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- Dns |
- Ipv4 |
- Localisation |
- Ports |
- Stack |
- id interne Stack |
+ {% include "buttons/sort.html" with prefix='switch' col='dns' text='Dns' %} |
+ {% include "buttons/sort.html" with prefix='switch' col='ip' text='Ipv4' %} |
+ {% include "buttons/sort.html" with prefix='switch' col='loc' text='Localisation' %} |
+ {% include "buttons/sort.html" with prefix='switch' col='ports' text='Ports' %} |
+ {% include "buttons/sort.html" with prefix='switch' col='stack' text='Stack' %} |
+ Id interne stack |
Détails |
|
diff --git a/topologie/views.py b/topologie/views.py
index 5eb2de74..dec681b6 100644
--- a/topologie/views.py
+++ b/topologie/views.py
@@ -49,7 +49,7 @@ from topologie.models import Switch, Port, Room, Stack
from topologie.forms import EditPortForm, NewSwitchForm, EditSwitchForm
from topologie.forms import AddPortForm, EditRoomForm, StackForm
from users.views import form
-
+from re2o.utils import SortTable
from machines.forms import DomainForm, NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm
from machines.views import generate_ipv4_mbf_param
from preferences.models import AssoOption, GeneralOption
@@ -59,15 +59,17 @@ from preferences.models import AssoOption, GeneralOption
@permission_required('cableur')
def index(request):
""" Vue d'affichage de tous les swicthes"""
- switch_list = Switch.objects.order_by(
- 'stack',
- 'stack_member_id',
- 'location'
- )\
+ switch_list = Switch.objects\
.select_related('switch_interface__domain__extension')\
.select_related('switch_interface__ipv4')\
.select_related('switch_interface__domain')\
.select_related('stack')
+ switch_list = SortTable.sort(
+ switch_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.TOPOLOGIE_INDEX
+ )
return render(request, 'topologie/index.html', {
'switch_list': switch_list
})
@@ -137,8 +139,13 @@ def index_port(request, switch_id):
.select_related('machine_interface__domain__extension')\
.select_related('machine_interface__machine__user')\
.select_related('related__switch__switch_interface__domain__extension')\
- .select_related('switch')\
- .order_by('port')
+ .select_related('switch')
+ port_list = SortTable.sort(
+ port_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.TOPOLOGIE_INDEX_PORT
+ )
return render(request, 'topologie/index_p.html', {
'port_list': port_list,
'id_switch': switch_id,
@@ -150,7 +157,13 @@ def index_port(request, switch_id):
@permission_required('cableur')
def index_room(request):
""" Affichage de l'ensemble des chambres"""
- room_list = Room.objects.order_by('name')
+ room_list = Room.objects
+ room_list = SortTable.sort(
+ room_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.TOPOLOGIE_INDEX_ROOM
+ )
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
paginator = Paginator(room_list, pagination_number)
@@ -172,8 +185,14 @@ def index_room(request):
@permission_required('infra')
def index_stack(request):
"""Affichage de la liste des stacks (affiche l'ensemble des switches)"""
- stack_list = Stack.objects.order_by('name')\
+ stack_list = Stack.objects\
.prefetch_related('switch_set__switch_interface__domain__extension')
+ stack_list = SortTable.sort(
+ stack_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.TOPOLOGIE_INDEX_STACK
+ )
return render(request, 'topologie/index_stack.html', {
'stack_list': stack_list
})
diff --git a/users/templates/users/aff_bans.html b/users/templates/users/aff_bans.html
index 693a7539..78834123 100644
--- a/users/templates/users/aff_bans.html
+++ b/users/templates/users/aff_bans.html
@@ -29,10 +29,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- Utilisateur |
+ {% include "buttons/sort.html" with prefix='ban' col="user" text="Utilisateur" %} |
Raison |
- Date de début |
- Date de fin |
+ {% include "buttons/sort.html" with prefix='ban' col="start" text="Date de début" %} |
+ {% include "buttons/sort.html" with prefix='ban' col="end" text="Date de fin" %} |
|
diff --git a/users/templates/users/aff_users.html b/users/templates/users/aff_users.html
index b4ded1f2..c03cfa74 100644
--- a/users/templates/users/aff_users.html
+++ b/users/templates/users/aff_users.html
@@ -29,10 +29,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- Prénom |
- Nom |
- Pseudo |
- Chambre |
+ {% include "buttons/sort.html" with prefix='user' col="name" text="Prénom" %} |
+ {% include "buttons/sort.html" with prefix='user' col="surname" text="Nom" %} |
+ {% include "buttons/sort.html" with prefix='user' col="pseudo" text="Pseudo" %} |
+ {% include "buttons/sort.html" with prefix='user' col="room" text="Chambre" %} |
Fin de cotisation le |
Connexion |
Profil |
diff --git a/users/templates/users/aff_whitelists.html b/users/templates/users/aff_whitelists.html
index 6665ad27..07d434c0 100644
--- a/users/templates/users/aff_whitelists.html
+++ b/users/templates/users/aff_whitelists.html
@@ -29,10 +29,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- Utilisateur |
+ {% include "buttons/sort.html" with prefix='white' col="user" text="Utilisateur" %} |
Raison |
- Date de début |
- Date de fin |
+ {% include "buttons/sort.html" with prefix='white' col="start" text="Date de début" %} |
+ {% include "buttons/sort.html" with prefix='white' col="end" text="Date de fin" %} |
|
diff --git a/users/views.py b/users/views.py
index 5b0b3910..d8d4be62 100644
--- a/users/views.py
+++ b/users/views.py
@@ -65,7 +65,7 @@ from machines.models import Machine
from preferences.models import OptionalUser, GeneralOption
from re2o.views import form
-from re2o.utils import all_has_access
+from re2o.utils import all_has_access, SortTable
def password_change_action(u_form, user, request, req=False):
""" Fonction qui effectue le changeemnt de mdp bdd"""
@@ -575,7 +575,13 @@ def index(request):
""" Affiche l'ensemble des users, need droit cableur """
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
- users_list = User.objects.select_related('room').order_by('state', 'name')
+ users_list = User.objects.select_related('room')
+ users_list = SortTable.sort(
+ users_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.USERS_INDEX
+ )
paginator = Paginator(users_list, pagination_number)
page = request.GET.get('page')
try:
@@ -595,8 +601,13 @@ def index_ban(request):
""" Affiche l'ensemble des ban, need droit cableur """
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
- ban_list = Ban.objects.order_by('date_start')\
- .select_related('user').reverse()
+ ban_list = Ban.objects.select_related('user')
+ ban_list = SortTable.sort(
+ ban_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.USERS_INDEX_BAN
+ )
paginator = Paginator(ban_list, pagination_number)
page = request.GET.get('page')
try:
@@ -616,8 +627,13 @@ def index_white(request):
""" Affiche l'ensemble des whitelist, need droit cableur """
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
- white_list = Whitelist.objects.select_related('user')\
- .order_by('date_start')
+ white_list = Whitelist.objects.select_related('user')
+ white_list = SortTable.sort(
+ white_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.USERS_INDEX_BAN
+ )
paginator = Paginator(white_list, pagination_number)
page = request.GET.get('page')
try:
@@ -776,9 +792,33 @@ def profil(request, userid):
.prefetch_related('interface_set__ipv4__ip_type__extension')\
.prefetch_related('interface_set__type')\
.prefetch_related('interface_set__domain__related_domain__extension')
+ machines = SortTable.sort(
+ machines,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.MACHINES_INDEX
+ )
factures = Facture.objects.filter(user=users)
+ factures = SortTable.sort(
+ factures,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.COTISATIONS_INDEX
+ )
bans = Ban.objects.filter(user=users)
+ bans = SortTable.sort(
+ bans,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.USERS_INDEX_BAN
+ )
whitelists = Whitelist.objects.filter(user=users)
+ whitelists = SortTable.sort(
+ whitelists,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.USERS_INDEX_WHITE
+ )
list_droits = Right.objects.filter(user=users)
options, _created = OptionalUser.objects.get_or_create()
user_solde = options.user_solde
|