diff --git a/recruitment/__pycache__/urls.cpython-312.pyc b/recruitment/__pycache__/urls.cpython-312.pyc index 0c55bfb..adce72e 100644 Binary files a/recruitment/__pycache__/urls.cpython-312.pyc and b/recruitment/__pycache__/urls.cpython-312.pyc differ diff --git a/recruitment/__pycache__/views.cpython-312.pyc b/recruitment/__pycache__/views.cpython-312.pyc index 41776d0..364a7ee 100644 Binary files a/recruitment/__pycache__/views.cpython-312.pyc and b/recruitment/__pycache__/views.cpython-312.pyc differ diff --git a/recruitment/urls.py b/recruitment/urls.py index 4bc00ac..c9e9b9c 100644 --- a/recruitment/urls.py +++ b/recruitment/urls.py @@ -109,5 +109,6 @@ urlpatterns = [ # users urls path('user/',views.user_detail,name='user_detail'), path('user/user_profile_image_update/',views.user_profile_image_update,name='user_profile_image_update'), + path('easy_logs/',views.easy_logs,name='easy_logs') ] diff --git a/recruitment/views.py b/recruitment/views.py index 68d11b1..e356d06 100644 --- a/recruitment/views.py +++ b/recruitment/views.py @@ -1,5 +1,6 @@ import json import requests +from django.utils.translation import gettext as _ from django.contrib.auth.models import User from rich import print from django.template.loader import render_to_string @@ -13,7 +14,7 @@ from django.urls import reverse from django.conf import settings from django.utils import timezone from .forms import ( - CandidateExamDateForm, + CandidateExamDateForm, ZoomMeetingForm, JobPostingForm, FormTemplateForm, @@ -23,9 +24,10 @@ from .forms import ( ProfileImageUploadForm, ) +from easyaudit.models import CRUDEvent, LoginEvent, RequestEvent from rest_framework import viewsets from django.contrib import messages -from django.core.paginator import Paginator +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from .linkedin_service import LinkedInService from .serializers import JobPostingSerializer, CandidateSerializer from django.shortcuts import get_object_or_404, render, redirect @@ -2394,3 +2396,50 @@ def user_detail(request, pk): } return render(request, 'user/profile.html', context) + + + + +def easy_logs(request): + """ + Function-based view to display Django Easy Audit logs with tab switching and pagination. + """ + logs_per_page = 20 + + # 1. Determine the active tab and the corresponding model/queryset + active_tab = request.GET.get('tab', 'crud') + + if active_tab == 'login': + queryset = LoginEvent.objects.order_by('-datetime') + tab_title = _("User Authentication") + elif active_tab == 'request': + queryset = RequestEvent.objects.order_by('-datetime') + tab_title = _("HTTP Requests") + else: # Default is 'crud' + queryset = CRUDEvent.objects.order_by('-datetime') + tab_title = _("Model Changes (CRUD)") + active_tab = 'crud' + + # 2. Apply Pagination + paginator = Paginator(queryset, logs_per_page) + page = request.GET.get('page') + + try: + # Get the page object for the requested page number + logs_page = paginator.page(page) + except PageNotAnInteger: + # If page is not an integer, deliver first page. + logs_page = paginator.page(1) + except EmptyPage: + # If page is out of range, deliver last page of results. + logs_page = paginator.page(paginator.num_pages) + + context = { + 'logs': logs_page, + 'total_count': queryset.count(), + 'active_tab': active_tab, + 'tab_title': tab_title, + } + + return render(request, "includes/easy_logs.html", context) + diff --git a/templates/base.html b/templates/base.html index 3738bdf..7ed1a2f 100644 --- a/templates/base.html +++ b/templates/base.html @@ -143,7 +143,9 @@
  • + {% if request.user.is_authenticated %}
  • {% trans "My Profile" %}
  • + {% endif %}
  • {% trans "Settings" %}
  • {% trans "Activity Log" %}
  • {% trans "Help & Support" %}
  • @@ -164,6 +166,7 @@ {% endif %}
  • + {% if request.user.is_authenticated %}
  • {% csrf_token %} @@ -177,6 +180,7 @@
  • + {% endif %} diff --git a/templates/includes/easy_logs.html b/templates/includes/easy_logs.html new file mode 100644 index 0000000..6b7433c --- /dev/null +++ b/templates/includes/easy_logs.html @@ -0,0 +1,337 @@ +{% extends "base.html" %} +{% load static %} +{% load i18n %} + +{% block title %}{% trans "Audit Dashboard" %}{% endblock %} + +{% block customCSS %} + +{% endblock %} + +{% block content %} +
    +

    + {% trans "System Audit Logs" %} +

    + + + +
    + + + +
    + +
    + +
    + + + + {% if active_tab == 'crud' %} + + + + + + + + + {% elif active_tab == 'login' %} + + + + + + + + {% elif active_tab == 'request' %} + + + + + + + + {% endif %} + + + + {% for log in logs.object_list %} + {% if active_tab == 'crud' %} + + + + + + + + + + {% elif active_tab == 'login' %} + + + + + + + + + {% elif active_tab == 'request' %} + + + + + + + + {% endif %} + {% empty %} + + {% endfor %} + +
    {% trans "Date/Time" %}{% trans "User" %}{% trans "Action" %}{% trans "Model" %}{% trans "Object PK" %}{% trans "Changes" %}
    {% trans "Date/Time" %}{% trans "User" %}{% trans "Type" %}{% trans "Status" %}{% trans "IP Address" %}
    {% trans "Date/Time" %}{% trans "User" %}{% trans "Method" %}{% trans "Path" %}
    {{ log.datetime|date:"Y-m-d H:i:s" }}{{ log.user.get_full_name|default:log.user.username|default:"N/A" }} + + {% if log.event_type == 1 %}{% trans "CREATE" %} + {% elif log.event_type == 2 %}{% trans "UPDATE" %} + {% else %}{% trans "DELETE" %}{% endif %} + + {{ log.content_type.app_label }}.{{ log.content_type.model }}{{ log.object_id }} +
    {{ log.changed_fields }}
    +
    {{ log.datetime|date:"Y-m-d H:i:s" }} + {% with user_obj=log.user %} + {% if user_obj %} + {{ user_obj.get_full_name|default:user_obj.username }} + {% else %} + {{ log.username|default:"N/A" }} + {% endif %} + {% endwith %} + + + + {% if log.login_type == 2 %} + {% trans "Failed" %} + {% else %} + {% trans "Success" %} + {% endif %} + {{ log.remote_ip|default:"Unknown" }}
    {{ log.datetime|date:"Y-m-d H:i:s" }}{{ log.user.get_full_name|default:log.user.username|default:"Anonymous" }} + {{ log.method }} + {{ log.url}}
    + {% trans "No logs found for this section or the database is empty." %} +
    +
    + + {% if logs.has_other_pages %} + + {% endif %} + +
    + +
    +
    +
    +{% endblock %} \ No newline at end of file