|
Server : LiteSpeed System : Linux terra.hostitbro.com 5.14.0-611.54.3.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Thu May 7 16:31:24 EDT 2026 x86_64 User : outerorb ( 1091) PHP Version : 8.1.34 Disable Function : mail Directory : /home2/outerorb/.trash/survey_system/ | |
|
Path: /home2/outerorb/.trash/survey_system/eventlog.php
Size: 20 KB
Permissions: 0666
<?php
require_once 'config.php';
require_once 'inc/eventlog.php';
// Check if user is logged in and is admin or manager
if (!is_logged_in()) {
header('Location: index.php');
exit;
}
$user = current_user();
if (!in_array($user['role'], ['admin', 'manager'])) {
header('Location: dashboard.php');
exit;
}
include __DIR__ . '/inc/header.php';
/**
* Format event details for user-friendly display
*/
function format_event_details($action, $details) {
switch ($action) {
case 'login':
return "User logged in: " . h($details['username']);
case 'logout':
return "User logged out: " . h($details['username']);
case 'login_failed':
$reason = $details['reason'] ?? 'unknown';
$reason_text = match($reason) {
'invalid_credentials' => 'Invalid username or password',
'account_disabled' => 'Account is disabled',
default => ucfirst(str_replace('_', ' ', $reason))
};
return "Login failed for " . h($details['username']) . ": " . $reason_text;
case 'user_created':
return "Created user '" . h($details['new_username']) . "' with role '" . h($details['role']) . "'" .
(isset($details['team']) ? " in team '" . h($details['team']) . "'" : "");
case 'user_updated':
$changes = $details['changes'] ?? [];
$change_list = [];
foreach ($changes as $field => $change) {
if (is_array($change) && isset($change['old'], $change['new'])) {
$change_list[] = ucfirst($field) . ": '" . h($change['old']) . "' → '" . h($change['new']) . "'";
} else {
$change_list[] = ucfirst($field) . " updated";
}
}
return "Updated user '" . h($details['username']) . "': " . implode(', ', $change_list);
case 'user_disabled':
return "Disabled user account (ID: " . h($details['user_id']) . ")";
case 'user_enabled':
return "Enabled user account (ID: " . h($details['user_id']) . ")";
case 'user_create_failed':
$reason = $details['reason'] ?? 'unknown';
$reason_text = match($reason) {
'username_exists' => 'Username already exists',
default => ucfirst(str_replace('_', ' ', $reason))
};
return "Failed to create user '" . h($details['username']) . "': " . $reason_text;
case 'user_disable_failed':
$reason = $details['reason'] ?? 'unknown';
$reason_text = match($reason) {
'self_disable' => 'Cannot disable own account',
default => ucfirst(str_replace('_', ' ', $reason))
};
return "Failed to disable user (ID: " . h($details['user_id']) . "): " . $reason_text;
case 'lead_created':
return "Created lead (ID: " . h($details['lead_id']) . ") with phone " . h($details['phone']) .
" and status '" . h($details['status']) . "'";
case 'lead_updated':
$changes = $details['changes'] ?? [];
$change_list = [];
foreach ($changes as $field => $change) {
if (is_array($change) && isset($change['old'], $change['new'])) {
$change_list[] = ucfirst(str_replace('_', ' ', $field)) . ": '" . h($change['old']) . "' → '" . h($change['new']) . "'";
} else {
$value = is_array($change) ? json_encode($change) : $change;
$change_list[] = ucfirst(str_replace('_', ' ', $field)) . " updated to '" . h($value) . "'";
}
}
return "Updated lead (ID: " . h($details['lead_id']) . "): " . implode(', ', $change_list);
case 'lead_deleted':
return "Deleted lead (ID: " . h($details['lead_id']) . ") - " . h($details['lead_name']) . " (" . h($details['lead_phone']) . ")";
case 'lead_comment_added':
return "Added comment to lead (ID: " . h($details['lead_id']) . "): " . h($details['comment_preview']);
case 'lead_dialed_status_changed':
return "Changed lead dialed status (ID: " . h($details['lead_id']) . ") to '" . h($details['dialed']) . "'";
case 'notification_marked_read':
return "Marked notification (ID: " . h($details['notification_id']) . ") as read";
case 'notifications_marked_all_read':
return "Marked all notifications as read";
case 'password_changed':
return "Changed password";
case 'data_export':
return "Exported " . h($details['record_count']) . " " . h($details['export_type']) . " records";
case 'phone_lookup':
return "Performed phone lookup for " . h($details['phone_number']) . " (" . ($details['result_found'] ? 'found' : 'not found') . ")";
case 'recording_search':
return "Searched recordings for phone " . h($details['phone']) . " (" . h($details['results_count']) . " results found)";
case 'feature_suggestion_submitted':
return "Submitted feature suggestion: " . h($details['suggestion_preview']);
default:
// Fallback to formatted JSON for unknown actions
return '<pre style="margin:0; font-size:0.8em;">' . h(json_encode($details, JSON_PRETTY_PRINT)) . '</pre>';
}
}
// Handle cleanup
if (isset($_POST['cleanup'])) {
cleanup_old_logs();
flash_set('success', 'Old logs cleaned up.');
header('Location: eventlog.php');
exit;
}
// Filters
$start_date = $_GET['start_date'] ?? '';
$end_date = $_GET['end_date'] ?? '';
$user_filter = $_GET['user_id'] ?? '';
$action_filter = $_GET['action'] ?? '';
$status_filter = $_GET['status'] ?? '';
$page = (int)($_GET['page'] ?? 1);
$per_page = 50;
$offset = ($page - 1) * $per_page;
// Build query
$query = "SELECT el.*, u.username, u.full_name FROM event_logs el LEFT JOIN users u ON el.user_id = u.id WHERE 1=1";
// If manager, filter to show only events from their team members
if ($user['role'] === 'manager') {
$query .= " AND (el.user_id IN (SELECT id FROM users WHERE team = :team AND role != 'admin') OR el.user_id IS NULL)";
}
if ($start_date) {
$query .= " AND DATE(el.`timestamp`) >= :start_date";
}
if ($end_date) {
$query .= " AND DATE(el.`timestamp`) <= :end_date";
}
if ($user_filter) {
$query .= " AND el.user_id = :user_id";
}
if ($action_filter) {
$query .= " AND el.action LIKE :action";
}
if ($status_filter) {
$query .= " AND el.status = :status";
}
$query .= " ORDER BY el.`timestamp` DESC LIMIT :limit OFFSET :offset";
// Get logs
$stmt = $pdo->prepare($query);
if ($user['role'] === 'manager') {
$stmt->bindValue(':team', $user['team']);
}
if ($start_date) {
$stmt->bindValue(':start_date', $start_date);
}
if ($end_date) {
$stmt->bindValue(':end_date', $end_date);
}
if ($user_filter) {
$stmt->bindValue(':user_id', $user_filter);
}
if ($action_filter) {
$stmt->bindValue(':action', '%' . $action_filter . '%');
}
if ($status_filter) {
$stmt->bindValue(':status', $status_filter);
}
$stmt->bindValue(':limit', $per_page, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$logs = $stmt->fetchAll();
// Get total count for pagination
$count_query = str_replace("SELECT el.*, u.username, u.full_name FROM event_logs el LEFT JOIN users u ON el.user_id = u.id WHERE 1=1", "SELECT COUNT(*) FROM event_logs el WHERE 1=1", $query);
$count_query = preg_replace('/ORDER BY.*$/', '', $count_query);
$count_stmt = $pdo->prepare($count_query);
if ($user['role'] === 'manager') {
$count_stmt->bindValue(':team', $user['team']);
}
if ($start_date) {
$count_stmt->bindValue(':start_date', $start_date);
}
if ($end_date) {
$count_stmt->bindValue(':end_date', $end_date);
}
if ($user_filter) {
$count_stmt->bindValue(':user_id', $user_filter);
}
if ($action_filter) {
$count_stmt->bindValue(':action', '%' . $action_filter . '%');
}
if ($status_filter) {
$count_stmt->bindValue(':status', $status_filter);
}
$count_stmt->execute();
$total_logs = $count_stmt->fetchColumn();
$total_pages = ceil($total_logs / $per_page);
// Get users for filter
if ($user['role'] === 'manager') {
// Managers only see users from their team (excluding admins)
$users_stmt = $pdo->prepare("SELECT id, username, full_name FROM users WHERE team = :team AND role != 'admin' ORDER BY username");
$users_stmt->execute(['team' => $user['team']]);
$users = $users_stmt->fetchAll();
} else {
// Admins see all users
$users_stmt = $pdo->query("SELECT id, username, full_name FROM users ORDER BY username");
$users = $users_stmt->fetchAll();
}
// Get unique actions for filter
$actions_stmt = $pdo->query("SELECT DISTINCT action FROM event_logs ORDER BY action");
$actions = $actions_stmt->fetchAll(PDO::FETCH_COLUMN);
// Handle export
if (isset($_GET['export'])) {
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="event_logs_' . date('Y-m-d') . '.csv"');
$output = fopen('php://output', 'w');
fputcsv($output, ['ID', 'Timestamp', 'User', 'Action', 'Details', 'IP', 'User Agent', 'Status']);
foreach ($logs as $log) {
fputcsv($output, [
$log['id'],
$log['timestamp'],
$log['username'] ?: $log['full_name'] ?: 'System',
$log['action'],
format_event_details($log['action'], json_decode($log['details'], true) ?: []),
$log['ip'],
$log['user_agent'],
$log['status']
]);
}
fclose($output);
exit;
}
?>
<style>
/* Light mode specific styles */
body:not(.dark-mode) .eventlog-card {
background: #eaf4fb;
}
body:not(.dark-mode) .eventlog-heading {
color: #6c757d;
}
body:not(.dark-mode) .eventlog-thead {
background: #e3eaf3;
}
</style>
<div class="container mt-5">
<div class="card shadow-sm eventlog-card" style="border-radius: 18px;">
<div class="card-body p-4">
<h2 class="mb-4 eventlog-heading" style="font-size: 1.4rem; font-weight: 600;">Event Logs</h2>
<?php if ($msg = flash_get('success')): ?>
<div class="alert alert-success"><?= h($msg) ?></div>
<?php endif; ?>
<form method="GET" class="mb-4">
<div class="row g-3">
<div class="col-md-2">
<label class="form-label">Start Date</label>
<input type="date" name="start_date" value="<?= h($start_date) ?>" class="form-control">
</div>
<div class="col-md-2">
<label class="form-label">End Date</label>
<input type="date" name="end_date" value="<?= h($end_date) ?>" class="form-control">
</div>
<div class="col-md-2">
<label class="form-label">User</label>
<select name="user_id" class="form-select">
<option value="">All Users</option>
<?php foreach ($users as $u): ?>
<option value="<?= $u['id'] ?>" <?= $user_filter == $u['id'] ? 'selected' : '' ?>>
<?= h($u['username']) ?> (<?= h($u['full_name'] ?? '') ?>)
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label class="form-label">Action</label>
<select name="action" class="form-select">
<option value="">All Actions</option>
<?php foreach ($actions as $act): ?>
<option value="<?= h($act) ?>" <?= $action_filter == $act ? 'selected' : '' ?>>
<?= h($act) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label class="form-label">Status</label>
<select name="status" class="form-select">
<option value="">All</option>
<option value="success" <?= $status_filter == 'success' ? 'selected' : '' ?>>Success</option>
<option value="failure" <?= $status_filter == 'failure' ? 'selected' : '' ?>>Failure</option>
</select>
</div>
<div class="col-md-2 d-flex align-items-end">
<button type="submit" class="btn btn-primary me-2">Filter</button>
<a href="?<?= http_build_query(array_merge($_GET, ['export' => 1])) ?>" class="btn btn-success">Export CSV</a>
</div>
</div>
</form>
<?php if ($user['role'] === 'admin'): ?>
<form method="POST" class="mb-3">
<button type="submit" name="cleanup" class="btn btn-warning" onclick="return confirm('Delete logs older than 30 days?')">Clean Up Old Logs</button>
</form>
<?php endif; ?>
<div class="table-responsive">
<table class="table table-striped align-middle mb-0" style="font-size: 0.9rem;">
<thead class="eventlog-thead">
<tr>
<th>EventID</th>
<th>Timestamp</th>
<th>User</th>
<th>Action</th>
<th>Details</th>
<th>IP</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<?php if (empty($logs)): ?>
<tr><td colspan="7" class="text-center">No logs found.</td></tr>
<?php else: ?>
<?php foreach ($logs as $log): ?>
<tr>
<td><?= $log['id'] ?></td>
<td><?= h($log['timestamp']) ?></td>
<td><?= h($log['username'] ?: $log['full_name'] ?: 'System') ?></td>
<td><?= h($log['action']) ?></td>
<td>
<?php
$details = json_decode($log['details'], true);
if ($details) {
echo '<small>' . format_event_details($log['action'], $details) . '</small>';
} else {
echo '-';
}
?>
</td>
<td><small><?= h($log['ip']) ?></small></td>
<td>
<span class="badge bg-<?= $log['status'] == 'success' ? 'success' : 'danger' ?>">
<?= h($log['status']) ?>
</span>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<?php if ($total_pages > 1): ?>
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
<?php
// Previous button
if ($page > 1): ?>
<li class="page-item">
<a class="page-link" href="?<?= http_build_query(array_merge($_GET, ['page' => $page - 1])) ?>" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<?php else: ?>
<li class="page-item disabled">
<span class="page-link">«</span>
</li>
<?php endif;
// Calculate page range to show
$start_page = max(1, $page - 2);
$end_page = min($total_pages, $page + 2);
// Adjust if we're near the beginning or end
if ($page <= 3) {
$end_page = min(5, $total_pages);
}
if ($page > $total_pages - 3) {
$start_page = max(1, $total_pages - 4);
}
// First page
if ($start_page > 1): ?>
<li class="page-item">
<a class="page-link" href="?<?= http_build_query(array_merge($_GET, ['page' => 1])) ?>">1</a>
</li>
<?php if ($start_page > 2): ?>
<li class="page-item disabled"><span class="page-link">...</span></li>
<?php endif;
endif;
// Page numbers
for ($i = $start_page; $i <= $end_page; $i++): ?>
<li class="page-item <?= $i == $page ? 'active' : '' ?>">
<a class="page-link" href="?<?= http_build_query(array_merge($_GET, ['page' => $i])) ?>"><?= $i ?></a>
</li>
<?php endfor;
// Last page
if ($end_page < $total_pages): ?>
<?php if ($end_page < $total_pages - 1): ?>
<li class="page-item disabled"><span class="page-link">...</span></li>
<?php endif; ?>
<li class="page-item">
<a class="page-link" href="?<?= http_build_query(array_merge($_GET, ['page' => $total_pages])) ?>"><?= $total_pages ?></a>
</li>
<?php endif;
// Next button
if ($page < $total_pages): ?>
<li class="page-item">
<a class="page-link" href="?<?= http_build_query(array_merge($_GET, ['page' => $page + 1])) ?>" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
<?php else: ?>
<li class="page-item disabled">
<span class="page-link">»</span>
</li>
<?php endif; ?>
</ul>
</nav>
<?php endif; ?>
</div>
</div>
</div>
<?php include __DIR__ . '/inc/footer.php'; ?>