Squashed commit message
Some checks failed
Telegram Mini App Shop Builder / Compute version metadata (push) Has been cancelled
Telegram Mini App Shop Builder / Run Frontend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run Backend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run PHP_CodeSniffer (push) Has been cancelled
Telegram Mini App Shop Builder / Build module. (push) Has been cancelled
Telegram Mini App Shop Builder / release (push) Has been cancelled
Some checks failed
Telegram Mini App Shop Builder / Compute version metadata (push) Has been cancelled
Telegram Mini App Shop Builder / Run Frontend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run Backend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run PHP_CodeSniffer (push) Has been cancelled
Telegram Mini App Shop Builder / Build module. (push) Has been cancelled
Telegram Mini App Shop Builder / release (push) Has been cancelled
This commit is contained in:
306
backend/src/bastion/Handlers/SettingsHandler.php
Executable file
306
backend/src/bastion/Handlers/SettingsHandler.php
Executable file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace Bastion\Handlers;
|
||||
|
||||
use Bastion\Exceptions\BotTokenConfiguratorException;
|
||||
use Bastion\Services\BotTokenConfigurator;
|
||||
use Bastion\Services\CronApiKeyRegenerator;
|
||||
use Bastion\Services\SettingsService;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Openguru\OpenCartFramework\Cache\CacheInterface;
|
||||
use Openguru\OpenCartFramework\Config\Settings;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Builder;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
|
||||
use Openguru\OpenCartFramework\Scheduler\Models\ScheduledJob;
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class SettingsHandler
|
||||
{
|
||||
private BotTokenConfigurator $botTokenConfigurator;
|
||||
private CronApiKeyRegenerator $cronApiKeyRegenerator;
|
||||
private Settings $settings;
|
||||
private SettingsService $settingsUpdateService;
|
||||
private CacheInterface $cache;
|
||||
private LoggerInterface $logger;
|
||||
private Builder $builder;
|
||||
private ConnectionInterface $connection;
|
||||
private ScheduledJob $scheduledJob;
|
||||
|
||||
public function __construct(
|
||||
BotTokenConfigurator $botTokenConfigurator,
|
||||
CronApiKeyRegenerator $cronApiKeyRegenerator,
|
||||
Settings $settings,
|
||||
SettingsService $settingsUpdateService,
|
||||
CacheInterface $cache,
|
||||
LoggerInterface $logger,
|
||||
Builder $builder,
|
||||
ConnectionInterface $connection,
|
||||
ScheduledJob $scheduledJob
|
||||
) {
|
||||
$this->botTokenConfigurator = $botTokenConfigurator;
|
||||
$this->cronApiKeyRegenerator = $cronApiKeyRegenerator;
|
||||
$this->settings = $settings;
|
||||
$this->settingsUpdateService = $settingsUpdateService;
|
||||
$this->cache = $cache;
|
||||
$this->logger = $logger;
|
||||
$this->builder = $builder;
|
||||
$this->connection = $connection;
|
||||
$this->scheduledJob = $scheduledJob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Перегенерировать секретный ключ в URL для cron-job.org (сохраняет cron.api_key).
|
||||
*/
|
||||
public function regenerateCronScheduleUrl(Request $request): JsonResponse
|
||||
{
|
||||
$newApiKey = $this->cronApiKeyRegenerator->regenerate();
|
||||
$scheduleUrl = $this->buildCronScheduleUrl(
|
||||
$this->settings->get('app.shop_base_url', ''),
|
||||
$newApiKey
|
||||
);
|
||||
|
||||
return new JsonResponse(['api_key' => $newApiKey, 'schedule_url' => $scheduleUrl]);
|
||||
}
|
||||
|
||||
public function configureBotToken(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$data = $this->botTokenConfigurator->configure(trim($request->json('botToken', '')));
|
||||
|
||||
return new JsonResponse($data);
|
||||
} catch (BotTokenConfiguratorException $e) {
|
||||
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
} catch (Exception $e) {
|
||||
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public function getSettingsForm(): JsonResponse
|
||||
{
|
||||
$data = Arr::getWithKeys($this->settings->getAll(), [
|
||||
'app',
|
||||
'telegram',
|
||||
'metrics',
|
||||
'store',
|
||||
'orders',
|
||||
'texts',
|
||||
'sliders',
|
||||
'mainpage_blocks',
|
||||
'pulse',
|
||||
'cron',
|
||||
]);
|
||||
|
||||
if (!isset($data['cron']['mode'])) {
|
||||
$data['cron']['mode'] = 'disabled';
|
||||
}
|
||||
|
||||
$data['forms'] = [];
|
||||
|
||||
// Add CRON system details (read-only)
|
||||
$data['cron']['cli_path'] = BP_REAL_BASE_PATH . '/cli.php';
|
||||
$data['cron']['last_run'] = $this->getLastCronRunDate();
|
||||
$data['cron']['schedule_url'] = $this->buildCronScheduleUrl(
|
||||
$this->settings->get('app.shop_base_url', ''),
|
||||
$this->settings->get('cron.api_key', '')
|
||||
);
|
||||
|
||||
$data['scheduled_jobs'] = $this->scheduledJob->all();
|
||||
|
||||
$forms = $this->builder->newQuery()
|
||||
->from('megapay_forms')
|
||||
->get();
|
||||
|
||||
if ($forms) {
|
||||
foreach ($forms as $form) {
|
||||
try {
|
||||
$schema = json_decode($form['schema'] ?? '[]', true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (\JsonException $exception) {
|
||||
$schema = [];
|
||||
}
|
||||
|
||||
$data['forms'][$form['alias']] = [
|
||||
'alias' => $form['alias'],
|
||||
'friendly_name' => $form['friendly_name'],
|
||||
'is_custom' => filter_var($form['is_custom'], FILTER_VALIDATE_BOOLEAN),
|
||||
'schema' => $schema,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return new JsonResponse(compact('data'));
|
||||
}
|
||||
|
||||
private function buildCronScheduleUrl(string $shopBaseUrl, string $apiKey): string
|
||||
{
|
||||
$base = rtrim($shopBaseUrl, '/');
|
||||
if ($base === '') {
|
||||
return '';
|
||||
}
|
||||
$params = http_build_query([
|
||||
'route' => 'extension/tgshop/handle',
|
||||
'api_action' => 'runSchedule',
|
||||
'api_key' => $apiKey,
|
||||
]);
|
||||
|
||||
return $base . '/index.php?' . $params;
|
||||
}
|
||||
|
||||
public function saveSettingsForm(Request $request): JsonResponse
|
||||
{
|
||||
$input = $request->json();
|
||||
|
||||
$this->validate($input);
|
||||
|
||||
// Remove dynamic properties before saving
|
||||
if (isset($input['cron'])) {
|
||||
unset($input['cron']['cli_path']);
|
||||
unset($input['cron']['last_run']);
|
||||
unset($input['cron']['schedule_url']);
|
||||
}
|
||||
|
||||
$this->settingsUpdateService->update(
|
||||
Arr::getWithKeys($input, [
|
||||
'app',
|
||||
'telegram',
|
||||
'metrics',
|
||||
'store',
|
||||
'orders',
|
||||
'texts',
|
||||
'sliders',
|
||||
'mainpage_blocks',
|
||||
'pulse',
|
||||
'cron',
|
||||
]),
|
||||
);
|
||||
|
||||
// Update forms
|
||||
$forms = Arr::get($input, 'forms', []);
|
||||
foreach ($forms as $form) {
|
||||
$schema = json_encode($form['schema'], JSON_THROW_ON_ERROR);
|
||||
$this->builder->newQuery()
|
||||
->where('alias', '=', $form['alias'])
|
||||
->update('megapay_forms', [
|
||||
'friendly_name' => $form['friendly_name'],
|
||||
'is_custom' => $form['is_custom'],
|
||||
'schema' => $schema,
|
||||
]);
|
||||
}
|
||||
|
||||
// Update scheduled jobs is_enabled and cron_expression
|
||||
$scheduledJobs = Arr::get($input, 'scheduled_jobs', []);
|
||||
foreach ($scheduledJobs as $job) {
|
||||
$id = (int) ($job['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
continue;
|
||||
}
|
||||
$isEnabled = filter_var($job['is_enabled'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||||
if ($isEnabled) {
|
||||
$this->scheduledJob->enable($id);
|
||||
} else {
|
||||
$this->scheduledJob->disable($id);
|
||||
}
|
||||
$cronExpression = trim((string) ($job['cron_expression'] ?? ''));
|
||||
if ($cronExpression !== '') {
|
||||
$this->scheduledJob->updateCronExpression($id, $cronExpression);
|
||||
}
|
||||
}
|
||||
|
||||
return new JsonResponse([], Response::HTTP_ACCEPTED);
|
||||
}
|
||||
|
||||
private function validate(array $input): void
|
||||
{
|
||||
}
|
||||
|
||||
public function resetCache(): JsonResponse
|
||||
{
|
||||
$this->cache->clear();
|
||||
|
||||
$this->logger->info('Cache cleared manually.');
|
||||
|
||||
return new JsonResponse([], Response::HTTP_ACCEPTED);
|
||||
}
|
||||
|
||||
private function getLastCronRunDate(): ?string
|
||||
{
|
||||
try {
|
||||
// Since we are in SettingsHandler, we already have access to container or we can inject SchedulerService
|
||||
// But SettingsHandler is constructed via DI. Let's add SchedulerService to constructor.
|
||||
// For now, let's use global retrieval via cache if possible, or assume it's injected.
|
||||
// But wait, getLastCronRunDate logic was in controller.
|
||||
// SchedulerService stores last run in cache. We have $this->cache here.
|
||||
|
||||
$lastRunTimestamp = $this->cache->get("scheduler.global_last_run");
|
||||
|
||||
if ($lastRunTimestamp) {
|
||||
return Carbon::createFromTimestamp($lastRunTimestamp)->toDateTimeString();
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSystemInfo(): JsonResponse
|
||||
{
|
||||
$info = [];
|
||||
|
||||
$info['PHP Version'] = PHP_VERSION;
|
||||
$info['PHP SAPI'] = PHP_SAPI;
|
||||
$info['PHP Memory Limit'] = ini_get('memory_limit');
|
||||
$info['PHP Memory Usage'] = $this->formatBytes(memory_get_usage(true));
|
||||
$info['PHP Peak Memory Usage'] = $this->formatBytes(memory_get_peak_usage(true));
|
||||
$info['PHP Max Execution Time'] = ini_get('max_execution_time') . 's';
|
||||
$info['PHP Upload Max Filesize'] = ini_get('upload_max_filesize');
|
||||
$info['PHP Post Max Size'] = ini_get('post_max_size');
|
||||
|
||||
try {
|
||||
$mysqlVersion = $this->connection->select('SELECT VERSION() as version');
|
||||
$info['MySQL Version'] = $mysqlVersion[0]['version'] ?? 'Unknown';
|
||||
} catch (Exception $e) {
|
||||
$info['MySQL Version'] = 'Error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
$cacheDriver = env('MEGAPAY_CACHE_DRIVER', 'mysql');
|
||||
$cacheClass = get_class($this->cache);
|
||||
$info['Cache Driver'] = $cacheDriver . ' (' . basename(str_replace('\\', '/', $cacheClass)) . ')';
|
||||
|
||||
$info['Module Version'] = module_version();
|
||||
$info['OpenCart Version'] = defined('VERSION') ? VERSION : 'Unknown';
|
||||
$info['OpenCart Core Version'] = defined('VERSION_CORE') ? VERSION_CORE : 'Unknown';
|
||||
|
||||
$info['Operating System'] = PHP_OS;
|
||||
$info['Server Software'] = $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown';
|
||||
$info['Document Root'] = $_SERVER['DOCUMENT_ROOT'] ?? 'Unknown';
|
||||
|
||||
$info['PHP Timezone'] = date_default_timezone_get();
|
||||
$info['Server Time'] = date('Y-m-d H:i:s');
|
||||
$info['UTC Time'] = gmdate('Y-m-d H:i:s');
|
||||
|
||||
$info['Loaded PHP Extensions'] = implode(', ', get_loaded_extensions());
|
||||
|
||||
$infoText = '';
|
||||
foreach ($info as $key => $value) {
|
||||
$infoText .= $key . ': ' . $value . "\n";
|
||||
}
|
||||
|
||||
return new JsonResponse(['data' => $infoText]);
|
||||
}
|
||||
|
||||
private function formatBytes(int $bytes, int $precision = 2): string
|
||||
{
|
||||
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
|
||||
for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
|
||||
$bytes /= 1024;
|
||||
}
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$i];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user