feat(admin): add runtime overview and independent saved UTM link builder
deploy-preland / deploy zoomstage.online (push) Successful in 57s

This commit is contained in:
Panfilov Konstantin committed 2026-10-25 18:17:23 +03:00
1 parent 48c71f3300
commit 2cfa2e2d2e
10 files changed
+421 -8

No files matched your search

+17 -2
View File
@@ -1,7 +1,7 @@
<?php
declare(strict_types=1);
require dirname(__DIR__).'/bootstrap.php';
use PrelandAdmin\{Auth,Store,Config,Transport,Jobs,Sets,Problem,Catalog};
use PrelandAdmin\{Auth,Store,Config,Transport,Jobs,Sets,Problem,Catalog,LinkBuilder};
header('X-Content-Type-Options: nosniff');header('X-Frame-Options: DENY');header('Referrer-Policy: same-origin');header('Cache-Control: no-store');
$path=parse_url($_SERVER['REQUEST_URI']??'/',PHP_URL_PATH);
if(!str_starts_with((string)$path,'/api/')) {require dirname(__DIR__).'/views/dashboard.php';exit;}
@@ -22,8 +22,23 @@ try {
if($path==='/api/login'&&$method==='POST')reply($auth->login((string)($data['username']??''),(string)($data['password']??''),$_SERVER['REMOTE_ADDR']??'unknown'));
$user=$auth->requireUser();
if($method!=='GET')$auth->csrf($_SERVER['HTTP_X_CSRF_TOKEN']??'');
if($path==='/api/state'&&$method==='GET')reply(['csrf'=>$_SESSION['csrf'],'user'=>$user,'targets'=>$store->targets()]);
if($path==='/api/logout'&&$method==='POST'){$auth->logout();reply([]);}
// Авторизация, idle timestamp и CSRF уже проверены; SSH/файловые операции
// не должны удерживать PHP session lock и блокировать соседние запросы.
session_write_close();
if($path==='/api/state'&&$method==='GET')reply(['csrf'=>$_SESSION['csrf'],'user'=>$user,'targets'=>$store->targets()]);
if($path==='/api/link-builder'){
$builder=new LinkBuilder($store);
if($method==='GET'){
if(array_diff(array_keys($_GET),['target'])||!is_string($_GET['target']??null))throw new Problem('Укажите ID подключения конструктора ссылки.');
reply($builder->get($_GET['target']));
}
if($method==='POST'){
if(count($data)!==2||array_diff(array_keys($data),['target','selection'])||!is_string($data['target']??null)||!(($data['selection']??null) instanceof stdClass))throw new Problem('Передайте ID подключения и объект выбора конструктора ссылки.');
reply($builder->save($data['target'],get_object_vars($data['selection'])));
}
throw new Problem('Метод конструктора ссылки не поддерживается.',405);
}
if($path==='/api/targets'&&$method==='POST')reply(['target'=>$store->saveTarget((array)($data['target']??[]),isset($data['secret'])?(string)$data['secret']:null)]);
if($path==='/api/targets'&&$method==='DELETE'){$store->deleteTarget((string)($data['id']??''));reply([]);}
if($path==='/api/targets/test'&&$method==='POST'){$id=(string)($data['id']??'');$t=$store->target($id);(new Transport($store,$t))->test();$store->verifyTarget($id,$t);reply(['message'=>'Пути, блокировка, чтение и права записи проверены.']);}