| Server IP : 188.114.96.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /polana/includes/ |
Upload File : |
<?php
declare(strict_types=1);
/** POLANA V18.0 - non-destructive menu lifecycle, listing and IndexNow bridge. */
function pv18_menu_trash_ready(): bool {
try { db()->query('SELECT menu_id FROM polana_menu_trash LIMIT 0'); return true; }
catch (Throwable $e) { return false; }
}
function pv18_menu_schema(): void {
db()->exec("CREATE TABLE IF NOT EXISTS polana_menu_trash (
menu_id INT UNSIGNED NOT NULL PRIMARY KEY,
previous_status VARCHAR(16) NOT NULL,
deleted_by INT UNSIGNED NULL,
deleted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_deleted_at (deleted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
}
function pv18_menu_kind(string $type): string {
return in_array($type, ['food','soft','wine'], true) ? $type : 'food';
}
function pv18_menu_notify(): void {
try {
require_once __DIR__.'/polana_indexnow.php';
if (function_exists('pin77_after_menu_change')) pin77_after_menu_change();
} catch (Throwable $e) { error_log('POLANA V18 IndexNow: '.$e->getMessage()); }
}
function pv18_menu_action(string $action, array $post): string {
if (!in_array($action, ['rename','publish','draft','archive','trash','restore','unarchive'], true))
throw new RuntimeException('Nieznana akcja karty.');
$id = (int)($post['id'] ?? 0);
if ($id < 1) throw new RuntimeException('Nieprawidłowy numer karty.');
if (!pv18_menu_trash_ready()) throw new RuntimeException('Najpierw uruchom instalator V18.0 (kosz menu).');
if (in_array($action,['trash','restore'],true)) require_admin_role();
$db=db(); $notify=false; $message='';
$db->beginTransaction();
try {
$stmt=$db->prepare('SELECT * FROM menus WHERE id=? FOR UPDATE');
$stmt->execute([$id]); $menu=$stmt->fetch(PDO::FETCH_ASSOC);
if (!$menu) throw new RuntimeException('Karta nie istnieje.');
$check=$db->prepare('SELECT previous_status FROM polana_menu_trash WHERE menu_id=?');
$check->execute([$id]); $inTrash=$check->fetchColumn();
if ($inTrash!==false && $action!=='restore') throw new RuntimeException('Karta jest w koszu — najpierw ją przywróć.');
if ($inTrash===false && $action==='restore') throw new RuntimeException('Ta karta nie jest w koszu.');
$status=(string)$menu['status'];
if ($action==='rename') {
$name=trim((string)($post['name']??''));
$length=function_exists('mb_strlen')?mb_strlen($name,'UTF-8'):strlen($name);
if ($length<1||$length>150) throw new RuntimeException('Nazwa: 1–150 znaków.');
$from=trim((string)($post['valid_from']??''));$to=trim((string)($post['valid_to']??''));
foreach ([$from,$to] as $d) if ($d!=='' && (!preg_match('/^\d{4}-\d{2}-\d{2}$/D',$d) || date('Y-m-d',strtotime($d))!==$d))
throw new RuntimeException('Nieprawidłowa data obowiązywania.');
if ($from!==''&&$to!==''&&$to<$from) throw new RuntimeException('Data końca jest wcześniejsza niż początek.');
$db->prepare('UPDATE menus SET name=?,valid_from=?,valid_to=? WHERE id=?')->execute([$name,$from?:null,$to?:null,$id]);
$notify=$status==='published';$message='Zmieniono nazwę i daty karty #'.$id.'.';
} elseif ($action==='publish') {
$from=(string)($menu['valid_from']??'');$to=(string)($menu['valid_to']??'');
$q=$db->prepare("SELECT id,valid_from,valid_to FROM menus WHERE id<>? AND menu_type=? AND status='published' FOR UPDATE");
$q->execute([$id,pv18_menu_kind((string)$menu['menu_type'])]);
$overlap=[];$overlapRows=[];
foreach ($q->fetchAll(PDO::FETCH_ASSOC) as $other) {
$oFrom=(string)($other['valid_from']??'');$oTo=(string)($other['valid_to']??'');
if (($to===''||$oFrom===''||$oFrom<=$to) && ($oTo===''||$from===''||$from<=$oTo)) { $overlap[]=(int)$other['id'];$overlapRows[(int)$other['id']]=$other; }
}
if ($overlap && empty($post['replace_conflicts']))
throw new RuntimeException('Istnieją opublikowane karty tego samego rodzaju z nakładającymi się datami (ID: '.implode(', ',$overlap).'). Zaznacz „Zastąp kolidujące”, jeśli chcesz je zarchiwizować.');
$trimmed=0;$archived=0;
if ($overlap) {
$upd=$db->prepare("UPDATE menus SET status='archived' WHERE id=? AND status='published'");
$shorten=$db->prepare("UPDATE menus SET valid_to=? WHERE id=? AND status='published'");
foreach ($overlap as $otherId) {
$other=$overlapRows[$otherId];
$otherFrom=(string)($other['valid_from']??'');
if($from!=='' && $from>date('Y-m-d') && ($otherFrom===''||$otherFrom<$from)){
// Keep the current menu public until the day before the future card begins.
$lastDay=(new DateTimeImmutable($from))->modify('-1 day')->format('Y-m-d');
$shorten->execute([$lastDay,$otherId]);$trimmed++;
} else {$upd->execute([$otherId]);$archived++;}
}
}
$db->prepare("UPDATE menus SET status='published' WHERE id=?")->execute([$id]);
$notify=true;$message='Opublikowano kartę #'.$id.'. Zarchiwizowano: '.$archived.', ustawiono datę końcową poprzednich: '.$trimmed.'.';
} elseif ($action==='archive') {
$db->prepare("UPDATE menus SET status='archived' WHERE id=?")->execute([$id]);
$notify=$status==='published';$message='Zarchiwizowano kartę #'.$id.'.';
} elseif ($action==='draft'||$action==='unarchive') {
$db->prepare("UPDATE menus SET status='draft' WHERE id=?")->execute([$id]);
$notify=$status==='published';$message='Karta #'.$id.' jest teraz szkicem.';
} elseif ($action==='trash') {
if ($status==='published') throw new RuntimeException('Najpierw zarchiwizuj opublikowaną kartę.');
$user=admin_user();
$db->prepare('INSERT INTO polana_menu_trash(menu_id,previous_status,deleted_by) VALUES(?,?,?)')
->execute([$id,$status,isset($user['id'])?(int)$user['id']:null]);
$db->prepare("UPDATE menus SET status='archived' WHERE id=?")->execute([$id]);
$message='Przeniesiono kartę #'.$id.' do kosza. Można ją przywrócić.';
} elseif ($action==='restore') {
$db->prepare('DELETE FROM polana_menu_trash WHERE menu_id=?')->execute([$id]);
$db->prepare("UPDATE menus SET status='draft' WHERE id=?")->execute([$id]);
$message='Przywrócono kartę #'.$id.' jako szkic.';
}
$db->commit();
} catch (Throwable $e) { if ($db->inTransaction()) $db->rollBack(); throw $e; }
admin_log('polana_v18_menu_'.$action, 'Menu #'.$id.' — '.$message);
if ($notify) pv18_menu_notify();
return $message;
}