diff --git a/inventory/views.py b/inventory/views.py index ed462472..7edd9fdd 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -31,7 +31,7 @@ from django.forms import HiddenInput, ValidationError from django.shortcuts import HttpResponse 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 Group from django.db.models import Value @@ -8273,106 +8273,26 @@ def user_management(request): } 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): -# context = super().get_context_data(**kwargs) -# # Process CRUD (Model Change) Events +# def AuditLogDashboardView(request): +# q=request.GET.get('q') + +# context={} # model_events_raw = CRUDEvent.objects.all().order_by('-datetime') # 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 # event_data = { # 'datetime': event.datetime, @@ -8386,8 +8306,8 @@ def AuditLogDashboardView(request): # 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)})") +# # 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 @@ -8418,19 +8338,152 @@ def AuditLogDashboardView(request): # '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 +# 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) + +# elif(q=='loginEvents'): +# auth_events = LoginEvent.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) + +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): try: diff --git a/templates/admin_management/audit_log_dashboard.html b/templates/admin_management/audit_log_dashboard.html deleted file mode 100644 index 21213e3c..00000000 --- a/templates/admin_management/audit_log_dashboard.html +++ /dev/null @@ -1,68 +0,0 @@ -{% extends "base.html" %} -{% load i18n custom_filters %} -{% block title %}{% trans "Accounts" %}{% endblock title %} -{% block accounts %} - - {% trans "Accounts"|capfirst %} - (current) - -{% endblock %} -{% block content %} -
No authentication audit events found.
{% endif %} diff --git a/templates/admin_management/model_logs.html b/templates/admin_management/model_logs.html index ab648cb7..3362cb52 100644 --- a/templates/admin_management/model_logs.html +++ b/templates/admin_management/model_logs.html @@ -22,69 +22,69 @@