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
+
+
+
+
+
+
+
+
+
+
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Webhooks Discord enregistrés
+
+ Aucun webhook configuré pour le moment.
+
+
+
+
+
+ | Nomination |
+ URL |
+ Type |
+ Actions |
+
+
+
+
+
+ |
+
+ |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ Bannières disponibles
+
+ Aucune bannière enregistrée pour le moment.
+
+
+
+
+
+ | Nom |
+ Prévisualisation |
+ Couleur |
+ Actions |
+
+
+
+
+
+ |
+
+ |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+