301 lines
12 KiB
PHP
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; ?>
|