Fix bulk actions selection and set timezone earlier

Improves bulk actions in the domains view by ensuring unique domain IDs are counted and selected, preventing double-counting from desktop and mobile checkboxes. Adds CSRF token to bulk actions forms for security. Moves timezone initialization to public/index.php to ensure it is set before any date operations, and updates base layout to reflect this change.
This commit is contained in:
Hosteroid
2025-10-11 21:22:39 +03:00
parent dcb7f685dd
commit 26ad852451
3 changed files with 44 additions and 8 deletions

View File

@@ -452,20 +452,26 @@ function updateBulkActions() {
const selectedCount = document.getElementById('selected-count'); const selectedCount = document.getElementById('selected-count');
const selectAllCheckbox = document.getElementById('select-all'); const selectAllCheckbox = document.getElementById('select-all');
if (checkboxes.length > 0) { // Get unique domain IDs (avoid counting both desktop and mobile checkboxes)
const uniqueIds = new Set(Array.from(checkboxes).map(cb => cb.value));
const count = uniqueIds.size;
if (count > 0) {
bulkActions.classList.remove('hidden'); bulkActions.classList.remove('hidden');
bulkActions.classList.add('flex'); bulkActions.classList.add('flex');
selectedCount.textContent = `${checkboxes.length} domain(s) selected`; selectedCount.textContent = `${count} domain(s) selected`;
} else { } else {
bulkActions.classList.add('hidden'); bulkActions.classList.add('hidden');
bulkActions.classList.remove('flex'); bulkActions.classList.remove('flex');
} }
// Update select all checkbox state // Update select all checkbox state
const allCheckboxes = document.querySelectorAll('.domain-checkbox, .domain-checkbox-mobile'); // Only count desktop checkboxes to avoid double counting
const allCheckboxes = document.querySelectorAll('.domain-checkbox');
const checkedDesktopBoxes = document.querySelectorAll('.domain-checkbox:checked');
if (selectAllCheckbox) { if (selectAllCheckbox) {
selectAllCheckbox.checked = allCheckboxes.length > 0 && checkboxes.length === allCheckboxes.length; selectAllCheckbox.checked = allCheckboxes.length > 0 && checkedDesktopBoxes.length === allCheckboxes.length;
selectAllCheckbox.indeterminate = checkboxes.length > 0 && checkboxes.length < allCheckboxes.length; selectAllCheckbox.indeterminate = checkedDesktopBoxes.length > 0 && checkedDesktopBoxes.length < allCheckboxes.length;
} }
} }
@@ -480,7 +486,9 @@ function clearSelection() {
function getSelectedIds() { function getSelectedIds() {
const checkboxes = document.querySelectorAll('.domain-checkbox:checked, .domain-checkbox-mobile:checked'); const checkboxes = document.querySelectorAll('.domain-checkbox:checked, .domain-checkbox-mobile:checked');
return Array.from(checkboxes).map(cb => cb.value); // Return unique IDs only (avoid duplicates from desktop and mobile views)
const ids = Array.from(checkboxes).map(cb => cb.value);
return [...new Set(ids)];
} }
function bulkRefresh() { function bulkRefresh() {
@@ -491,6 +499,13 @@ function bulkRefresh() {
form.method = 'POST'; form.method = 'POST';
form.action = '/domains/bulk-refresh'; form.action = '/domains/bulk-refresh';
// Add CSRF token
const csrfInput = document.createElement('input');
csrfInput.type = 'hidden';
csrfInput.name = 'csrf_token';
csrfInput.value = '<?= csrf_token() ?>';
form.appendChild(csrfInput);
ids.forEach(id => { ids.forEach(id => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'hidden'; input.type = 'hidden';
@@ -515,6 +530,13 @@ function bulkDelete() {
form.method = 'POST'; form.method = 'POST';
form.action = '/domains/bulk-delete'; form.action = '/domains/bulk-delete';
// Add CSRF token
const csrfInput = document.createElement('input');
csrfInput.type = 'hidden';
csrfInput.name = 'csrf_token';
csrfInput.value = '<?= csrf_token() ?>';
form.appendChild(csrfInput);
ids.forEach(id => { ids.forEach(id => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'hidden'; input.type = 'hidden';

View File

@@ -26,8 +26,7 @@ if (!isset($appName)) {
$appTimezone = $appSettings['app_timezone']; $appTimezone = $appSettings['app_timezone'];
$appVersion = $appSettings['app_version']; $appVersion = $appSettings['app_version'];
// Set PHP timezone // Note: Timezone is now set early in public/index.php (before controllers run)
date_default_timezone_set($appTimezone);
} }
?> ?>
<!DOCTYPE html> <!DOCTYPE html>

View File

@@ -58,6 +58,21 @@ if (!isset($_SESSION['user_id']) && isset($_COOKIE['remember_token']) && !$isIns
$authController->checkRememberToken(); $authController->checkRememberToken();
} }
// Set application timezone early (before any date operations)
if (!$isInstallerPath && file_exists($installedFlagFile)) {
try {
$settingModel = new \App\Models\Setting();
$timezone = $settingModel->getValue('app_timezone', 'UTC');
date_default_timezone_set($timezone);
} catch (\Exception $e) {
// Database not available, use UTC as fallback
date_default_timezone_set('UTC');
}
} else {
// Default to UTC during installation
date_default_timezone_set('UTC');
}
// Initialize application // Initialize application
$app = new Application(); $app = new Application();