From b9e633cf25e9d4dbb3503534d0872da02a38226a Mon Sep 17 00:00:00 2001 From: Jean-Romain Garnier Date: Fri, 24 Apr 2020 15:37:05 +0200 Subject: [PATCH] Add view to filter event logs --- logs/forms.py | 55 +++++++++++++++++++++- logs/models.py | 36 +++++++++++++- logs/templates/logs/search_stats_logs.html | 46 ++++++++++++++++++ logs/views.py | 37 +++++++++------ 4 files changed, 157 insertions(+), 17 deletions(-) create mode 100644 logs/templates/logs/search_stats_logs.html diff --git a/logs/forms.py b/logs/forms.py index 07e421c9..1ebfdcd4 100644 --- a/logs/forms.py +++ b/logs/forms.py @@ -25,15 +25,68 @@ from django.forms import Form from django.utils.translation import ugettext_lazy as _ from re2o.base import get_input_formats_help_text +import inspect + +# Import all models in which there are classes to be filtered on +import machines.models +import preferences.models +import tickets.models +import topologie.models +import users.models + + +def get_classes(module): + classes = [] + + for name, obj in inspect.getmembers(module): + if inspect.isclass(obj): + classes.append((obj, name)) + + return classes + + +# Get the list of all imported classes +modules = [machines.models, preferences.models, tickets.models, topologie.models, users.models] +classes = sum([get_classes(m) for m in modules]) + +CHOICES_ACTION_TYPE = classes + CHOICES_TYPE = ( ("ip", _("IPv4")), ("mac", _("MAC address")), ) +class ActionsSearchForm(Form): + """The form for a simple search""" + u = forms.CharField( + label=_("Performed by"), + max_length=100, + required=False, + queryset=users.models.User.objects.all() + ) + t = forms.MultipleChoiceField( + label=_("Action type"), + required=False, + widget=forms.CheckboxSelectMultiple, + choices=CHOICES_ACTION_TYPE, + initial=[i[0] for i in CHOICES_ACTION_TYPE], + ) + s = forms.DateField(required=False, label=_("Start date")) + e = forms.DateField(required=False, label=_("End date")) + + def __init__(self, *args, **kwargs): + super(MachineHistorySearchForm, self).__init__(*args, **kwargs) + self.fields["s"].help_text = get_input_formats_help_text( + self.fields["s"].input_formats + ) + self.fields["e"].help_text = get_input_formats_help_text( + self.fields["e"].input_formats + ) + + class MachineHistorySearchForm(Form): """The form for a simple search""" - q = forms.CharField( label=_("Search"), max_length=100, diff --git a/logs/models.py b/logs/models.py index b8789db8..cc261411 100644 --- a/logs/models.py +++ b/logs/models.py @@ -21,9 +21,10 @@ """logs.models The models definitions for the logs app """ -from reversion.models import Version +from reversion.models import Version, Revision from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import Group +from django.db.models import Q from machines.models import IpList from machines.models import Interface @@ -36,6 +37,39 @@ from topologie.models import Room from topologie.models import Port +class ActionsSearch: + def get(self, params): + """ + :param params: dict built by the search view + :return: QuerySet of Revision objects + """ + user = params.get("u", None) + start = params.get("s", None) + end = params.get("e", None) + actions_type = params.get("t", None) + + query = Q() + + if user: + query &= Q(user=user) + + if start: + query &= Q(date_created__geq=start) + + if end: + query &= Q(date_created__leq=end) + + if actions_type: + query &= Q(version_set__object__in=actions_type) + + return ( + Revision.objects.all() + .filter(query) + .select_related("user") + .prefetch_related("version_set__object") + ) + + class MachineHistorySearchEvent: def __init__(self, user, machine, interface, start=None, end=None): """ diff --git a/logs/templates/logs/search_stats_logs.html b/logs/templates/logs/search_stats_logs.html new file mode 100644 index 00000000..d0b56ea6 --- /dev/null +++ b/logs/templates/logs/search_stats_logs.html @@ -0,0 +1,46 @@ +{% extends 'logs/sidebar.html' %} +{% 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 © 2020 Jean-Romain Garnier + +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 bootstrap3 %} +{% load i18n %} + +{% block title %}{% trans "Search events" %}{% endblock %} + +{% block content %} + +
+

{% trans "Search events" %}

+ + {% bootstrap_field actions_form.u %} + {% bootstrap_field actions_form.t %} + {% bootstrap_field actions_form.s %} + {% bootstrap_field actions_form.e %} + {% trans "Search" as tr_search %} + {% bootstrap_button tr_search button_type="submit" icon="search" %} +
+
+
+
+
+
+{% endblock %} diff --git a/logs/views.py b/logs/views.py index ad78bd23..6075d928 100644 --- a/logs/views.py +++ b/logs/views.py @@ -102,13 +102,17 @@ from re2o.base import re2o_paginator, SortTable from re2o.acl import can_view_all, can_view_app, can_edit_history, can_view from .models import ( + ActionsSearch, MachineHistorySearch, UserHistory, MachineHistory, InterfaceHistory ) -from .forms import MachineHistorySearchForm +from .forms import ( + ActionsSearchForm, + MachineHistorySearchForm +) @login_required @@ -158,20 +162,23 @@ def index(request): def stats_logs(request): """Affiche l'ensemble des logs et des modifications sur les objets, classés par date croissante, en vrac""" - pagination_number = GeneralOption.get_cached_value("pagination_number") - revisions = ( - Revision.objects.all() - .select_related("user") - .prefetch_related("version_set__object") - ) - revisions = SortTable.sort( - revisions, - request.GET.get("col"), - request.GET.get("order"), - SortTable.LOGS_STATS_LOGS, - ) - revisions = re2o_paginator(request, revisions, pagination_number) - return render(request, "logs/stats_logs.html", {"revisions_list": revisions}) + actions_form = ActionsSearchForm(request.GET or None) + + if actions_form.is_valid(): + actions = ActionsSearch() + revisions = actions.get(actions_form.cleaned_data) + revisions = SortTable.sort( + revisions, + request.GET.get("col"), + request.GET.get("order"), + SortTable.LOGS_STATS_LOGS, + ) + + pagination_number = GeneralOption.get_cached_value("pagination_number") + revisions = re2o_paginator(request, revisions, pagination_number) + return render(request, "logs/stats_logs.html", {"revisions_list": revisions}) + + return render(request, "logs/search_stats_logs.html", {"actions_form": actions_form}) @login_required