[UPDT] BASE: Added history for models using django audit log

This commit is contained in:
Horilla
2024-08-02 14:27:23 +05:30
parent 830a8471ba
commit 974f6f6805
5 changed files with 190 additions and 6 deletions

View File

@@ -9,4 +9,4 @@
</div>
{{ form.is_enable.errors }}
</div>
{% endblock %}
{% endblock %}

View File

@@ -5,7 +5,11 @@ This module is used to write methods related to the history
"""
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.db import models
from django.shortcuts import render
from horilla.decorators import apply_decorators
class Bot:
@@ -146,3 +150,27 @@ def get_diff(instance):
if track_fields:
delta_changes = filter_history(delta_changes, track_fields)
return delta_changes
def history_tracking(request, obj_id, **kwargs):
model = kwargs.get("model")
decorator_strings = kwargs.get("decorators", [])
@apply_decorators(decorator_strings)
def _history_tracking(request, obj_id, model):
instance = model.objects.get(pk=obj_id)
histories = instance.horilla_history.all()
page_number = request.GET.get("page", 1)
paginator = Paginator(histories, 4)
page_obj = paginator.get_page(page_number)
context = {
"histories": page_obj,
"model_name": model,
}
return render(
request,
"horilla_audit/history_tracking.html",
context,
)
return _history_tracking(request, obj_id, model)

View File

@@ -0,0 +1,144 @@
{% load static %} {% load i18n %} {% load audit_filters %}
<div class="oh-activity-sidebar__header" style="position:sticky; top:0; background:#fff; z-index:10">
<a
style="cursor: pointer"
onclick="$('.oh-activity-sidebar--show').removeClass('oh-activity-sidebar--show');"
>
<ion-icon
name="chevron-forward-outline"
class="oh-activity-sidebar__header-icon me-2 oh-activity-sidebar__close md hydrated"
data-target="#activitySidebar"
role="img"
aria-label="chevron forward outline"
></ion-icon>
</a>
<h1 class="oh-main__titlebar-title fw-bold ml-3 mb-3 mt-3">
{{model_name|verbose_name}} {% trans "History" %}
</h1>
</div>
<div style="height:60vh; overflow-y:auto" id="infiniteContainer">
<div class="row" style="" id = "infinite">
{% if histories %} {% for history in histories %}
<div class="oh-history__container item">
<div
class="oh-history_date oh-card__title oh-card__title--sm fw-bold me-2"
>
<span class="oh-history_date-content">
<span class="dateformat_changer"
>{{ history.timestamp|date:"M. d, Y" }}</span
>&nbsp,&nbsp
<span class="timeformat_changer"
>{{ history.timestamp|date:"g:i A" }}</span
>
</span>
</div>
<div class="d-flex">
<div class="oh-history_user-img">
{% if history.actor.employee_get %}
<img
src="{{history.actor.employee_get.get_avatar}}"
alt=""
class="oh-history_user-pic"
/>
{% else %}
<img
src="https://ui-avatars.com/api/?name=Horilla+Bot&background=random"
alt=""
class="oh-history_user-pic"
/>
{% endif %}
<div class="oh-history_user-state oh-user_inactive"></div>
</div>
<div class="oh-history_user-details">
<span class="oh-history__username"
>{% if history.actor.employee_get %} {{history.actor.employee_get.get_full_name}} {% else %} Horilla Bot {% endif %}</span
>
<div class="oh-history_abt pb-0">
<span class="oh-history_task-state">
{% if history.action == 0 %}
{% trans "Created" %} {{model_name|verbose_name}}
{% elif history.action == 1 %}
{% trans "Updated" %} {{model_name|verbose_name}}
{% endif %}
</span>
</div>
<div class="oh-history_msg-container">
<div class="oh-history_task-tracker">
<ul class="ul">
{% for change,value in history.changes_dict.items %}
{% if value.type == 'm2m' %}
<li class="oh-history_task-list">
<div class="oh-history_track-value">
<span>{{model_name|verbose_name:change}}</span>
<img
src="{% static '/images/ui/arrow-right-line.svg' %}"
class="oh-progress_arrow"
alt=""
/>
<span class="oh-history-task-state"
><i
>{{value.objects|join:", "}}</i
></span
>
</div>
</li>
{% endif %}
{% endfor %}
{% for change,value in history.changes_display_dict.items %}
{% if not value.0 == "type" %}
<li class="oh-history_task-list">
<div class="oh-history_track-value">
<span>{{change}}</span>
<span class="oh-history_tracking-value"
><i>({{value.0}})</i></span
>
<img
src="{% static '/images/ui/arrow-right-line.svg' %}"
class="oh-progress_arrow"
alt=""
/>
<span class="oh-history-task-state"
><i>({{value.1}})</i></span
>
</div>
</li>
{% endif %}
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
{% if histories.has_next and forloop.last %}
<div class="scrollButton" hx-get="{{request.META.PATH_INFO}}?page={{ histories.next_page_number }}"
hx-swap="beforeend" hx-target="#infinite" hx-select=".item"
>
</div>
{% endif %}
</div>
{% endfor %}
{% else %}
<div
class="d-flex justify-content-center align-items-center"
style="height: 40vh"
>
<h5 class="oh-404__subtitle">{% trans "No history found." %}</h5>
</div>
{% endif %}
</div>
</div>
<script>
document.body.addEventListener('htmx:load', function(evt) {
var container ="#infiniteContainer";
var $container = $(container)
var $lastItem = $('.row .item .scrollButton').last();
$container.on('scroll', function() {
if ($container[0].scrollTop + $container[0].clientHeight + 2 >= $container[0].scrollHeight) {
$lastItem.click();
$lastItem.remove()
}
});
});
</script>

View File

@@ -1,9 +1,5 @@
from django import template
from django.core.paginator import Page, Paginator
from django.template.defaultfilters import register
from employee.models import Employee, EmployeeWorkInformation
@register.filter(name="fk_history")
def fk_history(instance, change):
@@ -18,3 +14,19 @@ def fk_history(instance, change):
value = str(value) + f" (Previous {change['field']} deleted)"
pass
return value
@register.filter(name="verbose_name")
def verbose_name(model, field_name=None):
""" "
This method is used to fine the verbose name of a field
"""
if not field_name:
model_name = model._meta.verbose_name.capitalize()
return model_name
try:
field = model._meta.get_field(field_name)
return field.verbose_name
except:
return field_name

View File

@@ -441,7 +441,7 @@
$(document).on("htmx:beforeRequest", function (event, data) {
var response = event.detail.xhr.response;
var target = $(event.detail.elt.getAttribute("hx-target"));
var avoid_target = ["BiometricDeviceTestFormTarget","reloadMessages"];
var avoid_target = ["BiometricDeviceTestFormTarget","reloadMessages", "infinite"];
if (!target.closest("form").length && avoid_target.indexOf(target.attr("id")) === -1) {
target.html(`<div class="animated-background"></div>`);
}