Commit 0e9baa60 authored by root's avatar root

Merge branch 'master' of https://gitlab.rezometz.org/rezo/re2o

parents 7935b653 8599cfd7
...@@ -36,7 +36,9 @@ def url_insert_param(url="", **kwargs): ...@@ -36,7 +36,9 @@ def url_insert_param(url="", **kwargs):
Return the URL with some specific parameters inserted into the query Return the URL with some specific parameters inserted into the query
part. If a URL has already some parameters, those requested will be part. If a URL has already some parameters, those requested will be
modified if already exisiting or will be added and the other parameters modified if already exisiting or will be added and the other parameters
will stay unmodified. will stay unmodified. If parameters with the same name are already in the
URL and a value is specified for this parameter, it will replace all
existing parameters.
**Tag name**:: **Tag name**::
...@@ -82,19 +84,22 @@ def url_insert_param(url="", **kwargs): ...@@ -82,19 +84,22 @@ def url_insert_param(url="", **kwargs):
# Get existing parameters in the url # Get existing parameters in the url
params = {} params = {}
if '?' in url: if '?' in url:
url, params = url.split('?', maxsplit=1) url, parameters = url.split('?', maxsplit=1)
params = { for parameter in parameters.split('&'):
p[:p.find('=')]: p[p.find('=')+1:] for p in params.split('&') p_name, p_value = parameter.split('=', maxsplit=1)
} if p_name not in params:
params[p_name] = []
params[p_name].append(p_value)
# Add the request parameters to the list of parameters # Add the request parameters to the list of parameters
for key, value in kwargs.items(): for key, value in kwargs.items():
params[key] = value params[key] = [value]
# Write the url # Write the url
url += '?' url += '?'
for param, value in params.items(): for param, value_list in params.items():
url += str(param) + '=' + str(value) + '&' for value in value_list:
url += str(param) + '=' + str(value) + '&'
# Remove the last '&' (or '?' if no parameters) # Remove the last '&' (or '?' if no parameters)
return url[:-1] return url[:-1]
...@@ -248,7 +248,7 @@ class SortTable: ...@@ -248,7 +248,7 @@ class SortTable:
if not fields: if not fields:
fields = values.get('default', []) fields = values.get('default', [])
request = request.order_by(*fields) request = request.order_by(*fields)
if order == 'desc': if values.get(col, None) and order == 'desc':
return request.reverse() return request.reverse()
else: else:
return request return request
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import unicode_literals """The field used in the admin view for the search app"""
from django.contrib import admin from __future__ import unicode_literals
# Register your models here. # Register your models here.
...@@ -20,21 +20,72 @@ ...@@ -20,21 +20,72 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""The forms used by the search app"""
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db.models import Q from django import forms
from simple_search import BaseSearchForm from django.forms import Form
CHOICES_USER = (
('0', 'Actifs'),
('1', 'Désactivés'),
('2', 'Archivés'),
)
CHOICES_AFF = (
('0', 'Utilisateurs'),
('1', 'Machines'),
('2', 'Factures'),
('3', 'Bannissements'),
('4', 'Accès à titre gracieux'),
('5', 'Chambres'),
('6', 'Ports'),
('7', 'Switchs'),
)
def initial_choices(c):
"""Return the choices that should be activated by default for a
given set of choices"""
return [i[0] for i in c]
from users.models import User, School class SearchForm(Form):
"""The form for a simple search"""
q = forms.CharField(label='Search', max_length=100)
class UserSearchForm(BaseSearchForm):
class Meta:
base_qs = User.objects
search_fields = ('^name', 'description', 'specifications', '=id')
# assumes a fulltext index has been defined on the fields class SearchFormPlus(Form):
# 'name,description,specifications,id' """The form for an advanced search (with filters)"""
fulltext_indexes = ( q = forms.CharField(
('name', 2), # name matches are weighted higher label='Search',
('name,description,specifications,id', 1), max_length=100,
) required=False
)
u = forms.MultipleChoiceField(
label="Filtre utilisateurs",
required=False,
widget=forms.CheckboxSelectMultiple,
choices=CHOICES_USER,
initial=initial_choices(CHOICES_USER)
)
a = forms.MultipleChoiceField(
label="Filtre affichage",
required=False,
widget=forms.CheckboxSelectMultiple,
choices=CHOICES_AFF,
initial=initial_choices(CHOICES_AFF)
)
s = forms.DateField(
required=False,
label="Date de début",
help_text='DD/MM/YYYY',
input_formats=['%d/%m/%Y']
)
e = forms.DateField(
required=False,
help_text='DD/MM/YYYY',
input_formats=['%d/%m/%Y'],
label="Date de fin"
)
# -*- 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 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.
from __future__ import unicode_literals
from django.db import models
from django import forms
from django.forms import Form
from django.forms import ModelForm
CHOICES = (
('0', 'Actifs'),
('1', 'Désactivés'),
('2', 'Archivés'),
)
CHOICES2 = (
(1, 'Active'),
("", 'Désactivée'),
)
CHOICES3 = (
('0', 'Utilisateurs'),
('1', 'Machines'),
('2', 'Factures'),
('3', 'Bannissements'),
('4', 'Accès à titre gracieux'),
('6', 'Switchs'),
('5', 'Ports'),
)
class SearchForm(Form):
search_field = forms.CharField(label = 'Search', max_length = 100)
class SearchFormPlus(Form):
search_field = forms.CharField(label = 'Search', max_length = 100, required=False)
filtre = forms.MultipleChoiceField(label="Filtre utilisateurs", required=False, widget =forms.CheckboxSelectMultiple,choices=CHOICES)
connexion = forms.MultipleChoiceField(label="Filtre connexion", required=False, widget =forms.CheckboxSelectMultiple,choices=CHOICES2)
affichage = forms.MultipleChoiceField(label="Filtre affichage", required=False, widget =forms.CheckboxSelectMultiple,choices=CHOICES3)
date_deb = forms.DateField(required=False, label="Date de début", help_text='DD/MM/YYYY', input_formats=['%d/%m/%Y'])
date_fin = forms.DateField(required=False, help_text='DD/MM/YYYY', input_formats=['%d/%m/%Y'], label="Date de fin")
...@@ -36,30 +36,35 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -36,30 +36,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<h2>Résultats dans les machines : </h2> <h2>Résultats dans les machines : </h2>
{% include "machines/aff_machines.html" with machines_list=machines_list %} {% include "machines/aff_machines.html" with machines_list=machines_list %}
{% endif %} {% endif %}
{% if facture_list %} {% if factures_list %}
<h2>Résultats dans les factures : </h2> <h2>Résultats dans les factures : </h2>
{% include "cotisations/aff_cotisations.html" with facture_list=facture_list %} {% include "cotisations/aff_cotisations.html" with facture_list=factures_list %}
{% endif %} {% endif %}
{% if white_list %} {% if whitelists_list %}
<h2>Résultats dans les accès à titre gracieux : </h2> <h2>Résultats dans les accès à titre gracieux : </h2>
{% include "users/aff_whitelists.html" with white_list=white_list %} {% include "users/aff_whitelists.html" with white_list=whitelists_list %}
{% endif %} {% endif %}
{% if ban_list %} {% if bans_list %}
<h2>Résultats dans les banissements : </h2> <h2>Résultats dans les banissements : </h2>
{% include "users/aff_bans.html" with ban_list=ban_list %} {% include "users/aff_bans.html" with ban_list=bans_list %}
{% endif %} {% endif %}
{% if switch_list %} {% if rooms_list %}
<h2>Résultats dans les switchs : </h2> <h2>Résultats dans les chambres : </h2>
{% include "topologie/aff_switch.html" with switch_list=switch_list %} {% include "topologie/aff_chambres.html" with room_list=rooms_list %}
{% endif %} {% endif %}
{% if port_list %} {% if switch_ports_list %}
<h2>Résultats dans les ports : </h2> <h2>Résultats dans les ports : </h2>
{% include "topologie/aff_port.html" with port_list=port_list %} {% include "topologie/aff_port.html" with port_list=switch_ports_list %}
{% endif %}
{% if switches_list %}
<h2>Résultats dans les switchs : </h2>
{% include "topologie/aff_switch.html" with switch_list=switches_list %}
{% endif %} {% endif %}
{% if not ban_list and not interfaces_list and not users_list and not facture_list and not white_list and not port_list and not switch_list%} {% if not users_list and not machines_list and not factures_list and not whitelists_list and not bans_list and not rooms_list and not switch_ports_list and not switches_list %}
<h3>Aucun résultat</h3> <h3>Aucun résultat</h3>
{% else %}
<h6>(Seulement les {{ max_result }} premiers résultats sont affichés dans chaque catégorie)</h6>
{% endif %} {% endif %}
<h6>(Seulement les {{ max_result }} premiers résultats sont affichés dans chaque catégorie)</h6>
<br /> <br />
<br /> <br />
<br /> <br />
......
...@@ -28,11 +28,14 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -28,11 +28,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}Recherche{% endblock %} {% block title %}Recherche{% endblock %}
{% block content %} {% block content %}
{% bootstrap_form_errors searchform %} {% bootstrap_form_errors search_form %}
<form class="form" method="post"> <form class="form">
{% csrf_token %} {% bootstrap_field search_form.q %}
{% bootstrap_form searchform %} {% include "buttons/multiple_checkbox_alt.html" with field=search_form.u %}
{% include "buttons/multiple_checkbox_alt.html" with field=search_form.a %}
{% bootstrap_field search_form.s %}
{% bootstrap_field search_form.e %}
{% bootstrap_button "Search" button_type="submit" icon="search" %} {% bootstrap_button "Search" button_type="submit" icon="search" %}
</form> </form>
<br /> <br />
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""The urls used by the search app"""
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf.urls import url from django.conf.urls import url
...@@ -28,5 +30,5 @@ from . import views ...@@ -28,5 +30,5 @@ from . import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.search, name='search'), url(r'^$', views.search, name='search'),
url(r'^avance/$', views.searchp, name='searchp'), url(r'^advanced/$', views.searchp, name='searchp'),
] ]
...@@ -20,115 +20,326 @@ ...@@ -20,115 +20,326 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# App de recherche pour re2o """The views for the search app, responsible for finding the matches
# Augustin lemesle, Gabriel Détraz, Goulven Kermarec Augustin lemesle, Gabriel Détraz, Goulven Kermarec, Maël Kervella
# Gplv2 Gplv2"""
from __future__ import unicode_literals from __future__ import unicode_literals
from django.shortcuts import render from django.shortcuts import render
from django.shortcuts import get_object_or_404
from django.template.context_processors import csrf
from django.template import Context, RequestContext, loader
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.db.models import Q from django.db.models import Q
from users.models import User, Ban, Whitelist from users.models import User, Ban, Whitelist
from machines.models import Machine, Interface from machines.models import Machine
from topologie.models import Port, Switch from topologie.models import Port, Switch, Room
from cotisations.models import Facture from cotisations.models import Facture
from search.models import SearchForm, SearchFormPlus
from preferences.models import GeneralOption from preferences.models import GeneralOption
from search.forms import (
SearchForm,
SearchFormPlus,
CHOICES_USER,
CHOICES_AFF,
initial_choices
)
from re2o.utils import SortTable
def is_int(variable):
""" Check if the variable can be casted to an integer """
def form(ctx, template, request): try:
c = ctx int(variable)
c.update(csrf(request)) except ValueError:
return render(request, template, c) return False
def search_result(search, type, request):
date_deb = None
date_fin = None
states=[]
co=[]
aff=[]
if(type):
aff = search.cleaned_data['affichage']
co = search.cleaned_data['connexion']
states = search.cleaned_data['filtre']
date_deb = search.cleaned_data['date_deb']
date_fin = search.cleaned_data['date_fin']
date_query = Q()
if aff==[]:
aff = ['0','1','2','3','4','5','6']
if date_deb != None:
date_query = date_query & Q(date__gte=date_deb)
if date_fin != None:
date_query = date_query & Q(date__lte=date_fin)
search = search.cleaned_data['search_field']
query1 = Q()
for s in states:
query1 = query1 | Q(state = s)
connexion = []
recherche = {'users_list': None, 'machines_list' : [], 'facture_list' : None, 'ban_list' : None, 'white_list': None, 'port_list': None, 'switch_list': None}
if request.user.has_perms(('cableur',)):
query = Q(user__pseudo__icontains = search) | Q(user__adherent__name__icontains = search) | Q(user__surname__icontains = search)
else: else:
query = (Q(user__pseudo__icontains = search) | Q(user__adherent__name__icontains = search) | Q(user__surname__icontains = search)) & Q(user = request.user) return True
for i in aff: def get_results(query, request, filters={}):
if i == '0': """ Construct the correct filters to match differents fields of some models
query_user_list = Q(adherent__room__name__icontains = search) | Q(club__room__name__icontains = search) | Q(pseudo__icontains = search) | Q(adherent__name__icontains = search) | Q(surname__icontains = search) & query1 with the given query according to the given filters.
if request.user.has_perms(('cableur',)): The match field are either CharField or IntegerField that will be displayed
recherche['users_list'] = User.objects.filter(query_user_list).order_by('state', 'surname').distinct() on the results page (else, one might not see why a result has matched the
else : query). IntegerField are matched against the query only if it can be casted
recherche['users_list'] = User.objects.filter(query_user_list & Q(id=request.user.id)).order_by('state', 'surname').distinct() to an int."""
if i == '1':
query_machine_list = Q(machine__user__pseudo__icontains = search) | Q(machine__user__adherent__name__icontains = search) | Q(machine__user__surname__icontains = search) | Q(mac_address__icontains = search) | Q(ipv4__ipv4__icontains = search) | Q(domain__name__icontains = search) | Q(domain__related_domain__name__icontains = search) start = filters.get('s', None)
if request.user.has_perms(('cableur',)): end = filters.get('e', None)
data = Interface.objects.filter(query_machine_list).distinct() user_state = filters.get('u', initial_choices(CHOICES_USER))
else: aff = filters.get('a', initial_choices(CHOICES_AFF))
data = Interface.objects.filter(query_machine_list & Q(machine__user__id = request.user.id)).distinct()
for d in data: options, _ = GeneralOption.objects.get_or_create()
recherche['machines_list'].append(d.machine) max_result = options.search_display_page
if i == '2':
recherche['facture_list'] = Facture.objects.filter(query & date_query).distinct() results = {
if i == '3': 'users_list': User.objects.none(),
recherche['ban_list'] = Ban.objects.filter(query).distinct() 'machines_list': Machine.objects.none(),
if i == '4': 'factures_list': Facture.objects.none(),
recherche['white_list'] = Whitelist.objects.filter(query).distinct() 'bans_list': Ban.objects.none(),
if i == '5': 'whitelists_list': Whitelist.objects.none(),
recherche['port_list'] = Port.objects.filter(details__icontains = search).distinct() 'rooms_list': Room.objects.none(),
if not request.user.has_perms(('cableur',)): 'switch_ports_list': Port.objects.none(),
recherche['port_list'] = None 'switches_list': Switch.objects.none()
if i == '6': }
recherche['switch_list'] = Switch.objects.filter(details__icontains = search).distinct()
if not request.user.has_perms(('cableur',)): # Users
recherche['switch_list'] = None if '0' in aff:
options, created = GeneralOption.objects.get_or_create() filter_user_list = (
search_display_page = options.search_display_page Q(
surname__icontains=query
for r in recherche: ) | Q(
if recherche[r] != None: adherent__name__icontains=query
recherche[r] = recherche[r][:search_display_page] ) | Q(
pseudo__icontains=query
recherche.update({'max_result': search_display_page}) ) | Q(
club__room__name__icontains=query
return recherche ) | Q(
adherent__room__name__icontains=query
)
) & Q(state__in=user_state)
if not request.user.has_perms(('cableur',)):
filter_user_list &= Q(id=request.user.id)
results['users_list'] = User.objects.filter(filter_user_list)
results['users_list'] = SortTable.sort(
results['users_list'],
request.GET.get('col'),
request.GET.get('order'),
SortTable.USERS_INDEX
)
# Machines
if '1' in aff:
filter_machine_list = Q(
name__icontains=query
) | (
Q(
user__pseudo__icontains=query
) & Q(
user__state__in=user_state
)
) | Q(
interface__domain__name__icontains=query
) | Q(
interface__domain__related_domain__name__icontains=query
) | Q(
interface__mac_address__icontains=query
) | Q(
interface__ipv4__ipv4__icontains=query
)
if not request.user.has_perms(('cableur',)):
filter_machine_list &= Q(user__id=request.user.id)
results['machines_list'] = Machine.objects.filter(filter_machine_list)
results['machines_list'] = SortTable.sort(
results['machines_list'],
request.GET.get('col'),
request.GET.get('order'),
SortTable.MACHINES_INDEX
)
# Factures
if '2' in aff:
filter_facture_list = Q(
user__pseudo__icontains=query
) & Q(
user__state__in=user_state
)
if start is not None:
filter_facture_list &= Q(date__gte=start)
if end is not None:
filter_facture_list &= Q(date__lte=end)
results['factures_list'] = Facture.objects.filter(filter_facture_list)
results['factures_list'] = SortTable.sort(
results['factures_list'],
request.GET.get('col'),
request.GET.get('order'),
SortTable.COTISATIONS_INDEX
)
# Bans
if '3' in aff:
date_filter = (
Q(
user__pseudo__icontains=query
) & Q(
user__state__in=user_state
)
) | Q(
raison__icontains=query
)
if start is not None:
date_filter &= (
Q(date_start__gte=start) & Q(date_end__gte=start)
) | (
Q(date_start__lte=start) & Q(date_end__gte=start)
) | (
Q(date_start__gte=start) & Q(date_end__lte=start)
)
if end is not None:
date_filter &= (
Q(date_start__lte=end) & Q(date_end__lte=end)
) | (
Q(date_start__lte=end) & Q(date_end__gte=end)
) | (
Q(date_start__gte=end) & Q(date_end__lte=end)
)
results['bans_list'] = Ban.objects.filter(date_filter)
results['bans_list'] = SortTable.sort(
results['bans_list'],
request.GET.get('col'),
request.GET.get('order'),
SortTable.USERS_INDEX_BAN
)
# Whitelists
if '4' in aff:
date_filter = (
Q(
user__pseudo__icontains=query
) & Q(
user__state__in=user_state