forked from UKSOURCE/cms.hailearning.edu.vn
314 lines
16 KiB
Plaintext
314 lines
16 KiB
Plaintext
<div class="container">
|
|
<div class="d-flex justify-content-between align-items-center mt-4 mb-4">
|
|
<div>
|
|
<h1 class="h3 mb-0" style="color: var(--primary-dark);">
|
|
<%= title %>
|
|
</h1>
|
|
<p class="text-muted mb-0">Detailed audit log information</p>
|
|
</div>
|
|
<div class="d-flex gap-2">
|
|
<a href="/admin/audit-logs" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left me-2"></i>Back to Audit Logs
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Main Information -->
|
|
<div class="col-12">
|
|
<div class="card border-0 shadow-sm mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0" style="color: var(--primary-dark);">
|
|
<i class="fas fa-info-circle me-2"></i>Audit Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">Model:</label>
|
|
<span class="badge ms-2" style="background-color: var(--primary-color); color: white;"><%= auditLog.model %></span>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">Action:</label>
|
|
<%
|
|
let actionStyle = 'background-color: var(--primary-color); color: white;';
|
|
if (auditLog.action.includes('CREATE')) actionStyle = 'background-color: #28a745; color: white;';
|
|
else if (auditLog.action.includes('UPDATE')) actionStyle = 'background-color: #ffc107; color: #212529;';
|
|
else if (auditLog.action.includes('DELETE')) actionStyle = 'background-color: #dc3545; color: white;';
|
|
%>
|
|
<span class="badge ms-2" style="<%= actionStyle %>"><%= auditLog.action %></span>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">Document ID:</label>
|
|
<code class="ms-2" style="background-color: #f8f9fa; color: var(--primary-dark);"><%= auditLog.documentId %></code>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">Date & Time:</label>
|
|
<div class="ms-2">
|
|
<%= new Date(auditLog.createdAt).toLocaleDateString() %>
|
|
<%= new Date(auditLog.createdAt).toLocaleTimeString() %>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">User:</label>
|
|
<div class="ms-2">
|
|
<% if (auditLog.performedBy) { %>
|
|
<strong style="color: var(--primary-dark);"><%= auditLog.performedBy.username %></strong><br>
|
|
<small class="text-muted"><%= auditLog.performedBy.email %></small>
|
|
<% } else { %>
|
|
<span class="text-muted">System</span>
|
|
<% } %>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">IP Address:</label>
|
|
<code class="ms-2" style="background-color: #f8f9fa; color: var(--primary-dark);"><%= auditLog.ipAddress %></code>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<% if (auditLog.userAgent) { %>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">User Agent:</label>
|
|
<div class="ms-2">
|
|
<small class="text-muted font-monospace"><%= auditLog.userAgent %></small>
|
|
</div>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Changes Details -->
|
|
<% if (auditLog.changes && auditLog.changes.length > 0) { %>
|
|
<div class="card border-0 shadow-sm mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0" style="color: var(--primary-dark);">
|
|
<i class="fas fa-edit me-2"></i>Field Changes
|
|
<span class="badge ms-2" style="background-color: var(--primary-color); color: white;"><%= auditLog.changes.length %></span>
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<% if (user && (user.role === 'admin' || user.role === 'superadmin')) { %>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th style="width: 200px; color: var(--primary-dark);">Field</th>
|
|
<th style="color: var(--primary-dark);">Before</th>
|
|
<th style="color: var(--primary-dark);">After</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% auditLog.changes.forEach((change, index) => { %>
|
|
<tr>
|
|
<td>
|
|
<strong style="color: var(--primary-dark);"><%= change.field %></strong>
|
|
</td>
|
|
<td>
|
|
<div class="change-value before">
|
|
<% if (change.before === null || change.before === undefined) { %>
|
|
<span class="text-muted fst-italic">null</span>
|
|
<% } else if (typeof change.before === 'object') { %>
|
|
<pre class="mb-0"><%= JSON.stringify(change.before, null, 2) %></pre>
|
|
<% } else { %>
|
|
<%= change.before %>
|
|
<% } %>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="change-value after">
|
|
<% if (change.after === null || change.after === undefined) { %>
|
|
<span class="text-muted fst-italic">null</span>
|
|
<% } else if (typeof change.after === 'object') { %>
|
|
<pre class="mb-0"><%= JSON.stringify(change.after, null, 2) %></pre>
|
|
<% } else { %>
|
|
<%= change.after %>
|
|
<% } %>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<% }); %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<% } else { %>
|
|
<div class="alert alert-info">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
<strong>Summary View:</strong> Detailed field values are restricted to administrators.
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th style="color: var(--primary-dark);">Field</th>
|
|
<th style="color: var(--primary-dark);">Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% auditLog.changes.forEach((change, index) => { %>
|
|
<tr>
|
|
<td>
|
|
<strong style="color: var(--primary-dark);"><%= change.field %></strong>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-info">Modified</span>
|
|
</td>
|
|
</tr>
|
|
<% }); %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
</div>
|
|
<% } %>
|
|
|
|
<!-- Summary Stats -->
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0" style="color: var(--primary-dark);">
|
|
<i class="fas fa-chart-bar me-2"></i>Summary
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row text-center">
|
|
<div class="col-6">
|
|
<div class="border-end">
|
|
<div class="h5 mb-0" style="color: var(--primary-color);">
|
|
<%= auditLog.changes ? auditLog.changes.length : 0 %>
|
|
</div>
|
|
<small class="text-muted">Fields Changed</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="h5 mb-0" style="color: var(--primary-color);">
|
|
<%= new Date(auditLog.createdAt).toLocaleDateString() === new Date().toLocaleDateString() ? 'Today' : 'Past' %>
|
|
</div>
|
|
<small class="text-muted">Timing</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Raw Data (Admin Only - Collapsible) -->
|
|
<!-- <% if (user && (user.role === 'admin' || user.role === 'superadmin')) { %>
|
|
<div class="card border-0 shadow-sm mt-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<button class="btn btn-link p-0 text-decoration-none" type="button" data-bs-toggle="collapse" data-bs-target="#rawDataCollapse" aria-expanded="false" style="color: var(--primary-dark);">
|
|
<i class="fas fa-code me-2"></i>Raw Data <span class="badge bg-warning text-dark ms-2">Admin Only</span>
|
|
<i class="fas fa-chevron-down ms-2"></i>
|
|
</button>
|
|
</h5>
|
|
</div>
|
|
<div class="collapse" id="rawDataCollapse">
|
|
<div class="card-body">
|
|
<div class="alert alert-info">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
<strong>Security Notice:</strong> Raw data contains sensitive information and is only visible to administrators.
|
|
</div>
|
|
<div class="row">
|
|
<% if (auditLog.before) { %>
|
|
<div class="col-md-6">
|
|
<h6 class="text-danger">Before:</h6>
|
|
<pre class="p-3 rounded" style="background-color: #f8f9fa; border: 1px solid #dee2e6; max-height: 400px; overflow-y: auto;"><%= JSON.stringify(auditLog.before, null, 2) %></pre>
|
|
</div>
|
|
<% } %>
|
|
<% if (auditLog.after) { %>
|
|
<div class="col-md-6">
|
|
<h6 class="text-success">After:</h6>
|
|
<pre class="p-3 rounded" style="background-color: #f8f9fa; border: 1px solid #dee2e6; max-height: 400px; overflow-y: auto;"><%= JSON.stringify(auditLog.after, null, 2) %></pre>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
|
|
<% if (!auditLog.before && !auditLog.after) { %>
|
|
<div class="text-center text-muted py-3">
|
|
<i class="fas fa-info-circle me-2"></i>No raw data available for this audit log.
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% } else { %>
|
|
<div class="card border-0 shadow-sm mt-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0" style="color: var(--primary-dark);">
|
|
<i class="fas fa-lock me-2"></i>Raw Data
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="alert alert-warning">
|
|
<i class="fas fa-shield-alt me-2"></i>
|
|
<strong>Access Restricted:</strong> Raw data access is limited to administrators for security reasons.
|
|
</div>
|
|
<div class="text-center text-muted py-3">
|
|
<i class="fas fa-user-shield" style="font-size: 3rem; opacity: 0.3;"></i>
|
|
<p class="mt-3">Contact your administrator if you need access to detailed raw data.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% } %> -->
|
|
</div>
|
|
|
|
<style>
|
|
.change-value {
|
|
max-width: 300px;
|
|
word-wrap: break-word;
|
|
overflow-wrap: break-word;
|
|
}
|
|
|
|
.change-value pre {
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
font-size: 0.8rem;
|
|
background-color: #f8f9fa;
|
|
border: 1px solid #dee2e6;
|
|
color: var(--primary-dark);
|
|
}
|
|
|
|
.change-value.before {
|
|
background-color: #fff5f5;
|
|
border-left: 3px solid #dc3545;
|
|
padding-left: 8px;
|
|
}
|
|
|
|
.change-value.after {
|
|
background-color: #f0fff4;
|
|
border-left: 3px solid #28a745;
|
|
padding-left: 8px;
|
|
}
|
|
|
|
.font-monospace {
|
|
font-family: 'Courier New', Courier, monospace;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.btn-link {
|
|
color: var(--primary-dark) !important;
|
|
}
|
|
|
|
.btn-link:hover {
|
|
color: var(--primary-color) !important;
|
|
}
|
|
|
|
.table th {
|
|
border-top: none;
|
|
font-weight: 600;
|
|
color: var(--primary-dark);
|
|
}
|
|
|
|
.card-header {
|
|
background-color: #f8f9fa !important;
|
|
border-bottom: 1px solid #dee2e6;
|
|
}
|
|
|
|
.badge {
|
|
font-size: 0.75em;
|
|
}
|
|
</style> |