feat: implement administrator-driven audit log purging with forced archival download

- Created find_older_than and delete_older_than database repository methods.
- Built a /auth/audit/purge POST endpoint that validates retention days (min 1 day).
- Serializes and streams matching logs as an attachment JSON download for archival before database deletion.
- Added a 'Purge Logs' button and modal interface in the administrator dashboard, automatically reloading the view after download.
This commit is contained in:
2026-05-30 18:41:59 +05:00
parent 4c98dd93ad
commit bb35206fff
5 changed files with 139 additions and 18 deletions
+37
View File
@@ -13,6 +13,9 @@
<p class="text-slate-400 text-sm mt-1">Review, search, and audit system activities and state changes</p>
</div>
<div class="flex items-center gap-3">
<button data-modal-target="purge-modal" class="inline-flex items-center justify-center rounded-xl text-xs font-bold transition-all px-4 py-2.5 bg-rose-950/40 border border-rose-900/30 hover:bg-rose-950/60 text-rose-400 shadow-md shadow-rose-950/10">
Purge Logs
</button>
<a href="/auth/users" class="inline-flex items-center justify-center rounded-xl text-xs font-bold transition-all px-4 py-2.5 bg-slate-900 border border-slate-800 hover:bg-slate-800 text-slate-300">
Manage Users
</a>
@@ -220,4 +223,38 @@
<a href="/auth/password" class="font-medium text-sky-400 hover:underline">← Back to Account Settings</a>
</div>
</div>
<!-- Purge Modal Dialog -->
<div id="purge-modal" class="modal-dialog fixed inset-0 z-50 flex items-center justify-center hidden" role="dialog" aria-modal="true">
<div class="modal-backdrop fixed inset-0 bg-[#07090e]/80 backdrop-blur-sm transition-opacity duration-300"></div>
<div class="modal-content relative z-10 w-full max-w-md scale-95 opacity-0 transition-all duration-300 border border-border bg-popover/95 backdrop-blur-xl p-6 shadow-2xl rounded-3xl">
<div class="mx-auto flex h-10 w-10 items-center justify-center rounded-full bg-rose-500/10 border border-rose-500/20 text-rose-400 mb-3">
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</div>
<h3 class="text-sm font-bold text-slate-100 text-center">Purge Audit Logs</h3>
<p class="text-xs text-slate-400 mt-2 text-center leading-relaxed">
Specify the number of days of logs to retain. This operation will permanently delete all logs older than this window. You will be forced to download a JSON archival dump of the purged logs before deletion.
</p>
<form method="POST" action="/auth/audit/purge" class="mt-4 space-y-4">
<div>
<label for="retention_days" class="block text-[11px] font-semibold text-slate-400 mb-1.5 text-left">Retention Period (Days)</label>
<input type="number" id="retention_days" name="retention_days" min="1" value="30" required
class="block h-10 w-full rounded-xl border border-border bg-background px-4 py-2 text-sm text-white placeholder-slate-650 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500/50">
<span class="text-[10px] text-slate-500 mt-1 block text-left">Minimum 1 day of logs must be retained.</span>
</div>
<div class="flex gap-3 pt-2">
<button type="button" class="modal-close flex-1 py-2.5 rounded-xl bg-secondary border border-border hover:bg-slate-800 transition text-xs font-semibold text-slate-200">
Cancel
</button>
<button type="submit" class="flex-1 py-2.5 rounded-xl bg-rose-650 hover:bg-rose-600 text-white shadow-lg shadow-rose-600/10 transition text-xs font-bold" onclick="setTimeout(() => { window.closeModal(document.getElementById('purge-modal')); window.location.reload(); }, 1500)">
Archived Purge
</button>
</div>
</form>
</div>
</div>
{% endblock %}
-17
View File
@@ -79,23 +79,6 @@
</div>
</div>
</div>
<div class="p-5 rounded-2xl bg-indigo-500/5 border border-indigo-500/10 flex items-start gap-4">
<div class="w-10 h-10 rounded-xl bg-indigo-500/10 flex items-center justify-center text-indigo-400 flex-shrink-0">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.109A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
</svg>
</div>
<div>
<h4 class="text-sm font-bold text-slate-200">Developer Roster</h4>
<p class="text-xs text-slate-400 mt-1 leading-relaxed">Manage team developer profiles, update their technical skills, or clear their metadata.</p>
<div class="mt-4">
<a href="/developers" class="inline-flex items-center justify-center rounded-xl text-xs font-bold transition-all px-4 py-2.5 bg-secondary border border-border hover:bg-secondary/80 text-slate-200">
Manage Developers
</a>
</div>
</div>
</div>
</div>
</div>