django easy audit implemetation
This commit is contained in:
parent
be037e7fa6
commit
90e6af08d8
@ -809,10 +809,8 @@ path(
|
||||
path('management/user_management/', views.user_management, name='user_management'),
|
||||
path('management/<str:content_type>/<slug:slug>/activate_account/', views.activate_account, name='activate_account'),
|
||||
path('management/<str:content_type>/<slug:slug>/permenant_delete_account/', views.permenant_delete_account, name='permenant_delete_account'),
|
||||
path('management/audit_log_management/', views.audit_log_management, name='audit_log_management'),
|
||||
path('management/audit_log_management/modellogs', views.ModelLogListView.as_view(), name='modellogs_list'),
|
||||
path('management/audit_log_management/authlogs', views.RequestLogListView.as_view(), name='authlogs_list'),
|
||||
path('management/audit_log_management/requestlogs', views. AuthLogListView.as_view(), name='requestlogs_list'),
|
||||
path('management/audit_log_dashboard/', views.AuditLogDashboardView.as_view(), name='audit_log_dashboard'),
|
||||
|
||||
|
||||
]
|
||||
|
||||
|
||||
@ -150,10 +150,12 @@ from .utils import (
|
||||
CarTransfer,
|
||||
)
|
||||
from .tasks import create_accounts_for_make, send_email
|
||||
|
||||
#djago easy audit log
|
||||
from easyaudit.models import RequestEvent, CRUDEvent, LoginEvent
|
||||
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
@ -8253,44 +8255,79 @@ def user_management(request):
|
||||
return render(request, "admin_management/user_management.html", context)
|
||||
|
||||
#audit log Management
|
||||
def audit_log_management(request):
|
||||
return render(request, "admin_management/audit_log_lists.html")
|
||||
|
||||
#audit logs views
|
||||
# class AuditLogDashboardView(TemplateView):
|
||||
# """
|
||||
# Displays a dashboard with tabs for different audit log types.
|
||||
# Fetches all necessary log data to pass to the template.
|
||||
# """
|
||||
# template_name = 'admin_management/audit_log_dashboard.html' # Name of your main template with tabs
|
||||
|
||||
class RequestLogListView(ListView):
|
||||
"""Displays a list of RequestEvents."""
|
||||
model = RequestEvent
|
||||
template_name = 'admin_management/request_logs.html'
|
||||
context_object_name = 'request_events'
|
||||
paginate_by = 20
|
||||
# def get_context_data(self, **kwargs):
|
||||
# context = super().get_context_data(**kwargs)
|
||||
|
||||
# # Fetch data for each log type
|
||||
# # Order by 'datetime' field as per easy_audit models
|
||||
# context['model_events'] = CRUDEvent.objects.all().order_by('-datetime')
|
||||
# context['auth_events'] = LoginEvent.objects.all().order_by('-datetime')
|
||||
# context['request_events'] = RequestEvent.objects.all().order_by('-datetime')
|
||||
# return context
|
||||
|
||||
|
||||
def get_queryset(self):
|
||||
# The field name in RequestEvent is 'datetime', not 'created'
|
||||
return RequestEvent.objects.all().order_by('-datetime')
|
||||
class AuditLogDashboardView(TemplateView):
|
||||
template_name = 'admin_management/audit_log_dashboard.html'
|
||||
|
||||
|
||||
class ModelLogListView(ListView):
|
||||
"""Displays a list of CRUDEvents (model changes)."""
|
||||
# Corrected: Use CRUDEvent model
|
||||
model = CRUDEvent
|
||||
template_name = 'admin_management/model_logs.html'
|
||||
context_object_name = 'model_events'
|
||||
paginate_by = 20
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
# The field name in CRUDEvent is 'datetime', not 'created'
|
||||
return CRUDEvent.objects.all().order_by('-datetime')
|
||||
# Process CRUD (Model Change) Events
|
||||
model_events_raw = CRUDEvent.objects.all().order_by('-datetime')
|
||||
processed_model_events = []
|
||||
|
||||
for event in model_events_raw:
|
||||
# Create a base dictionary for each event's data
|
||||
event_data = {
|
||||
'datetime': event.datetime,
|
||||
'user': event.user,
|
||||
'event_type_display': event.get_event_type_display(),
|
||||
'model_name': event.content_type.model,
|
||||
'object_id': event.object_id,
|
||||
'object_repr': event.object_repr,
|
||||
'field_changes': [] # This will be a list of dicts: [{'field': 'name', 'old': 'A', 'new': 'B'}]
|
||||
}
|
||||
|
||||
if event.changed_fields:
|
||||
try:
|
||||
changes = json.loads(event.changed_fields)
|
||||
for field_name, values in changes.items():
|
||||
# Ensure values are lists and have at least two elements
|
||||
old_value = values[0] if isinstance(values, list) and len(values) > 0 else None
|
||||
new_value = values[1] if isinstance(values, list) and len(values) > 1 else None
|
||||
|
||||
# Store each field change as a separate entry
|
||||
event_data['field_changes'].append({
|
||||
'field': field_name,
|
||||
'old': old_value,
|
||||
'new': new_value
|
||||
})
|
||||
except json.JSONDecodeError:
|
||||
# Handle invalid JSON; you might log this error
|
||||
event_data['field_changes'].append({
|
||||
'field': 'Error',
|
||||
'old': '',
|
||||
'new': 'Invalid JSON in changed_fields'
|
||||
})
|
||||
|
||||
processed_model_events.append(event_data)
|
||||
|
||||
context['model_events'] = processed_model_events
|
||||
context['auth_events'] = LoginEvent.objects.all().order_by('-datetime')
|
||||
context['request_events'] = RequestEvent.objects.all().order_by('-datetime')
|
||||
|
||||
return context
|
||||
|
||||
class AuthLogListView(ListView):
|
||||
"""Displays a list of LoginEvents (authentication events)."""
|
||||
model = LoginEvent
|
||||
template_name = 'admin_management/auth_logs.html'
|
||||
context_object_name = 'auth_events'
|
||||
paginate_by = 20
|
||||
|
||||
def get_queryset(self):
|
||||
# The field name in LoginEvent is 'datetime', not 'created'
|
||||
return LoginEvent.objects.all().order_by('-datetime')
|
||||
|
||||
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="row mt-4">
|
||||
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<h3 class=""><i class="fa-solid fa-book"></i> {% trans "Audit Log Management" %}</h3>
|
||||
</div>
|
||||
@ -50,12 +51,14 @@
|
||||
</div>
|
||||
|
||||
<!-- Capital Tab -->
|
||||
<div class="tab-pane fade" id="requestslog" role="tabpanel" aria-labelledby="requestslog-tab">
|
||||
{% comment %} <div class="tab-pane fade" id="requestslog" role="tabpanel" aria-labelledby="requestslog-tab">
|
||||
{% include "partials/search_box.html" %}
|
||||
{% include "admin_management/request_logs.html" %}
|
||||
</div>
|
||||
|
||||
</div> {% endcomment %}
|
||||
|
||||
<div class="tab-pane fade" id="requestslog" role="tabpanel" aria-labelledby="requestslog-tab">
|
||||
<p>Hello from Request Logs tab!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,29 +1,33 @@
|
||||
|
||||
{% if auth_events %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Timestamp</th>
|
||||
<th>User</th>
|
||||
<th>Event Type</th>
|
||||
<th>Username</th> {# Added username field #}
|
||||
<th>IP Address</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in auth_events %}
|
||||
<tr>
|
||||
<td>{{ event.datetime }}</td> {# Corrected field name #}
|
||||
<td>{{ event.user.username|default:"N/A" }}</td>
|
||||
<td>{{ event.get_login_type_display }}</td> {# Corrected: get_login_type_display #}
|
||||
<td>{{ event.username }}</td> {# Added username field #}
|
||||
<td>{{ event.remote_ip }}</td> {# Corrected field name #}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% load i18n custom_filters %}
|
||||
{% if auth_events %}
|
||||
<div class="table-responsive px-1 scrollbar mt-3">
|
||||
<table class= "table align-items-center table-flush table-hover">
|
||||
<thead>
|
||||
<tr class="bg-body-highlight">
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Timestamp") |capfirst }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("User") |capfirst }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Event Type") }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("username") |capfirst }}</th>
|
||||
<th class="sort white-space-nowrap align-middle"scope="col">{{ _("IP Address") |capfirst }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list">
|
||||
{% for event in auth_events %}
|
||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||
|
||||
<td class="align-middle product white-space-nowrap">{{event.datetime}}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ event.user.username|default:"N/A" }}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ event.get_login_type_display}}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ event.username}}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ event.remote_ip}}</td>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% else %}
|
||||
<p>No authentication audit events found.</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -14,10 +14,10 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="{% url 'audit_log_management' %}">
|
||||
<a href="{% url 'audit_log_dashboard' %}">
|
||||
<div class="card h-100">
|
||||
<div class="card-header text-center">
|
||||
<h5 class="card-title">{{ _("Audit Log Management")}}</h5>
|
||||
<h5 class="card-title">{{ _("Audit Log Dashboard")}}</h5>
|
||||
<span class="me-2"><i class="fas fa-user fa-2x"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,37 +1,94 @@
|
||||
{% load i18n custom_filters %}
|
||||
|
||||
{% if model_events %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Timestamp</th>
|
||||
<th>User</th>
|
||||
<th>Action</th>
|
||||
<th>Model</th>
|
||||
<th>Object ID</th>
|
||||
<th>Changes</th>
|
||||
<th>Object Repr</th> {# Added for object representation #}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in model_events %}
|
||||
{% if model_events %}
|
||||
<div class="table-responsive px-1 scrollbar mt-3">
|
||||
<table class="table align-items-center table-flush table-hover mt-3">
|
||||
<thead>
|
||||
<tr class="bg-body-highlight">
|
||||
<th>{% trans "Timestamp" %}</th>
|
||||
<th>{% trans "User" %}</th>
|
||||
<th>{% trans "Action" %}</th>
|
||||
<th>{% trans "Model" %}</th>
|
||||
<th>{% trans "Object ID" %}</th>
|
||||
<th>{% trans "Object Representation" %}</th>
|
||||
<th>{% trans "Field" %}</th> {# Dedicated column for field name #}
|
||||
<th>{% trans "Old Value" %}</th> {# Dedicated column for old value #}
|
||||
<th>{% trans "New Value" %}</th> {# Dedicated column for new value #}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in model_events %}
|
||||
{% if event.field_changes %}
|
||||
{# Loop through each individual field change for this event #}
|
||||
{% for change in event.field_changes %}
|
||||
<tr>
|
||||
{# Display common event details using rowspan for the first change #}
|
||||
{% if forloop.first %}
|
||||
<td rowspan="{{ event.field_changes|length }}">
|
||||
{{ event.datetime|date:"Y-m-d H:i:s" }}
|
||||
</td>
|
||||
<td rowspan="{{ event.field_changes|length }}">
|
||||
{{ event.user.username|default:"Anonymous" }}
|
||||
</td>
|
||||
<td rowspan="{{ event.field_changes|length }}">
|
||||
{{ event.event_type_display }}
|
||||
</td>
|
||||
<td rowspan="{{ event.field_changes|length }}">
|
||||
{{ event.model_name|title }}
|
||||
</td>
|
||||
<td rowspan="{{ event.field_changes|length }}">
|
||||
{{ event.object_id }}
|
||||
</td>
|
||||
<td rowspan="{{ event.field_changes|length }}">
|
||||
{{ event.object_repr }}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
{# Display the specific field change details in their own columns #}
|
||||
<td><strong>{{ change.field }}</strong></td>
|
||||
<td>
|
||||
{% if change.old is not None %}
|
||||
<pre style="white-space: pre-wrap; word-break: break-all; font-size: 0.85em; background-color: #f8f9fa; padding: 5px; border-radius: 3px;">{{ change.old }}</pre>
|
||||
{% else %}
|
||||
(None)
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if change.new is not None %}
|
||||
<pre style="white-space: pre-wrap; word-break: break-all; font-size: 0.85em; background-color: #f8f9fa; padding: 5px; border-radius: 3px;">{{ change.new }}</pre>
|
||||
{% else %}
|
||||
(None)
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{# Fallback for events with no specific field changes (e.g., CREATE, DELETE) #}
|
||||
<tr>
|
||||
<td>{{ event.datetime }}</td> {# Corrected field name #}
|
||||
<td>{{ event.datetime|date:"Y-m-d H:i:s" }}</td>
|
||||
<td>{{ event.user.username|default:"Anonymous" }}</td>
|
||||
<td>{{ event.get_event_type_display }}</td>
|
||||
<td>{{ event.content_type.model|title }}</td> {# Model name #}
|
||||
<td>{{ event.object_id }}</td> {# Object ID #}
|
||||
<td>
|
||||
{% if event.changed_fields %} {# Corrected field name #}
|
||||
<pre style="white-space: pre-wrap; word-break: break-all;">{{ event.changed_fields|safe }}</pre>
|
||||
<td>{{ event.event_type_display }}</td>
|
||||
<td>{{ event.model_name|title }}</td>
|
||||
<td>{{ event.object_id }}</td>
|
||||
<td>{{ event.object_repr }}</td>
|
||||
{# Span the 'Field', 'Old Value', 'New Value' columns #}
|
||||
<td colspan="3">
|
||||
{% if event.event_type_display == "Create" %}
|
||||
{% trans "Object created." %}
|
||||
{% elif event.event_type_display == "Delete" %}
|
||||
{% trans "Object deleted." %}
|
||||
{% else %}
|
||||
N/A
|
||||
{% trans "No specific field changes recorded." %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ event.object_repr }}</td> {# Object representation #}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No model change audit events found.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{% else %}
|
||||
<p>{% trans "No model change audit events found." %}</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
@ -1,29 +1,34 @@
|
||||
|
||||
{% if request_events %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Timestamp</th>
|
||||
<th>User</th>
|
||||
<th>URL</th> {# Changed from Path to URL based on model #}
|
||||
<th>Method</th>
|
||||
<th>IP Address</th>
|
||||
{# No status_code in RequestEvent model #}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in request_events %}
|
||||
<tr>
|
||||
<td>{{ event.datetime }}</td> {# Corrected field name #}
|
||||
<td>{{ event.user.username|default:"Anonymous" }}</td>
|
||||
<td>{{ event.url }}</td> {# Corrected field name #}
|
||||
<td>{{ event.method }}</td>
|
||||
<td>{{ event.remote_ip }}</td> {# Corrected field name #}
|
||||
{# Removed status_code as it's not in the model #}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% load i18n custom_filters %}
|
||||
{% if request_events %}
|
||||
<div class="table-responsive px-1 scrollbar mt-3">
|
||||
<table class= "table align-items-center table-flush table-hover">
|
||||
<thead>
|
||||
<tr class="bg-body-highlight">
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Timestamp") |capfirst }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("User") |capfirst }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("URL") }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Method") |capfirst }}</th>
|
||||
<th class="sort white-space-nowrap align-middle"scope="col">{{ _("IP Address") |capfirst }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list">
|
||||
{% for event in request_events %}
|
||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||
|
||||
<td class="align-middle product white-space-nowrap">{{event.datetime}}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ event.user.username|default:"Anonymous" }}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ event.url }}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ event.method}}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ event.remote_ip}}</td>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<p>No request audit events found.</p>
|
||||
<p>No request audit events found.</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user