feat(admin): ручные варианты UTM и независимый редактор config (#30)
This commit is contained in:
1 parent
47405b27d8
commit
941a4f01aa
28 files changed
+108
-174
No files matched your search
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace PrelandAdmin;
|
||||
final class Catalog
|
||||
{
|
||||
public static function read(Store $store,\stdClass $config): ?array {
|
||||
$catalog=$store->read('catalog.json',null);if(!is_array($catalog)||!is_string($catalog['generated_at']??null))return null;
|
||||
$at=strtotime($catalog['generated_at']);if($at===false||$at<time()-180||$at>time()+30)return null;
|
||||
$host=static fn($value)=>strtolower(rtrim((string)parse_url(str_contains((string)$value,'://')?(string)$value:'https://'.$value,PHP_URL_HOST),'.'));
|
||||
if(!$host($config->host??'')||$host($catalog['host']??'')!==$host($config->host??''))return null;
|
||||
foreach(['degr','tp','cons'] as $group){if(!is_array($catalog['groups'][$group]??null))return null;foreach($catalog['groups'][$group] as $entry)if(!is_array($entry)||!is_int($entry['number']??null)||$entry['number']<1||$entry['number']>9||!is_string($entry['name']??null))return null;}
|
||||
return $catalog;
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ final class Config
|
||||
}
|
||||
$change['path']=$path;return $change;
|
||||
}
|
||||
public static function validate(\stdClass $config, callable $setExists,?array $catalog=null): array {
|
||||
public static function validate(\stdClass $config): array {
|
||||
self::assertWritable($config);
|
||||
PercentWeights::validate($config);
|
||||
if (isset($config->host)) {
|
||||
@@ -74,7 +74,7 @@ final class Config
|
||||
$number=static function($value) use($maps,$canonical): string {
|
||||
if (!is_int($value) && !is_string($value)) throw new Problem('Вариант UTM должен быть номером.');
|
||||
$value=(string)$value;
|
||||
if (isset($maps[$canonical])) { $digit=array_search($value,$maps[$canonical],true); if ($digit!==false) return (string)$digit; if (!isset($maps[$canonical][$value])) throw new Problem("Недопустимый вариант {$canonical}."); }
|
||||
if (isset($maps[$canonical])) { $digit=array_search($value,$maps[$canonical],true); if ($digit!==false) return (string)$digit; }
|
||||
if (!preg_match('/^[1-9]$/D',$value)) throw new Problem('Вариант UTM должен быть 1–9.');
|
||||
return $value;
|
||||
};
|
||||
@@ -83,15 +83,8 @@ final class Config
|
||||
$digit=$number($variant);
|
||||
if (isset($seen[$digit])) throw new Problem('Конфликт semantic и numeric вариантов UTM.'); $seen[$digit]=true;
|
||||
if ((!is_int($weight) && !is_float($weight)) || !is_finite((float)$weight) || $weight<0) throw new Problem('Вес должен быть конечным неотрицательным числом.');
|
||||
if ($canonical==='indpic' && !$setExists((int)$digit)) throw new Problem("Набор {$digit} отсутствует или не прошёл проверку.");
|
||||
if($catalog!==null&&in_array($canonical,['degr','tp','cons'],true)&&!in_array((int)$digit,array_column($catalog['groups'][$canonical]??[],'number'),true))throw new Problem("Группа {$canonical} {$digit} отсутствует в доступном каталоге основного сайта.");
|
||||
}
|
||||
if (in_array($canonical,['indpic','degr','tp'],true)&&!isset($seen[$default])) throw new Problem("Добавьте вариант {$default} в таблицу весов {$key} (допустим вес 0).");
|
||||
if ($canonical==='indpic' && !$setExists((int)$default)) throw new Problem("Набор default {$default} отсутствует или не прошёл проверку.");
|
||||
if (in_array($canonical,['degr','tp','cons'],true)) {
|
||||
if($catalog===null)$warnings[]="{$canonical}: существование группы на основном сайте не проверено.";
|
||||
elseif(!in_array((int)$default,array_column($catalog['groups'][$canonical]??[],'number'),true))throw new Problem("Группа default {$canonical} {$default} отсутствует в доступном каталоге основного сайта.");
|
||||
}
|
||||
}
|
||||
return $warnings;
|
||||
}
|
||||
|
||||
+2
-2
@@ -93,8 +93,8 @@ final class Copy
|
||||
$changes[]=['path'=>['utm',$canonical,'default'],'value'=>$default];
|
||||
$changes[]=['path'=>['utm',$canonical,'weights'],'value'=>$weights];
|
||||
}
|
||||
// Наличие физических наборов и каталог проверяются отдельно на каждом получателе.
|
||||
Config::validate($projection,static fn(int $number): bool=>true);
|
||||
// Редактор проверяет формат конфига, а не реализацию вариантов на сайтах.
|
||||
Config::validate($projection);
|
||||
return $changes;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -41,7 +41,7 @@ final class Jobs
|
||||
if(isset($p['changes']))foreach($p['changes'] as &$change){if(isset($change['value_json']))$change['value']=json_decode($change['value_json'],false,64,JSON_THROW_ON_ERROR);}unset($change);
|
||||
if($type==='copy')Copy::assertAliases($current['config']);
|
||||
$next=$type==='restore'?Config::decode($this->store->backupContent($target['id'],$p['id'])):Config::patch($current['config'],$p['changes']??[]);
|
||||
$checked=[];$warnings=Config::validate($next,function($number)use($target,&$checked){if(array_key_exists($number,$checked))return $checked[$number];try{(new Sets($this->store))->check($target,$number);return $checked[$number]=true;}catch(\Throwable){return $checked[$number]=false;}},Catalog::read($this->store,$next));
|
||||
$warnings=Config::validate($next);
|
||||
$content=Config::encode($next);$job['results'][$index]['desired_hash']=hash('sha256',$content);$save();
|
||||
$written=$transport->writeConfig($expected,$content);$out=['message'=>'Настройки сохранены и проверены.','version'=>$written['version'],'warnings'=>$warnings];
|
||||
}else{
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace PrelandAdmin;
|
||||
final class LinkBuilder
|
||||
{
|
||||
private const KEYS = ['indpic', 'theme', 'degr', 'reg', 'banch', 'tp', 'cons', 'focus'];
|
||||
private const ENUMS = ['theme', 'reg', 'banch', 'focus'];
|
||||
|
||||
public function __construct(private readonly Store $store) {}
|
||||
|
||||
@@ -72,8 +71,7 @@ final class LinkBuilder
|
||||
$selection = [];
|
||||
foreach (self::KEYS as $key) {
|
||||
$value = $input[$key] ?? null;
|
||||
if (!is_string($value) || ($value !== 'rnd' && !preg_match('/^[1-9]$/D', $value))
|
||||
|| (in_array($key, self::ENUMS, true) && !in_array($value, ['1', '2', 'rnd'], true))) {
|
||||
if (!is_string($value) || ($value !== 'rnd' && !preg_match('/^[1-9]$/D', $value))) {
|
||||
throw new Problem("Недопустимое значение параметра {$key} конструктора ссылки.");
|
||||
}
|
||||
$selection[$key] = $value;
|
||||
|
||||
Reference in new issue
Block a user