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

Merge branch 'master' into refactor_history

This commit is contained in:
root 2017-11-14 00:58:10 +01:00
commit 6a1dfacb47
16 changed files with 625 additions and 208 deletions

21
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,21 @@
---
image: debian:stretch
stages:
- lint
lint:
stage: lint
variables:
LANG: 'en_US.UTF-8'
LC_ALL: 'en_US.UTF-8'
LANGUAGE: 'en_US.UTF-8'
script:
- apt-get -qq update
- DEBIAN_FRONTEND=noninteractive apt-get -qq install -y locales python3-pip python3-django
- sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- pip3 install -q pylint-django
- pylint --load-plugins pylint_django cotisations machines re2o logs topologie preferences search users || if [ $? -ne 1 ]; then exit 0; else exit 1; fi

View file

@ -56,8 +56,10 @@ class NewFactureForm(ModelForm):
self.fields['banque'].empty_label = "Non renseigné" self.fields['banque'].empty_label = "Non renseigné"
self.fields['paiement'].empty_label = "Séléctionner\ self.fields['paiement'].empty_label = "Séléctionner\
un moyen de paiement" un moyen de paiement"
self.fields['paiement'].widget.attrs['data-cheque'] = Paiement.objects\ paiement_list = Paiement.objects.filter(type_paiement=1)
.filter(type_paiement=1).first().id if paiement_list:
self.fields['paiement'].widget\
.attrs['data-cheque'] = paiement_list.first().id
class Meta: class Meta:
model = Facture model = Facture

View file

@ -154,11 +154,12 @@ def authorize(data):
else: else:
nas_type = None nas_type = None
if not nas_type or nas_type.port_access_mode == '802.1X': if not nas_type or nas_type.port_access_mode == '802.1X':
user = data.get('User-Name', '') user = data.get('User-Name', '').decode('utf-8', errors='replace')
user = user.split('@', 1)[0] user = user.split('@', 1)[0]
mac = data.get('Calling-Station-Id', '') mac = data.get('Calling-Station-Id', '')
result, log, password = check_user_machine_and_register(nas_type, user, mac) result, log, password = check_user_machine_and_register(nas_type, user, mac)
logger.info(log.encode('utf-8')) logger.info(log.encode('utf-8'))
logger.info(user.encode('utf-8'))
if not result: if not result:
return radiusd.RLM_MODULE_REJECT return radiusd.RLM_MODULE_REJECT
@ -247,6 +248,9 @@ def check_user_machine_and_register(nas_type, username, mac_address):
return (False, u"Machine enregistrée sur le compte d'un autre user...", '') return (False, u"Machine enregistrée sur le compte d'un autre user...", '')
elif not interface.is_active: elif not interface.is_active:
return (False, u"Machine desactivée", '') return (False, u"Machine desactivée", '')
elif not interface.ipv4:
interface.assign_ipv4()
return (True, u"Ok, Reassignation de l'ipv4", user.pwd_ntlm)
else: else:
return (True, u"Access ok", user.pwd_ntlm) return (True, u"Access ok", user.pwd_ntlm)
elif nas_type: elif nas_type:
@ -324,8 +328,13 @@ def decide_vlan_and_register_switch(nas, nas_type, port_number, mac_address):
return (sw_name, u'Access Ok, Capture de la mac...' + extra_log, DECISION_VLAN) return (sw_name, u'Access Ok, Capture de la mac...' + extra_log, DECISION_VLAN)
else: else:
return (sw_name, u'Erreur dans le register mac %s' % reason + unicode(mac_address), VLAN_NOK) return (sw_name, u'Erreur dans le register mac %s' % reason + unicode(mac_address), VLAN_NOK)
elif not interface.first().is_active: else:
interface = interface.first()
if not interface.is_active:
return (sw_name, u'Machine non active / adherent non cotisant', VLAN_NOK) return (sw_name, u'Machine non active / adherent non cotisant', VLAN_NOK)
elif not interface.ipv4:
interface.assign_ipv4()
return (sw_name, u"Ok, Reassignation de l'ipv4" + extra_log, DECISION_VLAN)
else: else:
return (sw_name, u'Machine OK' + extra_log, DECISION_VLAN) return (sw_name, u'Machine OK' + extra_log, DECISION_VLAN)

View file

@ -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,18 +84,21 @@ 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():
for value in value_list:
url += str(param) + '=' + str(value) + '&' url += str(param) + '=' + str(value) + '&'
# Remove the last '&' (or '?' if no parameters) # Remove the last '&' (or '?' if no parameters)

View file

@ -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

View file

@ -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.
"""The field used in the admin view for the search app"""
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib import admin
# Register your models here. # Register your models here.

View file

@ -20,21 +20,83 @@
# 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
from users.models import User, School CHOICES_USER = (
('0', 'Actifs'),
class UserSearchForm(BaseSearchForm): ('1', 'Désactivés'),
class Meta: ('2', 'Archivés'),
base_qs = User.objects )
search_fields = ('^name', 'description', 'specifications', '=id')
CHOICES_AFF = (
# assumes a fulltext index has been defined on the fields ('0', 'Utilisateurs'),
# 'name,description,specifications,id' ('1', 'Machines'),
fulltext_indexes = ( ('2', 'Factures'),
('name', 2), # name matches are weighted higher ('3', 'Bannissements'),
('name,description,specifications,id', 1), ('4', 'Accès à titre gracieux'),
('5', 'Chambres'),
('6', 'Ports'),
('7', 'Switchs'),
)
def initial_choices(choice_set):
"""Return the choices that should be activated by default for a
given set of choices"""
return [i[0] for i in choice_set]
class SearchForm(Form):
"""The form for a simple search"""
q = forms.CharField(
label='Recherche',
help_text=(
'Utilisez « » et «,» pour spécifier différents mots, «"query"» '
'pour une recherche exacte et «\\» pour échapper un caractère.'
),
max_length=100
)
class SearchFormPlus(Form):
"""The form for an advanced search (with filters)"""
q = forms.CharField(
label='Recherche',
help_text=(
'Utilisez « » et «,» pour spécifier différents mots, «"query"» '
'pour une recherche exacte et «\\» pour échapper un caractère.'
),
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"
) )

View file

@ -1,62 +0,0 @@
# -*- 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")

View file

@ -28,38 +28,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}Résultats de la recherche{% endblock %} {% block title %}Résultats de la recherche{% endblock %}
{% block content %} {% block content %}
{% if users_list %} {% if users %}
<h2>Résultats dans les utilisateurs</h2> <h2>Résultats dans les utilisateurs</h2>
{% include "users/aff_users.html" with users_list=users_list %} {% include "users/aff_users.html" with users_list=users %}
{% endif%} {% endif%}
{% if machines_list %} {% if machines %}
<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 %}
{% endif %} {% endif %}
{% if facture_list %} {% if factures %}
<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 %}
{% endif %} {% endif %}
{% if white_list %} {% if whitelists %}
<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 %}
{% endif %} {% endif %}
{% if ban_list %} {% if bans %}
<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 %}
{% endif %} {% endif %}
{% if switch_list %} {% if rooms %}
<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 %}
{% endif %} {% endif %}
{% if port_list %} {% if ports %}
<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=ports %}
{% 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 switches %}
<h2>Résultats dans les switchs : </h2>
{% include "topologie/aff_switch.html" with switch_list=switches %}
{% endif %}
{% if not users and not machines and not factures and not whitelists and not bans and not rooms and not ports and not switches %}
<h3>Aucun résultat</h3> <h3>Aucun résultat</h3>
{% endif %} {% else %}
<h6>(Seulement les {{ max_result }} premiers résultats sont affichés dans chaque catégorie)</h6> <h6>(Seulement les {{ max_result }} premiers résultats sont affichés dans chaque catégorie)</h6>
{% endif %}
<br /> <br />
<br /> <br />
<br /> <br />

View file

@ -28,11 +28,22 @@ 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 %} {% if search_form.u %}
{% include "buttons/multiple_checkbox_alt.html" with field=search_form.u %}
{% endif %}
{% if search_form.a %}
{% include "buttons/multiple_checkbox_alt.html" with field=search_form.a %}
{% endif %}
{% if search_form.s %}
{% bootstrap_field search_form.s %}
{% endif %}
{% if search_form.e %}
{% bootstrap_field search_form.e %}
{% endif %}
{% bootstrap_button "Search" button_type="submit" icon="search" %} {% bootstrap_button "Search" button_type="submit" icon="search" %}
</form> </form>
<br /> <br />

View file

@ -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
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'),
] ]

View file

@ -20,115 +20,418 @@
# 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 form(ctx, template, request):
c = ctx
c.update(csrf(request))
return render(request, template, c)
def search_result(search, type, request): def is_int(variable):
date_deb = None """ Check if the variable can be casted to an integer """
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 = [] try:
int(variable)
recherche = {'users_list': None, 'machines_list' : [], 'facture_list' : None, 'ban_list' : None, 'white_list': None, 'port_list': None, 'switch_list': None} except ValueError:
return False
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 finish_results(results, col, order):
if i == '0': """Sort the results by applying filters and then limit them to the
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 number of max results. Finally add the info of the nmax number of results
if request.user.has_perms(('cableur',)): to the dict"""
recherche['users_list'] = User.objects.filter(query_user_list).order_by('state', 'surname').distinct()
else :
recherche['users_list'] = User.objects.filter(query_user_list & Q(id=request.user.id)).order_by('state', 'surname').distinct()
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)
if request.user.has_perms(('cableur',)):
data = Interface.objects.filter(query_machine_list).distinct()
else:
data = Interface.objects.filter(query_machine_list & Q(machine__user__id = request.user.id)).distinct()
for d in data:
recherche['machines_list'].append(d.machine)
if i == '2':
recherche['facture_list'] = Facture.objects.filter(query & date_query).distinct()
if i == '3':
recherche['ban_list'] = Ban.objects.filter(query).distinct()
if i == '4':
recherche['white_list'] = Whitelist.objects.filter(query).distinct()
if i == '5':
recherche['port_list'] = Port.objects.filter(details__icontains = search).distinct()
if not request.user.has_perms(('cableur',)):
recherche['port_list'] = None
if i == '6':
recherche['switch_list'] = Switch.objects.filter(details__icontains = search).distinct()
if not request.user.has_perms(('cableur',)):
recherche['switch_list'] = None
options, created = GeneralOption.objects.get_or_create()
search_display_page = options.search_display_page
for r in recherche: results['users'] = SortTable.sort(
if recherche[r] != None: results['users'],
recherche[r] = recherche[r][:search_display_page] col,
order,
SortTable.USERS_INDEX
)
results['machines'] = SortTable.sort(
results['machines'],
col,
order,
SortTable.MACHINES_INDEX
)
results['factures'] = SortTable.sort(
results['factures'],
col,
order,
SortTable.COTISATIONS_INDEX
)
results['bans'] = SortTable.sort(
results['bans'],
col,
order,
SortTable.USERS_INDEX_BAN
)
results['whitelists'] = SortTable.sort(
results['whitelists'],
col,
order,
SortTable.USERS_INDEX_WHITE
)
results['rooms'] = SortTable.sort(
results['rooms'],
col,
order,
SortTable.TOPOLOGIE_INDEX_ROOM
)
results['ports'] = SortTable.sort(
results['ports'],
col,
order,
SortTable.TOPOLOGIE_INDEX_PORT
)
results['switches'] = SortTable.sort(
results['switches'],
col,
order,
SortTable.TOPOLOGIE_INDEX
)
recherche.update({'max_result': search_display_page}) options, _ = GeneralOption.objects.get_or_create()
max_result = options.search_display_page
for name, val in results.items():
results[name] = val.distinct()[:max_result]
results.update({'max_result': max_result})
return results
def search_single_word(word, filters, is_cableur, user_id,
start, end, user_state, aff):
""" Construct the correct filters to match differents fields of some models
with the given query according to the given filters.
The match field are either CharField or IntegerField that will be displayed
on the results page (else, one might not see why a result has matched the
query). IntegerField are matched against the query only if it can be casted
to an int."""
# Users
if '0' in aff:
filter_users = (
Q(
surname__icontains=word
) | Q(
adherent__name__icontains=word
) | Q(
pseudo__icontains=word
) | Q(
club__room__name__icontains=word
) | Q(
adherent__room__name__icontains=word
)
) & Q(state__in=user_state)
if not is_cableur:
filter_users &= Q(id=user_id)
filters['users'] |= filter_users
# Machines
if '1' in aff:
filter_machines = Q(
name__icontains=word
) | (
Q(
user__pseudo__icontains=word
) & Q(
user__state__in=user_state
)
) | Q(
interface__domain__name__icontains=word
) | Q(
interface__domain__related_domain__name__icontains=word
) | Q(
interface__mac_address__icontains=word
) | Q(
interface__ipv4__ipv4__icontains=word
)
if not is_cableur:
filter_machines &= Q(user__id=user_id)
filters['machines'] |= filter_machines
# Factures
if '2' in aff:
filter_factures = Q(
user__pseudo__icontains=word
) & Q(
user__state__in=user_state
)
if start is not None:
filter_factures &= Q(date__gte=start)
if end is not None:
filter_factures &= Q(date__lte=end)
filters['factures'] |= filter_factures
# Bans
if '3' in aff:
filter_bans = (
Q(
user__pseudo__icontains=word
) & Q(
user__state__in=user_state
)
) | Q(
raison__icontains=word
)
if start is not None:
filter_bans &= (
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:
filter_bans &= (
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)
)
filters['bans'] |= filter_bans
# Whitelists
if '4' in aff:
filter_whitelists = (
Q(
user__pseudo__icontains=word
) & Q(
user__state__in=user_state
)
) | Q(
raison__icontains=word
)
if start is not None:
filter_whitelists &= (
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:
filter_whitelists &= (
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)
)
filters['whitelists'] |= filter_whitelists
# Rooms
if '5' in aff and is_cableur:
filter_rooms = Q(
details__icontains=word
) | Q(
name__icontains=word
) | Q(
port__details=word
)
filters['rooms'] |= filter_rooms
# Switch ports
if '6' in aff and is_cableur:
filter_ports = Q(
room__name__icontains=word
) | Q(
machine_interface__domain__name__icontains=word
) | Q(
related__switch__switch_interface__domain__name__icontains=word
) | Q(
radius__icontains=word
) | Q(
vlan_force__name__icontains=word
) | Q(
details__icontains=word
)
if is_int(word):
filter_ports |= Q(
port=word
)
filters['ports'] |= filter_ports
# Switches
if '7' in aff and is_cableur:
filter_switches = Q(
switch_interface__domain__name__icontains=word
) | Q(
switch_interface__ipv4__ipv4__icontains=word
) | Q(
location__icontains=word
) | Q(
stack__name__icontains=word
) | Q(
model__reference__icontains=word
) | Q(
model__constructor__name__icontains=word
) | Q(
details__icontains=word
)
if is_int(word):
filter_switches |= Q(
number=word
) | Q(
stack_member_id=word
)
filters['switches'] |= filter_switches
return filters
def get_words(query):
"""Function used to split the uery in different words to look for.
The rules are simple :
- anti-slash ('\\') is used to escape characters
- anything between quotation marks ('"') is kept intact (not
interpreted as separators) excepts anti-slashes used to escape
- spaces (' ') and commas (',') are used to separated words
"""
words = []
i = 0
keep_intact = False
escaping_char = False
for char in query:
if i >= len(words):
# We are starting a new word
words.append('')
if escaping_char:
# The last char war a \ so we escape this char
escaping_char = False
words[i] += char
continue
if char == '\\':
# We need to escape the next char
escaping_char = True
continue
if char == '"':
# Toogle the keep_intact state, if true, we are between two "
keep_intact = not keep_intact
continue
if keep_intact:
# If we are between two ", ignore separators
words[i] += char
continue
if char == ' ' or char == ',':
# If we encouter a separator outside of ", we create a new word
if words[i] is not '':
i += 1
continue
# If we haven't encountered any special case, add the char to the word
words[i] += char
return words
def get_results(query, request, params):
"""The main function of the search procedure. It gather the filters for
each of the different words of the query and concatenate them into a
single filter. Then it calls 'finish_results' and return the queryset of
objects to display as results"""
start = params.get('s', None)
end = params.get('e', None)
user_state = params.get('u', initial_choices(CHOICES_USER))
aff = params.get('a', initial_choices(CHOICES_AFF))
filters = {
'users': Q(),
'machines': Q(),
'factures': Q(),
'bans': Q(),
'whitelists': Q(),
'rooms': Q(),
'ports': Q(),
'switches': Q()
}
words = get_words(query)
for word in words:
filters = search_single_word(
word,
filters,
request.user.has_perms(('cableur',)),
request.user.id,
start,
end,
user_state,
aff
)
results = {
'users': User.objects.filter(filters['users']),
'machines': Machine.objects.filter(filters['machines']),
'factures': Facture.objects.filter(filters['factures']),
'bans': Ban.objects.filter(filters['bans']),
'whitelists': Whitelist.objects.filter(filters['whitelists']),
'rooms': Room.objects.filter(filters['rooms']),
'ports': Port.objects.filter(filters['ports']),
'switches': Switch.objects.filter(filters['switches'])
}
results = finish_results(
results,
request.GET.get('col'),
request.GET.get('order')
)
results.update({'search_term': query})
return results
return recherche
@login_required @login_required
def search(request): def search(request):
search = SearchForm(request.POST or None) """ La page de recherche standard """
if search.is_valid(): search_form = SearchForm(request.GET or None)
return form(search_result(search, False, request), 'search/index.html',request) if search_form.is_valid():
return form({'searchform' : search}, 'search/search.html', request) return render(
request,
'search/index.html',
get_results(
search_form.cleaned_data.get('q', ''),
request,
search_form.cleaned_data
)
)
return render(request, 'search/search.html', {'search_form': search_form})
@login_required @login_required
def searchp(request): def searchp(request):
search = SearchFormPlus(request.POST or None) """ La page de recherche avancée """
if search.is_valid(): search_form = SearchFormPlus(request.GET or None)
return form(search_result(search, True, request), 'search/index.html',request) if search_form.is_valid():
return form({'searchform' : search}, 'search/search.html', request) return render(
request,
'search/index.html',
get_results(
search_form.cleaned_data.get('q', ''),
request,
search_form.cleaned_data
)
)
return render(request, 'search/search.html', {'search_form': search_form})

View file

@ -49,6 +49,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</head> </head>
<body> <body>
{% include "cookie_banner.html" %}
<div id="wrap"> <div id="wrap">
<nav class="navbar navbar-inverse"> <nav class="navbar navbar-inverse">
<div class="container-fluid"> <div class="container-fluid">
@ -72,10 +73,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endif %} {% endif %}
</ul> </ul>
<div class="col-sm-3 col-md-3 navbar-right"> <div class="col-sm-3 col-md-3 navbar-right">
<form action="{% url "search:search"%}" method="POST" class="navbar-form" role="search"> <form action="{% url "search:search"%}" class="navbar-form" role="search">
{% csrf_token %}
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control" placeholder="Search" name="search_field" id="search-term"> <input type="text" class="form-control" placeholder="Search" name="q" id="search-term" {% if search_term %}value="{{ search_term }}"{% endif %}>
<div class="input-group-btn"> <div class="input-group-btn">
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button> <button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
<a href="{% url "search:searchp" %}" class="btn btn-default" role="button"><i class="glyphicon glyphicon-plus"></i></a> <a href="{% url "search:searchp" %}" class="btn btn-default" role="button"><i class="glyphicon glyphicon-plus"></i></a>
@ -155,7 +155,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th scope="row">Adhésion</th> <th scope="row">Adhésion</th>
<td class="text-right"> <td class="text-right">
{% if request_user.end_adhesion != None %} {% if request_user.is_adherent %}
<font color="green">jusqu'au {{ request_user.end_adhesion|date:"d b Y" }}</font> <font color="green">jusqu'au {{ request_user.end_adhesion|date:"d b Y" }}</font>
{% else %} {% else %}
<font color="red">Non adhérent</font> <font color="red">Non adhérent</font>
@ -198,7 +198,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<footer class="navbar"> <footer class="navbar">
<div class="containerfluid text-center"> <div class="containerfluid text-center">
<p>Re2o 2016 - Gabriel Détraz, <a href="https://gitlab.rezometz.org/lhark">Goulven Kermarec</a>, Augustin Lemesle</p> <p>Re2o 2016 - Gabriel Détraz, <a href="https://gitlab.rezometz.org/lhark">Goulven Kermarec</a>, Augustin Lemesle, Maël Kervella</p>
</div> </div>
</footer> </footer>

View file

@ -0,0 +1,40 @@
{% 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 %}
<div class="form-group {% if field.form.errors %}{% if field.errors %}has-error{% else %}has-success{% endif %}{% endif %}">
<label class="control-label" for="{{ field.id_for_label }}">
{{ field.label }}
</label>
<div id="{{ field.auto_id }}" data-toggle="buttons">
{% for val in field.field.choices %}
<label for="id_u_{{ val.0 }}" class="btn btn-default{% if val.0 in field.initial %} active{% endif %}">
<input {% if val.0 in field.initial %}checked="checked" {% endif %}class="" id="id_u_{{ val.0 }}" name="{{ field.name }}" title="" type="checkbox" value="{{ val.0 }}" /> {{ val.1 }}
</label>
{% endfor %}
</div>
{% for error in field.errors %}
<div class="help-block">{{ error }}</div>
{% endfor %}
<div class="help-block">{{ field.help_text }}</div>
</div>

View file

@ -0,0 +1,19 @@
{% if not 'accept_cookies' in request.COOKIES%}
<script>
function accept_cookie() {
var d = new Date();
var expiration_time = 7 * 24 * 60 * 60 * 1000; // Accepte les cookies pendant 7 jours.
d.setTime(d.getTime() + expiration_time);
var expires = "expires="+ d.toUTCString();
document.cookie = "accept_cookies=1;" + expires + ";path=/";
var banner = document.getElementById("cookie_banner");
banner.parentNode.removeChild(banner);
}
</script>
<div class="navbar text-center" id="cookie_banner">
<p>Ce site utilise des cookies. En poursuivant sur ce site j'accepte l'utilisation des cookies sur ce site.</p>
<a class="btn btn-primary btn-sm" role="button" onclick="accept_cookie();" title="Accepter">
J'ai compris !
</a>
</div>
{% endif %}