Autosave: 20260408-162933

This commit is contained in:
Flatlogic Bot 2026-04-08 16:29:33 +00:00
parent f8ced7fba3
commit 761c0bd6af
10 changed files with 1973 additions and 0 deletions

View File

@ -524,6 +524,8 @@ $current_session_user = isset($_SESSION['user']) ? (string) $_SESSION['user'] :
<a href="scmanufactures.php">Manufactures</a>
<a href="scvaisseaux.php">Vaisseaux</a>
<a href="scpreset.php">Presets Vaisseau</a>
<a href="scwebhook.php">SC Webhook</a>
<a href="scnotification.php">SC Notification</a>
</nav>
<?php if ($flash_message !== ''): ?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

243
db/scdiscord.php Normal file
View File

@ -0,0 +1,243 @@
<?php
require_once __DIR__ . '/config.php';
function scdiscord_bootstrap(): void
{
static $bootstrapped = false;
if ($bootstrapped) {
return;
}
$db = db();
$db->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,
];
}

View File

@ -406,6 +406,8 @@ if ($edit_id > 0) {
<a href="scmanufactures.php">Manufactures</a>
<a href="scvaisseaux.php">Vaisseaux</a>
<a href="scpreset.php">Presets Vaisseau</a>
<a href="scwebhook.php">SC Webhook</a>
<a href="scnotification.php">SC Notification</a>
</nav>
<?php if ($flash_message !== ''): ?>

View File

@ -278,6 +278,8 @@ $current_session_user = $_SESSION['user'] ?? '';
<a href="scmanufactures.php" class="active">Manufactures</a>
<a href="scvaisseaux.php">Vaisseaux</a>
<a href="scpreset.php">Presets Vaisseau</a>
<a href="scwebhook.php">SC Webhook</a>
<a href="scnotification.php">SC Notification</a>
</nav>
<?php if ($flash_message !== ''): ?>

View File

@ -335,6 +335,8 @@ $current_session_user = $_SESSION['user'] ?? '';
<a href="scmanufactures.php">Manufactures</a>
<a href="scvaisseaux.php">Vaisseaux</a>
<a href="scpreset.php">Presets Vaisseau</a>
<a href="scwebhook.php">SC Webhook</a>
<a href="scnotification.php">SC Notification</a>
</nav>
<?php if ($flash_message !== ''): ?>

969
scnotification.php Normal file
View File

@ -0,0 +1,969 @@
<?php
require_once __DIR__ . '/db/auth.php';
require_once __DIR__ . '/db/scdiscord.php';
auth_start_session();
auth_bootstrap();
scdiscord_bootstrap();
if (!auth_is_logged_in()) {
header('Location: index.php');
exit;
}
$db = db();
$csrf_token = auth_csrf_token();
$flash = auth_flash_get();
$flash_type = $flash['type'] ?? '';
$flash_message = $flash['message'] ?? '';
$current_session_user = $_SESSION['user'] ?? '';
$current_session_role = $_SESSION['role'] ?? 'member';
$role_label = ($current_session_role === 'admin') ? 'Administrateur' : 'Membre';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$submitted_csrf = (string) ($_POST['csrf_token'] ?? '');
if (!auth_validate_csrf($submitted_csrf)) {
auth_flash_set('error', 'Jeton CSRF invalide.');
header('Location: scnotification.php');
exit;
}
$_SESSION['scnotification_old'] = $_POST;
$action = (string) ($_POST['action'] ?? '');
if ($action === 'send_notification') {
$cl_scnotification_webhook_id = (int) ($_POST['cl_scnotification_webhook_id'] ?? 0);
$cl_scnotification_banner_id = (int) ($_POST['cl_scnotification_banner_id'] ?? 0);
$use_custom_banner = isset($_POST['cl_scnotification_use_custom_banner']);
$cl_scnotification_custom_banner_url = trim((string) ($_POST['cl_scnotification_custom_banner_url'] ?? ''));
$notify_here = isset($_POST['cl_scnotification_notify_here']);
$notify_everyone = isset($_POST['cl_scnotification_notify_everyone']);
$cl_scnotification_title = trim((string) ($_POST['cl_scnotification_title'] ?? ''));
$cl_scnotification_message = trim((string) ($_POST['cl_scnotification_message'] ?? ''));
$show_footer = isset($_POST['cl_scnotification_show_footer']);
$cl_scnotification_footer_text = trim((string) ($_POST['cl_scnotification_footer_text'] ?? ''));
$cl_scnotification_footer_icon_url = trim((string) ($_POST['cl_scnotification_footer_icon_url'] ?? ''));
$show_reactions = isset($_POST['cl_scnotification_show_reactions']);
$show_thread = isset($_POST['cl_scnotification_show_thread']);
$show_org = isset($_POST['cl_scnotification_show_org']);
$cl_scnotification_org_value = trim((string) ($_POST['cl_scnotification_org_value'] ?? ''));
$show_pvp = isset($_POST['cl_scnotification_show_pvp']);
$cl_scnotification_pvp_value = trim((string) ($_POST['cl_scnotification_pvp_value'] ?? ''));
$include_schedule = isset($_POST['cl_scnotification_include_schedule']);
$cl_scnotification_location = trim((string) ($_POST['cl_scnotification_location'] ?? ''));
$cl_scnotification_start_date = trim((string) ($_POST['cl_scnotification_start_date'] ?? ''));
$cl_scnotification_departure_time = trim((string) ($_POST['cl_scnotification_departure_time'] ?? ''));
$include_briefing_time = isset($_POST['cl_scnotification_include_briefing_time']);
$cl_scnotification_briefing_time = trim((string) ($_POST['cl_scnotification_briefing_time'] ?? ''));
$include_end_date = isset($_POST['cl_scnotification_include_end_date']);
$cl_scnotification_end_date = trim((string) ($_POST['cl_scnotification_end_date'] ?? ''));
$include_end_time = isset($_POST['cl_scnotification_include_end_time']);
$cl_scnotification_end_time = trim((string) ($_POST['cl_scnotification_end_time'] ?? ''));
$show_channel_url = isset($_POST['cl_scnotification_show_channel_url']);
$cl_scnotification_channel_url = trim((string) ($_POST['cl_scnotification_channel_url'] ?? ''));
$show_inventory_url = isset($_POST['cl_scnotification_show_inventory_url']);
$cl_scnotification_inventory_url = trim((string) ($_POST['cl_scnotification_inventory_url'] ?? ''));
$show_source_url = isset($_POST['cl_scnotification_show_source_url']);
$cl_scnotification_source_url = trim((string) ($_POST['cl_scnotification_source_url'] ?? ''));
if ($cl_scnotification_webhook_id <= 0) {
auth_flash_set('error', 'Veuillez sélectionner un webhook Discord.');
header('Location: scnotification.php');
exit;
}
if ($cl_scnotification_message === '') {
auth_flash_set('error', 'Le champ description est obligatoire pour envoyer la notification.');
header('Location: scnotification.php');
exit;
}
$stmt_webhook = $db->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', 'LURL 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 dorganisation',
'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 linventaire](' . $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é nest 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 lenvoi 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);
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SC Notification | R.E.A.C.T. Admin</title>
<link rel="stylesheet" type="text/css" href="css/styles.css">
<link rel="stylesheet" type="text/css" href="css/default.css">
<style>
:root {
--primary: #f4a31d;
--primary-soft: rgba(244, 163, 29, 0.16);
--bg: #2b2b2b;
--bg-page: #1a1a1a;
--card: #565656;
--card-deep: #4a4a4a;
--field: #454545;
--border: rgba(255,255,255,0.08);
--text-soft: #d5d5d5;
--text-muted: #a9a9a9;
--success: #6fe08f;
--danger: #ff8a8a;
}
@font-face {
font-family: 'Electrolize';
src: url('fonts/Electrolize-Regular.ttf') format('truetype');
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
background: linear-gradient(180deg, #4a4a4a 0%, var(--bg-page) 100%);
font-family: 'Electrolize', sans-serif;
color: #f6f6f6;
}
.admin-layout {
max-width: 1460px;
margin: 0 auto;
padding: 2rem;
}
.admin-topbar, .page-shell, .history-card {
background: rgba(53, 53, 53, 0.98);
border: 1px solid var(--border);
border-radius: 14px;
box-shadow: 0 14px 38px rgba(0, 0, 0, 0.28);
}
.admin-topbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
padding: 1.4rem 1.8rem;
margin-bottom: 2rem;
}
.topbar-info h1 {
margin: 0;
font-size: 1.55rem;
color: #fff;
}
.topbar-info p {
margin: 0.35rem 0 0;
color: var(--primary);
font-size: 0.88rem;
}
.btn-modern {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
padding: 0.72rem 1.1rem;
border-radius: 6px;
border: 1px solid var(--primary);
background: transparent;
color: #fff;
text-decoration: none;
text-transform: uppercase;
font-size: 0.82rem;
cursor: pointer;
transition: 0.22s ease;
font-family: 'Electrolize', sans-serif;
}
.btn-modern:hover {
background: var(--primary);
color: #111;
}
.btn-modern.danger {
border-color: #f06a6a;
color: #f06a6a;
}
.btn-modern.danger:hover {
background: #f06a6a;
color: #fff;
}
.nav-tabs {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255,255,255,0.08);
}
.nav-tabs a {
color: #a5a5a5;
text-decoration: none;
text-transform: uppercase;
font-size: 0.88rem;
}
.nav-tabs a.active,
.nav-tabs a:hover {
color: var(--primary);
}
.flash {
margin-bottom: 1rem;
padding: 1rem 1.15rem;
border-radius: 10px;
border: 1px solid rgba(255,255,255,0.08);
background: rgba(255,255,255,0.04);
}
.flash.success { color: var(--success); border-color: rgba(111,224,143,0.28); }
.flash.error { color: var(--danger); border-color: rgba(255,138,138,0.28); }
.page-shell {
padding: 1rem;
}
.page-title {
padding: 0.65rem 0.9rem 1rem;
font-size: 1.12rem;
color: #fff;
}
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.form-column {
display: grid;
gap: 1rem;
}
.section-card {
background: var(--card);
border: 1px solid rgba(0,0,0,0.18);
border-radius: 8px;
padding: 1rem;
}
.section-title {
margin: 0 0 0.9rem;
color: var(--primary);
font-size: 1rem;
line-height: 1.2;
display: flex;
align-items: center;
gap: 0.5rem;
}
.section-title::before {
content: '';
width: 3px;
height: 18px;
background: var(--primary);
border-radius: 999px;
}
.field-row { margin-bottom: 0.85rem; }
.field-row:last-child { margin-bottom: 0; }
label, .inline-label {
display: block;
margin-bottom: 0.45rem;
font-size: 0.83rem;
color: var(--text-soft);
}
.check {
display: flex;
align-items: center;
gap: 0.55rem;
font-size: 0.9rem;
margin-bottom: 0.7rem;
color: #ededed;
}
.control,
textarea,
select,
input[type="text"],
input[type="url"],
input[type="date"],
input[type="time"] {
width: 100%;
padding: 0.8rem 0.85rem;
border-radius: 5px;
border: 1px solid rgba(255,255,255,0.06);
background: var(--field);
color: #fff;
font-family: 'Electrolize', sans-serif;
}
textarea {
min-height: 180px;
resize: vertical;
}
input[disabled], select[disabled], textarea[disabled] {
opacity: 0.5;
cursor: not-allowed;
}
.subgrid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.8rem;
}
.char-counter {
margin-top: 0.3rem;
font-size: 0.72rem;
color: var(--text-muted);
text-align: right;
}
.submit-wrap {
margin-top: 1rem;
}
.submit-wrap .btn-modern {
width: 100%;
padding: 0.95rem 1.2rem;
background: var(--primary);
color: #111;
font-weight: bold;
}
.submit-wrap .btn-modern:hover {
filter: brightness(1.06);
}
.history-card {
margin-top: 1.5rem;
padding: 1.2rem;
}
.history-card h2 {
margin: 0 0 1rem;
color: var(--primary);
font-size: 1rem;
text-transform: uppercase;
}
.history-list {
display: grid;
gap: 0.7rem;
}
.history-item {
padding: 0.85rem 0.95rem;
border-radius: 8px;
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.06);
}
.history-meta {
margin-top: 0.25rem;
color: var(--text-muted);
font-size: 0.78rem;
}
.status-pill {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.2rem 0.55rem;
border-radius: 999px;
font-size: 0.72rem;
text-transform: uppercase;
}
.status-pill.ok {
background: rgba(111,224,143,0.16);
color: #a7efba;
}
.status-pill.ko {
background: rgba(255,138,138,0.16);
color: #ffb0b0;
}
.empty-state {
padding: 1.2rem;
border: 1px dashed rgba(255,255,255,0.12);
border-radius: 10px;
text-align: center;
color: var(--text-muted);
}
@media (max-width: 1024px) {
.form-grid, .subgrid-2 { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="admin-layout">
<header class="admin-topbar">
<div class="topbar-info">
<h1>R.E.A.C.T. SC Notification</h1>
<p>Niveau d'accès : <strong><?php echo htmlspecialchars($role_label, ENT_QUOTES, 'UTF-8'); ?></strong> | Session : <strong><?php echo htmlspecialchars($current_session_user, ENT_QUOTES, 'UTF-8'); ?></strong></p>
</div>
<div class="topbar-actions">
<a href="index.php" class="btn-modern">Site</a>
<a href="logout.php" class="btn-modern danger">Exit</a>
</div>
</header>
<nav class="nav-tabs">
<?php if (auth_is_admin()): ?>
<a href="admin.php">Utilisateurs</a>
<a href="scitems.php">Base d'Objets</a>
<a href="scmining.php">Scanner Minage</a>
<a href="scmanufactures.php">Manufactures</a>
<a href="scvaisseaux.php">Vaisseaux</a>
<?php endif; ?>
<a href="scpreset.php">Presets Vaisseau</a>
<a href="scwebhook.php">SC Webhook</a>
<a href="scnotification.php" class="active">SC Notification</a>
</nav>
<?php if ($flash_message !== ''): ?>
<div class="flash <?php echo htmlspecialchars($flash_type, ENT_QUOTES, 'UTF-8'); ?>">
<?php echo htmlspecialchars($flash_message, ENT_QUOTES, 'UTF-8'); ?>
</div>
<?php endif; ?>
<div class="page-shell">
<div class="page-title">Envoi d'une notification sur Discord</div>
<form method="post">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" value="send_notification">
<div class="form-grid">
<div class="form-column">
<section class="section-card">
<h2 class="section-title">Canal de notification</h2>
<div class="field-row">
<select class="control" name="cl_scnotification_webhook_id" required>
<option value="">Sélectionner un webhook</option>
<?php foreach ($webhooks as $webhook): ?>
<?php $selected = (string) $webhook['cl_scwebhook_id'] === scnotification_old_value($old, 'cl_scnotification_webhook_id'); ?>
<option value="<?php echo (int) $webhook['cl_scwebhook_id']; ?>" <?php echo $selected ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($webhook['cl_scwebhook_name'] . (((int) $webhook['cl_scwebhook_is_forum'] === 1) ? ' [forum]' : ''), ENT_QUOTES, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</section>
<section class="section-card">
<h2 class="section-title">Bannière et Couleur de bordure</h2>
<div class="field-row">
<select class="control" name="cl_scnotification_banner_id" id="cl_scnotification_banner_id">
<option value="">Aucune bannière</option>
<?php foreach ($banners as $banner): ?>
<?php $selected = (string) $banner['cl_scbanner_id'] === scnotification_old_value($old, 'cl_scnotification_banner_id'); ?>
<option value="<?php echo (int) $banner['cl_scbanner_id']; ?>" <?php echo $selected ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($banner['cl_scbanner_name'] . ' [' . scdiscord_normalize_hex_color((string) ($banner['cl_scbanner_border_color'] ?? '#ffae00')) . ']', ENT_QUOTES, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<label class="check">
<input type="checkbox" name="cl_scnotification_use_custom_banner" id="cl_scnotification_use_custom_banner" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_use_custom_banner') ? 'checked' : ''; ?>>
<span>Utiliser une bannière personnalisée</span>
</label>
<div class="field-row">
<input type="url" class="control" name="cl_scnotification_custom_banner_url" id="cl_scnotification_custom_banner_url" placeholder="URL personnalisée https://.../png" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_custom_banner_url'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
</section>
<section class="section-card">
<h2 class="section-title">Message</h2>
<label class="check">
<input type="checkbox" name="cl_scnotification_notify_here" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_notify_here') ? 'checked' : ''; ?>>
<span>Notifier avec @here</span>
</label>
<label class="check">
<input type="checkbox" name="cl_scnotification_notify_everyone" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_notify_everyone', true) ? 'checked' : ''; ?>>
<span>Notifier avec @everyone</span>
</label>
<div class="field-row">
<label for="cl_scnotification_title">Titre :</label>
<input type="text" class="control" id="cl_scnotification_title" name="cl_scnotification_title" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_title'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
<div class="field-row">
<label for="cl_scnotification_message">Description :</label>
<textarea id="cl_scnotification_message" name="cl_scnotification_message" maxlength="2500" placeholder="Compatible avec le Markdown Discord..."><?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_message'), ENT_QUOTES, 'UTF-8'); ?></textarea>
<div class="char-counter"><span id="messageCount">2500</span> caractères restants</div>
</div>
</section>
<section class="section-card">
<h2 class="section-title">Options Footer</h2>
<label class="check">
<input type="checkbox" name="cl_scnotification_show_footer" id="cl_scnotification_show_footer" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_show_footer', true) ? 'checked' : ''; ?>>
<span>Afficher le footer</span>
</label>
<div class="field-row">
<label for="cl_scnotification_footer_text">Texte du footer :</label>
<input type="text" class="control footer-toggle" id="cl_scnotification_footer_text" name="cl_scnotification_footer_text" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_footer_text', 'R.E.A.C.T Initiative'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
<div class="field-row">
<label for="cl_scnotification_footer_icon_url">URL icône footer :</label>
<input type="url" class="control footer-toggle" id="cl_scnotification_footer_icon_url" name="cl_scnotification_footer_icon_url" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_footer_icon_url'), ENT_QUOTES, 'UTF-8'); ?>" placeholder="*.png">
</div>
</section>
<section class="section-card">
<h2 class="section-title">Réactions &amp; Fils</h2>
<label class="check">
<input type="checkbox" name="cl_scnotification_show_reactions" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_show_reactions') ? 'checked' : ''; ?>>
<span>Afficher les réactions 👍 / / / 👎</span>
</label>
<label class="check">
<input type="checkbox" name="cl_scnotification_show_thread" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_show_thread', true) ? 'checked' : ''; ?>>
<span>Afficher le fil de discussion</span>
</label>
</section>
</div>
<div class="form-column">
<section class="section-card">
<h2 class="section-title">Tenue d'organisation &amp; PvP</h2>
<label class="check">
<input type="checkbox" name="cl_scnotification_show_org" id="cl_scnotification_show_org" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_show_org') ? 'checked' : ''; ?>>
<span>Afficher la tenue d'organisation</span>
</label>
<div class="field-row">
<select class="control org-toggle" name="cl_scnotification_org_value" id="cl_scnotification_org_value">
<?php foreach (['Non', 'Tenue civile', 'Tenue organisation', 'Tenue lourde'] as $option): ?>
<option value="<?php echo htmlspecialchars($option, ENT_QUOTES, 'UTF-8'); ?>" <?php echo scnotification_old_value($old, 'cl_scnotification_org_value', 'Non') === $option ? 'selected' : ''; ?>><?php echo htmlspecialchars($option, ENT_QUOTES, 'UTF-8'); ?></option>
<?php endforeach; ?>
</select>
</div>
<label class="check">
<input type="checkbox" name="cl_scnotification_show_pvp" id="cl_scnotification_show_pvp" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_show_pvp') ? 'checked' : ''; ?>>
<span>Afficher les risques PvP</span>
</label>
<div class="field-row">
<select class="control pvp-toggle" name="cl_scnotification_pvp_value" id="cl_scnotification_pvp_value">
<?php foreach (['Inexistant', 'Faible', 'Modéré', 'Important', 'Extrême'] as $option): ?>
<option value="<?php echo htmlspecialchars($option, ENT_QUOTES, 'UTF-8'); ?>" <?php echo scnotification_old_value($old, 'cl_scnotification_pvp_value', 'Inexistant') === $option ? 'selected' : ''; ?>><?php echo htmlspecialchars($option, ENT_QUOTES, 'UTF-8'); ?></option>
<?php endforeach; ?>
</select>
</div>
</section>
<section class="section-card">
<h2 class="section-title">Lieu, Date et Heure</h2>
<label class="check">
<input type="checkbox" name="cl_scnotification_include_schedule" id="cl_scnotification_include_schedule" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_include_schedule') ? 'checked' : ''; ?>>
<span>Inclure date, lieu et heures</span>
</label>
<div class="field-row">
<label for="cl_scnotification_location">Lieu de ralliement :</label>
<input type="text" class="control schedule-toggle" id="cl_scnotification_location" name="cl_scnotification_location" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_location'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
<div class="field-row subgrid-2">
<div>
<label for="cl_scnotification_start_date">Date de début :</label>
<input type="date" class="control schedule-toggle" id="cl_scnotification_start_date" name="cl_scnotification_start_date" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_start_date'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
<div>
<label for="cl_scnotification_departure_time">Heure de départ :</label>
<input type="time" class="control schedule-toggle" id="cl_scnotification_departure_time" name="cl_scnotification_departure_time" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_departure_time', '21:30'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
</div>
<label class="check">
<input type="checkbox" name="cl_scnotification_include_briefing_time" id="cl_scnotification_include_briefing_time" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_include_briefing_time') ? 'checked' : ''; ?>>
<span>Inclure une heure de briefing</span>
</label>
<div class="field-row">
<label for="cl_scnotification_briefing_time">Heure de briefing :</label>
<input type="time" class="control briefing-toggle" id="cl_scnotification_briefing_time" name="cl_scnotification_briefing_time" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_briefing_time', '21:00'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
<label class="check">
<input type="checkbox" name="cl_scnotification_include_end_date" id="cl_scnotification_include_end_date" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_include_end_date') ? 'checked' : ''; ?>>
<span>Inclure une date de fin</span>
</label>
<div class="field-row">
<label for="cl_scnotification_end_date">Date de fin :</label>
<input type="date" class="control enddate-toggle" id="cl_scnotification_end_date" name="cl_scnotification_end_date" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_end_date'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
<label class="check">
<input type="checkbox" name="cl_scnotification_include_end_time" id="cl_scnotification_include_end_time" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_include_end_time') ? 'checked' : ''; ?>>
<span>Inclure une heure de fin</span>
</label>
<div class="field-row">
<label for="cl_scnotification_end_time">Heure de fin :</label>
<input type="time" class="control endtime-toggle" id="cl_scnotification_end_time" name="cl_scnotification_end_time" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_end_time', '00:00'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
</section>
<section class="section-card">
<h2 class="section-title">URL externes</h2>
<label class="check">
<input type="checkbox" name="cl_scnotification_show_channel_url" id="cl_scnotification_show_channel_url" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_show_channel_url') ? 'checked' : ''; ?>>
<span>Afficher un lien de canal Discord</span>
</label>
<div class="field-row">
<label for="cl_scnotification_channel_url">URL Canal :</label>
<input type="url" class="control channelurl-toggle" id="cl_scnotification_channel_url" name="cl_scnotification_channel_url" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_channel_url', 'https://discord.com/channels/...'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
<label class="check">
<input type="checkbox" name="cl_scnotification_show_inventory_url" id="cl_scnotification_show_inventory_url" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_show_inventory_url') ? 'checked' : ''; ?>>
<span>Afficher une URL de l'inventaire A.R.I.A</span>
</label>
<div class="field-row">
<label for="cl_scnotification_inventory_url">URL Inventaire :</label>
<input type="url" class="control inventoryurl-toggle" id="cl_scnotification_inventory_url" name="cl_scnotification_inventory_url" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_inventory_url', 'https://aria.blackops-agency.fr/...'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
<label class="check">
<input type="checkbox" name="cl_scnotification_show_source_url" id="cl_scnotification_show_source_url" value="1" <?php echo scnotification_old_checked($old, 'cl_scnotification_show_source_url') ? 'checked' : ''; ?>>
<span>Afficher une URL source</span>
</label>
<div class="field-row">
<label for="cl_scnotification_source_url">URL Source :</label>
<input type="url" class="control sourceurl-toggle" id="cl_scnotification_source_url" name="cl_scnotification_source_url" value="<?php echo htmlspecialchars(scnotification_old_value($old, 'cl_scnotification_source_url', 'https://...'), ENT_QUOTES, 'UTF-8'); ?>">
</div>
</section>
</div>
</div>
<div class="submit-wrap">
<button type="submit" class="btn-modern">Envoyer</button>
</div>
</form>
</div>
<section class="history-card">
<h2>Historique récent</h2>
<?php if (empty($recent_notifications)): ?>
<div class="empty-state">Aucune notification na encore été envoyée.</div>
<?php else: ?>
<div class="history-list">
<?php foreach ($recent_notifications as $item): ?>
<div class="history-item">
<div>
<strong><?php echo htmlspecialchars($item['cl_scnotification_title'] !== '' ? $item['cl_scnotification_title'] : 'Notification sans titre', ENT_QUOTES, 'UTF-8'); ?></strong>
<span class="status-pill <?php echo ((int) $item['cl_scnotification_success'] === 1) ? 'ok' : 'ko'; ?>">
<?php echo ((int) $item['cl_scnotification_success'] === 1) ? 'Envoyée' : 'Erreur'; ?>
</span>
</div>
<div class="history-meta">
Webhook : <strong><?php echo htmlspecialchars($item['cl_scwebhook_name'], ENT_QUOTES, 'UTF-8'); ?></strong>
<?php if (!empty($item['cl_scbanner_name'])): ?>
| Bannière : <strong><?php echo htmlspecialchars($item['cl_scbanner_name'], ENT_QUOTES, 'UTF-8'); ?></strong>
<?php endif; ?>
| Par : <strong><?php echo htmlspecialchars($item['cl_scnotification_created_by'], ENT_QUOTES, 'UTF-8'); ?></strong>
| Le : <strong><?php echo htmlspecialchars($item['cl_scnotification_created_at'], ENT_QUOTES, 'UTF-8'); ?></strong>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</section>
</div>
<script>
const messageField = document.getElementById('cl_scnotification_message');
const messageCount = document.getElementById('messageCount');
function updateCounter() {
const remaining = 2500 - (messageField.value || '').length;
messageCount.textContent = remaining;
}
function toggleByCheckbox(checkboxId, selector, invert = false) {
const checkbox = document.getElementById(checkboxId);
const targets = document.querySelectorAll(selector);
if (!checkbox) return;
const enabled = invert ? !checkbox.checked : checkbox.checked;
targets.forEach((target) => {
target.disabled = !enabled;
});
}
function syncStates() {
toggleByCheckbox('cl_scnotification_use_custom_banner', '#cl_scnotification_custom_banner_url');
toggleByCheckbox('cl_scnotification_show_footer', '.footer-toggle');
toggleByCheckbox('cl_scnotification_show_org', '.org-toggle');
toggleByCheckbox('cl_scnotification_show_pvp', '.pvp-toggle');
toggleByCheckbox('cl_scnotification_include_schedule', '.schedule-toggle');
const scheduleEnabled = document.getElementById('cl_scnotification_include_schedule')?.checked;
document.getElementById('cl_scnotification_include_briefing_time').disabled = !scheduleEnabled;
document.getElementById('cl_scnotification_include_end_date').disabled = !scheduleEnabled;
document.getElementById('cl_scnotification_include_end_time').disabled = !scheduleEnabled;
toggleByCheckbox('cl_scnotification_include_briefing_time', '.briefing-toggle');
toggleByCheckbox('cl_scnotification_include_end_date', '.enddate-toggle');
toggleByCheckbox('cl_scnotification_include_end_time', '.endtime-toggle');
if (!scheduleEnabled) {
document.querySelectorAll('.briefing-toggle, .enddate-toggle, .endtime-toggle').forEach(el => el.disabled = true);
}
toggleByCheckbox('cl_scnotification_show_channel_url', '.channelurl-toggle');
toggleByCheckbox('cl_scnotification_show_inventory_url', '.inventoryurl-toggle');
toggleByCheckbox('cl_scnotification_show_source_url', '.sourceurl-toggle');
}
updateCounter();
messageField.addEventListener('input', updateCounter);
[
'cl_scnotification_use_custom_banner',
'cl_scnotification_show_footer',
'cl_scnotification_show_org',
'cl_scnotification_show_pvp',
'cl_scnotification_include_schedule',
'cl_scnotification_include_briefing_time',
'cl_scnotification_include_end_date',
'cl_scnotification_include_end_time',
'cl_scnotification_show_channel_url',
'cl_scnotification_show_inventory_url',
'cl_scnotification_show_source_url'
].forEach((id) => {
const el = document.getElementById(id);
if (el) {
el.addEventListener('change', syncStates);
}
});
syncStates();
</script>
</body>
</html>

View File

@ -331,6 +331,8 @@ $presets = $stmt_list->fetchAll();
<a href="scvaisseaux.php">Vaisseaux</a>
<?php endif; ?>
<a href="scpreset.php" class="active">Presets Vaisseau</a>
<a href="scwebhook.php">SC Webhook</a>
<a href="scnotification.php">SC Notification</a>
</nav>
<?php if ($flash_message !== ''): ?>

View File

@ -289,6 +289,8 @@ $current_session_user = $_SESSION['user'] ?? '';
<a href="scmanufactures.php">Manufactures</a>
<a href="scvaisseaux.php" class="active">Vaisseaux</a>
<a href="scpreset.php">Presets Vaisseau</a>
<a href="scwebhook.php">SC Webhook</a>
<a href="scnotification.php">SC Notification</a>
</nav>
<?php if ($flash_message !== ''): ?>

749
scwebhook.php Normal file
View File

@ -0,0 +1,749 @@
<?php
require_once __DIR__ . '/db/auth.php';
require_once __DIR__ . '/db/scdiscord.php';
auth_start_session();
auth_bootstrap();
scdiscord_bootstrap();
if (!auth_is_admin()) {
header('Location: index.php');
exit;
}
$db = db();
$csrf_token = auth_csrf_token();
$flash = auth_flash_get();
$flash_type = $flash['type'] ?? '';
$flash_message = $flash['message'] ?? '';
$current_session_user = $_SESSION['user'] ?? '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$submitted_csrf = (string) ($_POST['csrf_token'] ?? '');
if (!auth_validate_csrf($submitted_csrf)) {
auth_flash_set('error', 'Jeton CSRF invalide.');
header('Location: scwebhook.php');
exit;
}
$action = (string) ($_POST['action'] ?? '');
if ($action === 'add_webhook' || $action === 'update_webhook') {
$webhook_id = (int) ($_POST['webhook_id'] ?? 0);
$cl_scwebhook_name = trim((string) ($_POST['cl_scwebhook_name'] ?? ''));
$cl_scwebhook_url = trim((string) ($_POST['cl_scwebhook_url'] ?? ''));
$cl_scwebhook_is_forum = isset($_POST['cl_scwebhook_is_forum']) ? 1 : 0;
if ($cl_scwebhook_name === '' || $cl_scwebhook_url === '') {
auth_flash_set('error', 'Le nom et lURL du webhook sont obligatoires.');
header('Location: scwebhook.php');
exit;
}
if (!filter_var($cl_scwebhook_url, FILTER_VALIDATE_URL)) {
auth_flash_set('error', 'LURL du webhook Discord est invalide.');
header('Location: scwebhook.php');
exit;
}
try {
if ($action === 'add_webhook') {
$stmt = $db->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é à lhistorique 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 dimage de la bannière sont obligatoires.');
header('Location: scwebhook.php');
exit;
}
if (!filter_var($cl_scbanner_url, FILTER_VALIDATE_URL)) {
auth_flash_set('error', 'LURL 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();
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SC Webhook | R.E.A.C.T. Admin</title>
<link rel="stylesheet" type="text/css" href="css/styles.css">
<link rel="stylesheet" type="text/css" href="css/default.css">
<style>
:root {
--primary: #f6a21a;
--primary-soft: rgba(246, 162, 26, 0.16);
--primary-glow: rgba(246, 162, 26, 0.38);
--bg-dark: #0d1016;
--card-bg: rgba(44, 44, 48, 0.96);
--card-bg-secondary: rgba(58, 58, 63, 0.96);
--border-glow: rgba(255, 255, 255, 0.08);
--danger: #ff6767;
--success: #52d273;
--muted: #aaaaaa;
}
@font-face {
font-family: 'Electrolize';
src: url('fonts/Electrolize-Regular.ttf') format('truetype');
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
background: linear-gradient(180deg, #262626 0%, #12141b 100%);
color: #f4f4f4;
font-family: 'Electrolize', sans-serif;
}
.admin-layout {
max-width: 1450px;
margin: 0 auto;
padding: 2rem;
}
.admin-topbar, .glass-card {
background: var(--card-bg);
border: 1px solid var(--border-glow);
border-radius: 12px;
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.28);
}
.admin-topbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
padding: 1.5rem 2rem;
margin-bottom: 2rem;
}
.topbar-info h1 {
margin: 0;
font-size: 1.6rem;
letter-spacing: 1px;
color: #fff;
}
.topbar-info p {
margin: 0.35rem 0 0;
color: var(--primary);
font-size: 0.9rem;
}
.btn-modern {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.45rem;
padding: 0.75rem 1.1rem;
border-radius: 6px;
border: 1px solid var(--primary);
background: transparent;
color: #fff;
text-decoration: none;
text-transform: uppercase;
font-size: 0.82rem;
cursor: pointer;
transition: 0.25s ease;
font-family: 'Electrolize', sans-serif;
}
.btn-modern:hover {
background: var(--primary);
color: #0d1016;
box-shadow: 0 0 18px var(--primary-glow);
}
.btn-modern.danger {
border-color: var(--danger);
color: var(--danger);
}
.btn-modern.danger:hover {
background: var(--danger);
color: #fff;
box-shadow: none;
}
.btn-modern.secondary {
border-color: #6e6e6e;
color: #d6d6d6;
}
.btn-modern.secondary:hover {
background: #6e6e6e;
color: #fff;
box-shadow: none;
}
.btn-mini {
padding: 0.45rem 0.8rem;
font-size: 0.72rem;
}
.nav-tabs {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255,255,255,0.08);
}
.nav-tabs a {
color: #989898;
text-decoration: none;
text-transform: uppercase;
font-size: 0.88rem;
transition: color 0.2s ease;
}
.nav-tabs a.active,
.nav-tabs a:hover {
color: var(--primary);
}
.flash {
margin-bottom: 1.5rem;
padding: 1rem 1.2rem;
border-radius: 8px;
border: 1px solid rgba(255,255,255,0.08);
background: rgba(255,255,255,0.04);
}
.flash.success { border-color: rgba(82, 210, 115, 0.35); color: #9ef0b4; }
.flash.error { border-color: rgba(255, 103, 103, 0.35); color: #ff9d9d; }
.page-grid {
display: grid;
grid-template-columns: 420px 1fr;
gap: 2rem;
}
.stack {
display: grid;
gap: 1.5rem;
}
.glass-card {
padding: 1.5rem;
}
.glass-card h2 {
margin: 0 0 1.25rem;
color: var(--primary);
font-size: 1.1rem;
text-transform: uppercase;
letter-spacing: 0.6px;
}
.section-note {
margin: -0.5rem 0 1.2rem;
color: var(--muted);
font-size: 0.82rem;
line-height: 1.5;
}
.form-grid {
display: grid;
gap: 1rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
color: #d8d8d8;
font-size: 0.82rem;
text-transform: uppercase;
}
.form-control {
width: 100%;
padding: 0.82rem 0.9rem;
border-radius: 6px;
border: 1px solid rgba(255,255,255,0.08);
background: var(--card-bg-secondary);
color: #fff;
font-family: 'Electrolize', sans-serif;
}
.form-control[type="color"] {
min-height: 48px;
padding: 0.35rem;
}
.checkbox-row {
display: flex;
align-items: center;
gap: 0.7rem;
color: #e7e7e7;
font-size: 0.9rem;
}
.list-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
}
.table-wrap {
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 0.9rem 0.75rem;
border-bottom: 1px solid rgba(255,255,255,0.08);
vertical-align: top;
text-align: left;
font-size: 0.88rem;
}
th {
color: var(--primary);
text-transform: uppercase;
font-size: 0.75rem;
letter-spacing: 0.5px;
}
.muted {
color: var(--muted);
font-size: 0.8rem;
}
.pill {
display: inline-flex;
align-items: center;
padding: 0.2rem 0.55rem;
border-radius: 999px;
background: rgba(255,255,255,0.07);
font-size: 0.72rem;
color: #fff;
}
.pill.forum {
background: rgba(246, 162, 26, 0.18);
color: #ffd38c;
}
.banner-preview {
width: 120px;
max-height: 42px;
object-fit: cover;
border-radius: 6px;
border: 1px solid rgba(255,255,255,0.08);
display: block;
background: #17191e;
}
.color-chip {
display: inline-flex;
align-items: center;
gap: 0.45rem;
}
.color-chip::before {
content: '';
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--chip-color, #ffae00);
box-shadow: 0 0 0 2px rgba(255,255,255,0.08);
}
.actions-inline {
display: flex;
flex-wrap: wrap;
gap: 0.45rem;
justify-content: flex-end;
}
.empty-state {
padding: 2rem;
border: 1px dashed rgba(255,255,255,0.12);
border-radius: 10px;
color: #9a9a9a;
text-align: center;
}
@media (max-width: 1100px) {
.page-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="admin-layout">
<header class="admin-topbar">
<div class="topbar-info">
<h1>R.E.A.C.T. SC Webhook</h1>
<p>Niveau d'accès : <strong>Administrateur</strong> | Session : <strong><?php echo htmlspecialchars($current_session_user, ENT_QUOTES, 'UTF-8'); ?></strong></p>
</div>
<div class="topbar-actions">
<a href="index.php" class="btn-modern">Site</a>
<a href="logout.php" class="btn-modern danger">Exit</a>
</div>
</header>
<nav class="nav-tabs">
<a href="admin.php">Utilisateurs</a>
<a href="scitems.php">Base d'Objets</a>
<a href="scmining.php">Scanner Minage</a>
<a href="scmanufactures.php">Manufactures</a>
<a href="scvaisseaux.php">Vaisseaux</a>
<a href="scpreset.php">Presets Vaisseau</a>
<a href="scwebhook.php" class="active">SC Webhook</a>
<a href="scnotification.php">SC Notification</a>
</nav>
<?php if ($flash_message !== ''): ?>
<div class="flash <?php echo htmlspecialchars($flash_type, ENT_QUOTES, 'UTF-8'); ?>">
<?php echo htmlspecialchars($flash_message, ENT_QUOTES, 'UTF-8'); ?>
</div>
<?php endif; ?>
<div class="page-grid">
<aside class="stack">
<section class="glass-card">
<h2 id="webhookFormTitle">Nouveau webhook Discord</h2>
<p class="section-note">Ajoute la nomination du webhook et son URL. Active loption forum si ce webhook doit créer un fil lors de lenvoi.</p>
<form method="post" id="webhookForm" class="form-grid">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" id="webhookAction" value="add_webhook">
<input type="hidden" name="webhook_id" id="webhookId" value="">
<div class="form-group">
<label for="cl_scwebhook_name">Nomination du webhook</label>
<input type="text" id="cl_scwebhook_name" name="cl_scwebhook_name" class="form-control" required placeholder="Ex : news-bops-cig">
</div>
<div class="form-group">
<label for="cl_scwebhook_url">Lien du webhook</label>
<input type="url" id="cl_scwebhook_url" name="cl_scwebhook_url" class="form-control" required placeholder="https://discord.com/api/webhooks/...">
</div>
<label class="checkbox-row">
<input type="checkbox" id="cl_scwebhook_is_forum" name="cl_scwebhook_is_forum" value="1">
<span>Webhook de type forum / fil de discussion</span>
</label>
<button type="submit" class="btn-modern" id="webhookSubmitBtn">Ajouter le webhook</button>
<button type="button" class="btn-modern secondary" id="webhookCancelBtn" style="display:none;" onclick="resetWebhookForm()">Annuler lédition</button>
</form>
</section>
<section class="glass-card">
<h2 id="bannerFormTitle">Nouvelle bannière</h2>
<p class="section-note">Chaque bannière stocke un nom, un lien dimage et une couleur de bordure utilisée dans lembed Discord.</p>
<form method="post" id="bannerForm" class="form-grid">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" id="bannerAction" value="add_banner">
<input type="hidden" name="banner_id" id="bannerId" value="">
<div class="form-group">
<label for="cl_scbanner_name">Nom de la bannière</label>
<input type="text" id="cl_scbanner_name" name="cl_scbanner_name" class="form-control" required placeholder="Ex : Alerte Rouge">
</div>
<div class="form-group">
<label for="cl_scbanner_url">Lien image</label>
<input type="url" id="cl_scbanner_url" name="cl_scbanner_url" class="form-control" required placeholder="https://.../banniere.png">
</div>
<div class="form-group">
<label for="cl_scbanner_border_color">Couleur de bordure</label>
<input type="color" id="cl_scbanner_border_color" name="cl_scbanner_border_color" class="form-control" value="#ffae00">
</div>
<button type="submit" class="btn-modern" id="bannerSubmitBtn">Ajouter la bannière</button>
<button type="button" class="btn-modern secondary" id="bannerCancelBtn" style="display:none;" onclick="resetBannerForm()">Annuler lédition</button>
</form>
</section>
</aside>
<main class="list-grid">
<section class="glass-card">
<h2>Webhooks Discord enregistrés</h2>
<?php if (empty($webhooks)): ?>
<div class="empty-state">Aucun webhook configuré pour le moment.</div>
<?php else: ?>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Nomination</th>
<th>URL</th>
<th>Type</th>
<th style="text-align:right;">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($webhooks as $webhook): ?>
<tr>
<td>
<strong><?php echo htmlspecialchars($webhook['cl_scwebhook_name'], ENT_QUOTES, 'UTF-8'); ?></strong>
</td>
<td>
<span class="muted"><?php echo htmlspecialchars(scdiscord_mask_webhook_url((string) $webhook['cl_scwebhook_url']), ENT_QUOTES, 'UTF-8'); ?></span>
</td>
<td>
<span class="pill <?php echo ((int) $webhook['cl_scwebhook_is_forum'] === 1) ? 'forum' : ''; ?>">
<?php echo ((int) $webhook['cl_scwebhook_is_forum'] === 1) ? 'Forum' : 'Classique'; ?>
</span>
</td>
<td>
<div class="actions-inline">
<button
type="button"
class="btn-modern btn-mini"
onclick='editWebhook(<?php echo json_encode([
'id' => (int) $webhook['cl_scwebhook_id'],
'name' => (string) $webhook['cl_scwebhook_name'],
'url' => (string) $webhook['cl_scwebhook_url'],
'is_forum' => (int) $webhook['cl_scwebhook_is_forum'],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>)'
>Éditer</button>
<form method="post" onsubmit="return confirm('Supprimer ce webhook Discord ?');">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" value="delete_webhook">
<input type="hidden" name="webhook_id" value="<?php echo (int) $webhook['cl_scwebhook_id']; ?>">
<button type="submit" class="btn-modern btn-mini danger">Supprimer</button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</section>
<section class="glass-card">
<h2>Bannières disponibles</h2>
<?php if (empty($banners)): ?>
<div class="empty-state">Aucune bannière enregistrée pour le moment.</div>
<?php else: ?>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Nom</th>
<th>Prévisualisation</th>
<th>Couleur</th>
<th style="text-align:right;">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($banners as $banner): ?>
<tr>
<td>
<strong><?php echo htmlspecialchars($banner['cl_scbanner_name'], ENT_QUOTES, 'UTF-8'); ?></strong>
</td>
<td>
<img class="banner-preview" src="<?php echo htmlspecialchars($banner['cl_scbanner_url'], ENT_QUOTES, 'UTF-8'); ?>" alt="Prévisualisation bannière">
</td>
<td>
<span class="color-chip" style="--chip-color: <?php echo htmlspecialchars(scdiscord_normalize_hex_color((string) ($banner['cl_scbanner_border_color'] ?? '#ffae00')), ENT_QUOTES, 'UTF-8'); ?>;">
<?php echo htmlspecialchars(scdiscord_normalize_hex_color((string) ($banner['cl_scbanner_border_color'] ?? '#ffae00')), ENT_QUOTES, 'UTF-8'); ?>
</span>
</td>
<td>
<div class="actions-inline">
<button
type="button"
class="btn-modern btn-mini"
onclick='editBanner(<?php echo json_encode([
'id' => (int) $banner['cl_scbanner_id'],
'name' => (string) $banner['cl_scbanner_name'],
'url' => (string) $banner['cl_scbanner_url'],
'border_color' => (string) ($banner['cl_scbanner_border_color'] ?? '#ffae00'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>)'
>Éditer</button>
<form method="post" onsubmit="return confirm('Supprimer cette bannière ?');">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" value="delete_banner">
<input type="hidden" name="banner_id" value="<?php echo (int) $banner['cl_scbanner_id']; ?>">
<button type="submit" class="btn-modern btn-mini danger">Supprimer</button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</section>
</main>
</div>
</div>
<script>
function editWebhook(webhook) {
document.getElementById('webhookFormTitle').textContent = 'Modifier le webhook Discord';
document.getElementById('webhookAction').value = 'update_webhook';
document.getElementById('webhookId').value = webhook.id || '';
document.getElementById('cl_scwebhook_name').value = webhook.name || '';
document.getElementById('cl_scwebhook_url').value = webhook.url || '';
document.getElementById('cl_scwebhook_is_forum').checked = Number(webhook.is_forum || 0) === 1;
document.getElementById('webhookSubmitBtn').textContent = 'Mettre à jour le webhook';
document.getElementById('webhookCancelBtn').style.display = 'inline-flex';
}
function resetWebhookForm() {
document.getElementById('webhookFormTitle').textContent = 'Nouveau webhook Discord';
document.getElementById('webhookAction').value = 'add_webhook';
document.getElementById('webhookId').value = '';
document.getElementById('cl_scwebhook_name').value = '';
document.getElementById('cl_scwebhook_url').value = '';
document.getElementById('cl_scwebhook_is_forum').checked = false;
document.getElementById('webhookSubmitBtn').textContent = 'Ajouter le webhook';
document.getElementById('webhookCancelBtn').style.display = 'none';
}
function editBanner(banner) {
document.getElementById('bannerFormTitle').textContent = 'Modifier la bannière';
document.getElementById('bannerAction').value = 'update_banner';
document.getElementById('bannerId').value = banner.id || '';
document.getElementById('cl_scbanner_name').value = banner.name || '';
document.getElementById('cl_scbanner_url').value = banner.url || '';
document.getElementById('cl_scbanner_border_color').value = banner.border_color || '#ffae00';
document.getElementById('bannerSubmitBtn').textContent = 'Mettre à jour la bannière';
document.getElementById('bannerCancelBtn').style.display = 'inline-flex';
}
function resetBannerForm() {
document.getElementById('bannerFormTitle').textContent = 'Nouvelle bannière';
document.getElementById('bannerAction').value = 'add_banner';
document.getElementById('bannerId').value = '';
document.getElementById('cl_scbanner_name').value = '';
document.getElementById('cl_scbanner_url').value = '';
document.getElementById('cl_scbanner_border_color').value = '#ffae00';
document.getElementById('bannerSubmitBtn').textContent = 'Ajouter la bannière';
document.getElementById('bannerCancelBtn').style.display = 'none';
}
</script>
</body>
</html>