Files

301 lines
12 KiB
PHP

<?php
ob_start();
require_once __DIR__ . '/../public/includes/init_admin.php';
// FIX: cast pour comparaison stricte
$refId = (int) ($_SESSION['reference_id'] ?? 0);
if ($refId === 88888888):
// CSRF par session
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// FIX: back URL sûr (référer interne uniquement)
$fallbackBack = '/admin/index.php';
if (! empty($_SERVER['HTTP_REFERER'])) {
$ref = parse_url($_SERVER['HTTP_REFERER']);
if (! empty($ref['host']) && $ref['host'] === ($_SERVER['HTTP_HOST'] ?? '')) {
$fallbackBack = $_SERVER['HTTP_REFERER'];
}
}
// Helpers
function h($s)
{return htmlspecialchars((string) $s, ENT_QUOTES, 'UTF-8');}
function admin_url(string $page, array $params = []): string
{
$q = http_build_query(array_merge(['page' => $page], $params));
return '/admin/index.php?' . $q;
}
// Whitelist des vues
$views = [
'maintenance' => __DIR__ . '/tools/maintenance.php',
'add_video' => __DIR__ . '/tools/add_video.php',
'gerer_praticiens' => __DIR__ . '/tools/gerer_praticiens.php',
'cleanup_inscriptions' => __DIR__ . '/tools/cleanup_inscriptions.php',
'purge_conversations' => __DIR__ . '/tools/purge_conversations.php',
'purger_mess_upload' => __DIR__ . '/tools/gc.php',
'logs' => __DIR__ . '/tools/logs.php',
// nouveaux
'audit' => __DIR__ . '/tools/audit.php',
'reauth' => __DIR__ . '/tools/reauth.php',
'backup_db' => __DIR__ . '/tools/backup_db.php',
'cleanup_rdv' => __DIR__ . '/tools/cleanup_rdv.php',
'afficher_messages' => __DIR__ . '/tools/afficher_messages.php',
'new_inscrits' => __DIR__ . '/tools/new_clients.php',
'mail_praticiens' => __DIR__ . '/tools/mailing_praticiens.php',
'mailing_client' => __DIR__ . '/tools/mailing_client.php',
'connecter_en_admin' => __DIR__ . '/tools/connecter_en_admin.php',
'clean_uploads' => __DIR__ . '/tools/clean_uploads.php',
];
$page = $_GET['page'] ?? null;
$key = (is_string($page) && isset($views[$page])) ? $page : 'maintenance';
?>
<!doctype html>
<html lang="<?php echo h($lang ?? 'ru') ?>">
<head>
<meta charset="utf-8">
<title><?php echo h($translations['admin_title'] ?? 'Admin') ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Police Montserrat -->
<script src="/js/sweetalert2@11.js"></script>
<!-- Bootstrap -->
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/includes/admin_style.css?v=202602">
</head>
<body>
<header class="site-header py-2 border-bottom">
<div class="container d-flex justify-content-between align-items-center">
<div class="header-left">
<div class="brand">
<a href="<?php echo h($fallbackBack) ?>"
id="btnBack"
class="btn btn-light btn-circle me-2"
style="border-radius:5px; box-shadow:0 1px 2px rgba(0,0,0,.08);"
aria-label="<?php echo h($translations['retour'] ?? 'Retour') ?>">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" aria-hidden="true">
<path d="M15 6l-6 6 6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
<a href="/admin/index.php" aria-label="<?php echo h($translations['home'] ?? 'Home') ?>">
<img src="/public/uploads/img/logo_u.png" alt="<?php echo h($translations['site_name'] ?? 'uslugi.fr') ?>" class="logo-mobile">
<img src="/public/uploads/img/logo.png" alt="<?php echo h($translations['site_name'] ?? 'uslugi.fr') ?>" class="logo-desktop">
</a>
</div>
<div class="lang-switch">
<?php require __DIR__ . '/../includes/menu_langue.php'; ?>
</div>
</div>
<nav class="header-actions d-flex align-items-center gap-3 position-relative">
<div class="menu-wrap">
<button type="button" id="btnMenu" class="btn p-0 border-0 bg-transparent" aria-label="<?php echo h($translations['menu_admin'] ?? 'Menu') ?>">
<div class="avatar d-flex align-items-center justify-content-center"
style="width:40px;height:40px;border-radius:50%;background:#38378B;color:white;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M19.14,12.94a7.48,7.48,0,0,0,0-1.88l2.11-1.65a.5.5,0,0,0,.12-.64l-2-3.46a.5.5,0,0,0-.61-.22l-2.49,1a7.28,7.28,0,0,0-1.63-.95l-.38-2.65A.5.5,0,0,0,13.78,3H10.22a.5.5,0,0,0-.49.42L9.35,6.07a7.28,7.28,0,0,0-1.63.95l-2.49-1a.5.5,0,0,0-.61.22l-2,3.46a.5.5,0,0,0,.12.64L4.86,11.06a7.48,7.48,0,0,0,0,1.88L2.75,14.59a.5.5,0,0,0-.12.64l2,3.46a.5.5,0,0,0,.61.22l2.49-1a7.28,7.28,0,0,0,1.63.95l.38,2.65a.5.5,0,0,0,.49.42h3.56a.5.5,0,0,0,.49-.42l.38-2.65a7.28,7.28,0,0,0,1.63-.95l2.49,1a.5.5,0,0,0,.61-.22l2-3.46a.5.5,0,0,0-.12-.64ZM12,15.5A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z"/>
</svg>
</div>
</button>
<ul class="dropdown-menu-custom menu-panel" id="menu" aria-hidden="true">
<li class="has-submenu">
<button type="button" class="submenu-toggle" aria-expanded="false">
<?php echo h($translations['menu_stats'] ?? 'Statistiques & suivi') ?>
<span class="submenu-arrow">▾</span>
</button>
<ul class="submenu" hidden>
<!--<li onclick="window.open('https://staging.uslugi.fr/matomo/index.php','_blank')">
<?php echo h($translations['admin_analytic'] ?? 'Analytics') ?>
</li>-->
<li onclick="location.href='<?php echo h(admin_url('logs')) ?>'">
<?php echo h($translations['afficher_logs'] ?? 'Logs') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('audit')) ?>'">
<?php echo h($translations['audit'] ?? 'Audit') ?>
</li>
</ul>
</li>
<li class="has-submenu">
<button type="button" class="submenu-toggle" aria-expanded="false">
<?php echo h($translations['menu_users'] ?? 'Utilisateurs') ?>
<span class="submenu-arrow">▾</span>
</button>
<ul class="submenu" hidden>
<li onclick="location.href='<?php echo h(admin_url('new_inscrits')) ?>'">
<?php echo h($translations['les_inscrits'] ?? 'Les inscrits') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('gerer_praticiens')) ?>'">
<?php echo h($translations['gerer_praticiens'] ?? 'Gérer praticiens') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('connecter_en_admin')) ?>'">
<?php echo h($translations['connecter_en_admin'] ?? 'Войти от имени пользователя') ?>
</li>
</ul>
</li>
<li class="has-submenu">
<button type="button" class="submenu-toggle" aria-expanded="false">
<?php echo h($translations['menu_communication'] ?? 'Communication') ?>
<span class="submenu-arrow">▾</span>
</button>
<ul class="submenu" hidden>
<li onclick="location.href='<?php echo h(admin_url('mail_praticiens')) ?>'">
<?php echo h($translations['mail_praticiens'] ?? 'Рассылка практикующим') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('mailing_client')) ?>'">
<?php echo h($translations['mail_clients'] ?? 'Рассылка клиентам') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('afficher_messages')) ?>'">
<?php echo h($translations['afficher_messages'] ?? 'Afficher Messages') ?>
</li>
</ul>
</li>
<li class="has-submenu">
<button type="button" class="submenu-toggle" aria-expanded="false">
<?php echo h($translations['menu_content'] ?? 'Contenu') ?>
<span class="submenu-arrow">▾</span>
</button>
<ul class="submenu" hidden>
<li onclick="location.href='<?php echo h(admin_url('add_video')) ?>'">
<?php echo h($translations['add_video'] ?? 'Ajouter une vidéo') ?>
</li>
</ul>
</li>
<li class="has-submenu">
<button type="button" class="submenu-toggle" aria-expanded="false">
<?php echo h($translations['menu_maintenance'] ?? 'Maintenance') ?>
<span class="submenu-arrow">▾</span>
</button>
<ul class="submenu" hidden>
<li onclick="location.href='<?php echo h(admin_url('cleanup_inscriptions')) ?>'">
<?php echo h($translations['supp_inscr'] ?? 'Supp. inscriptions') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('clean_uploads')) ?>'">
<?php echo h($translations['supp_uploads'] ?? 'Supp. uploads') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('purge_conversations')) ?>'">
<?php echo h($translations['purger_messages'] ?? 'Supp. messages') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('purger_mess_upload')) ?>'">
<?php echo h($translations['purger_mess_upload'] ?? 'Supp. Upload') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('cleanup_rdv')) ?>'">
<?php echo h($translations['cleanup_rdv'] ?? 'Cleanup RDV') ?>
</li>
<li onclick="location.href='<?php echo h(admin_url('backup_db')) ?>'">
<?php echo h($translations['backup_db'] ?? 'Backup DB') ?>
</li>
</ul>
</li>
<li class="menu-item-form">
<form method="POST" action="/public/deconnexion.php" class="menu-logout-form">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(ensure_csrf_token(), ENT_QUOTES, 'UTF-8') ?>">
<button type="submit" class="menu-logout-btn">
<?php echo htmlspecialchars($translations['menu_deconnexion'] ?? 'Déconnexion') ?>
</button>
</form>
</li>
</ul>
</div>
</nav>
</div>
</header>
<div class="main1">
<div class="container my-3">
<?php
$_GET['page'] = $key;
$path = $views[$key] ?? null;
if ($path && is_file($path)) {
require $path;
} else {
echo '<div class="alert alert-warning">' . h($translations['admin_view_missing'] ?? 'Vue manquante :') . ' ' . h($key) . '</div>';
}
?>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const toggles = document.querySelectorAll('.submenu-toggle');
toggles.forEach(toggle => {
toggle.addEventListener('click', function (e) {
e.stopPropagation();
const parent = this.closest('.has-submenu');
const submenu = parent.querySelector('.submenu');
const isOpen = parent.classList.contains('open');
// ferme les autres
document.querySelectorAll('.has-submenu.open').forEach(item => {
if (item !== parent) {
item.classList.remove('open');
const sub = item.querySelector('.submenu');
const btn = item.querySelector('.submenu-toggle');
if (sub) sub.hidden = true;
if (btn) btn.setAttribute('aria-expanded', 'false');
}
});
// toggle courant
parent.classList.toggle('open', !isOpen);
submenu.hidden = isOpen;
this.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
});
});
});
</script>
<script>
function toggleMenu() {
const menu = document.getElementById('menu');
if (!menu) return;
menu.style.display = (menu.style.display === 'block') ? 'none' : 'block';
}
function closeMenu() {
const menu = document.getElementById('menu');
if (menu) menu.style.display = 'none';
closeSubmenus();
}
document.getElementById('btnMenu')?.addEventListener('click', toggleMenu);
document.addEventListener('click', (e) => {
const menu = document.getElementById('menu');
if (!menu) return;
const toggle = document.getElementById('btnMenu');
if (toggle && !toggle.contains(e.target) && !menu.contains(e.target)) {
closeMenu();
}
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeMenu();
});
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<?php if (ob_get_level() > 0) {
ob_end_flush();
}?>
</body>
</html>
<?php endif; ?>