diff --git a/admin.php b/admin.php index 89bfd44..16294d6 100644 --- a/admin.php +++ b/admin.php @@ -524,6 +524,8 @@ $current_session_user = isset($_SESSION['user']) ? (string) $_SESSION['user'] : Manufactures Vaisseaux Presets Vaisseau + SC Webhook + SC Notification diff --git a/assets/pasted-20260408-155112-5f68f53a.png b/assets/pasted-20260408-155112-5f68f53a.png new file mode 100644 index 0000000..09b2068 Binary files /dev/null and b/assets/pasted-20260408-155112-5f68f53a.png differ diff --git a/db/scdiscord.php b/db/scdiscord.php new file mode 100644 index 0000000..59a58a4 --- /dev/null +++ b/db/scdiscord.php @@ -0,0 +1,243 @@ +exec( + "CREATE TABLE IF NOT EXISTS tbl_scwebhooks ( + cl_scwebhook_id INT(11) NOT NULL AUTO_INCREMENT, + cl_scwebhook_name VARCHAR(255) NOT NULL, + cl_scwebhook_url TEXT NOT NULL, + cl_scwebhook_is_forum TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (cl_scwebhook_id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" + ); + + $db->exec( + "CREATE TABLE IF NOT EXISTS tbl_scbanners ( + cl_scbanner_id INT(11) NOT NULL AUTO_INCREMENT, + cl_scbanner_name VARCHAR(255) NOT NULL, + cl_scbanner_url TEXT NOT NULL, + cl_scbanner_border_color VARCHAR(20) NOT NULL DEFAULT '#ffae00', + PRIMARY KEY (cl_scbanner_id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" + ); + + $columns_stmt = $db->query("SHOW COLUMNS FROM tbl_scbanners LIKE 'cl_scbanner_border_color'"); + $has_border_color = (bool) $columns_stmt->fetch(); + if (!$has_border_color) { + $db->exec("ALTER TABLE tbl_scbanners ADD COLUMN cl_scbanner_border_color VARCHAR(20) NOT NULL DEFAULT '#ffae00' AFTER cl_scbanner_url"); + } + + $db->exec( + "CREATE TABLE IF NOT EXISTS tbl_scnotifications ( + cl_scnotification_id INT(11) NOT NULL AUTO_INCREMENT, + cl_scnotification_webhook_id INT(11) NOT NULL, + cl_scnotification_banner_id INT(11) DEFAULT NULL, + cl_scnotification_title VARCHAR(255) NOT NULL DEFAULT '', + cl_scnotification_message TEXT NOT NULL, + cl_scnotification_payload LONGTEXT NOT NULL, + cl_scnotification_response LONGTEXT DEFAULT NULL, + cl_scnotification_success TINYINT(1) NOT NULL DEFAULT 0, + cl_scnotification_created_by VARCHAR(190) NOT NULL, + cl_scnotification_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (cl_scnotification_id), + KEY idx_scnotification_webhook (cl_scnotification_webhook_id), + KEY idx_scnotification_banner (cl_scnotification_banner_id), + CONSTRAINT fk_scnotification_webhook FOREIGN KEY (cl_scnotification_webhook_id) + REFERENCES tbl_scwebhooks (cl_scwebhook_id) + ON UPDATE CASCADE + ON DELETE RESTRICT, + CONSTRAINT fk_scnotification_banner FOREIGN KEY (cl_scnotification_banner_id) + REFERENCES tbl_scbanners (cl_scbanner_id) + ON UPDATE CASCADE + ON DELETE SET NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" + ); + + $stmt_existing_red = $db->prepare('SELECT cl_scbanner_id FROM tbl_scbanners WHERE cl_scbanner_name = :name LIMIT 1'); + $stmt_existing_red->execute(['name' => 'Alerte Rouge']); + $existing_red_banner = $stmt_existing_red->fetch(PDO::FETCH_ASSOC); + + if ($existing_red_banner) { + $stmt_update_red = $db->prepare( + 'UPDATE tbl_scbanners + SET cl_scbanner_border_color = CASE + WHEN cl_scbanner_border_color IS NULL OR cl_scbanner_border_color = "" OR cl_scbanner_border_color = "#ffae00" + THEN :border_color + ELSE cl_scbanner_border_color + END + WHERE cl_scbanner_id = :id' + ); + $stmt_update_red->execute([ + 'border_color' => '#ff3b30', + 'id' => $existing_red_banner['cl_scbanner_id'], + ]); + } + + $bootstrapped = true; +} + +function scdiscord_mask_webhook_url(string $url): string +{ + $trimmed = trim($url); + if ($trimmed === '') { + return ''; + } + + $length = strlen($trimmed); + if ($length <= 24) { + return str_repeat('•', max(8, $length)); + } + + return substr($trimmed, 0, 32) . str_repeat('•', 18) . substr($trimmed, -10); +} + +function scdiscord_normalize_hex_color(string $color): string +{ + $candidate = strtoupper(trim($color)); + if ($candidate === '') { + return '#FFAE00'; + } + + if ($candidate[0] !== '#') { + $candidate = '#' . $candidate; + } + + if (!preg_match('/^#[0-9A-F]{6}$/', $candidate)) { + return '#FFAE00'; + } + + return $candidate; +} + +function scdiscord_hex_to_decimal(string $color): int +{ + return hexdec(ltrim(scdiscord_normalize_hex_color($color), '#')); +} + +function scdiscord_build_mentions(bool $notify_here, bool $notify_everyone): array +{ + $parts = []; + + if ($notify_here) { + $parts[] = '@here'; + } + + if ($notify_everyone) { + $parts[] = '@everyone'; + } + + return $parts; +} + +function scdiscord_build_thread_name(string $title, string $location, string $start_date): string +{ + $parts = []; + + if ($title !== '') { + $parts[] = $title; + } + + if ($location !== '') { + $parts[] = $location; + } + + if ($start_date !== '') { + $parts[] = $start_date; + } + + $thread_name = trim(implode(' • ', $parts)); + + if ($thread_name === '') { + $thread_name = 'Notification Discord'; + } + + return mb_substr($thread_name, 0, 100); +} + +function scdiscord_post_webhook(string $webhook_url, array $payload): array +{ + $target_url = $webhook_url; + $separator = (str_contains($target_url, '?')) ? '&' : '?'; + $target_url .= $separator . 'wait=true'; + + $json_payload = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + + if ($json_payload === false) { + return [ + 'success' => false, + 'http_code' => 0, + 'response' => 'Erreur d\'encodage JSON.', + ]; + } + + if (function_exists('curl_init')) { + $ch = curl_init($target_url); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $json_payload, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Content-Length: ' . strlen($json_payload), + ], + CURLOPT_RETURNTRANSFER => true, + CURLOPT_TIMEOUT => 20, + ]); + + $response = curl_exec($ch); + $http_code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curl_error = curl_error($ch); + curl_close($ch); + + if ($response === false) { + return [ + 'success' => false, + 'http_code' => $http_code, + 'response' => $curl_error !== '' ? $curl_error : 'Erreur CURL inconnue.', + ]; + } + + return [ + 'success' => $http_code >= 200 && $http_code < 300, + 'http_code' => $http_code, + 'response' => $response, + ]; + } + + $context = stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'header' => "Content-Type: application/json\r\n", + 'content' => $json_payload, + 'timeout' => 20, + 'ignore_errors' => true, + ], + ]); + + $response = @file_get_contents($target_url, false, $context); + $http_code = 0; + if (isset($http_response_header) && is_array($http_response_header)) { + foreach ($http_response_header as $header_line) { + if (preg_match('#^HTTP/\S+\s+(\d{3})#', $header_line, $matches)) { + $http_code = (int) $matches[1]; + break; + } + } + } + + return [ + 'success' => $response !== false && $http_code >= 200 && $http_code < 300, + 'http_code' => $http_code, + 'response' => $response === false ? 'Erreur lors de la requête HTTP.' : $response, + ]; +} diff --git a/scitems.php b/scitems.php index 7239f8f..71485b0 100644 --- a/scitems.php +++ b/scitems.php @@ -406,6 +406,8 @@ if ($edit_id > 0) { Manufactures Vaisseaux Presets Vaisseau + SC Webhook + SC Notification diff --git a/scmanufactures.php b/scmanufactures.php index e6e3ac0..82705d6 100644 --- a/scmanufactures.php +++ b/scmanufactures.php @@ -278,6 +278,8 @@ $current_session_user = $_SESSION['user'] ?? ''; Manufactures Vaisseaux Presets Vaisseau + SC Webhook + SC Notification diff --git a/scmining.php b/scmining.php index 36c9fb1..8bd03cf 100644 --- a/scmining.php +++ b/scmining.php @@ -335,6 +335,8 @@ $current_session_user = $_SESSION['user'] ?? ''; Manufactures Vaisseaux Presets Vaisseau + SC Webhook + SC Notification diff --git a/scnotification.php b/scnotification.php new file mode 100644 index 0000000..96f2851 --- /dev/null +++ b/scnotification.php @@ -0,0 +1,969 @@ +prepare('SELECT * FROM tbl_scwebhooks WHERE cl_scwebhook_id = :id LIMIT 1'); + $stmt_webhook->execute(['id' => $cl_scnotification_webhook_id]); + $webhook = $stmt_webhook->fetch(); + + if (!$webhook) { + auth_flash_set('error', 'Webhook Discord introuvable.'); + header('Location: scnotification.php'); + exit; + } + + $banner = null; + if ($cl_scnotification_banner_id > 0) { + $stmt_banner = $db->prepare('SELECT * FROM tbl_scbanners WHERE cl_scbanner_id = :id LIMIT 1'); + $stmt_banner->execute(['id' => $cl_scnotification_banner_id]); + $banner = $stmt_banner->fetch(); + } + + if ($use_custom_banner && $cl_scnotification_custom_banner_url !== '' && !filter_var($cl_scnotification_custom_banner_url, FILTER_VALIDATE_URL)) { + auth_flash_set('error', 'L’URL de bannière personnalisée est invalide.'); + header('Location: scnotification.php'); + exit; + } + + foreach ([ + 'URL canal Discord' => [$show_channel_url, $cl_scnotification_channel_url], + 'URL inventaire' => [$show_inventory_url, $cl_scnotification_inventory_url], + 'URL source' => [$show_source_url, $cl_scnotification_source_url], + 'Icône du footer' => [$show_footer && $cl_scnotification_footer_icon_url !== '', $cl_scnotification_footer_icon_url], + ] as $label => [$enabled, $value]) { + if ($enabled && $value !== '' && !filter_var($value, FILTER_VALIDATE_URL)) { + auth_flash_set('error', $label . ' invalide.'); + header('Location: scnotification.php'); + exit; + } + } + + $mentions = scdiscord_build_mentions($notify_here, $notify_everyone); + $banner_image_url = $use_custom_banner && $cl_scnotification_custom_banner_url !== '' + ? $cl_scnotification_custom_banner_url + : (string) ($banner['cl_scbanner_url'] ?? ''); + $border_color = (string) ($banner['cl_scbanner_border_color'] ?? '#ffae00'); + + $fields = []; + + if ($show_org && $cl_scnotification_org_value !== '' && mb_strtolower($cl_scnotification_org_value) !== 'non') { + $fields[] = [ + 'name' => 'Tenue d’organisation', + 'value' => mb_substr($cl_scnotification_org_value, 0, 1024), + 'inline' => true, + ]; + } + + if ($show_pvp && $cl_scnotification_pvp_value !== '' && mb_strtolower($cl_scnotification_pvp_value) !== 'inexistant') { + $fields[] = [ + 'name' => 'Risques PvP', + 'value' => mb_substr($cl_scnotification_pvp_value, 0, 1024), + 'inline' => true, + ]; + } + + if ($include_schedule) { + if ($cl_scnotification_location !== '') { + $fields[] = ['name' => 'Lieu de ralliement', 'value' => mb_substr($cl_scnotification_location, 0, 1024), 'inline' => false]; + } + if ($cl_scnotification_start_date !== '') { + $fields[] = ['name' => 'Date de début', 'value' => mb_substr($cl_scnotification_start_date, 0, 1024), 'inline' => true]; + } + if ($cl_scnotification_departure_time !== '') { + $fields[] = ['name' => 'Heure de départ', 'value' => mb_substr($cl_scnotification_departure_time, 0, 1024), 'inline' => true]; + } + if ($include_briefing_time && $cl_scnotification_briefing_time !== '') { + $fields[] = ['name' => 'Heure de briefing', 'value' => mb_substr($cl_scnotification_briefing_time, 0, 1024), 'inline' => true]; + } + if ($include_end_date && $cl_scnotification_end_date !== '') { + $fields[] = ['name' => 'Date de fin', 'value' => mb_substr($cl_scnotification_end_date, 0, 1024), 'inline' => true]; + } + if ($include_end_time && $cl_scnotification_end_time !== '') { + $fields[] = ['name' => 'Heure de fin', 'value' => mb_substr($cl_scnotification_end_time, 0, 1024), 'inline' => true]; + } + } + + if ($show_channel_url && $cl_scnotification_channel_url !== '') { + $fields[] = ['name' => 'Canal Discord', 'value' => '[Ouvrir le canal](' . $cl_scnotification_channel_url . ')', 'inline' => false]; + } + + if ($show_inventory_url && $cl_scnotification_inventory_url !== '') { + $fields[] = ['name' => 'Inventaire A.R.I.A', 'value' => '[Consulter l’inventaire](' . $cl_scnotification_inventory_url . ')', 'inline' => false]; + } + + if ($show_source_url && $cl_scnotification_source_url !== '') { + $fields[] = ['name' => 'Source', 'value' => '[Ouvrir la source](' . $cl_scnotification_source_url . ')', 'inline' => false]; + } + + if ($show_reactions) { + $fields[] = ['name' => 'Réactions', 'value' => '👍 / ⏳ / ❓ / 👎', 'inline' => false]; + } + + $embed = [ + 'description' => mb_substr($cl_scnotification_message, 0, 4096), + 'color' => scdiscord_hex_to_decimal($border_color), + ]; + + if ($cl_scnotification_title !== '') { + $embed['title'] = mb_substr($cl_scnotification_title, 0, 256); + } + + if (!empty($fields)) { + $embed['fields'] = $fields; + } + + if ($banner_image_url !== '') { + $embed['image'] = ['url' => $banner_image_url]; + } + + if ($show_footer && ($cl_scnotification_footer_text !== '' || $cl_scnotification_footer_icon_url !== '')) { + $embed['footer'] = []; + if ($cl_scnotification_footer_text !== '') { + $embed['footer']['text'] = mb_substr($cl_scnotification_footer_text, 0, 2048); + } + if ($cl_scnotification_footer_icon_url !== '') { + $embed['footer']['icon_url'] = $cl_scnotification_footer_icon_url; + } + } + + $payload = [ + 'embeds' => [$embed], + ]; + + if (!empty($mentions)) { + $payload['content'] = implode(' ', $mentions); + $payload['allowed_mentions'] = ['parse' => ['everyone']]; + } + + $is_forum_webhook = ((int) ($webhook['cl_scwebhook_is_forum'] ?? 0) === 1); + if ($is_forum_webhook) { + $payload['thread_name'] = scdiscord_build_thread_name( + $cl_scnotification_title, + $cl_scnotification_location, + $cl_scnotification_start_date + ); + } elseif ($show_thread) { + $embed['fields'][] = [ + 'name' => 'Fil de discussion', + 'value' => 'Le webhook sélectionné n’est pas de type forum.', + 'inline' => false, + ]; + $payload['embeds'] = [$embed]; + } + + $result = scdiscord_post_webhook((string) $webhook['cl_scwebhook_url'], $payload); + + $stmt_log = $db->prepare( + 'INSERT INTO tbl_scnotifications ( + cl_scnotification_webhook_id, + cl_scnotification_banner_id, + cl_scnotification_title, + cl_scnotification_message, + cl_scnotification_payload, + cl_scnotification_response, + cl_scnotification_success, + cl_scnotification_created_by + ) VALUES ( + :webhook_id, + :banner_id, + :title, + :message, + :payload, + :response, + :success, + :created_by + )' + ); + $stmt_log->execute([ + 'webhook_id' => $cl_scnotification_webhook_id, + 'banner_id' => $cl_scnotification_banner_id > 0 ? $cl_scnotification_banner_id : null, + 'title' => $cl_scnotification_title, + 'message' => $cl_scnotification_message, + 'payload' => json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'response' => (string) ($result['response'] ?? ''), + 'success' => !empty($result['success']) ? 1 : 0, + 'created_by' => $current_session_user !== '' ? $current_session_user : 'Inconnu', + ]); + + if (!empty($result['success'])) { + unset($_SESSION['scnotification_old']); + auth_flash_set('success', 'Notification Discord envoyée avec succès.'); + } else { + auth_flash_set('error', 'Échec de l’envoi Discord (HTTP ' . (int) ($result['http_code'] ?? 0) . ').'); + } + + header('Location: scnotification.php'); + exit; + } +} + +$old = $_SESSION['scnotification_old'] ?? []; +unset($_SESSION['scnotification_old']); + +$stmt_webhooks = $db->query('SELECT * FROM tbl_scwebhooks ORDER BY cl_scwebhook_name ASC'); +$webhooks = $stmt_webhooks->fetchAll(); + +$stmt_banners = $db->query('SELECT * FROM tbl_scbanners ORDER BY cl_scbanner_name ASC'); +$banners = $stmt_banners->fetchAll(); + +$stmt_recent = $db->query( + 'SELECT n.cl_scnotification_id, + n.cl_scnotification_title, + n.cl_scnotification_success, + n.cl_scnotification_created_at, + n.cl_scnotification_created_by, + w.cl_scwebhook_name, + b.cl_scbanner_name + FROM tbl_scnotifications n + JOIN tbl_scwebhooks w ON w.cl_scwebhook_id = n.cl_scnotification_webhook_id + LEFT JOIN tbl_scbanners b ON b.cl_scbanner_id = n.cl_scnotification_banner_id + ORDER BY n.cl_scnotification_id DESC + LIMIT 8' +); +$recent_notifications = $stmt_recent->fetchAll(); + +function scnotification_old_value(array $old, string $key, string $default = ''): string +{ + $value = $old[$key] ?? $default; + return is_string($value) ? $value : $default; +} + +function scnotification_old_checked(array $old, string $key, bool $default = false): bool +{ + if (empty($old)) { + return $default; + } + + return array_key_exists($key, $old); +} +?> + + + + + + SC Notification | R.E.A.C.T. Admin + + + + + +
+
+
+

R.E.A.C.T. SC Notification

+

Niveau d'accès : | Session :

+
+
+ Site + Exit +
+
+ + + + +
+ +
+ + +
+
Envoi d'une notification sur Discord
+
+ + + +
+
+
+

Canal de notification

+
+ +
+
+ +
+

Bannière et Couleur de bordure

+
+ +
+ +
+ +
+
+ +
+

Message

+ + +
+ + +
+
+ + +
2500 caractères restants
+
+
+ +
+

Options Footer

+ +
+ + +
+
+ + +
+
+ +
+

Réactions & Fils

+ + +
+
+ +
+
+

Tenue d'organisation & PvP

+ +
+ +
+ +
+ +
+
+ +
+

Lieu, Date et Heure

+ +
+ + +
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+

URL externes

+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+ +
+ +
+
+
+ +
+

Historique récent

+ +
Aucune notification n’a encore été envoyée.
+ +
+ +
+
+ + + + +
+
+ Webhook : + + | Bannière : + + | Par : + | Le : +
+
+ +
+ +
+
+ + + + diff --git a/scpreset.php b/scpreset.php index 7bd74e7..d87ea5b 100644 --- a/scpreset.php +++ b/scpreset.php @@ -331,6 +331,8 @@ $presets = $stmt_list->fetchAll(); Vaisseaux Presets Vaisseau + SC Webhook + SC Notification diff --git a/scvaisseaux.php b/scvaisseaux.php index 0e27741..6360ea3 100644 --- a/scvaisseaux.php +++ b/scvaisseaux.php @@ -289,6 +289,8 @@ $current_session_user = $_SESSION['user'] ?? ''; Manufactures Vaisseaux Presets Vaisseau + SC Webhook + SC Notification diff --git a/scwebhook.php b/scwebhook.php new file mode 100644 index 0000000..2dab5ca --- /dev/null +++ b/scwebhook.php @@ -0,0 +1,749 @@ +prepare('INSERT INTO tbl_scwebhooks (cl_scwebhook_name, cl_scwebhook_url, cl_scwebhook_is_forum) VALUES (:name, :url, :is_forum)'); + $stmt->execute([ + 'name' => $cl_scwebhook_name, + 'url' => $cl_scwebhook_url, + 'is_forum' => $cl_scwebhook_is_forum, + ]); + auth_flash_set('success', 'Webhook Discord ajouté avec succès.'); + } else { + if ($webhook_id <= 0) { + throw new RuntimeException('ID de webhook invalide.'); + } + + $stmt = $db->prepare('UPDATE tbl_scwebhooks SET cl_scwebhook_name = :name, cl_scwebhook_url = :url, cl_scwebhook_is_forum = :is_forum WHERE cl_scwebhook_id = :id'); + $stmt->execute([ + 'name' => $cl_scwebhook_name, + 'url' => $cl_scwebhook_url, + 'is_forum' => $cl_scwebhook_is_forum, + 'id' => $webhook_id, + ]); + auth_flash_set('success', 'Webhook Discord mis à jour.'); + } + } catch (Throwable $e) { + auth_flash_set('error', 'Erreur webhook : ' . $e->getMessage()); + } + + header('Location: scwebhook.php'); + exit; + } + + if ($action === 'delete_webhook') { + $webhook_id = (int) ($_POST['webhook_id'] ?? 0); + + if ($webhook_id > 0) { + try { + $stmt_usage = $db->prepare('SELECT COUNT(*) FROM tbl_scnotifications WHERE cl_scnotification_webhook_id = :id'); + $stmt_usage->execute(['id' => $webhook_id]); + $usage_total = (int) $stmt_usage->fetchColumn(); + + if ($usage_total > 0) { + auth_flash_set('error', 'Suppression refusée : ce webhook est déjà relié à l’historique des notifications.'); + } else { + $stmt = $db->prepare('DELETE FROM tbl_scwebhooks WHERE cl_scwebhook_id = :id'); + $stmt->execute(['id' => $webhook_id]); + auth_flash_set('success', 'Webhook Discord supprimé.'); + } + } catch (Throwable $e) { + auth_flash_set('error', 'Erreur suppression webhook : ' . $e->getMessage()); + } + } + + header('Location: scwebhook.php'); + exit; + } + + if ($action === 'add_banner' || $action === 'update_banner') { + $banner_id = (int) ($_POST['banner_id'] ?? 0); + $cl_scbanner_name = trim((string) ($_POST['cl_scbanner_name'] ?? '')); + $cl_scbanner_url = trim((string) ($_POST['cl_scbanner_url'] ?? '')); + $cl_scbanner_border_color = scdiscord_normalize_hex_color((string) ($_POST['cl_scbanner_border_color'] ?? '')); + + if ($cl_scbanner_name === '' || $cl_scbanner_url === '') { + auth_flash_set('error', 'Le nom et le lien d’image de la bannière sont obligatoires.'); + header('Location: scwebhook.php'); + exit; + } + + if (!filter_var($cl_scbanner_url, FILTER_VALIDATE_URL)) { + auth_flash_set('error', 'L’URL de la bannière est invalide.'); + header('Location: scwebhook.php'); + exit; + } + + try { + if ($action === 'add_banner') { + $stmt = $db->prepare('INSERT INTO tbl_scbanners (cl_scbanner_name, cl_scbanner_url, cl_scbanner_border_color) VALUES (:name, :url, :border_color)'); + $stmt->execute([ + 'name' => $cl_scbanner_name, + 'url' => $cl_scbanner_url, + 'border_color' => $cl_scbanner_border_color, + ]); + auth_flash_set('success', 'Bannière Discord ajoutée avec succès.'); + } else { + if ($banner_id <= 0) { + throw new RuntimeException('ID de bannière invalide.'); + } + + $stmt = $db->prepare('UPDATE tbl_scbanners SET cl_scbanner_name = :name, cl_scbanner_url = :url, cl_scbanner_border_color = :border_color WHERE cl_scbanner_id = :id'); + $stmt->execute([ + 'name' => $cl_scbanner_name, + 'url' => $cl_scbanner_url, + 'border_color' => $cl_scbanner_border_color, + 'id' => $banner_id, + ]); + auth_flash_set('success', 'Bannière Discord mise à jour.'); + } + } catch (Throwable $e) { + auth_flash_set('error', 'Erreur bannière : ' . $e->getMessage()); + } + + header('Location: scwebhook.php'); + exit; + } + + if ($action === 'delete_banner') { + $banner_id = (int) ($_POST['banner_id'] ?? 0); + + if ($banner_id > 0) { + try { + $stmt = $db->prepare('DELETE FROM tbl_scbanners WHERE cl_scbanner_id = :id'); + $stmt->execute(['id' => $banner_id]); + auth_flash_set('success', 'Bannière Discord supprimée.'); + } catch (Throwable $e) { + auth_flash_set('error', 'Erreur suppression bannière : ' . $e->getMessage()); + } + } + + header('Location: scwebhook.php'); + exit; + } +} + +$stmt_webhooks = $db->query('SELECT * FROM tbl_scwebhooks ORDER BY cl_scwebhook_name ASC'); +$webhooks = $stmt_webhooks->fetchAll(); + +$stmt_banners = $db->query('SELECT * FROM tbl_scbanners ORDER BY cl_scbanner_name ASC'); +$banners = $stmt_banners->fetchAll(); +?> + + + + + + SC Webhook | R.E.A.C.T. Admin + + + + + +
+
+
+

R.E.A.C.T. SC Webhook

+

Niveau d'accès : Administrateur | Session :

+
+
+ Site + Exit +
+
+ + + + +
+ +
+ + +
+ + +
+
+

Webhooks Discord enregistrés

+ +
Aucun webhook configuré pour le moment.
+ +
+ + + + + + + + + + + + + + + + + + + +
NominationURLTypeActions
+ + + + + + + + +
+ +
+ + + + +
+
+
+
+ +
+ +
+

Bannières disponibles

+ +
Aucune bannière enregistrée pour le moment.
+ +
+ + + + + + + + + + + + + + + + + + + +
NomPrévisualisationCouleurActions
+ + + + + + + + +
+ +
+ + + + +
+
+
+
+ +
+
+
+
+ + + +