hospital-management/templates/core/audit_log_detail.html
2025-08-12 13:33:25 +03:00

360 lines
17 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Audit Log Detail - {{ audit_log.action }}{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Breadcrumb -->
<div class="row">
<div class="col-12">
<div class="page-title-box d-sm-flex align-items-center justify-content-between">
<h4 class="mb-sm-0">Audit Log Detail</h4>
<div class="page-title-right">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'core:audit_log' %}">Audit Logs</a></li>
<li class="breadcrumb-item active">Log Detail</li>
</ol>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Main Content -->
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<div class="avatar-sm me-3">
<span class="avatar-title rounded-circle bg-{% if audit_log.event_type == 'CREATE' %}success{% elif audit_log.event_type == 'UPDATE' %}primary{% elif audit_log.event_type == 'DELETE' %}danger{% elif audit_log.event_type == 'LOGIN' %}info{% elif audit_log.event_type == 'LOGOUT' %}secondary{% else %}warning{% endif %} text-white">
<i class="fas fa-{% if audit_log.event_type == 'CREATE' %}plus{% elif audit_log.event_type == 'UPDATE' %}edit{% elif audit_log.event_type == 'DELETE' %}trash{% elif audit_log.event_type == 'LOGIN' %}sign-in-alt{% elif audit_log.event_type == 'LOGOUT' %}sign-out-alt{% else %}exclamation{% endif %}"></i>
</span>
</div>
</div>
<div class="flex-grow-1">
<h5 class="card-title mb-0">{{ audit_log.action }}</h5>
<small class="text-muted">{{ audit_log.get_event_type_display }} | {{ audit_log.get_event_category_display }}</small>
</div>
</div>
</div>
<div class="card-body">
<div class="row mb-4">
<div class="col-md-6">
<div class="d-flex mb-3">
<div class="flex-shrink-0">
<i class="fas fa-clock text-muted me-2"></i>
</div>
<div class="flex-grow-1">
<h6 class="mb-0">Timestamp</h6>
<p class="text-muted mb-0">{{ audit_log.timestamp|date:"M d, Y g:i:s A" }}</p>
<small class="text-muted">{{ audit_log.timestamp|timesince }} ago</small>
</div>
</div>
</div>
<div class="col-md-6">
<div class="d-flex mb-3">
<div class="flex-shrink-0">
<i class="fas fa-user text-muted me-2"></i>
</div>
<div class="flex-grow-1">
<h6 class="mb-0">User</h6>
<p class="text-muted mb-0">
{% if audit_log.user %}
{{ audit_log.user.get_full_name|default:audit_log.user.username }}
{% else %}
System
{% endif %}
</p>
{% if audit_log.user %}
<small class="text-muted">{{ audit_log.user.email }}</small>
{% endif %}
</div>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<div class="d-flex mb-3">
<div class="flex-shrink-0">
<i class="fas fa-tag text-muted me-2"></i>
</div>
<div class="flex-grow-1">
<h6 class="mb-0">Event Type</h6>
<p class="mb-0">
<span class="badge bg-{% if audit_log.event_type == 'CREATE' %}success{% elif audit_log.event_type == 'UPDATE' %}primary{% elif audit_log.event_type == 'DELETE' %}danger{% elif audit_log.event_type == 'LOGIN' %}info{% elif audit_log.event_type == 'LOGOUT' %}secondary{% else %}warning{% endif %}">
{{ audit_log.get_event_type_display }}
</span>
</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="d-flex mb-3">
<div class="flex-shrink-0">
<i class="fas fa-folder text-muted me-2"></i>
</div>
<div class="flex-grow-1">
<h6 class="mb-0">Category</h6>
<p class="mb-0">
<span class="badge bg-info">
{{ audit_log.get_event_category_display }}
</span>
</p>
</div>
</div>
</div>
</div>
<div class="mb-4">
<h6 class="text-muted mb-2">Description</h6>
<div class="p-3 bg-light rounded">
{{ audit_log.description }}
</div>
</div>
{% if audit_log.content_type %}
<div class="mb-4">
<h6 class="text-muted mb-2">Affected Object</h6>
<div class="p-3 bg-light rounded">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="fas fa-database text-muted me-2"></i>
</div>
<div class="flex-grow-1">
<p class="mb-0">
<strong>{{ audit_log.content_type.name|title }}</strong>
{% if audit_log.object_id %}
<span class="text-muted">(ID: {{ audit_log.object_id }})</span>
{% endif %}
</p>
</div>
</div>
</div>
</div>
{% endif %}
{% if audit_log.data %}
<div class="mb-4">
<h6 class="text-muted mb-2">Changed Data</h6>
<div class="p-3 bg-light rounded">
<pre class="mb-0"><code>{{ audit_log.data|pprint }}</code></pre>
</div>
</div>
{% endif %}
{% if audit_log.ip_address %}
<div class="mb-4">
<h6 class="text-muted mb-2">Request Information</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered mb-0">
<tbody>
<tr>
<th style="width: 30%">IP Address</th>
<td>{{ audit_log.ip_address }}</td>
</tr>
{% if audit_log.user_agent %}
<tr>
<th>User Agent</th>
<td>{{ audit_log.user_agent }}</td>
</tr>
{% endif %}
{% if audit_log.request_method %}
<tr>
<th>Request Method</th>
<td>{{ audit_log.request_method }}</td>
</tr>
{% endif %}
{% if audit_log.request_path %}
<tr>
<th>Request Path</th>
<td>{{ audit_log.request_path }}</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Quick Actions -->
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-bolt me-2"></i>
Quick Actions
</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<a href="{% url 'core:audit_log' %}" class="btn btn-outline-primary">
<i class="fas fa-arrow-left me-2"></i>
Back to Audit Logs
</a>
<button type="button" class="btn btn-outline-secondary" onclick="exportLog()">
<i class="fas fa-download me-2"></i>
Export Log Entry
</button>
{% if audit_log.content_type and audit_log.object_id %}
<button type="button" class="btn btn-outline-info" onclick="viewRelatedObject()">
<i class="fas fa-external-link-alt me-2"></i>
View Related Object
</button>
{% endif %}
{% if audit_log.event_type == 'UPDATE' %}
<button type="button" class="btn btn-outline-warning" onclick="viewChanges()">
<i class="fas fa-history me-2"></i>
View Changes
</button>
{% endif %}
</div>
</div>
</div>
<!-- Related Logs -->
{% if related_logs %}
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-link me-2"></i>
Related Logs
</h5>
</div>
<div class="card-body">
<div class="list-group">
{% for log in related_logs %}
<a href="{% url 'core:audit_log_detail' log.pk %}" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">{{ log.action }}</h6>
<small class="text-muted">{{ log.timestamp|timesince }} ago</small>
</div>
<p class="mb-1 text-muted">{{ log.description|truncatechars:80 }}</p>
<small>
<span class="badge bg-{% if log.event_type == 'CREATE' %}success{% elif log.event_type == 'UPDATE' %}primary{% elif log.event_type == 'DELETE' %}danger{% elif log.event_type == 'LOGIN' %}info{% elif log.event_type == 'LOGOUT' %}secondary{% else %}warning{% endif %}">
{{ log.get_event_type_display }}
</span>
{% if log.user %}
<span class="text-muted">by {{ log.user.get_full_name|default:log.user.username }}</span>
{% endif %}
</small>
</a>
{% endfor %}
</div>
</div>
</div>
{% endif %}
<!-- Tenant Information -->
{% if audit_log.tenant %}
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-building me-2"></i>
Tenant Information
</h5>
</div>
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<div class="flex-shrink-0">
<div class="avatar-sm me-3">
<span class="avatar-title rounded-circle bg-primary text-white">
{{ audit_log.tenant.name|first|upper }}
</span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-0">{{ audit_log.tenant.name }}</h6>
<small class="text-muted">{{ audit_log.tenant.get_organization_type_display }}</small>
</div>
</div>
<div class="mb-0">
<div class="d-flex justify-content-between align-items-center mb-1">
<small class="text-muted">Status</small>
<small class="text-{% if audit_log.tenant.is_active %}success{% else %}danger{% endif %}">
{% if audit_log.tenant.is_active %}Active{% else %}Inactive{% endif %}
</small>
</div>
<div class="progress" style="height: 6px;">
<div class="progress-bar bg-{% if audit_log.tenant.is_active %}success{% else %}danger{% endif %}"
style="width: {% if audit_log.tenant.is_active %}100{% else %}100{% endif %}%"></div>
</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
function exportLog() {
window.open('{% url "core:audit_log_detail" audit_log.pk %}?export=json', '_blank');
}
function viewRelatedObject() {
{% if audit_log.content_type and audit_log.object_id %}
// This is a simplified approach - in a real app, you'd need to determine the correct URL
// based on the content type and object ID
const contentType = '{{ audit_log.content_type.model }}';
const objectId = '{{ audit_log.object_id }}';
// Map common content types to their URLs
const urlMap = {
'tenant': `/core/tenants/${objectId}/`,
'department': `/core/departments/${objectId}/`,
'systemconfiguration': `/core/system-configuration/${objectId}/`,
'systemnotification': `/core/notifications/${objectId}/`,
'user': `/accounts/users/${objectId}/`,
'patient': `/patients/profiles/${objectId}/`,
'employee': `/hr/employees/${objectId}/`,
'medicalbill': `/billing/bills/${objectId}/`,
'appointment': `/appointments/${objectId}/`,
};
const url = urlMap[contentType] || '#';
if (url !== '#') {
window.open(url, '_blank');
} else {
alert(`Cannot navigate to object of type: ${contentType}`);
}
{% endif %}
}
function viewChanges() {
{% if audit_log.data %}
const data = {{ audit_log.data|safe }};
let changes = '';
if (data.changes) {
for (const [field, values] of Object.entries(data.changes)) {
changes += `Field: ${field}\n`;
changes += `Old value: ${values[0]}\n`;
changes += `New value: ${values[1]}\n\n`;
}
alert(`Changes:\n\n${changes}`);
} else {
alert('No detailed change information available');
}
{% else %}
alert('No change data available for this log entry');
{% endif %}
}
</script>
{% endblock %}