272 lines
9.5 KiB
JavaScript
272 lines
9.5 KiB
JavaScript
/**
|
|
* @fileoverview Manages the events page functionality.
|
|
* This file handles event filtering, pagination, and modal interactions.
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Elements
|
|
const eventTypeFilter = document.getElementById('eventTypeFilter');
|
|
const dateRangeFilter = document.getElementById('dateRangeFilter');
|
|
const userFilter = document.getElementById('userFilter');
|
|
const applyFiltersBtn = document.getElementById('applyFilters');
|
|
const eventsTableBody = document.getElementById('eventsTableBody');
|
|
const prevPageBtn = document.getElementById('prevPage');
|
|
const nextPageBtn = document.getElementById('nextPage');
|
|
const currentPageSpan = document.getElementById('currentPage');
|
|
const totalPagesSpan = document.getElementById('totalPages');
|
|
const eventDetailsModal = document.getElementById('eventDetailsModal');
|
|
const eventDetailsContent = document.getElementById('eventDetailsContent');
|
|
|
|
// State
|
|
let currentPage = 1;
|
|
let totalPages = 1;
|
|
let currentFilters = {
|
|
eventType: '',
|
|
dateRange: '24h',
|
|
userId: ''
|
|
};
|
|
|
|
/**
|
|
* Loads events based on current filters and page
|
|
*/
|
|
async function loadEvents() {
|
|
try {
|
|
const response = await fetch(`/api/events?page=${currentPage}&${new URLSearchParams(currentFilters)}`);
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
renderEvents(data.events);
|
|
updatePagination(data.total_pages);
|
|
} else {
|
|
console.error('Failed to load events:', data.error);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading events:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Renders events in the table
|
|
*/
|
|
function renderEvents(events) {
|
|
if (!Array.isArray(events)) {
|
|
console.error('Invalid events data received:', events);
|
|
return;
|
|
}
|
|
|
|
const eventRows = events.map(event => {
|
|
if (!event || typeof event !== 'object') {
|
|
console.error('Invalid event data:', event);
|
|
return '';
|
|
}
|
|
|
|
// Determine badge color and text based on event type
|
|
let badgeClass = 'bg-secondary';
|
|
let eventText = event.event_type || 'Unknown Event';
|
|
|
|
switch(event.event_type) {
|
|
case 'user_login':
|
|
badgeClass = 'bg-success';
|
|
eventText = 'User Login';
|
|
break;
|
|
case 'user_logout':
|
|
badgeClass = 'bg-secondary';
|
|
eventText = 'User Logout';
|
|
break;
|
|
case 'user_register':
|
|
badgeClass = 'bg-info';
|
|
eventText = 'User Registration';
|
|
break;
|
|
case 'user_update':
|
|
badgeClass = 'bg-primary';
|
|
eventText = 'User Update';
|
|
break;
|
|
case 'file_upload':
|
|
badgeClass = 'bg-success';
|
|
eventText = 'File Upload';
|
|
break;
|
|
case 'file_delete':
|
|
badgeClass = 'bg-danger';
|
|
eventText = 'File Delete';
|
|
break;
|
|
case 'file_download':
|
|
badgeClass = 'bg-info';
|
|
eventText = 'File Download';
|
|
break;
|
|
case 'file_restore':
|
|
badgeClass = 'bg-warning';
|
|
eventText = 'File Restore';
|
|
break;
|
|
case 'file_move':
|
|
badgeClass = 'bg-primary';
|
|
eventText = 'File Move';
|
|
break;
|
|
case 'file_rename':
|
|
badgeClass = 'bg-info';
|
|
eventText = 'File Rename';
|
|
break;
|
|
case 'file_star':
|
|
badgeClass = 'bg-warning';
|
|
eventText = 'File Star';
|
|
break;
|
|
case 'file_unstar':
|
|
badgeClass = 'bg-secondary';
|
|
eventText = 'File Unstar';
|
|
break;
|
|
case 'room_create':
|
|
badgeClass = 'bg-success';
|
|
eventText = 'Room Create';
|
|
break;
|
|
case 'room_delete':
|
|
badgeClass = 'bg-danger';
|
|
eventText = 'Room Delete';
|
|
break;
|
|
case 'room_update':
|
|
badgeClass = 'bg-primary';
|
|
eventText = 'Room Update';
|
|
break;
|
|
case 'room_join':
|
|
badgeClass = 'bg-info';
|
|
eventText = 'Room Join';
|
|
break;
|
|
case 'room_leave':
|
|
badgeClass = 'bg-secondary';
|
|
eventText = 'Room Leave';
|
|
break;
|
|
case 'conversation_create':
|
|
badgeClass = 'bg-success';
|
|
eventText = 'Conversation Create';
|
|
break;
|
|
case 'conversation_delete':
|
|
badgeClass = 'bg-danger';
|
|
eventText = 'Conversation Delete';
|
|
break;
|
|
case 'message_sent':
|
|
badgeClass = 'bg-primary';
|
|
eventText = 'Message Sent';
|
|
break;
|
|
case 'attachment_download':
|
|
badgeClass = 'bg-info';
|
|
eventText = 'Attachment Download';
|
|
break;
|
|
}
|
|
|
|
const timestamp = event.timestamp ? new Date(event.timestamp).toLocaleString() : '-';
|
|
const username = event.user?.username || 'Unknown User';
|
|
const lastName = event.user?.last_name || '';
|
|
const eventId = event.id || '';
|
|
const ipAddress = event.ip_address || '-';
|
|
|
|
return `
|
|
<tr>
|
|
<td>${timestamp}</td>
|
|
<td><span class="badge ${badgeClass}">${eventText}</span></td>
|
|
<td>${username} ${lastName}</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-secondary"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#eventDetailsModal"
|
|
data-event-id="${eventId}">
|
|
<i class="fas fa-info-circle"></i> View Details
|
|
</button>
|
|
</td>
|
|
<td>${ipAddress}</td>
|
|
</tr>
|
|
`;
|
|
}).join('');
|
|
|
|
eventsTableBody.innerHTML = eventRows;
|
|
|
|
// Add event listeners to detail buttons
|
|
document.querySelectorAll('[data-event-id]').forEach(button => {
|
|
button.addEventListener('click', () => {
|
|
const eventId = button.dataset.eventId;
|
|
if (eventId) {
|
|
showEventDetails(eventId);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Updates pagination controls
|
|
*/
|
|
function updatePagination(total) {
|
|
totalPages = total;
|
|
currentPageSpan.textContent = currentPage;
|
|
totalPagesSpan.textContent = totalPages;
|
|
|
|
prevPageBtn.classList.toggle('disabled', currentPage === 1);
|
|
nextPageBtn.classList.toggle('disabled', currentPage === totalPages);
|
|
}
|
|
|
|
/**
|
|
* Shows event details in modal
|
|
*/
|
|
async function showEventDetails(eventId) {
|
|
try {
|
|
const response = await fetch(`/api/events/${eventId}`);
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
const event = data.event;
|
|
eventDetailsContent.textContent = JSON.stringify(event.details, null, 2);
|
|
} else {
|
|
console.error('Failed to load event details:', data.error);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading event details:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Loads users for the user filter
|
|
*/
|
|
async function loadUsers() {
|
|
try {
|
|
const response = await fetch('/api/users');
|
|
const data = await response.json();
|
|
|
|
const userFilter = document.getElementById('userFilter');
|
|
userFilter.innerHTML = '<option value="">All Users</option>';
|
|
|
|
data.users.forEach(user => {
|
|
const option = document.createElement('option');
|
|
option.value = user.id;
|
|
option.textContent = `${user.username} ${user.last_name || ''}`.trim();
|
|
userFilter.appendChild(option);
|
|
});
|
|
} catch (error) {
|
|
console.error('Error loading users:', error);
|
|
}
|
|
}
|
|
|
|
// Event Listeners
|
|
applyFiltersBtn.addEventListener('click', () => {
|
|
currentFilters = {
|
|
eventType: eventTypeFilter.value,
|
|
dateRange: dateRangeFilter.value,
|
|
userId: userFilter.value
|
|
};
|
|
currentPage = 1;
|
|
loadEvents();
|
|
});
|
|
|
|
prevPageBtn.addEventListener('click', () => {
|
|
if (currentPage > 1) {
|
|
currentPage--;
|
|
loadEvents();
|
|
}
|
|
});
|
|
|
|
nextPageBtn.addEventListener('click', () => {
|
|
if (currentPage < totalPages) {
|
|
currentPage++;
|
|
loadEvents();
|
|
}
|
|
});
|
|
|
|
// Initialize
|
|
loadUsers();
|
|
loadEvents();
|
|
});
|