Public badge for restored photos and commenter link retrieval/regeneration
This commit is contained in:
parent
9207c739fc
commit
0995989b56
|
|
@ -132,7 +132,7 @@ BRANCH=master bash scripts/deploy.sh
|
||||||
- после загрузки автоматический prefill имени (code_name) из имени файла,
|
- после загрузки автоматический prefill имени (code_name) из имени файла,
|
||||||
- для каждой карточки фото можно отредактировать: имя, сортировку, комментарий и добавить/заменить фото "после",
|
- для каждой карточки фото можно отредактировать: имя, сортировку, комментарий и добавить/заменить фото "после",
|
||||||
- запись в таблицы `sections`, `photos`, `photo_files`,
|
- запись в таблицы `sections`, `photos`, `photo_files`,
|
||||||
- персональные комментаторы (генерация ссылок),
|
- персональные комментаторы (генерация ссылок + повторный просмотр/перевыпуск ссылки),
|
||||||
- плоские комментарии к фото,
|
- плоские комментарии к фото,
|
||||||
- удаление комментариев админом,
|
- удаление комментариев админом,
|
||||||
- watermark на выдаче версии "после".
|
- watermark на выдаче версии "после".
|
||||||
|
|
|
||||||
22
admin.php
22
admin.php
|
|
@ -114,6 +114,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($action === 'regenerate_commenter_token') {
|
||||||
|
$id = (int)($_POST['id'] ?? 0);
|
||||||
|
if ($id > 0) {
|
||||||
|
$token = commenterRegenerateToken($id);
|
||||||
|
$link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost') . '/?viewer=' . urlencode($token);
|
||||||
|
$message = 'Токен обновлён | ссылка: ' . $link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($action === 'delete_comment') {
|
if ($action === 'delete_comment') {
|
||||||
$id = (int)($_POST['id'] ?? 0);
|
$id = (int)($_POST['id'] ?? 0);
|
||||||
if ($id > 0) {
|
if ($id > 0) {
|
||||||
|
|
@ -371,9 +380,20 @@ function nextUniqueCodeName(string $base): string
|
||||||
<?php if ($adminMode === 'comments'): ?>
|
<?php if ($adminMode === 'comments'): ?>
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<h3>Комментаторы и комментарии</h3>
|
<h3>Комментаторы и комментарии</h3>
|
||||||
<table class="tbl"><tr><th>Пользователь</th><th>Действие</th></tr>
|
<table class="tbl"><tr><th>Пользователь</th><th>Ссылка</th><th>Действия</th></tr>
|
||||||
<?php foreach($commenters as $u): ?>
|
<?php foreach($commenters as $u): ?>
|
||||||
|
<?php $viewerLink = !empty($u['token_plain']) ? ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost') . '/?viewer=' . urlencode((string)$u['token_plain'])) : ''; ?>
|
||||||
<tr><td><?= h((string)$u['display_name']) ?></td><td>
|
<tr><td><?= h((string)$u['display_name']) ?></td><td>
|
||||||
|
<?php if ($viewerLink !== ''): ?>
|
||||||
|
<input class="in" type="text" readonly value="<?= h($viewerLink) ?>" onclick="this.select()" style="min-width:320px">
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="small">Нет сохранённой ссылки (старый пользователь)</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td><td style="display:flex;gap:8px;flex-wrap:wrap">
|
||||||
|
<form method="post" action="?token=<?= urlencode($tokenIncoming) ?>&mode=comments">
|
||||||
|
<input type="hidden" name="action" value="regenerate_commenter_token"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="id" value="<?= (int)$u['id'] ?>">
|
||||||
|
<button class="btn" type="submit">Новая ссылка</button>
|
||||||
|
</form>
|
||||||
<form method="post" action="?token=<?= urlencode($tokenIncoming) ?>&mode=comments" onsubmit="return confirm('Удалить пользователя?')">
|
<form method="post" action="?token=<?= urlencode($tokenIncoming) ?>&mode=comments" onsubmit="return confirm('Удалить пользователя?')">
|
||||||
<input type="hidden" name="action" value="delete_commenter"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="id" value="<?= (int)$u['id'] ?>">
|
<input type="hidden" name="action" value="delete_commenter"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="id" value="<?= (int)$u['id'] ?>">
|
||||||
<button class="btn btn-danger" type="submit">Удалить доступ</button>
|
<button class="btn btn-danger" type="submit">Удалить доступ</button>
|
||||||
|
|
|
||||||
|
|
@ -178,8 +178,9 @@ function outputWatermarked(string $path, string $mime): never
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<div class="cards">
|
<div class="cards">
|
||||||
<?php foreach($photos as $p): ?>
|
<?php foreach($photos as $p): ?>
|
||||||
<a class="card" href="?photo_id=<?= (int)$p['id'] ?>§ion_id=<?= (int)$activeSectionId ?><?= $viewerToken!=='' ? '&viewer=' . urlencode($viewerToken) : '' ?>" style="text-decoration:none;color:inherit">
|
<a class="card" href="?photo_id=<?= (int)$p['id'] ?>§ion_id=<?= (int)$activeSectionId ?><?= $viewerToken!=='' ? '&viewer=' . urlencode($viewerToken) : '' ?>" style="text-decoration:none;color:inherit;position:relative">
|
||||||
<?php if (!empty($p['before_file_id'])): ?><img src="?action=image&file_id=<?= (int)$p['before_file_id'] ?>" alt=""><?php endif; ?>
|
<?php if (!empty($p['before_file_id'])): ?><img src="?action=image&file_id=<?= (int)$p['before_file_id'] ?>" alt=""><?php endif; ?>
|
||||||
|
<?php if (!empty($p['after_file_id'])): ?><span title="Есть обработанная версия" style="position:absolute;top:8px;right:8px;background:rgba(31,111,235,.92);color:#fff;font-size:11px;line-height:1;padding:6px 7px;border-radius:999px">AI</span><?php endif; ?>
|
||||||
<div class="cap"><strong><?= h((string)$p['code_name']) ?></strong><br><span class="muted"><?= h((string)($p['description'] ?? '')) ?></span></div>
|
<div class="cap"><strong><?= h((string)$p['code_name']) ?></strong><br><span class="muted"><?= h((string)($p['description'] ?? '')) ?></span></div>
|
||||||
</a>
|
</a>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,8 @@ function commenterCreate(string $displayName): array
|
||||||
{
|
{
|
||||||
$token = bin2hex(random_bytes(16));
|
$token = bin2hex(random_bytes(16));
|
||||||
$hash = hash('sha256', $token);
|
$hash = hash('sha256', $token);
|
||||||
$st = db()->prepare('INSERT INTO comment_users(display_name, token_hash, is_active) VALUES (:n,:h,1)');
|
$st = db()->prepare('INSERT INTO comment_users(display_name, token_hash, token_plain, is_active) VALUES (:n,:h,:p,1)');
|
||||||
$st->execute(['n' => $displayName, 'h' => $hash]);
|
$st->execute(['n' => $displayName, 'h' => $hash, 'p' => $token]);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => (int)db()->lastInsertId(),
|
'id' => (int)db()->lastInsertId(),
|
||||||
|
|
@ -121,6 +121,15 @@ function commenterDelete(int $id): void
|
||||||
$st->execute(['id' => $id]);
|
$st->execute(['id' => $id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function commenterRegenerateToken(int $id): string
|
||||||
|
{
|
||||||
|
$token = bin2hex(random_bytes(16));
|
||||||
|
$hash = hash('sha256', $token);
|
||||||
|
$st = db()->prepare('UPDATE comment_users SET token_hash=:h, token_plain=:p WHERE id=:id');
|
||||||
|
$st->execute(['h' => $hash, 'p' => $token, 'id' => $id]);
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
function commentsByPhoto(int $photoId): array
|
function commentsByPhoto(int $photoId): array
|
||||||
{
|
{
|
||||||
$sql = 'SELECT c.*, u.display_name
|
$sql = 'SELECT c.*, u.display_name
|
||||||
|
|
|
||||||
2
migrations/003_comment_users_plain_token.sql
Normal file
2
migrations/003_comment_users_plain_token.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE comment_users
|
||||||
|
ADD COLUMN token_plain VARCHAR(128) NULL AFTER token_hash;
|
||||||
Loading…
Reference in New Issue
Block a user