Add Pushover notification channel and improve status detection
Introduces Pushover as a new notification channel with priority-based alerts, device targeting, and custom sounds. Enhances domain status detection for .nl and .eu domains, ensuring accurate handling when expiration dates or explicit status flags are missing. Fixes PHP 8.x compatibility issues with null parameters in date functions and improves error handling and logging by replacing error_log() with a centralized Logger service. Updates documentation and migrations for version 1.1.1.
This commit is contained in:
@@ -94,7 +94,11 @@ class AuthController extends Controller
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
error_log("Login failed: User '$username' not found or not active");
|
||||
$logger = new \App\Services\Logger();
|
||||
$logger->warning("Login failed - User not found or not active", [
|
||||
'username' => $username,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
|
||||
]);
|
||||
$_SESSION['error'] = 'Invalid username or password';
|
||||
$this->redirect('/login');
|
||||
return;
|
||||
@@ -102,14 +106,22 @@ class AuthController extends Controller
|
||||
|
||||
// Verify password
|
||||
if (!$this->userModel->verifyPassword($password, $user['password'])) {
|
||||
error_log("Login failed: Password verification failed for user '$username'");
|
||||
error_log("Stored hash: {$user['password']}");
|
||||
$logger = new \App\Services\Logger();
|
||||
$logger->warning("Login failed - Password verification failed", [
|
||||
'username' => $username,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
|
||||
]);
|
||||
$_SESSION['error'] = 'Invalid username or password';
|
||||
$this->redirect('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
error_log("Login successful for user '$username'");
|
||||
$logger = new \App\Services\Logger();
|
||||
$logger->info("Login successful", [
|
||||
'username' => $username,
|
||||
'user_id' => $user['id'],
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
|
||||
]);
|
||||
|
||||
// Check if email verification is required
|
||||
$requireVerification = $this->settingModel->getValue('require_email_verification');
|
||||
@@ -310,7 +322,11 @@ class AuthController extends Controller
|
||||
$notificationService->notifyWelcome($userId, $username);
|
||||
} catch (\Exception $e) {
|
||||
// Don't fail registration if notification fails
|
||||
error_log("Failed to create welcome notification: " . $e->getMessage());
|
||||
$logger = new \App\Services\Logger();
|
||||
$logger->error("Failed to create welcome notification", [
|
||||
'user_id' => $userId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
// Check if email verification is required
|
||||
@@ -684,7 +700,11 @@ class AuthController extends Controller
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Silently fail - remember me is not critical
|
||||
error_log("Failed to create remember token: " . $e->getMessage());
|
||||
$logger = new \App\Services\Logger();
|
||||
$logger->error("Failed to create remember token", [
|
||||
'user_id' => $userId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ class DomainController extends Controller
|
||||
}
|
||||
|
||||
// Create domain
|
||||
$status = $this->whoisService->getDomainStatus($whoisData['expiration_date'], $whoisData['status'] ?? []);
|
||||
$status = $this->whoisService->getDomainStatus($whoisData['expiration_date'], $whoisData['status'] ?? [], $whoisData);
|
||||
|
||||
// Warn if domain is available (not registered)
|
||||
if ($status === 'available') {
|
||||
@@ -462,7 +462,7 @@ class DomainController extends Controller
|
||||
// Use WHOIS expiration date if available, otherwise preserve manual expiration date
|
||||
$expirationDate = $whoisData['expiration_date'] ?? $domain['expiration_date'];
|
||||
|
||||
$status = $this->whoisService->getDomainStatus($expirationDate, $whoisData['status'] ?? []);
|
||||
$status = $this->whoisService->getDomainStatus($expirationDate, $whoisData['status'] ?? [], $whoisData);
|
||||
|
||||
$this->domainModel->update($id, [
|
||||
'registrar' => $whoisData['registrar'],
|
||||
@@ -673,7 +673,7 @@ class DomainController extends Controller
|
||||
continue;
|
||||
}
|
||||
|
||||
$status = $this->whoisService->getDomainStatus($whoisData['expiration_date'], $whoisData['status'] ?? []);
|
||||
$status = $this->whoisService->getDomainStatus($whoisData['expiration_date'], $whoisData['status'] ?? [], $whoisData);
|
||||
|
||||
// Track available domains
|
||||
if ($status === 'available') {
|
||||
@@ -792,7 +792,7 @@ class DomainController extends Controller
|
||||
// Use WHOIS expiration date if available, otherwise preserve manual expiration date
|
||||
$expirationDate = $whoisData['expiration_date'] ?? $domain['expiration_date'];
|
||||
|
||||
$status = $this->whoisService->getDomainStatus($expirationDate, $whoisData['status'] ?? []);
|
||||
$status = $this->whoisService->getDomainStatus($expirationDate, $whoisData['status'] ?? [], $whoisData);
|
||||
|
||||
$this->domainModel->update($id, [
|
||||
'registrar' => $whoisData['registrar'],
|
||||
|
||||
@@ -52,6 +52,8 @@ class InstallerController extends Controller
|
||||
'019_add_webhook_channel_type.sql',
|
||||
'020_create_tags_system.sql',
|
||||
'021_add_avatar_field.sql',
|
||||
'022_add_pushover_channel_type.sql',
|
||||
'023_update_app_version_to_1.1.1.sql',
|
||||
];
|
||||
|
||||
try {
|
||||
@@ -175,7 +177,7 @@ class InstallerController extends Controller
|
||||
$stmt->execute([$migration]);
|
||||
}
|
||||
|
||||
// Return only new migrations for v1.1.0
|
||||
// Return only new migrations for v1.1.x
|
||||
return [
|
||||
'009_add_authentication_features.sql',
|
||||
'010_add_app_version_setting.sql',
|
||||
@@ -189,7 +191,9 @@ class InstallerController extends Controller
|
||||
'018_add_user_isolation.sql',
|
||||
'019_add_webhook_channel_type.sql',
|
||||
'020_create_tags_system.sql',
|
||||
'021_add_avatar_field.sql'
|
||||
'021_add_avatar_field.sql',
|
||||
'022_add_pushover_channel_type.sql',
|
||||
'023_update_app_version_to_1.1.1.sql',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -373,6 +377,8 @@ class InstallerController extends Controller
|
||||
'019_add_webhook_channel_type.sql',
|
||||
'020_create_tags_system.sql',
|
||||
'021_add_avatar_field.sql',
|
||||
'022_add_pushover_channel_type.sql',
|
||||
'023_update_app_version_to_1.1.1.sql',
|
||||
];
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO migrations (migration) VALUES (?) ON DUPLICATE KEY UPDATE migration=migration");
|
||||
@@ -591,10 +597,12 @@ class InstallerController extends Controller
|
||||
|
||||
// Determine from/to versions based on migrations
|
||||
$fromVersion = '1.0.0';
|
||||
$toVersion = '1.1.0';
|
||||
$toVersion = '1.1.1';
|
||||
|
||||
// Detect version based on which migrations were run
|
||||
if (in_array('011_create_sessions_table.sql', $executed) ||
|
||||
if (in_array('022_add_pushover_channel_type.sql', $executed)) {
|
||||
$toVersion = '1.1.1';
|
||||
} elseif (in_array('011_create_sessions_table.sql', $executed) ||
|
||||
in_array('012_link_remember_tokens_to_sessions.sql', $executed) ||
|
||||
in_array('013_create_user_notifications_table.sql', $executed)) {
|
||||
$toVersion = '1.1.0';
|
||||
|
||||
@@ -305,6 +305,9 @@ class NotificationGroupController extends Controller
|
||||
case 'webhook':
|
||||
$missingField = 'webhook URL';
|
||||
break;
|
||||
case 'pushover':
|
||||
$missingField = empty($_POST['pushover_api_token']) ? 'API token' : 'user key';
|
||||
break;
|
||||
}
|
||||
|
||||
$_SESSION['error'] = "Invalid channel configuration: Missing {$missingField}";
|
||||
@@ -545,6 +548,39 @@ class NotificationGroupController extends Controller
|
||||
}
|
||||
return ['webhook_url' => $webhookUrl];
|
||||
|
||||
case 'pushover':
|
||||
$apiToken = trim($data['pushover_api_token'] ?? '');
|
||||
$userKey = trim($data['pushover_user_key'] ?? '');
|
||||
|
||||
// Both API token and user key are required
|
||||
if (empty($apiToken) || empty($userKey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Basic validation for Pushover token format (30 characters, alphanumeric)
|
||||
if (!preg_match('/^[a-zA-Z0-9]{30}$/', $apiToken) || !preg_match('/^[a-zA-Z0-9]{30}$/', $userKey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$config = [
|
||||
'api_token' => $apiToken,
|
||||
'user_key' => $userKey
|
||||
];
|
||||
|
||||
// Optional: Device name
|
||||
$device = trim($data['pushover_device'] ?? '');
|
||||
if (!empty($device)) {
|
||||
$config['device'] = $device;
|
||||
}
|
||||
|
||||
// Optional: Sound
|
||||
$sound = trim($data['pushover_sound'] ?? '');
|
||||
if (!empty($sound)) {
|
||||
$config['sound'] = $sound;
|
||||
}
|
||||
|
||||
return $config;
|
||||
|
||||
case 'webhook':
|
||||
$webhookUrl = trim($data['webhook_url'] ?? '');
|
||||
if (empty($webhookUrl) || !filter_var($webhookUrl, FILTER_VALIDATE_URL)) {
|
||||
|
||||
@@ -45,7 +45,11 @@ class ProfileController extends Controller
|
||||
$this->sessionModel->cleanOldSessions();
|
||||
} catch (\Exception $e) {
|
||||
// Silent fail - don't break the page
|
||||
error_log("Session cleanup failed: " . $e->getMessage());
|
||||
$logger = new \App\Services\Logger();
|
||||
$logger->error('Session cleanup failed', [
|
||||
'user_id' => \Core\Auth::id(),
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
// Get all active sessions
|
||||
|
||||
@@ -179,7 +179,11 @@ class UserController extends Controller
|
||||
$notificationService->notifyWelcome($userId, $username);
|
||||
} catch (\Exception $e) {
|
||||
// Don't fail user creation if notification fails
|
||||
error_log("Failed to create welcome notification: " . $e->getMessage());
|
||||
$logger = new \App\Services\Logger();
|
||||
$logger->error("Failed to create welcome notification", [
|
||||
'user_id' => $userId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
$_SESSION['success'] = 'User created successfully';
|
||||
|
||||
Reference in New Issue
Block a user