8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-05 01:16:27 +00:00

Add views to get IP / MAC history

This commit is contained in:
Jean-Romain Garnier 2020-04-22 18:17:06 +02:00 committed by Gabriel Detraz
parent 6088f5c91b
commit ec22065a34
5 changed files with 358 additions and 0 deletions

57
logs/forms.py Normal file
View file

@ -0,0 +1,57 @@
# 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.
"""The forms used by the search app"""
from django import forms
from django.forms import Form
from django.utils.translation import ugettext_lazy as _
from re2o.base import get_input_formats_help_text
CHOICES_TYPE = (
("ip", _("IPv4")),
("mac", _("MAC")),
)
class MachineHistoryForm(Form):
"""The form for a simple search"""
q = forms.CharField(
label=_("Search"),
max_length=100,
)
t = forms.CharField(
label=_("Search type"),
widget=forms.Select,
choices=CHOICES_TYPE,
initial=0,
)
s = forms.DateField(required=False, label=_("Start date"))
e = forms.DateField(required=False, label=_("End date"))
def __init__(self, *args, **kwargs):
super(MachineHistoryForm, 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
)

169
logs/models.py Normal file
View file

@ -0,0 +1,169 @@
# -*- 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 © 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.
"""machines.models
The models definitions for the Machines app
"""
from reversion.models import Version
from machines.models import IpList
from machines.models import Interface
from machines.models import Machine
from users.models import User
class HistoryEvent:
def __init__(self, user: User, machine: Version, interface: Version, start=None, end=None):
self.user = user
self.machine = machine
self.interface = interface
self.ipv4 = IpList.objects.get(id=interface.field_dict["ipv4_id"]).ipv4
self.mac = self.interface.field_dict["mac_address"]
self.start_date = start
self.end_date = end
self.comment = interface.revision.get_comment() or None
def is_similar(self, elt2):
return (
elt2 is not None
and self.user.id == elt2.user.id
and self.ipv4 == elt2.ipv4
and self.machine.field_dict["id"] == elt2.machine.field_dict["id"]
and self.interface.field_dict["id"] == elt2.interface.field_dict["id"]
)
def __repr__(self):
return "{} ({} - ): from {} to {} ({})".format(
self.machine,
self.mac,
self.ipv4,
self.start_date,
self.end_date,
self.comment or "No comment"
)
class MachineHistory:
def __init__(self):
self.events = []
self.__last_evt = None
def get(self, search, params):
self.start = params.get("s", None)
self.end = params.get("e", None)
search_type = params.get("t", 0)
self.events = []
if search_type == "ip":
return self.__get_by_ip(search)
elif search_type == "mac":
return self.__get_by_mac(search)
return None
def __add_revision(self, user: User, machine: Version, interface: Version):
evt = HistoryEvent(user, machine, interface)
evt.start_date = interface.revision.date_created
# Try not to recreate events if unnecessary
if evt.is_similar(self.__last_evt):
return
# Mark the end of validity of the last element
if self.__last_evt and not self.__last_evt.end_date:
self.__last_evt.end_date = evt.start_date
# If the event ends before the given date, remove it
if self.start and evt.start_date < self.start:
self.__last_evt = None
self.events.pop()
# Make sure the new event starts before the given end date
if self.end and evt.start_date > self.end:
return
# Save the new element
self.events.append(evt)
self.__last_evt = evt
def __get_interfaces_for_ip(self, ip: str):
"""
Returns an iterable object with the Version objects
of Interfaces with the given IP
"""
# TODO: Deleted IpList
ip_id = IpList.objects.get(ipv4=ip).id
return filter(
lambda x: x.field_dict["ipv4_id"] == ip_id,
Version.objects.get_for_model(Interface).order_by("revision__date_created")
)
def __get_interfaces_for_mac(self, mac: str):
"""
Returns an iterable object with the Version objects
of Interfaces with the given MAC
"""
# TODO: What if IpList was deleted?
return filter(
lambda x: str(x.field_dict["mac_address"]) == mac,
Version.objects.get_for_model(Interface).order_by("revision__date_created")
)
def __get_machines_for_interface(self, interface: Version):
"""
Returns an iterable object with the Verison objects
of Machines to which the given interface was attributed
"""
machine_id = interface.field_dict["machine_id"]
return filter(
lambda x: x.field_dict["id"] == machine_id,
Version.objects.get_for_model(Machine).order_by("revision__date_created")
)
def __get_user_for_machine(self, machine: Version):
"""
Returns the user to which the given machine belongs
"""
# TODO: What if user was deleted?
user_id = machine.field_dict["user_id"]
return User.objects.get(id=user_id)
def __get_by_ip(self, ip: str):
interfaces = self.__get_interfaces_for_ip(ip)
for interface in interfaces:
machines = self.__get_machines_for_interface(interface)
for machine in machines:
user = self.__get_user_for_machine(machine)
self.__add_revision(user, machine, interface)
return self.events
def __get_by_mac(self, mac: str):
interfaces = self.__get_interfaces_for_mac(mac)
for interface in interfaces:
machines = self.__get_machines_for_interface(interface)
for machine in machines:
user = self.__get_user_for_machine(machine)
self.__add_revision(user, machine, interface)
return self.events

View file

@ -0,0 +1,59 @@
{% extends 'log/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 results" %}{% endblock %}
{% block content %}
{% if events %}
<table class="table table-striped">
<thead>
<tr>
<th>User</th>
<th>IPv4</th>
<th>MAC</th>
<th>Start date</th>
<th>End date</th>
<th>Comment</th>
</tr>
</thead>
{% for event in events %}
<tr>
<td>{{ event.user.pseudo }}</td>
<td>{{ event.ipv4 }}</td>
<td>{{ event.mac }}</td>
<td>{{ event.start_date }}</td>
<td>{{ event.end_date }}</td>
<td>{{ event.comment }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<h3>{% trans "No result" %}</h3>
{% endif %}
<br />
<br />
<br />
{% endblock %}

View file

@ -0,0 +1,48 @@
{% 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" %}{% endblock %}
{% block content %}
<form class="form">
{% bootstrap_field history_form.q %}
{% bootstrap_form_errors history_form.t %}
{% if history_form.s %}
{% bootstrap_field history_form.s %}
{% endif %}
{% if history_form.e %}
{% bootstrap_field history_form.e %}
{% endif %}
{% trans "Search" as tr_search %}
{% bootstrap_button tr_search button_type="submit" icon="search" %}
</form>
<br />
<br />
<br />
<br />
<br />
{% endblock %}

View file

@ -101,6 +101,9 @@ from re2o.utils import (
from re2o.base import re2o_paginator, SortTable from re2o.base import re2o_paginator, SortTable
from re2o.acl import can_view_all, can_view_app, can_edit_history from re2o.acl import can_view_all, can_view_app, can_edit_history
from .models import MachineHistory
from .forms import MachineHistoryForm
@login_required @login_required
@can_view_app("logs") @can_view_app("logs")
@ -478,6 +481,28 @@ def stats_actions(request):
return render(request, "logs/stats_users.html", {"stats_list": stats}) return render(request, "logs/stats_users.html", {"stats_list": stats})
@login_required
@can_view_app("users")
def search_machine_history(request):
"""Vue qui permet de rechercher l'historique des machines ayant utilisé
une IP ou une adresse MAC"""
history_form = MachineHistoryForm(request.GET or None)
if history_form.is_valid():
history = MachineHistory()
return render(
request,
"logs/machine_history.html",
{
"events":
history.get(
history_form.cleaned_data.get("q", ""),
history_form.cleaned_data
)
},
)
return render(request, "logs/search_machine_history.html", {"history_form": history_form})
def history(request, application, object_name, object_id): def history(request, application, object_name, object_id):
"""Render history for a model. """Render history for a model.