8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-21 19:03:11 +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

@ -16,7 +16,7 @@ dessus, qui accèdent à la base de donnée en passant par django (ex : dhcp), e
chargeant la liste de toutes les mac-ip, ou la liste des mac-ip autorisées sur
le réseau (adhérent à jour de cotisation).
#Installation
# Installation
## Installation des dépendances

View file

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

View file

@ -154,12 +154,13 @@ def authorize(data):
else:
nas_type = None
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]
mac = data.get('Calling-Station-Id', '')
result, log, password = check_user_machine_and_register(nas_type, user, mac)
logger.info(log.encode('utf-8'))
logger.info(user.encode('utf-8'))
if not result:
return radiusd.RLM_MODULE_REJECT
else:
@ -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...", '')
elif not interface.is_active:
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:
return (True, u"Access ok", user.pwd_ntlm)
elif nas_type:
@ -324,9 +328,14 @@ 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)
else:
return (sw_name, u'Erreur dans le register mac %s' % reason + unicode(mac_address), VLAN_NOK)
elif not interface.first().is_active:
return (sw_name, u'Machine non active / adherent non cotisant', VLAN_NOK)
else:
return (sw_name, u'Machine OK' + extra_log, DECISION_VLAN)
interface = interface.first()
if not interface.is_active:
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:
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
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.
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**::
@ -82,19 +84,22 @@ def url_insert_param(url="", **kwargs):
# 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('&')
}
url, parameters = url.split('?', maxsplit=1)
for parameter in parameters.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
for key, value in kwargs.items():
params[key] = value
params[key] = [value]
# Write the url
url += '?'
for param, value in params.items():
url += str(param) + '=' + str(value) + '&'
for param, value_list in params.items():
for value in value_list:
url += str(param) + '=' + str(value) + '&'
# Remove the last '&' (or '?' if no parameters)
return url[:-1]

View file

@ -248,7 +248,7 @@ class SortTable:
if not fields:
fields = values.get('default', [])
request = request.order_by(*fields)
if order == 'desc':
if values.get(col, None) and order == 'desc':
return request.reverse()
else:
return request

View file

@ -21,8 +21,8 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 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 django.contrib import admin
# Register your models here.

View file

@ -20,21 +20,83 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""The forms used by the search app"""
from __future__ import unicode_literals
from django.db.models import Q
from simple_search import BaseSearchForm
from django import forms
from django.forms import Form
from users.models import User, School
CHOICES_USER = (
('0', 'Actifs'),
('1', 'Désactivés'),
('2', 'Archivés'),
)
class UserSearchForm(BaseSearchForm):
class Meta:
base_qs = User.objects
search_fields = ('^name', 'description', 'specifications', '=id')
CHOICES_AFF = (
('0', 'Utilisateurs'),
('1', 'Machines'),
('2', 'Factures'),
('3', 'Bannissements'),
('4', 'Accès à titre gracieux'),
('5', 'Chambres'),
('6', 'Ports'),
('7', 'Switchs'),
)
# assumes a fulltext index has been defined on the fields
# 'name,description,specifications,id'
fulltext_indexes = (
('name', 2), # name matches are weighted higher
('name,description,specifications,id', 1),
)
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 content %}
{% if users_list %}
{% if users %}
<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%}
{% if machines_list %}
{% if machines %}
<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 %}
{% if facture_list %}
{% if factures %}
<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 %}
{% if white_list %}
{% if whitelists %}
<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 %}
{% if ban_list %}
{% if bans %}
<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 %}
{% if switch_list %}
<h2>Résultats dans les switchs : </h2>
{% include "topologie/aff_switch.html" with switch_list=switch_list %}
{% if rooms %}
<h2>Résultats dans les chambres : </h2>
{% include "topologie/aff_chambres.html" with room_list=rooms %}
{% endif %}
{% if port_list %}
{% if ports %}
<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 %}
{% 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>
{% else %}
<h6>(Seulement les {{ max_result }} premiers résultats sont affichés dans chaque catégorie)</h6>
{% endif %}
<h6>(Seulement les {{ max_result }} premiers résultats sont affichés dans chaque catégorie)</h6>
<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 content %}
{% bootstrap_form_errors searchform %}
{% bootstrap_form_errors search_form %}
<form class="form" method="post">
{% csrf_token %}
{% bootstrap_form searchform %}
<form class="form">
{% bootstrap_field search_form.q %}
{% 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" %}
</form>
<br />

View file

@ -20,6 +20,8 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""The urls used by the search app"""
from __future__ import unicode_literals
from django.conf.urls import url
@ -28,5 +30,5 @@ from . import views
urlpatterns = [
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.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# App de recherche pour re2o
# Augustin lemesle, Gabriel Détraz, Goulven Kermarec
# Gplv2
"""The views for the search app, responsible for finding the matches
Augustin lemesle, Gabriel Détraz, Goulven Kermarec, Maël Kervella
Gplv2"""
from __future__ import unicode_literals
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.db.models import Q
from users.models import User, Ban, Whitelist
from machines.models import Machine, Interface
from topologie.models import Port, Switch
from machines.models import Machine
from topologie.models import Port, Switch, Room
from cotisations.models import Facture
from search.models import SearchForm, SearchFormPlus
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):
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}
def is_int(variable):
""" Check if the variable can be casted to an integer """
if request.user.has_perms(('cableur',)):
query = Q(user__pseudo__icontains = search) | Q(user__adherent__name__icontains = search) | Q(user__surname__icontains = search)
try:
int(variable)
except ValueError:
return False
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:
if i == '0':
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
if request.user.has_perms(('cableur',)):
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
def finish_results(results, col, order):
"""Sort the results by applying filters and then limit them to the
number of max results. Finally add the info of the nmax number of results
to the dict"""
for r in recherche:
if recherche[r] != None:
recherche[r] = recherche[r][:search_display_page]
results['users'] = SortTable.sort(
results['users'],
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
def search(request):
search = SearchForm(request.POST or None)
if search.is_valid():
return form(search_result(search, False, request), 'search/index.html',request)
return form({'searchform' : search}, 'search/search.html', request)
""" La page de recherche standard """
search_form = SearchForm(request.GET or None)
if search_form.is_valid():
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
def searchp(request):
search = SearchFormPlus(request.POST or None)
if search.is_valid():
return form(search_result(search, True, request), 'search/index.html',request)
return form({'searchform' : search}, 'search/search.html', request)
""" La page de recherche avancée """
search_form = SearchFormPlus(request.GET or None)
if search_form.is_valid():
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>
<body>
{% include "cookie_banner.html" %}
<div id="wrap">
<nav class="navbar navbar-inverse">
<div class="container-fluid">
@ -72,10 +73,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endif %}
</ul>
<div class="col-sm-3 col-md-3 navbar-right">
<form action="{% url "search:search"%}" method="POST" class="navbar-form" role="search">
{% csrf_token %}
<form action="{% url "search:search"%}" class="navbar-form" role="search">
<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">
<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>
@ -155,7 +155,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr>
<th scope="row">Adhésion</th>
<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>
{% else %}
<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">
<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>
</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 %}