Files
2026-03-05 10:25:39 +01:00

322 lines
15 KiB
PHP

<?php
require_once __DIR__ . '/../../public/includes/init_admin.php';
/** УКАЖИ ID администратора-практиканта здесь */
const ADMIN_PRACTICIEN_ID = 88888888; // <-- заменить на реальный ID
$me = (int)($_SESSION['reference_id'] ?? 0);
if ($me !== ADMIN_PRACTICIEN_ID) {
http_response_code(403);
echo '<div class="container py-5"><div class="alert alert-danger">'
. htmlspecialchars($translations['non_autorise'] ?? 'Доступ запрещён.', ENT_QUOTES, 'UTF-8')
. '</div></div>';
return;
}
$mustReauth = function(int $ttl=600){
$t=(int)($_SESSION['admin_reauth_at']??0);
return ($t===0||(time()-$t)>$ttl);
};
if ($mustReauth()){
$qs=http_build_query(['page'=>'reauth','redir'=>($_SERVER['REQUEST_URI']??'index.php?page=maintenance')]);
header('Location:?'.$qs);
exit;
}
// -- PDO si absent
if (!isset($pdo)) { require_once '../../includes/db.php'; }
// CSRF
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
$CSRF = $_SESSION['csrf_token'];
// helpers
function e($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
$flash = ['type'=>null,'msg'=>null];
// ---- Обработка POST ----
$action = $_POST['do'] ?? null;
try {
if ($action === 'update_main') {
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf'] ?? '')) throw new Exception('CSRF');
$pid = (int)($_POST['id'] ?? 0);
$url = trim($_POST['video'] ?? '');
$stmt = $pdo->prepare("UPDATE praticien SET video = :video WHERE id = :id");
$stmt->execute(['video' => ($url !== '' ? $url : null), 'id' => $pid]);
$flash = ['type'=>'success','msg'=>($translations['admin_video_flash_main_saved'] ?? 'Основное видео сохранено.')];
$_GET['id'] = $pid;
}
if ($action === 'add_extra') {
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf'] ?? '')) throw new Exception('CSRF');
$pid = (int)($_POST['id'] ?? 0);
$url = trim($_POST['url'] ?? '');
$title = trim($_POST['title'] ?? '');
$ordre = (int)($_POST['ordre'] ?? 0);
if ($url === '') throw new Exception($translations['admin_video_err_url_required'] ?? 'Укажите URL');
$stmt = $pdo->prepare("INSERT INTO praticien_video (praticien_id, url, title, ordre) VALUES (?,?,?,?)");
$stmt->execute([$pid, $url, ($title !== '' ? $title : null), $ordre]);
$flash = ['type'=>'success','msg'=>($translations['admin_video_flash_added'] ?? 'Видео добавлено.')];
$_GET['id'] = $pid;
}
if ($action === 'update_extra') {
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf'] ?? '')) throw new Exception('CSRF');
$pid = (int)($_POST['pid'] ?? 0);
$vid = (int)($_POST['vid'] ?? 0);
$url = trim($_POST['url'] ?? '');
$title = trim($_POST['title'] ?? '');
$ordre = (int)($_POST['ordre'] ?? 0);
if ($vid <= 0 || $url === '') throw new Exception($translations['admin_video_err_check_fields'] ?? 'Проверьте поля');
$stmt = $pdo->prepare("UPDATE praticien_video SET url=?, title=?, ordre=? WHERE id=?");
$stmt->execute([$url, ($title !== '' ? $title : null), $ordre, $vid]);
$flash = ['type'=>'success','msg'=>($translations['admin_video_flash_updated'] ?? 'Видео обновлено.')];
$_GET['id'] = $pid;
}
if ($action === 'delete_extra') {
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf'] ?? '')) throw new Exception('CSRF');
$pid = (int)($_POST['pid'] ?? 0);
$vid = (int)($_POST['vid'] ?? 0);
if ($vid <= 0) throw new Exception($translations['admin_video_err_unknown_id'] ?? 'Неизвестный ID');
$stmt = $pdo->prepare("DELETE FROM praticien_video WHERE id=?");
$stmt->execute([$vid]);
$flash = ['type'=>'success','msg'=>($translations['admin_video_flash_deleted'] ?? 'Видео удалено.')];
$_GET['id'] = $pid;
}
} catch (Exception $ex) {
$flash = ['type'=>'danger','msg'=>($translations['err_prefixe'] ?? 'Ошибка: ') . $ex->getMessage()];
}
// ---- РЕЖИМ A: список всех практиков ----
if (empty($_GET['id'])) {
$rows = $pdo->query("
SELECT id, titre, nom, prenom, specialite, photo, video
FROM praticien
ORDER BY nom ASC, prenom ASC
")->fetchAll(PDO::FETCH_ASSOC);
?>
<div class="shadow p-4 rounded bg-light">
<h2 class="mb-3 text-center"><?= e($translations['admin_video_title'] ?? '🎬 Видео практиков — Администрирование') ?></h2>
<?php if ($flash['msg']): ?>
<div class="alert alert-<?= e($flash['type']) ?>"><?= e($flash['msg']) ?></div>
<?php endif; ?>
<div class="mb-3">
<input type="text" class="form-control" id="filter"
placeholder="<?= e($translations['admin_video_filter_placeholder'] ?? 'Фильтр (имя, специальность)…') ?>">
</div>
<div class="table-responsive">
<table class="table table-bordered table-hover align-middle mobile-cards" id="tab">
<thead class="table-light">
<tr>
<th style="width:70px;"><?= e($translations['admin_video_th_photo'] ?? 'Фото') ?></th>
<th><?= e($translations['admin_video_th_name'] ?? 'Имя') ?></th>
<th><?= e($translations['admin_video_th_specialite'] ?? 'Специальность') ?></th>
<th><?= e($translations['admin_video_th_main_video'] ?? 'Основное видео') ?></th>
<th class="text-center" style="width:150px;"><?= e($translations['admin_video_th_actions'] ?? 'Действия') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($rows as $r):
$name = trim($r['prenom'].' '.$r['nom']);
$photo = !empty($r['photo']) ? '/public/uploads/'.e($r['photo']) : '/public/uploads/img/user_placeholder.png';
?>
<tr data-hay="<?= e(mb_strtolower($name.' '.$r['specialite'])) ?>">
<td><img src="<?= $photo ?>" alt="" class="rounded" style="width:48px;height:48px;object-fit:cover;"></td>
<td><?= e($name) ?></td>
<td><?= e($r['specialite'] ?? '') ?></td>
<td>
<?php if (!empty($r['video'])): ?>
<span class="badge bg-success"><?= e($translations['admin_video_badge_set'] ?? 'указано') ?></span>
<a class="ms-2" href="<?= e($r['video']) ?>" target="_blank" rel="noopener">
<?= e($translations['admin_video_open'] ?? 'открыть') ?>
</a>
<?php else: ?>
<span class="badge bg-secondary"><?= e($translations['admin_video_badge_not_set'] ?? 'не указано') ?></span>
<?php endif; ?>
</td>
<td class="text-center">
<a class="btn btn-sm btn-danger" href="index.php?page=add_video&id=<?= (int)$r['id'] ?>">
<?= e($translations['admin_video_manage'] ?? 'Управлять') ?>
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<script>
// Простой фильтр по таблице (на клиенте)
document.getElementById('filter').addEventListener('input', function(){
const q = (this.value || '').trim().toLowerCase();
document.querySelectorAll('#tab tbody tr').forEach(tr=>{
const hay = (tr.dataset.hay || '').toLowerCase();
tr.style.display = !q || hay.includes(q) ? '' : 'none';
});
});
</script>
<?php
return;
}
// ---- РЕЖИМ B: управление конкретным практиком ----
$pid = (int)$_GET['id'];
$st = $pdo->prepare("SELECT id, titre, nom, prenom, specialite, photo, video FROM praticien WHERE id=?");
$st->execute([$pid]);
$praticien = $st->fetch(PDO::FETCH_ASSOC);
if (!$praticien) {
echo '<div class="container py-5"><div class="alert alert-warning">'
. e($translations['admin_video_not_found'] ?? 'Практикант не найден.')
. '</div><a href="add_video.php" class="btn btn-secondary mt-2">⬅️ '
. e($translations['admin_video_back'] ?? 'Назад')
. '</a></div>';
return;
}
$extras = $pdo->prepare("SELECT id, url, title, ordre, created_at FROM praticien_video WHERE praticien_id=? ORDER BY ordre ASC, id DESC");
$extras->execute([$pid]);
$videos = $extras->fetchAll(PDO::FETCH_ASSOC);
$name = trim($praticien['prenom'].' '.$praticien['nom']);
$photo = !empty($praticien['photo']) ? '/public/uploads/'.e($praticien['photo']) : '/public/uploads/img/user_placeholder.png';
?>
<div class="shadow p-4 rounded bg-light">
<a href="index.php?page=add_video" class="btn btn-outline-secondary mb-3" style="border-radius:999px;">
⬅️ <?= e($translations['admin_video_back_to_list'] ?? 'Назад к списку') ?>
</a>
<?php if ($flash['msg']): ?>
<div class="alert alert-<?= e($flash['type']) ?>"><?= e($flash['msg']) ?></div>
<?php endif; ?>
<div class="card shadow-sm mb-4">
<div class="card-body d-flex gap-3 align-items-center">
<img src="<?= $photo ?>" class="rounded" style="width:64px;height:64px;object-fit:cover;" alt="">
<div>
<h5 class="mb-1"><?= e($name) ?></h5>
<div class="text-muted"><?= e($praticien['specialite'] ?? '') ?></div>
</div>
</div>
</div>
<!-- Основное видео (praticien.video) -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-light"><strong><?= e($translations['admin_video_main_block_title'] ?? 'Основное видео') ?></strong></div>
<div class="card-body">
<form method="post" class="row g-3">
<div class="col-12">
<label class="form-label"><?= e($translations['admin_video_main_url_label'] ?? 'URL видео (YouTube, Vimeo, Dailymotion, MP4…)') ?></label>
<input type="url" name="video" class="form-control"
placeholder="<?= e($translations['admin_video_url_placeholder'] ?? 'https://…') ?>"
value="<?= e($praticien['video'] ?? '') ?>">
<div class="form-text"><?= e($translations['admin_video_main_help'] ?? 'Поле сохраняется в praticien.video и используется на публичных страницах.') ?></div>
</div>
<div class="col-12">
<input type="hidden" name="csrf" value="<?= e($CSRF) ?>">
<input type="hidden" name="id" value="<?= (int)$pid ?>">
<input type="hidden" name="do" value="update_main">
<button class="btn btn-danger" style="border-radius:999px;"><?= e($translations['enregistrer'] ?? 'Сохранить') ?></button>
<?php if (!empty($praticien['video'])): ?>
<a class="btn btn-outline-secondary ms-2" target="_blank" rel="noopener" href="<?= e($praticien['video']) ?>">
<?= e($translations['admin_video_open_video'] ?? 'Открыть видео') ?>
</a>
<?php endif; ?>
</div>
</form>
</div>
</div>
<!-- Дополнительные видео (praticien_video) -->
<div class="card shadow-sm">
<div class="card-header bg-light"><strong><?= e($translations['admin_video_extra_block_title'] ?? 'Дополнительные видео (необязательно)') ?></strong></div>
<div class="card-body">
<form method="post" class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label"><?= e($translations['admin_video_title_label_optional'] ?? 'Название (необязательно)') ?></label>
<input type="text" name="title" class="form-control"
placeholder="<?= e($translations['admin_video_title_placeholder'] ?? 'Презентация кабинета') ?>">
</div>
<div class="col-md-3">
<label class="form-label"><?= e($translations['admin_video_order_label'] ?? 'Порядок') ?></label>
<input type="number" name="ordre" class="form-control" value="0" min="0" step="1">
</div>
<div class="col-12">
<label class="form-label"><?= e($translations['admin_video_url_label'] ?? 'URL видео') ?></label>
<input type="url" name="url" class="form-control"
placeholder="<?= e($translations['admin_video_url_placeholder'] ?? 'https://…') ?>">
</div>
<div class="col-12">
<input type="hidden" name="csrf" value="<?= e($CSRF) ?>">
<input type="hidden" name="id" value="<?= (int)$pid ?>">
<input type="hidden" name="do" value="add_extra">
<button class="btn btn-success" style="border-radius:999px;"><?= e($translations['admin_video_add'] ?? 'Добавить') ?></button>
</div>
</form>
<?php if (empty($videos)): ?>
<div class="text-muted"><?= e($translations['admin_video_no_extras'] ?? 'Пока нет дополнительных видео.') ?></div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead class="table-light">
<tr>
<th style="width:80px;"><?= e($translations['admin_video_th_order'] ?? 'Порядок') ?></th>
<th><?= e($translations['admin_video_th_title'] ?? 'Название') ?></th>
<th><?= e($translations['admin_video_th_url'] ?? 'URL') ?></th>
<th style="width:180px;"><?= e($translations['admin_video_th_actions'] ?? 'Действия') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($videos as $v): ?>
<tr>
<form method="post">
<td style="width:80px;">
<input type="number" name="ordre" class="form-control" value="<?= (int)$v['ordre'] ?>" min="0" step="1">
</td>
<td>
<input type="text" name="title" class="form-control" value="<?= e($v['title']) ?>"
placeholder="<?= e($translations['admin_video_title_optional_placeholder'] ?? 'Название (необязательно)') ?>">
</td>
<td>
<input type="url" name="url" class="form-control" value="<?= e($v['url']) ?>">
</td>
<td class="d-flex gap-2">
<input type="hidden" name="csrf" value="<?= e($CSRF) ?>">
<input type="hidden" name="pid" value="<?= (int)$pid ?>">
<input type="hidden" name="vid" value="<?= (int)$v['id'] ?>">
<button name="do" value="update_extra" class="btn btn-outline-primary btn-sm">
<?= e($translations['enregistrer'] ?? 'Сохранить') ?>
</button>
<button name="do" value="delete_extra" class="btn btn-outline-danger btn-sm"
onclick="return confirm('<?= e($translations['admin_video_confirm_delete'] ?? 'Удалить это видео?') ?>')">
<?= e($translations['supprimer'] ?? 'Удалить') ?>
</button>
</td>
</form>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>