From adc28b97f064f1720a184b80334bf96086b84f35 Mon Sep 17 00:00:00 2001 From: Hosteroid Date: Thu, 9 Oct 2025 16:38:52 +0300 Subject: [PATCH] Fixed Discord issue Enhanced error messages for missing channel configuration fields in NotificationGroupController. Updated Discord and Slack webhook input handling to use distinct field names, improved form validation and required field logic in the edit group view, and added user guidance for webhook URLs. --- .../NotificationGroupController.php | 26 ++++- app/Views/groups/edit.php | 104 ++++++++++++++++-- 2 files changed, 114 insertions(+), 16 deletions(-) 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; + }); +}