diff --git a/app/Controllers/NotificationGroupController.php b/app/Controllers/NotificationGroupController.php index 7a58484..a01a6bd 100644 --- a/app/Controllers/NotificationGroupController.php +++ b/app/Controllers/NotificationGroupController.php @@ -131,7 +131,21 @@ class NotificationGroupController extends Controller $config = $this->buildChannelConfig($channelType, $_POST); if (!$config) { - $_SESSION['error'] = 'Invalid channel configuration'; + $missingField = ''; + switch ($channelType) { + case 'email': + $missingField = 'email address'; + break; + case 'telegram': + $missingField = empty($_POST['bot_token']) ? 'bot token' : 'chat ID'; + break; + case 'discord': + case 'slack': + $missingField = 'webhook URL'; + break; + } + + $_SESSION['error'] = "Invalid channel configuration: Missing {$missingField}"; $this->redirect("/groups/edit?id=$groupId"); return; } @@ -179,12 +193,14 @@ class NotificationGroupController extends Controller ]; case 'discord': - if (empty($data['webhook_url'])) return null; - return ['webhook_url' => $data['webhook_url']]; + $webhookUrl = $data['discord_webhook_url'] ?? ''; + if (empty($webhookUrl)) return null; + return ['webhook_url' => $webhookUrl]; case 'slack': - if (empty($data['webhook_url'])) return null; - return ['webhook_url' => $data['webhook_url']]; + $webhookUrl = $data['slack_webhook_url'] ?? ''; + if (empty($webhookUrl)) return null; + return ['webhook_url' => $webhookUrl]; default: return null; diff --git a/app/Views/groups/edit.php b/app/Views/groups/edit.php index aed22a8..6497861 100644 --- a/app/Views/groups/edit.php +++ b/app/Views/groups/edit.php @@ -194,15 +194,17 @@ ob_start(); @@ -213,11 +215,12 @@ ob_start(); - + name="slack_webhook_url" + class="w-full px-3 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-colors text-sm font-mono" + placeholder="https://hooks.slack.com/services/..." + autocomplete="off">

Create in Slack App Settings → Incoming Webhooks

@@ -285,17 +288,96 @@ ob_start(); function toggleChannelFields() { const channelType = document.getElementById('channel_type').value; + // Get all input fields + const emailField = document.getElementById('email'); + const botTokenField = document.getElementById('bot_token'); + const chatIdField = document.getElementById('chat_id'); + const discordWebhook = document.getElementById('discord_webhook'); + const slackWebhook = document.getElementById('slack_webhook'); + + // Remove required from all + emailField.removeAttribute('required'); + botTokenField.removeAttribute('required'); + chatIdField.removeAttribute('required'); + discordWebhook.removeAttribute('required'); + slackWebhook.removeAttribute('required'); + // Hide all fields document.getElementById('email_fields').classList.add('hidden'); document.getElementById('telegram_fields').classList.add('hidden'); document.getElementById('discord_fields').classList.add('hidden'); document.getElementById('slack_fields').classList.add('hidden'); - // Show selected field + // Show selected field and make required if (channelType) { document.getElementById(channelType + '_fields').classList.remove('hidden'); + + // Set required based on type + switch(channelType) { + case 'email': + emailField.setAttribute('required', 'required'); + break; + case 'telegram': + botTokenField.setAttribute('required', 'required'); + chatIdField.setAttribute('required', 'required'); + break; + case 'discord': + discordWebhook.setAttribute('required', 'required'); + discordWebhook.focus(); // Auto-focus for easy paste + break; + case 'slack': + slackWebhook.setAttribute('required', 'required'); + slackWebhook.focus(); + break; + } } } + +// Form validation before submit +const addChannelForm = document.querySelector('form[action="/channels/add"]'); +if (addChannelForm) { + addChannelForm.addEventListener('submit', function(e) { + const channelType = document.getElementById('channel_type').value; + + if (!channelType) { + e.preventDefault(); + alert('Please select a channel type'); + return false; + } + + // Validate Discord webhook + if (channelType === 'discord') { + const webhookField = document.getElementById('discord_webhook'); + const webhookUrl = webhookField.value.trim(); + + if (!webhookUrl) { + e.preventDefault(); + alert('Please enter the Discord webhook URL'); + webhookField.focus(); + return false; + } + if (!webhookUrl.includes('discord.com/api/webhooks/')) { + e.preventDefault(); + alert('Invalid Discord webhook URL. It should start with:\nhttps://discord.com/api/webhooks/'); + webhookField.focus(); + return false; + } + } + + // Validate Slack webhook + if (channelType === 'slack') { + const webhookUrl = document.getElementById('slack_webhook').value.trim(); + if (!webhookUrl) { + e.preventDefault(); + alert('Please enter the Slack webhook URL'); + document.getElementById('slack_webhook').focus(); + return false; + } + } + + return true; + }); +}