mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-08 00:28:16 -06:00
Closes #1571: extras_useraction to log remote_addr
This commit is contained in:
parent
6378b95e0b
commit
246d9b8620
@ -25,6 +25,7 @@ from utilities.views import (
|
|||||||
BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, ComponentDeleteView,
|
BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, ComponentDeleteView,
|
||||||
ComponentEditView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
ComponentEditView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||||
)
|
)
|
||||||
|
from utilities.utils import get_ip_address
|
||||||
from . import filters, forms, tables
|
from . import filters, forms, tables
|
||||||
from .models import (
|
from .models import (
|
||||||
CONNECTION_STATUS_CONNECTED, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device,
|
CONNECTION_STATUS_CONNECTED, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device,
|
||||||
@ -1030,7 +1031,7 @@ def consoleport_connect(request, pk):
|
|||||||
escape(consoleport.cs_port.name),
|
escape(consoleport.cs_port.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, consoleport, msg)
|
UserAction.objects.log_edit(request.user, consoleport, msg, get_ip_address(request))
|
||||||
return redirect('dcim:device', pk=consoleport.device.pk)
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1075,7 +1076,7 @@ def consoleport_disconnect(request, pk):
|
|||||||
escape(cs_port.name),
|
escape(cs_port.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, consoleport, msg)
|
UserAction.objects.log_edit(request.user, consoleport, msg, get_ip_address(request))
|
||||||
return redirect('dcim:device', pk=consoleport.device.pk)
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1150,7 +1151,7 @@ def consoleserverport_connect(request, pk):
|
|||||||
escape(consoleserverport.name),
|
escape(consoleserverport.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, consoleport, msg)
|
UserAction.objects.log_edit(request.user, consoleport, msg, get_ip_address(request))
|
||||||
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1195,7 +1196,7 @@ def consoleserverport_disconnect(request, pk):
|
|||||||
escape(consoleserverport.name),
|
escape(consoleserverport.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, consoleport, msg)
|
UserAction.objects.log_edit(request.user, consoleport, msg, get_ip_address(request))
|
||||||
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1269,7 +1270,7 @@ def powerport_connect(request, pk):
|
|||||||
escape(powerport.power_outlet.name),
|
escape(powerport.power_outlet.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, powerport, msg)
|
UserAction.objects.log_edit(request.user, powerport, msg, get_ip_address(request))
|
||||||
return redirect('dcim:device', pk=powerport.device.pk)
|
return redirect('dcim:device', pk=powerport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1314,7 +1315,7 @@ def powerport_disconnect(request, pk):
|
|||||||
escape(power_outlet.name),
|
escape(power_outlet.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, powerport, msg)
|
UserAction.objects.log_edit(request.user, powerport, msg, get_ip_address(request))
|
||||||
return redirect('dcim:device', pk=powerport.device.pk)
|
return redirect('dcim:device', pk=powerport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1389,7 +1390,7 @@ def poweroutlet_connect(request, pk):
|
|||||||
escape(poweroutlet.name),
|
escape(poweroutlet.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, powerport, msg)
|
UserAction.objects.log_edit(request.user, powerport, msg, get_ip_address(request))
|
||||||
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1434,7 +1435,7 @@ def poweroutlet_disconnect(request, pk):
|
|||||||
escape(poweroutlet.name),
|
escape(poweroutlet.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, powerport, msg)
|
UserAction.objects.log_edit(request.user, powerport, msg, get_ip_address(request))
|
||||||
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1709,7 +1710,7 @@ def interfaceconnection_add(request, pk):
|
|||||||
escape(interfaceconnection.interface_b.name),
|
escape(interfaceconnection.interface_b.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, interfaceconnection, msg)
|
UserAction.objects.log_edit(request.user, interfaceconnection, msg, get_ip_address(request))
|
||||||
|
|
||||||
if '_addanother' in request.POST:
|
if '_addanother' in request.POST:
|
||||||
base_url = reverse('dcim:interfaceconnection_add', kwargs={'pk': device.pk})
|
base_url = reverse('dcim:interfaceconnection_add', kwargs={'pk': device.pk})
|
||||||
@ -1757,7 +1758,7 @@ def interfaceconnection_delete(request, pk):
|
|||||||
escape(interfaceconnection.interface_b.name),
|
escape(interfaceconnection.interface_b.name),
|
||||||
)
|
)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_edit(request.user, interfaceconnection, msg)
|
UserAction.objects.log_edit(request.user, interfaceconnection, msg, get_ip_address(request))
|
||||||
if form.cleaned_data['device']:
|
if form.cleaned_data['device']:
|
||||||
return redirect('dcim:device', pk=form.cleaned_data['device'].pk)
|
return redirect('dcim:device', pk=form.cleaned_data['device'].pk)
|
||||||
else:
|
else:
|
||||||
|
20
netbox/extras/migrations/0009_useraction_ip_address.py
Executable file
20
netbox/extras/migrations/0009_useraction_ip_address.py
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.1 on 2017-10-12 07:53
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('extras', '0008_reports'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='useraction',
|
||||||
|
name='ip_address',
|
||||||
|
field=models.GenericIPAddressField(null=True, unpack_ipv4=True),
|
||||||
|
),
|
||||||
|
]
|
@ -414,44 +414,46 @@ class ReportResult(models.Model):
|
|||||||
class UserActionManager(models.Manager):
|
class UserActionManager(models.Manager):
|
||||||
|
|
||||||
# Actions affecting a single object
|
# Actions affecting a single object
|
||||||
def log_action(self, user, obj, action, message):
|
def log_action(self, user, obj, action, message, ip_address):
|
||||||
self.model.objects.create(
|
self.model.objects.create(
|
||||||
content_type=ContentType.objects.get_for_model(obj),
|
content_type=ContentType.objects.get_for_model(obj),
|
||||||
object_id=obj.pk,
|
object_id=obj.pk,
|
||||||
user=user,
|
user=user,
|
||||||
action=action,
|
action=action,
|
||||||
message=message,
|
message=message,
|
||||||
|
ip_address=ip_address,
|
||||||
)
|
)
|
||||||
|
|
||||||
def log_create(self, user, obj, message=''):
|
def log_create(self, user, obj, message, ip_address):
|
||||||
self.log_action(user, obj, ACTION_CREATE, message)
|
self.log_action(user, obj, ACTION_CREATE, message, ip_address)
|
||||||
|
|
||||||
def log_edit(self, user, obj, message=''):
|
def log_edit(self, user, obj, message, ip_address):
|
||||||
self.log_action(user, obj, ACTION_EDIT, message)
|
self.log_action(user, obj, ACTION_EDIT, message, ip_address)
|
||||||
|
|
||||||
def log_delete(self, user, obj, message=''):
|
def log_delete(self, user, obj, message, ip_address):
|
||||||
self.log_action(user, obj, ACTION_DELETE, message)
|
self.log_action(user, obj, ACTION_DELETE, message, ip_address)
|
||||||
|
|
||||||
# Actions affecting multiple objects
|
# Actions affecting multiple objects
|
||||||
def log_bulk_action(self, user, content_type, action, message):
|
def log_bulk_action(self, user, content_type, action, message, ip_address):
|
||||||
self.model.objects.create(
|
self.model.objects.create(
|
||||||
content_type=content_type,
|
content_type=content_type,
|
||||||
user=user,
|
user=user,
|
||||||
action=action,
|
action=action,
|
||||||
message=message,
|
message=message,
|
||||||
|
ip_address=ip_address,
|
||||||
)
|
)
|
||||||
|
|
||||||
def log_import(self, user, content_type, message=''):
|
def log_import(self, user, content_type, message, ip_address):
|
||||||
self.log_bulk_action(user, content_type, ACTION_IMPORT, message)
|
self.log_bulk_action(user, content_type, ACTION_IMPORT, message, ip_address)
|
||||||
|
|
||||||
def log_bulk_create(self, user, content_type, message=''):
|
def log_bulk_create(self, user, content_type, message, ip_address):
|
||||||
self.log_bulk_action(user, content_type, ACTION_BULK_CREATE, message)
|
self.log_bulk_action(user, content_type, ACTION_BULK_CREATE, message, ip_address)
|
||||||
|
|
||||||
def log_bulk_edit(self, user, content_type, message=''):
|
def log_bulk_edit(self, user, content_type, message, ip_address):
|
||||||
self.log_bulk_action(user, content_type, ACTION_BULK_EDIT, message)
|
self.log_bulk_action(user, content_type, ACTION_BULK_EDIT, message, ip_address)
|
||||||
|
|
||||||
def log_bulk_delete(self, user, content_type, message=''):
|
def log_bulk_delete(self, user, content_type, message, ip_address):
|
||||||
self.log_bulk_action(user, content_type, ACTION_BULK_DELETE, message)
|
self.log_bulk_action(user, content_type, ACTION_BULK_DELETE, message, ip_address)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
@ -465,6 +467,7 @@ class UserAction(models.Model):
|
|||||||
object_id = models.PositiveIntegerField(blank=True, null=True)
|
object_id = models.PositiveIntegerField(blank=True, null=True)
|
||||||
action = models.PositiveSmallIntegerField(choices=ACTION_CHOICES)
|
action = models.PositiveSmallIntegerField(choices=ACTION_CHOICES)
|
||||||
message = models.TextField(blank=True)
|
message = models.TextField(blank=True)
|
||||||
|
ip_address = models.GenericIPAddressField(null=True, unpack_ipv4=True)
|
||||||
|
|
||||||
objects = UserActionManager()
|
objects = UserActionManager()
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ from django.views.generic import View
|
|||||||
|
|
||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.views import ObjectDeleteView, ObjectEditView
|
from utilities.views import ObjectDeleteView, ObjectEditView
|
||||||
|
from utilities.utils import get_ip_address
|
||||||
from .forms import ImageAttachmentForm
|
from .forms import ImageAttachmentForm
|
||||||
from .models import ImageAttachment, ReportResult, UserAction
|
from .models import ImageAttachment, ReportResult, UserAction
|
||||||
from .reports import get_report, get_reports
|
from .reports import get_report, get_reports
|
||||||
@ -113,6 +114,6 @@ class ReportRunView(PermissionRequiredMixin, View):
|
|||||||
result = 'failed' if report.failed else 'passed'
|
result = 'failed' if report.failed else 'passed'
|
||||||
msg = "Ran report {} ({})".format(report.full_name, result)
|
msg = "Ran report {} ({})".format(report.full_name, result)
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
UserAction.objects.log_create(request.user, report.result, msg)
|
UserAction.objects.log_create(request.user, report.result, msg, get_ip_address(request))
|
||||||
|
|
||||||
return redirect('extras:report', name=report.full_name)
|
return redirect('extras:report', name=report.full_name)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Time</th>
|
<th>Time</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
|
<th>IP Address</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -15,6 +16,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ action.time|date:'SHORT_DATETIME_FORMAT' }}</td>
|
<td>{{ action.time|date:'SHORT_DATETIME_FORMAT' }}</td>
|
||||||
<td>{{ action.icon }} {{ action.message|safe }}</td>
|
<td>{{ action.icon }} {{ action.message|safe }}</td>
|
||||||
|
<td>{% if action.ip_address %}{{ action.ip_address }}{% endif %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -37,3 +37,12 @@ def foreground_color(bg_color):
|
|||||||
return '000000'
|
return '000000'
|
||||||
else:
|
else:
|
||||||
return 'ffffff'
|
return 'ffffff'
|
||||||
|
|
||||||
|
|
||||||
|
def get_ip_address(request):
|
||||||
|
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||||
|
if x_forwarded_for:
|
||||||
|
ip_address = x_forwarded_for.split(',')[0]
|
||||||
|
else:
|
||||||
|
ip_address = request.META.get('REMOTE_ADDR')
|
||||||
|
return ip_address
|
||||||
|
@ -22,6 +22,7 @@ from django.views.generic import View
|
|||||||
|
|
||||||
from extras.models import CustomField, CustomFieldValue, ExportTemplate, UserAction
|
from extras.models import CustomField, CustomFieldValue, ExportTemplate, UserAction
|
||||||
from utilities.forms import BootstrapMixin, CSVDataField
|
from utilities.forms import BootstrapMixin, CSVDataField
|
||||||
|
from utilities.utils import get_ip_address
|
||||||
from .error_handlers import handle_protectederror
|
from .error_handlers import handle_protectederror
|
||||||
from .forms import ConfirmationForm
|
from .forms import ConfirmationForm
|
||||||
from .paginator import EnhancedPaginator
|
from .paginator import EnhancedPaginator
|
||||||
@ -210,9 +211,9 @@ class ObjectEditView(GetReturnURLMixin, View):
|
|||||||
msg = '{} {}'.format(msg, escape(obj))
|
msg = '{} {}'.format(msg, escape(obj))
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
if obj_created:
|
if obj_created:
|
||||||
UserAction.objects.log_create(request.user, obj, msg)
|
UserAction.objects.log_create(request.user, obj, msg, get_ip_address(request))
|
||||||
else:
|
else:
|
||||||
UserAction.objects.log_edit(request.user, obj, msg)
|
UserAction.objects.log_edit(request.user, obj, msg, get_ip_address(request))
|
||||||
|
|
||||||
if '_addanother' in request.POST:
|
if '_addanother' in request.POST:
|
||||||
return redirect(request.get_full_path())
|
return redirect(request.get_full_path())
|
||||||
@ -275,7 +276,7 @@ class ObjectDeleteView(GetReturnURLMixin, View):
|
|||||||
|
|
||||||
msg = 'Deleted {} {}'.format(self.model._meta.verbose_name, obj)
|
msg = 'Deleted {} {}'.format(self.model._meta.verbose_name, obj)
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
UserAction.objects.log_delete(request.user, obj, msg)
|
UserAction.objects.log_delete(request.user, obj, msg, get_ip_address(request))
|
||||||
|
|
||||||
return_url = form.cleaned_data.get('return_url')
|
return_url = form.cleaned_data.get('return_url')
|
||||||
if return_url is not None and is_safe_url(url=return_url, host=request.get_host()):
|
if return_url is not None and is_safe_url(url=return_url, host=request.get_host()):
|
||||||
@ -355,7 +356,7 @@ class BulkCreateView(View):
|
|||||||
# If we make it to this point, validation has succeeded on all new objects.
|
# If we make it to this point, validation has succeeded on all new objects.
|
||||||
msg = "Added {} {}".format(len(new_objs), model._meta.verbose_name_plural)
|
msg = "Added {} {}".format(len(new_objs), model._meta.verbose_name_plural)
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
UserAction.objects.log_bulk_create(request.user, ContentType.objects.get_for_model(model), msg)
|
UserAction.objects.log_bulk_create(request.user, ContentType.objects.get_for_model(model), msg, get_ip_address(request))
|
||||||
|
|
||||||
if '_addanother' in request.POST:
|
if '_addanother' in request.POST:
|
||||||
return redirect(request.path)
|
return redirect(request.path)
|
||||||
@ -440,7 +441,7 @@ class BulkImportView(View):
|
|||||||
if new_objs:
|
if new_objs:
|
||||||
msg = 'Imported {} {}'.format(len(new_objs), new_objs[0]._meta.verbose_name_plural)
|
msg = 'Imported {} {}'.format(len(new_objs), new_objs[0]._meta.verbose_name_plural)
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
UserAction.objects.log_import(request.user, ContentType.objects.get_for_model(new_objs[0]), msg)
|
UserAction.objects.log_import(request.user, ContentType.objects.get_for_model(new_objs[0]), msg, get_ip_address(request))
|
||||||
|
|
||||||
return render(request, "import_success.html", {
|
return render(request, "import_success.html", {
|
||||||
'table': obj_table,
|
'table': obj_table,
|
||||||
@ -536,7 +537,7 @@ class BulkEditView(View):
|
|||||||
if updated_count:
|
if updated_count:
|
||||||
msg = 'Updated {} {}'.format(updated_count, self.cls._meta.verbose_name_plural)
|
msg = 'Updated {} {}'.format(updated_count, self.cls._meta.verbose_name_plural)
|
||||||
messages.success(self.request, msg)
|
messages.success(self.request, msg)
|
||||||
UserAction.objects.log_bulk_edit(request.user, ContentType.objects.get_for_model(self.cls), msg)
|
UserAction.objects.log_bulk_edit(request.user, ContentType.objects.get_for_model(self.cls), msg, get_ip_address(request))
|
||||||
return redirect(return_url)
|
return redirect(return_url)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -671,7 +672,7 @@ class BulkDeleteView(View):
|
|||||||
|
|
||||||
msg = 'Deleted {} {}'.format(deleted_count, self.cls._meta.verbose_name_plural)
|
msg = 'Deleted {} {}'.format(deleted_count, self.cls._meta.verbose_name_plural)
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
UserAction.objects.log_bulk_delete(request.user, ContentType.objects.get_for_model(self.cls), msg)
|
UserAction.objects.log_bulk_delete(request.user, ContentType.objects.get_for_model(self.cls), msg, get_ip_address(request))
|
||||||
return redirect(return_url)
|
return redirect(return_url)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user