feat(admin): скрытие доменов и сохраняемый порядок колонок (#26)
This commit is contained in:
1 parent
dd6d221dd7
commit
00fbef9ede
12 files changed
+252
-33
No files matched your search
+24
-7
@@ -29,6 +29,9 @@ try {
|
||||
// Авторизация, idle timestamp и CSRF уже проверены; SSH/файловые операции
|
||||
// не должны удерживать PHP session lock и блокировать соседние запросы.
|
||||
session_write_close();
|
||||
// Удаление и постановка заданий используют одну блокировку: транспорт нельзя
|
||||
// удалить между проверкой существования подключения и записью задания.
|
||||
$enqueue=static function(callable $create,array $selections)use($store){return $store->locked('targets',function()use($create,$selections,$store){foreach($selections as $selection){$id=is_array($selection)?($selection['id']??null):$selection;if(!is_string($id))throw new Problem('Некорректная цель задания.');$store->target($id);}return $create();});};
|
||||
if($path==='/api/state'&&$method==='GET')reply(['csrf'=>$_SESSION['csrf'],'user'=>$user,'targets'=>$store->targets()]);
|
||||
if($path==='/api/utm-notes'){
|
||||
$notes=new Notes($store);
|
||||
@@ -52,6 +55,14 @@ try {
|
||||
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/visibility'&&$method==='POST'){
|
||||
if(count($data)!==2||array_diff(array_keys($data),['id','hidden'])||!is_string($data['id']??null)||!is_bool($data['hidden']??null))throw new Problem('Передайте строковый ID и логическое значение hidden.');
|
||||
reply(['targets'=>$store->setTargetVisibility($data['id'],$data['hidden'])]);
|
||||
}
|
||||
if($path==='/api/targets/order'&&$method==='POST'){
|
||||
if(count($data)!==1||!is_array($data['ids']??null)||!array_is_list($data['ids']))throw new Problem('Передайте список строковых ID в поле ids.');
|
||||
reply(['targets'=>$store->orderTargets($data['ids'])]);
|
||||
}
|
||||
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'=>'Пути, блокировка, чтение и права записи проверены.']);}
|
||||
if($path==='/api/config'&&$method==='GET'){
|
||||
@@ -61,23 +72,29 @@ try {
|
||||
}
|
||||
if($path==='/api/copy'){
|
||||
if($method!=='POST')throw new Problem('Метод копирования не поддерживается.',405);
|
||||
reply(['job'=>(new Copy($store))->create($data)],202);
|
||||
reply(['job'=>$enqueue(fn()=>(new Copy($store))->create($data),[])],202);
|
||||
}
|
||||
if($path==='/api/apply'&&$method==='POST'){$data['targets']=array_map(static fn($t)=>(array)$t,(array)($data['targets']??[]));$data['changes']=array_map(static fn($c)=>(array)$c,(array)($data['changes']??[]));reply(['job'=>$jobs->create('apply',$data)],202);}
|
||||
if($path==='/api/apply'&&$method==='POST'){$data['targets']=array_map(static fn($t)=>(array)$t,(array)($data['targets']??[]));$data['changes']=array_map(static fn($c)=>(array)$c,(array)($data['changes']??[]));reply(['job'=>$enqueue(fn()=>$jobs->create('apply',$data),$data['targets'])],202);}
|
||||
if($path==='/api/jobs'&&$method==='GET')reply(isset($_GET['id'])?['job'=>$jobs->get((string)$_GET['id'])]:['jobs'=>$jobs->all()]);
|
||||
if($path==='/api/jobs/retry'&&$method==='POST')reply(['job'=>$jobs->retry((string)($data['id']??''),(array)($data['targets']??[]))],202);
|
||||
if($path==='/api/jobs/retry'&&$method==='POST')reply(['job'=>$enqueue(fn()=>$jobs->retry((string)($data['id']??''),(array)($data['targets']??[])),(array)($data['targets']??[]))],202);
|
||||
if($path==='/api/backups'&&$method==='GET'){$id=(string)($_GET['target']??'');$store->target($id);reply(['backups'=>$store->backups($id)]);}
|
||||
if($path==='/api/restore'&&$method==='POST')reply(['job'=>$jobs->create('restore',$data)],202);
|
||||
if($path==='/api/restore'&&$method==='POST')reply(['job'=>$enqueue(fn()=>$jobs->create('restore',$data),[$data['target']??null])],202);
|
||||
if($path==='/api/sets'&&$method==='GET'){$target=$store->target((string)($_GET['target']??''));$read=(new Transport($store,$target))->readConfig();reply(['sets'=>$sets->list($target,$read['config']),'version'=>$read['version']]);}
|
||||
if($path==='/api/sets/upload'&&$method==='POST'){
|
||||
if(($_FILES['file']['error']??UPLOAD_ERR_NO_FILE)!==UPLOAD_ERR_OK||!is_uploaded_file($_FILES['file']['tmp_name']))throw new Problem('ZIP не получен либо превышает лимит 64 МиБ.');
|
||||
$number=Sets::number($data['number']??0);$prepared=$sets->prepareZip($_FILES['file']['tmp_name'],$number);
|
||||
$targets=json_decode((string)($data['targets']??'[]'),true,16,JSON_THROW_ON_ERROR);
|
||||
reply(['job'=>$jobs->create('upload',['targets'=>$targets,'number'=>$number,'name'=>(string)($data['name']??''),'prepared'=>$prepared])],202);
|
||||
reply(['job'=>$enqueue(fn()=>$jobs->create('upload',['targets'=>$targets,'number'=>$number,'name'=>(string)($data['name']??''),'prepared'=>$prepared]),$targets)],202);
|
||||
}
|
||||
if(in_array($path,['/api/sets/check','/api/sets/register'],true)&&$method==='POST'){$data['number']=Sets::number($data['number']??0);reply(['job'=>$jobs->create($path==='/api/sets/check'?'check':'register',$data)],202);}
|
||||
if(in_array($path,['/api/sets/check','/api/sets/register'],true)&&$method==='POST'){$data['number']=Sets::number($data['number']??0);reply(['job'=>$enqueue(fn()=>$jobs->create($path==='/api/sets/check'?'check':'register',$data),(array)($data['targets']??(isset($data['target'])?[$data['target']]:[])))],202);}
|
||||
if(in_array($path,['/api/sets/name','/api/sets/delete'],true)&&$method==='POST'){$target=$store->target((string)($data['target']??''));$number=Sets::number($data['number']??0);if($path==='/api/sets/name')$sets->name($target,$number,(string)($data['name']??''));else $sets->delete($target,$number);reply([]);}
|
||||
throw new Problem('Маршрут не найден.',404);
|
||||
}catch(Problem $e){http_response_code($e->status);echo json_encode(['ok'=>false,'error'=>$e->getMessage()],JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR);}
|
||||
}catch(Problem $e){
|
||||
// Запоздалый 401 (анонимный запрос, истечение сессии, ошибка входа) не должен
|
||||
// подменять или удалять cookie более нового успешного входа. Истёкший backing
|
||||
// Auth уже отзывает на сервере; явный logout возвращает 200 и очищает cookie.
|
||||
if($e->status===401)header_remove('Set-Cookie');
|
||||
http_response_code($e->status);echo json_encode(['ok'=>false,'error'=>$e->getMessage()],JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR);
|
||||
}
|
||||
catch(JsonException){http_response_code(400);echo json_encode(['ok'=>false,'error'=>'Некорректный JSON запроса.'],JSON_UNESCAPED_UNICODE);}
|
||||
catch(Throwable){http_response_code(500);echo json_encode(['ok'=>false,'error'=>'Операция не выполнена. Проверьте доступность и повторите.'],JSON_UNESCAPED_UNICODE);}
|
||||
Reference in new issue
Block a user