added the pagination for auditlog dashboard
This commit is contained in:
parent
679188dad8
commit
bf17338a29
@ -31,7 +31,7 @@ from django.forms import HiddenInput, ValidationError
|
|||||||
from django.shortcuts import HttpResponse
|
from django.shortcuts import HttpResponse
|
||||||
|
|
||||||
from django.db.models import Sum, F, Count
|
from django.db.models import Sum, F, Count
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator,EmptyPage, PageNotAnInteger
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.db.models import Value
|
from django.db.models import Value
|
||||||
@ -8273,106 +8273,26 @@ def user_management(request):
|
|||||||
}
|
}
|
||||||
return render(request, "admin_management/user_management.html", context)
|
return render(request, "admin_management/user_management.html", context)
|
||||||
|
|
||||||
#audit log Management
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# 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 AuditLogDashboardView(request):
|
|
||||||
query=request.GET.get('q')
|
|
||||||
context={}
|
|
||||||
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:
|
|
||||||
print(f"Debugging CRUDEvent ID: {event.id}, User: {event.user}, Model: {event.content_type.model}")
|
|
||||||
print(f"Raw event.changed_fields: '{event.changed_fields}' (Type: {type(event.changed_fields)})")
|
|
||||||
changes = json.loads(event.changed_fields)
|
|
||||||
#change_fields returns 'null' for no changes to a field i.e. if the field remains the same
|
|
||||||
if isinstance(changes, dict): # Check if 'changes' is a dictionary
|
|
||||||
for field_name, values in changes.items():
|
|
||||||
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
|
|
||||||
event_data['field_changes'].append({
|
|
||||||
'field': field_name,
|
|
||||||
'old': old_value,
|
|
||||||
'new': new_value
|
|
||||||
})
|
|
||||||
elif changes is None: # Handle case where JSON was 'null' string like when no changes detected for a field or if it saved without a change
|
|
||||||
|
|
||||||
event_data['field_changes'].append({
|
|
||||||
'field': 'Info',
|
|
||||||
'old': '',
|
|
||||||
'new': 'No specific field changes recorded (JSON was null)'
|
|
||||||
})
|
|
||||||
else: # Handle valid JSON but not a dictionary (e.g., "[]", 123)
|
|
||||||
event_data['field_changes'].append({
|
|
||||||
'field': 'Error',
|
|
||||||
'old': '',
|
|
||||||
'new': f'Unexpected JSON format: {type(changes).__name__}'
|
|
||||||
})
|
|
||||||
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')
|
|
||||||
if(query=='userActions'):
|
|
||||||
return render(request,'admin_management/model_logs.html',context)
|
|
||||||
elif(query=='loginEvents'):
|
|
||||||
return render(request,'admin_management/auth_logs.html',context)
|
|
||||||
else:
|
|
||||||
return render(request,'admin_management/request_logs.html',context)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# class AuditLogDashboardView(TemplateView):
|
|
||||||
# template_name = 'admin_management/audit_log_dashboard.html'
|
|
||||||
# paginate_by = 20
|
|
||||||
|
|
||||||
# def get_context_data(self, **kwargs):
|
# def AuditLogDashboardView(request):
|
||||||
# context = super().get_context_data(**kwargs)
|
# q=request.GET.get('q')
|
||||||
|
|
||||||
# # Process CRUD (Model Change) Events
|
# context={}
|
||||||
# model_events_raw = CRUDEvent.objects.all().order_by('-datetime')
|
# model_events_raw = CRUDEvent.objects.all().order_by('-datetime')
|
||||||
# processed_model_events = []
|
# processed_model_events = []
|
||||||
|
# page = request.GET.get('page', 1)
|
||||||
|
|
||||||
# for event in model_events_raw:
|
|
||||||
|
|
||||||
|
# # context['model_events'] = processed_model_events
|
||||||
|
# # context['auth_events'] = LoginEvent.objects.all().order_by('-datetime')
|
||||||
|
# # context['request_events'] = RequestEvent.objects.all().order_by('-datetime')
|
||||||
|
# if(q=='userActions'):
|
||||||
|
# for event in model_events_raw:
|
||||||
# # Create a base dictionary for each event's data
|
# # Create a base dictionary for each event's data
|
||||||
# event_data = {
|
# event_data = {
|
||||||
# 'datetime': event.datetime,
|
# 'datetime': event.datetime,
|
||||||
@ -8386,8 +8306,8 @@ def AuditLogDashboardView(request):
|
|||||||
|
|
||||||
# if event.changed_fields:
|
# if event.changed_fields:
|
||||||
# try:
|
# try:
|
||||||
# print(f"Debugging CRUDEvent ID: {event.id}, User: {event.user}, Model: {event.content_type.model}")
|
# # print(f"Debugging CRUDEvent ID: {event.id}, User: {event.user}, Model: {event.content_type.model}")
|
||||||
# print(f"Raw event.changed_fields: '{event.changed_fields}' (Type: {type(event.changed_fields)})")
|
# # print(f"Raw event.changed_fields: '{event.changed_fields}' (Type: {type(event.changed_fields)})")
|
||||||
# changes = json.loads(event.changed_fields)
|
# changes = json.loads(event.changed_fields)
|
||||||
# #change_fields returns 'null' for no changes to a field i.e. if the field remains the same
|
# #change_fields returns 'null' for no changes to a field i.e. if the field remains the same
|
||||||
# if isinstance(changes, dict): # Check if 'changes' is a dictionary
|
# if isinstance(changes, dict): # Check if 'changes' is a dictionary
|
||||||
@ -8421,16 +8341,149 @@ def AuditLogDashboardView(request):
|
|||||||
# })
|
# })
|
||||||
|
|
||||||
# processed_model_events.append(event_data)
|
# processed_model_events.append(event_data)
|
||||||
|
# paginator=Paginator(processed_model_events,10)
|
||||||
|
# page_obj=paginator.page(page)
|
||||||
|
# context={
|
||||||
|
# 'page_obj':page_obj
|
||||||
|
# }
|
||||||
|
# return render(request,'admin_management/model_logs.html',context)
|
||||||
|
|
||||||
# context['model_events'] = processed_model_events
|
# elif(q=='loginEvents'):
|
||||||
# context['auth_events'] = LoginEvent.objects.all().order_by('-datetime')
|
# auth_events = LoginEvent.objects.all().order_by('-datetime')
|
||||||
# context['request_events'] = RequestEvent.objects.all().order_by('-datetime')
|
# paginator=Paginator(auth_events,10)
|
||||||
|
# page_obj=paginator.page(page)
|
||||||
|
# context={
|
||||||
|
# 'page_obj':page_obj
|
||||||
|
# }
|
||||||
|
# return render(request,'admin_management/auth_logs.html',context)
|
||||||
|
# else:
|
||||||
|
# request_events= RequestEvent.objects.all().order_by('-datetime')
|
||||||
|
# paginator=Paginator(request_events,10)
|
||||||
|
# page_obj=paginator.page(page)
|
||||||
|
# context={
|
||||||
|
# 'page_obj':page_obj
|
||||||
|
# }
|
||||||
|
# return render(request,'admin_management/request_logs.html',context)
|
||||||
|
|
||||||
# return context
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def AuditLogDashboardView(request):
|
||||||
|
"""
|
||||||
|
Displays audit logs (User Actions, Login Events, Request Events) with pagination.
|
||||||
|
Log type is determined by the 'q' query parameter (e.g., ?q=userActions).
|
||||||
|
Pagination page number is passed as a query parameter (e.g., ?page=2).
|
||||||
|
"""
|
||||||
|
q = request.GET.get('q') # Get the log type from the 'q' query parameter
|
||||||
|
current_pagination_page = request.GET.get('page', 1)
|
||||||
|
context = {}
|
||||||
|
template_name = None
|
||||||
|
logs_per_page = 30 # Define logs per page once
|
||||||
|
|
||||||
|
# --- Determine Data Source and Template based on 'q' parameter ---
|
||||||
|
if q=='userRequests': # This block handles cases where 'q' is 'requestEvents', None, or any other invalid value.
|
||||||
|
# It defaults to Request Logs if 'q' is not 'userActions' or 'loginEvents'.
|
||||||
|
template_name = 'admin_management/request_logs.html'
|
||||||
|
context['title'] = 'Request Logs Dashboard'
|
||||||
|
request_events = RequestEvent.objects.all().order_by('-datetime')
|
||||||
|
paginator = Paginator(request_events, logs_per_page)
|
||||||
|
try:
|
||||||
|
page_obj = paginator.page(current_pagination_page)
|
||||||
|
except PageNotAnInteger:
|
||||||
|
page_obj = paginator.page(1)
|
||||||
|
except EmptyPage:
|
||||||
|
page_obj = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
|
|
||||||
|
elif q == 'loginEvents':
|
||||||
|
template_name = 'admin_management/auth_logs.html'
|
||||||
|
context['title'] = 'Login Events Dashboard'
|
||||||
|
auth_events = LoginEvent.objects.all().order_by('-datetime')
|
||||||
|
paginator = Paginator(auth_events, logs_per_page)
|
||||||
|
try:
|
||||||
|
page_obj = paginator.page(current_pagination_page)
|
||||||
|
except PageNotAnInteger:
|
||||||
|
page_obj = paginator.page(1)
|
||||||
|
except EmptyPage:
|
||||||
|
page_obj = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
|
else:
|
||||||
|
template_name = 'admin_management/model_logs.html'
|
||||||
|
context['title'] = 'User Actions Dashboard'
|
||||||
|
|
||||||
|
# OPTIMIZATION: Get the QuerySet but don't evaluate it yet
|
||||||
|
model_events_queryset = CRUDEvent.objects.all().order_by('-datetime')
|
||||||
|
|
||||||
|
# 1. Paginate the raw QuerySet FIRST
|
||||||
|
paginator = Paginator(model_events_queryset, logs_per_page)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get the page object, which contains only the raw QuerySet objects for the current page
|
||||||
|
page_obj_raw = paginator.page(current_pagination_page)
|
||||||
|
except PageNotAnInteger:
|
||||||
|
page_obj_raw = paginator.page(1)
|
||||||
|
except EmptyPage:
|
||||||
|
page_obj_raw = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
|
# 2. Now, process 'field_changes' ONLY for the events on the current page
|
||||||
|
processed_model_events_for_page = []
|
||||||
|
for event in page_obj_raw.object_list: # Loop only through the current page's items
|
||||||
|
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': []
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.changed_fields:
|
||||||
|
try:
|
||||||
|
changes = json.loads(event.changed_fields)
|
||||||
|
if isinstance(changes, dict):
|
||||||
|
for field_name, values in changes.items():
|
||||||
|
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
|
||||||
|
event_data['field_changes'].append({
|
||||||
|
'field': field_name,
|
||||||
|
'old': old_value,
|
||||||
|
'new': new_value
|
||||||
|
})
|
||||||
|
elif changes is None:
|
||||||
|
event_data['field_changes'].append({
|
||||||
|
'field': 'Info',
|
||||||
|
'old': '',
|
||||||
|
'new': 'No specific field changes recorded (JSON was null)'
|
||||||
|
})
|
||||||
|
else: # Handle valid JSON but not a dictionary (e.g., "[]", 123)
|
||||||
|
event_data['field_changes'].append({
|
||||||
|
'field': 'Error',
|
||||||
|
'old': '',
|
||||||
|
'new': f'Unexpected JSON format: {type(changes).__name__}'
|
||||||
|
})
|
||||||
|
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_for_page.append(event_data)
|
||||||
|
|
||||||
|
# 3. Replace the object_list of the original page_obj with the processed data
|
||||||
|
# This keeps all pagination properties (has_next, number, etc.) intact.
|
||||||
|
page_obj_raw.object_list = processed_model_events_for_page
|
||||||
|
page_obj = page_obj_raw # This will be passed to the context
|
||||||
|
|
||||||
|
# Pass the final page object to the context
|
||||||
|
context['page_obj'] = page_obj
|
||||||
|
|
||||||
|
return render(request, template_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def activate_account(request, content_type, slug):
|
def activate_account(request, content_type, slug):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
{% load i18n custom_filters %}
|
|
||||||
{% block title %}{% trans "Accounts" %}{% endblock title %}
|
|
||||||
{% block accounts %}
|
|
||||||
<a class="nav-link active fw-bold">
|
|
||||||
{% trans "Accounts"|capfirst %}
|
|
||||||
<span class="visually-hidden">(current)</span>
|
|
||||||
</a>
|
|
||||||
{% 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 Dashboard" %}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Log Type Tabs -->
|
|
||||||
<div class="mb-4">
|
|
||||||
<ul class="nav nav-tabs" id="accountTypeTabs" role="tablist">
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link active" id="modellogs-tab" data-bs-toggle="tab" data-bs-target="#modellogs" type="button" role="tab" aria-controls="modellogs" aria-selected="true">
|
|
||||||
<i class="fas fa-wallet me-2"></i>{% trans "User Actions" %}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link" id="authlogs-tab" data-bs-toggle="tab" data-bs-target="#authlogs" type="button" role="tab" aria-controls="authlogs" aria-selected="false">
|
|
||||||
<i class="fas fa-boxes me-2"></i>{% trans "User Login Events" %}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link" id="requestslog-tab" data-bs-toggle="tab" data-bs-target="#requestslog" type="button" role="tab" aria-controls="requestslog" aria-selected="false">
|
|
||||||
<i class="fas fa-landmark me-2"></i>{% trans "User Page Requests" %}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="tab-content p-3 border border-top-0 rounded-bottom" id="accountTypeTabsContent">
|
|
||||||
<!-- modellogs Tab -->
|
|
||||||
<div class="tab-pane fade show active" id="modellogs" role="tabpanel" aria-labelledby="modellogs-tab">
|
|
||||||
{% include "partials/search_box.html" %}
|
|
||||||
{% include "admin_management/model_logs.html" %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- authlogs Tab -->
|
|
||||||
<div class="tab-pane fade" id="authlogs" role="tabpanel" aria-labelledby="authlogs-tab">
|
|
||||||
{% include "partials/search_box.html" %}
|
|
||||||
{% include "admin_management/auth_logs.html" %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- requestslog Tab -->
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
@ -22,7 +22,7 @@
|
|||||||
<div class="tab-content p-3 border border-top-0 rounded-bottom" id="accountTypeTabsContent">
|
<div class="tab-content p-3 border border-top-0 rounded-bottom" id="accountTypeTabsContent">
|
||||||
<!-- modellogs Tab -->
|
<!-- modellogs Tab -->
|
||||||
|
|
||||||
{% if auth_events %}
|
{% if page_obj %}
|
||||||
<div class="table-responsive px-1 scrollbar mt-3">
|
<div class="table-responsive px-1 scrollbar mt-3">
|
||||||
<table class= "table align-items-center table-flush table-hover">
|
<table class= "table align-items-center table-flush table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
@ -35,7 +35,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="list">
|
<tbody class="list">
|
||||||
{% for event in auth_events %}
|
{% for event in page_obj.object_list %}
|
||||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
<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.datetime}}</td>
|
||||||
@ -49,6 +49,14 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="d-flex justify-content-end mt-3">
|
||||||
|
<div class="d-flex">
|
||||||
|
{% if is_paginated %}
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include 'partials/pagination_audit.html' with q='loginEvents' %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>No authentication audit events found.</p>
|
<p>No authentication audit events found.</p>
|
||||||
|
|||||||
@ -22,69 +22,69 @@
|
|||||||
<div class="tab-content p-3 border border-top-0 rounded-bottom" id="accountTypeTabsContent">
|
<div class="tab-content p-3 border border-top-0 rounded-bottom" id="accountTypeTabsContent">
|
||||||
<!-- modellogs Tab -->
|
<!-- modellogs Tab -->
|
||||||
|
|
||||||
{% if model_events %}
|
{% if page_obj %}
|
||||||
<div class="table-responsive px-1 scrollbar mt-3">
|
<div class="table-responsive px-1 scrollbar mt-3">
|
||||||
<table class="table align-items-center table-flush table-hover mt-3">
|
<table class="table align-items-center table-flush table-hover mt-3">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="bg-body-highlight">
|
<tr class="bg-body-highlight">
|
||||||
<th>{% trans "Timestamp" %}</th>
|
<th>{% trans "Timestamp" %}</th>
|
||||||
<th>{% trans "User" %}</th>
|
<th>{% trans "User" %}</th>
|
||||||
<th>{% trans "Action" %}</th>
|
<th>{% trans "Action" %}</th>
|
||||||
<th>{% trans "Model" %}</th>
|
<th>{% trans "Model" %}</th>
|
||||||
<th>{% trans "Object ID" %}</th>
|
<th>{% trans "Object ID" %}</th>
|
||||||
<th>{% trans "Object Representation" %}</th>
|
<th>{% trans "Object Representation" %}</th>
|
||||||
<th>{% trans "Field" %}</th> {# Dedicated column for field name #}
|
<th>{% trans "Field" %}</th> {# Dedicated column for field name #}
|
||||||
<th>{% trans "Old Value" %}</th> {# Dedicated column for old value #}
|
<th>{% trans "Old Value" %}</th> {# Dedicated column for old value #}
|
||||||
<th>{% trans "New Value" %}</th> {# Dedicated column for new value #}
|
<th>{% trans "New Value" %}</th> {# Dedicated column for new value #}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for event in model_events %}
|
{% for event in page_obj.object_list %}
|
||||||
{% if event.field_changes %}
|
{% if event.field_changes %}
|
||||||
{# Loop through each individual field change for this event #}
|
{# Loop through each individual field change for this event #}
|
||||||
{% for change in event.field_changes %}
|
{% for change in event.field_changes %}
|
||||||
<tr>
|
<tr>
|
||||||
{# Display common event details using rowspan for the first change #}
|
{# Display common event details using rowspan for the first change #}
|
||||||
{% if forloop.first %}
|
{% if forloop.first %}
|
||||||
<td rowspan="{{ event.field_changes|length }}">
|
<td rowspan="{{ event.field_changes|length }}">
|
||||||
{{ event.datetime|date:"Y-m-d H:i:s" }}
|
{{ event.datetime|date:"Y-m-d H:i:s" }}
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="{{ event.field_changes|length }}">
|
<td rowspan="{{ event.field_changes|length }}">
|
||||||
{{ event.user.username|default:"Anonymous" }}
|
{{ event.user.username|default:"Anonymous" }}
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="{{ event.field_changes|length }}">
|
<td rowspan="{{ event.field_changes|length }}">
|
||||||
{{ event.event_type_display }}
|
{{ event.event_type_display }}
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="{{ event.field_changes|length }}">
|
<td rowspan="{{ event.field_changes|length }}">
|
||||||
{{ event.model_name|title }}
|
{{ event.model_name|title }}
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="{{ event.field_changes|length }}">
|
<td rowspan="{{ event.field_changes|length }}">
|
||||||
{{ event.object_id }}
|
{{ event.object_id }}
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="{{ event.field_changes|length }}">
|
<td rowspan="{{ event.field_changes|length }}">
|
||||||
{{ event.object_repr }}
|
{{ event.object_repr }}
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# Display the specific field change details in their own columns #}
|
{# Display the specific field change details in their own columns #}
|
||||||
<td><strong>{{ change.field }}</strong></td>
|
<td><strong>{{ change.field }}</strong></td>
|
||||||
<td>
|
<td>
|
||||||
{% if change.old is not None %}
|
{% 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>
|
<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 %}
|
{% else %}
|
||||||
(None)
|
(None)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if change.new is not None %}
|
{% 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>
|
<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 %}
|
{% else %}
|
||||||
(None)
|
(None)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{# Fallback for events with no specific field changes (e.g., CREATE, DELETE) #}
|
{# Fallback for events with no specific field changes (e.g., CREATE, DELETE) #}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ event.datetime|date:"Y-m-d H:i:s" }}</td>
|
<td>{{ event.datetime|date:"Y-m-d H:i:s" }}</td>
|
||||||
@ -94,7 +94,7 @@
|
|||||||
<td>{{ event.object_id }}</td>
|
<td>{{ event.object_id }}</td>
|
||||||
<td>{{ event.object_repr }}</td>
|
<td>{{ event.object_repr }}</td>
|
||||||
{# Span the 'Field', 'Old Value', 'New Value' columns #}
|
{# Span the 'Field', 'Old Value', 'New Value' columns #}
|
||||||
<td colspan="3">
|
<td>
|
||||||
{% if event.event_type_display == "Create" %}
|
{% if event.event_type_display == "Create" %}
|
||||||
{% trans "Object created." %}
|
{% trans "Object created." %}
|
||||||
{% elif event.event_type_display == "Delete" %}
|
{% elif event.event_type_display == "Delete" %}
|
||||||
@ -110,6 +110,8 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{% include 'partials/pagination_audit.html' with q='userActions' %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{% trans "No model change audit events found." %}</p>
|
<p>{% trans "No model change audit events found." %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<ul class="nav nav-tabs" id="accountTypeTabs" role="tablist">
|
<ul class="nav nav-tabs" id="accountTypeTabs" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
|
<li class="nav-item me-3" role="presentation">
|
||||||
<a href="{% url 'audit_log_dashboard' %}?q=userActions">
|
<a href="{% url 'audit_log_dashboard' %}?q=userActions">
|
||||||
<i class="fas fa-wallet me-2"></i>{% trans "User Actions" %}
|
<i class="fas fa-history me-2"></i>{% trans "User Actions" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item me-3" role="presentation">
|
||||||
<a href="{% url 'audit_log_dashboard' %}?q=loginEvents">
|
<a href="{% url 'audit_log_dashboard' %}?q=loginEvents">
|
||||||
<i class="fas fa-boxes me-2"></i>{% trans "User LoginEvents" %}
|
<i class="fas fa-right-to-bracket me-2"></i>{% trans "User Login Events" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a href="{% url 'audit_log_dashboard' %}?q=userRequests">
|
<a href="{% url 'audit_log_dashboard' %}?q=userRequests">
|
||||||
<i class="fas fa-landmark me-2"></i>{% trans "User PageRequests" %}
|
<i class="fas fa-file-alt me-2"></i>{% trans "User Page Requests" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<div class="tab-content p-3 border border-top-0 rounded-bottom" id="accountTypeTabsContent">
|
<div class="tab-content p-3 border border-top-0 rounded-bottom" id="accountTypeTabsContent">
|
||||||
<!-- modellogs Tab -->
|
<!-- modellogs Tab -->
|
||||||
{% if request_events %}
|
{% if page_obj %}
|
||||||
<div class="table-responsive px-1 scrollbar mt-3">
|
<div class="table-responsive px-1 scrollbar mt-3">
|
||||||
<table class= "table align-items-center table-flush table-hover">
|
<table class= "table align-items-center table-flush table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="list">
|
<tbody class="list">
|
||||||
{% for event in request_events %}
|
{% for event in page_obj.object_list %}
|
||||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
<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.datetime}}</td>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
{% include 'partials/pagination_audit.html' with q='userRequests' %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>No request audit events found.</p>
|
<p>No request audit events found.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
32
templates/partials/pagination_audit.html
Normal file
32
templates/partials/pagination_audit.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{% load i18n static %}
|
||||||
|
|
||||||
|
<div class="row align-items-center justify-content-center py-4 pe-0 fs-9">
|
||||||
|
<div class="col-auto d-flex">
|
||||||
|
{# Previous Button #}
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Previous' %}">
|
||||||
|
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}" aria-hidden="true"></span>
|
||||||
|
<span>{% trans "Previous" %}</span>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="page-link disabled" aria-disabled="true">
|
||||||
|
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}" aria-hidden="true"></span>
|
||||||
|
<span>{% trans "Previous" %}</span>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{# Next Button #}
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Next' %}">
|
||||||
|
<span>{% trans "Next" %}</span>
|
||||||
|
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %}" aria-hidden="true"></span>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="page-link disabled" aria-disabled="true">
|
||||||
|
<span>{% trans "Next" %}</span>
|
||||||
|
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %}" aria-hidden="true"></span>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Loading…
x
Reference in New Issue
Block a user