#3525 -- Rework settings to be fetched on-demand to avoid collisions.
This commit is contained in:
parent
d9b828a821
commit
4aa1902dae
|
@ -10,42 +10,41 @@ use Psr\Container\ContainerInterface;
|
|||
return [
|
||||
|
||||
// URL Router helper
|
||||
App\Http\Router::class => function (
|
||||
Environment $environment,
|
||||
Slim\App $app,
|
||||
App\Entity\Settings $settings
|
||||
) {
|
||||
$route_parser = $app->getRouteCollector()->getRouteParser();
|
||||
return new App\Http\Router($environment, $route_parser, $settings);
|
||||
},
|
||||
App\Http\RouterInterface::class => DI\Get(App\Http\Router::class),
|
||||
|
||||
// Error handler
|
||||
App\Http\ErrorHandler::class => DI\autowire(),
|
||||
Slim\Interfaces\ErrorHandlerInterface::class => DI\Get(App\Http\ErrorHandler::class),
|
||||
|
||||
// HTTP client
|
||||
GuzzleHttp\Client::class => function (Psr\Log\LoggerInterface $logger) {
|
||||
$stack = GuzzleHttp\HandlerStack::create();
|
||||
|
||||
$stack->unshift(function (callable $handler) {
|
||||
return function (Psr\Http\Message\RequestInterface $request, array $options) use ($handler) {
|
||||
$options[GuzzleHttp\RequestOptions::VERIFY] = Composer\CaBundle\CaBundle::getSystemCaRootBundlePath();
|
||||
return $handler($request, $options);
|
||||
};
|
||||
}, 'ssl_verify');
|
||||
$stack->unshift(
|
||||
function (callable $handler) {
|
||||
return function (Psr\Http\Message\RequestInterface $request, array $options) use ($handler) {
|
||||
$options[GuzzleHttp\RequestOptions::VERIFY] = Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(
|
||||
);
|
||||
return $handler($request, $options);
|
||||
};
|
||||
},
|
||||
'ssl_verify'
|
||||
);
|
||||
|
||||
$stack->push(GuzzleHttp\Middleware::log(
|
||||
$logger,
|
||||
new GuzzleHttp\MessageFormatter('HTTP client {method} call to {uri} produced response {code}'),
|
||||
Psr\Log\LogLevel::DEBUG
|
||||
));
|
||||
$stack->push(
|
||||
GuzzleHttp\Middleware::log(
|
||||
$logger,
|
||||
new GuzzleHttp\MessageFormatter('HTTP client {method} call to {uri} produced response {code}'),
|
||||
Psr\Log\LogLevel::DEBUG
|
||||
)
|
||||
);
|
||||
|
||||
return new GuzzleHttp\Client([
|
||||
'handler' => $stack,
|
||||
GuzzleHttp\RequestOptions::HTTP_ERRORS => false,
|
||||
GuzzleHttp\RequestOptions::TIMEOUT => 3.0,
|
||||
]);
|
||||
return new GuzzleHttp\Client(
|
||||
[
|
||||
'handler' => $stack,
|
||||
GuzzleHttp\RequestOptions::HTTP_ERRORS => false,
|
||||
GuzzleHttp\RequestOptions::TIMEOUT => 3.0,
|
||||
]
|
||||
);
|
||||
},
|
||||
|
||||
// DBAL
|
||||
|
@ -128,13 +127,15 @@ return [
|
|||
$eventManager->addEventSubscriber($eventAuditLog);
|
||||
$eventManager->addEventSubscriber($eventChangeTracking);
|
||||
|
||||
return new App\Doctrine\DecoratedEntityManager(function () use (
|
||||
$connectionOptions,
|
||||
$config,
|
||||
$eventManager
|
||||
) {
|
||||
return Doctrine\ORM\EntityManager::create($connectionOptions, $config, $eventManager);
|
||||
});
|
||||
return new App\Doctrine\DecoratedEntityManager(
|
||||
function () use (
|
||||
$connectionOptions,
|
||||
$config,
|
||||
$eventManager
|
||||
) {
|
||||
return Doctrine\ORM\EntityManager::create($connectionOptions, $config, $eventManager);
|
||||
}
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
throw new App\Exception\BootstrapException($e->getMessage());
|
||||
}
|
||||
|
@ -143,11 +144,6 @@ return [
|
|||
App\Doctrine\ReloadableEntityManagerInterface::class => DI\Get(App\Doctrine\DecoratedEntityManager::class),
|
||||
Doctrine\ORM\EntityManagerInterface::class => DI\Get(App\Doctrine\DecoratedEntityManager::class),
|
||||
|
||||
// Database settings
|
||||
App\Entity\Settings::class => function (App\Entity\Repository\SettingsTableRepository $settingsTableRepo) {
|
||||
return $settingsTableRepo->readSettings();
|
||||
},
|
||||
|
||||
// Redis cache
|
||||
Redis::class => function (Environment $environment) {
|
||||
$redis_host = $environment->isDocker() ? 'redis' : 'localhost';
|
||||
|
@ -303,7 +299,9 @@ return [
|
|||
},
|
||||
|
||||
// Symfony Validator
|
||||
Symfony\Component\Validator\ConstraintValidatorFactoryInterface::class => DI\autowire(App\Validator\ConstraintValidatorFactory::class),
|
||||
Symfony\Component\Validator\ConstraintValidatorFactoryInterface::class => DI\autowire(
|
||||
App\Validator\ConstraintValidatorFactory::class
|
||||
),
|
||||
|
||||
Symfony\Component\Validator\Validator\ValidatorInterface::class => function (
|
||||
Doctrine\Common\Annotations\Reader $annotation_reader,
|
||||
|
@ -323,7 +321,6 @@ return [
|
|||
App\Plugins $plugins,
|
||||
Environment $environment
|
||||
) {
|
||||
|
||||
// Configure message sending middleware
|
||||
$sendMessageMiddleware = new Symfony\Component\Messenger\Middleware\SendMessageMiddleware($queueManager);
|
||||
$sendMessageMiddleware->setLogger($logger);
|
||||
|
@ -355,17 +352,21 @@ return [
|
|||
|
||||
// On testing, messages are handled directly when called
|
||||
if ($environment->isTesting()) {
|
||||
return new Symfony\Component\Messenger\MessageBus([
|
||||
$handleMessageMiddleware,
|
||||
]);
|
||||
return new Symfony\Component\Messenger\MessageBus(
|
||||
[
|
||||
$handleMessageMiddleware,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// Compile finished message bus.
|
||||
return new Symfony\Component\Messenger\MessageBus([
|
||||
$sendMessageMiddleware,
|
||||
$uniqueMiddleware,
|
||||
$handleMessageMiddleware,
|
||||
]);
|
||||
return new Symfony\Component\Messenger\MessageBus(
|
||||
[
|
||||
$sendMessageMiddleware,
|
||||
$uniqueMiddleware,
|
||||
$handleMessageMiddleware,
|
||||
]
|
||||
);
|
||||
},
|
||||
|
||||
// Supervisor manager
|
||||
|
@ -401,66 +402,4 @@ return [
|
|||
},
|
||||
|
||||
App\Media\MetadataManagerInterface::class => DI\get(App\Media\GetId3\GetId3MetadataManager::class),
|
||||
|
||||
// Asset Management
|
||||
App\Assets::class => function (App\Config $config, Environment $environment) {
|
||||
$libraries = $config->get('assets');
|
||||
|
||||
$versioned_files = [];
|
||||
$assets_file = $environment->getBaseDirectory() . '/web/static/assets.json';
|
||||
if (file_exists($assets_file)) {
|
||||
$versioned_files = json_decode(file_get_contents($assets_file), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
$vueComponents = [];
|
||||
$assets_file = $environment->getBaseDirectory() . '/web/static/webpack.json';
|
||||
if (file_exists($assets_file)) {
|
||||
$vueComponents = json_decode(file_get_contents($assets_file), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
return new App\Assets($environment, $libraries, $versioned_files, $vueComponents);
|
||||
},
|
||||
|
||||
// Synchronized (Cron) Tasks
|
||||
App\Sync\TaskLocator::class => function (ContainerInterface $di) {
|
||||
return new App\Sync\TaskLocator($di, [
|
||||
App\Event\GetSyncTasks::SYNC_NOWPLAYING => [
|
||||
App\Sync\Task\BuildQueueTask::class,
|
||||
App\Sync\Task\NowPlayingTask::class,
|
||||
App\Sync\Task\ReactivateStreamerTask::class,
|
||||
],
|
||||
App\Event\GetSyncTasks::SYNC_SHORT => [
|
||||
App\Sync\Task\CheckRequests::class,
|
||||
App\Sync\Task\RunBackupTask::class,
|
||||
App\Sync\Task\CleanupRelaysTask::class,
|
||||
],
|
||||
App\Event\GetSyncTasks::SYNC_MEDIUM => [
|
||||
App\Sync\Task\CheckMediaTask::class,
|
||||
App\Sync\Task\CheckFolderPlaylistsTask::class,
|
||||
App\Sync\Task\CheckUpdatesTask::class,
|
||||
],
|
||||
App\Event\GetSyncTasks::SYNC_LONG => [
|
||||
App\Sync\Task\RunAnalyticsTask::class,
|
||||
App\Sync\Task\RunAutomatedAssignmentTask::class,
|
||||
App\Sync\Task\CleanupHistoryTask::class,
|
||||
App\Sync\Task\CleanupStorageTask::class,
|
||||
App\Sync\Task\RotateLogsTask::class,
|
||||
App\Sync\Task\UpdateGeoLiteTask::class,
|
||||
],
|
||||
]);
|
||||
},
|
||||
|
||||
// Web Hooks
|
||||
App\Webhook\ConnectorLocator::class => function (
|
||||
ContainerInterface $di,
|
||||
App\Config $config
|
||||
) {
|
||||
$webhooks = $config->get('webhooks');
|
||||
$services = [];
|
||||
foreach ($webhooks['webhooks'] as $webhook_key => $webhook_info) {
|
||||
$services[$webhook_key] = $webhook_info['class'];
|
||||
}
|
||||
|
||||
return new App\Webhook\ConnectorLocator($di, $services);
|
||||
},
|
||||
];
|
||||
|
|
|
@ -14,8 +14,6 @@ class Acl
|
|||
public const GLOBAL_LOGS = 'view system logs';
|
||||
public const GLOBAL_SETTINGS = 'administer settings';
|
||||
public const GLOBAL_API_KEYS = 'administer api keys';
|
||||
public const GLOBAL_USERS = 'administer user accounts';
|
||||
public const GLOBAL_PERMISSIONS = 'administer permissions';
|
||||
public const GLOBAL_STATIONS = 'administer stations';
|
||||
public const GLOBAL_CUSTOM_FIELDS = 'administer custom fields';
|
||||
public const GLOBAL_BACKUPS = 'administer backups';
|
||||
|
|
145
src/Assets.php
145
src/Assets.php
|
@ -3,6 +3,7 @@
|
|||
namespace App;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
use function base64_encode;
|
||||
|
@ -43,41 +44,35 @@ class Assets
|
|||
|
||||
public function __construct(
|
||||
Environment $environment,
|
||||
array $libraries = [],
|
||||
array $versioned_files = [],
|
||||
array $vueComponents = []
|
||||
Config $config,
|
||||
?ServerRequestInterface $request
|
||||
) {
|
||||
$this->environment = $environment;
|
||||
$this->request = $request;
|
||||
|
||||
$libraries = $config->get('assets');
|
||||
foreach ($libraries as $library_name => $library) {
|
||||
$this->addLibrary($library, $library_name);
|
||||
}
|
||||
|
||||
$versioned_files = [];
|
||||
$assets_file = $environment->getBaseDirectory() . '/web/static/assets.json';
|
||||
if (file_exists($assets_file)) {
|
||||
$versioned_files = json_decode(file_get_contents($assets_file), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
$this->versioned_files = $versioned_files;
|
||||
|
||||
$vueComponents = [];
|
||||
$assets_file = $environment->getBaseDirectory() . '/web/static/webpack.json';
|
||||
if (file_exists($assets_file)) {
|
||||
$vueComponents = json_decode(file_get_contents($assets_file), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
$this->addVueComponents($vueComponents);
|
||||
|
||||
$this->csp_nonce = preg_replace('/[^A-Za-z0-9\+\/=]/', '', base64_encode(random_bytes(18)));
|
||||
$this->csp_domains = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new copy of this object for a specific request.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*/
|
||||
public function withRequest(ServerRequestInterface $request): self
|
||||
{
|
||||
$newAssets = clone $this;
|
||||
$newAssets->setRequest($request);
|
||||
|
||||
return $newAssets;
|
||||
}
|
||||
|
||||
public function setRequest(ServerRequestInterface $request): void
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
protected function addVueComponents(array $vueComponents = []): void
|
||||
{
|
||||
if (!empty($vueComponents['entrypoints'])) {
|
||||
|
@ -162,14 +157,16 @@ class Assets
|
|||
*/
|
||||
public function addJs($js_script): self
|
||||
{
|
||||
$this->load([
|
||||
'order' => 100,
|
||||
'files' => [
|
||||
'js' => [
|
||||
(is_array($js_script)) ? $js_script : ['src' => $js_script],
|
||||
$this->load(
|
||||
[
|
||||
'order' => 100,
|
||||
'files' => [
|
||||
'js' => [
|
||||
(is_array($js_script)) ? $js_script : ['src' => $js_script],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -250,12 +247,14 @@ class Assets
|
|||
*/
|
||||
public function addInlineJs($js_script, int $order = 100): self
|
||||
{
|
||||
$this->load([
|
||||
'order' => $order,
|
||||
'inline' => [
|
||||
'js' => (is_array($js_script)) ? $js_script : [$js_script],
|
||||
],
|
||||
]);
|
||||
$this->load(
|
||||
[
|
||||
'order' => $order,
|
||||
'inline' => [
|
||||
'js' => (is_array($js_script)) ? $js_script : [$js_script],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -268,14 +267,16 @@ class Assets
|
|||
*/
|
||||
public function addCss($css_script, int $order = 100): self
|
||||
{
|
||||
$this->load([
|
||||
'order' => $order,
|
||||
'files' => [
|
||||
'css' => [
|
||||
(is_array($css_script)) ? $css_script : ['src' => $css_script],
|
||||
$this->load(
|
||||
[
|
||||
'order' => $order,
|
||||
'files' => [
|
||||
'css' => [
|
||||
(is_array($css_script)) ? $css_script : ['src' => $css_script],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -287,12 +288,14 @@ class Assets
|
|||
*/
|
||||
public function addInlineCss($css_script): self
|
||||
{
|
||||
$this->load([
|
||||
'order' => 100,
|
||||
'inline' => [
|
||||
'css' => (is_array($css_script)) ? $css_script : [$css_script],
|
||||
],
|
||||
]);
|
||||
$this->load(
|
||||
[
|
||||
'order' => 100,
|
||||
'inline' => [
|
||||
'css' => (is_array($css_script)) ? $css_script : [$css_script],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -310,10 +313,13 @@ class Assets
|
|||
foreach ($this->loaded as $item) {
|
||||
if (!empty($item['files']['css'])) {
|
||||
foreach ($item['files']['css'] as $file) {
|
||||
$compiled_attributes = $this->compileAttributes($file, [
|
||||
'rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
]);
|
||||
$compiled_attributes = $this->compileAttributes(
|
||||
$file,
|
||||
[
|
||||
'rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
]
|
||||
);
|
||||
|
||||
$result[] = '<link ' . implode(' ', $compiled_attributes) . ' />';
|
||||
}
|
||||
|
@ -349,9 +355,12 @@ class Assets
|
|||
foreach ($this->loaded as $item) {
|
||||
if (!empty($item['files']['js'])) {
|
||||
foreach ($item['files']['js'] as $file) {
|
||||
$compiled_attributes = $this->compileAttributes($file, [
|
||||
'type' => 'text/javascript',
|
||||
]);
|
||||
$compiled_attributes = $this->compileAttributes(
|
||||
$file,
|
||||
[
|
||||
'type' => 'text/javascript',
|
||||
]
|
||||
);
|
||||
|
||||
$result[] = '<script ' . implode(' ', $compiled_attributes) . '></script>';
|
||||
}
|
||||
|
@ -397,9 +406,12 @@ class Assets
|
|||
protected function sort(): void
|
||||
{
|
||||
if (!$this->is_sorted) {
|
||||
uasort($this->loaded, function ($a, $b): int {
|
||||
return $a['order'] <=> $b['order']; // SPACESHIP!
|
||||
});
|
||||
uasort(
|
||||
$this->loaded,
|
||||
function ($a, $b): int {
|
||||
return $a['order'] <=> $b['order']; // SPACESHIP!
|
||||
}
|
||||
);
|
||||
|
||||
$this->is_sorted = true;
|
||||
}
|
||||
|
@ -480,4 +492,23 @@ class Assets
|
|||
$this->csp_domains[$domain] = $domain;
|
||||
}
|
||||
}
|
||||
|
||||
public function writeCsp(ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
$csp = [];
|
||||
if ('https' === $this->request->getUri()->getScheme()) {
|
||||
$csp[] = 'upgrade-insecure-requests';
|
||||
}
|
||||
|
||||
// CSP JavaScript policy
|
||||
// Note: unsafe-eval included for Vue template compiling
|
||||
$csp_script_src = $this->getCspDomains();
|
||||
$csp_script_src[] = "'self'";
|
||||
$csp_script_src[] = "'unsafe-eval'";
|
||||
$csp_script_src[] = "'nonce-" . $this->getCspNonce() . "'";
|
||||
|
||||
$csp[] = 'script-src ' . implode(' ', $csp_script_src);
|
||||
|
||||
return $response->withHeader('Content-Security-Policy', implode('; ', $csp));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ class ListCommand extends CommandAbstract
|
|||
{
|
||||
public function __invoke(
|
||||
SymfonyStyle $io,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo
|
||||
Entity\Repository\SettingsRepository $settingsTableRepo
|
||||
): int {
|
||||
$io->title(__('AzuraCast Settings'));
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ class SetCommand extends CommandAbstract
|
|||
{
|
||||
public function __invoke(
|
||||
SymfonyStyle $io,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo,
|
||||
Entity\Repository\SettingsRepository $settingsTableRepo,
|
||||
string $settingKey,
|
||||
string $settingValue
|
||||
): int {
|
||||
|
|
|
@ -17,7 +17,7 @@ class SetupCommand extends CommandAbstract
|
|||
OutputInterface $output,
|
||||
Environment $environment,
|
||||
ContainerInterface $di,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\StationRepository $stationRepo,
|
||||
AzuraCastCentral $acCentral,
|
||||
bool $update = false,
|
||||
|
@ -78,7 +78,7 @@ class SetupCommand extends CommandAbstract
|
|||
|
||||
$this->runCommand($output, 'queue:clear');
|
||||
|
||||
$settings = $settingsTableRepo->updateSettings();
|
||||
$settings = $settingsRepo->readSettings(true);
|
||||
$settings->setNowplaying(null);
|
||||
|
||||
$stationRepo->clearNowPlaying();
|
||||
|
@ -97,7 +97,7 @@ class SetupCommand extends CommandAbstract
|
|||
$settings->setAppUniqueIdentifier(null);
|
||||
}
|
||||
|
||||
$settingsTableRepo->writeSettings($settings);
|
||||
$settingsRepo->writeSettings($settings);
|
||||
|
||||
$io->newLine();
|
||||
|
||||
|
|
|
@ -4,9 +4,7 @@ namespace App\Controller\Admin;
|
|||
|
||||
use App\Config;
|
||||
use App\Controller\AbstractLogViewerController;
|
||||
use App\Entity\Repository\StorageLocationRepository;
|
||||
use App\Entity\Settings;
|
||||
use App\Entity\StorageLocation;
|
||||
use App\Entity;
|
||||
use App\Exception\NotFoundException;
|
||||
use App\File;
|
||||
use App\Flysystem\Filesystem;
|
||||
|
@ -22,9 +20,9 @@ use Symfony\Component\Messenger\MessageBus;
|
|||
|
||||
class BackupsController extends AbstractLogViewerController
|
||||
{
|
||||
protected Settings $settings;
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
protected StorageLocationRepository $storageLocationRepo;
|
||||
protected Entity\Repository\StorageLocationRepository $storageLocationRepo;
|
||||
|
||||
protected RunBackupTask $backupTask;
|
||||
|
||||
|
@ -33,14 +31,14 @@ class BackupsController extends AbstractLogViewerController
|
|||
protected string $csrfNamespace = 'admin_backups';
|
||||
|
||||
public function __construct(
|
||||
StorageLocationRepository $storageLocationRepo,
|
||||
Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\StorageLocationRepository $storageLocationRepo,
|
||||
RunBackupTask $backup_task,
|
||||
MessageBus $messageBus
|
||||
) {
|
||||
$this->storageLocationRepo = $storageLocationRepo;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
|
||||
$this->settings = $settings;
|
||||
$this->backupTask = $backup_task;
|
||||
$this->messageBus = $messageBus;
|
||||
}
|
||||
|
@ -48,7 +46,8 @@ class BackupsController extends AbstractLogViewerController
|
|||
public function __invoke(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$backups = [];
|
||||
foreach ($this->storageLocationRepo->findAllByType(StorageLocation::TYPE_BACKUP) as $storageLocation) {
|
||||
$storageLocations = $this->storageLocationRepo->findAllByType(Entity\StorageLocation::TYPE_BACKUP);
|
||||
foreach ($storageLocations as $storageLocation) {
|
||||
$fs = $storageLocation->getFilesystem();
|
||||
foreach ($fs->listContents('', true) as $file) {
|
||||
$file['storageLocationId'] = $storageLocation->getId();
|
||||
|
@ -58,14 +57,18 @@ class BackupsController extends AbstractLogViewerController
|
|||
}
|
||||
$backups = array_reverse($backups);
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'admin/backups/index', [
|
||||
'backups' => $backups,
|
||||
'is_enabled' => $this->settings->isBackupEnabled(),
|
||||
'last_run' => $this->settings->getBackupLastRun(),
|
||||
'last_result' => $this->settings->getBackupLastResult(),
|
||||
'last_output' => $this->settings->getBackupLastOutput(),
|
||||
'csrf' => $request->getCsrf()->generate($this->csrfNamespace),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'admin/backups/index',
|
||||
[
|
||||
'backups' => $backups,
|
||||
'is_enabled' => $this->settings->isBackupEnabled(),
|
||||
'last_run' => $this->settings->getBackupLastRun(),
|
||||
'last_result' => $this->settings->getBackupLastResult(),
|
||||
'last_output' => $this->settings->getBackupLastOutput(),
|
||||
'csrf' => $request->getCsrf()->generate($this->csrfNamespace),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function configureAction(
|
||||
|
@ -78,11 +81,15 @@ class BackupsController extends AbstractLogViewerController
|
|||
return $response->withRedirect($request->getRouter()->fromHere('admin:backups:index'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'system/form_page', [
|
||||
'form' => $settingsForm,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Configure Backups'),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'system/form_page',
|
||||
[
|
||||
'form' => $settingsForm,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Configure Backups'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function runAction(
|
||||
|
@ -90,9 +97,17 @@ class BackupsController extends AbstractLogViewerController
|
|||
Response $response,
|
||||
Config $config
|
||||
): ResponseInterface {
|
||||
$runForm = new Form($config->get('forms/backup_run', [
|
||||
'storageLocations' => $this->storageLocationRepo->fetchSelectByType(StorageLocation::TYPE_BACKUP, true),
|
||||
]));
|
||||
$runForm = new Form(
|
||||
$config->get(
|
||||
'forms/backup_run',
|
||||
[
|
||||
'storageLocations' => $this->storageLocationRepo->fetchSelectByType(
|
||||
Entity\StorageLocation::TYPE_BACKUP,
|
||||
true
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
// Handle submission.
|
||||
if ($request->isPost() && $runForm->isValid($request->getParsedBody())) {
|
||||
|
@ -113,18 +128,26 @@ class BackupsController extends AbstractLogViewerController
|
|||
|
||||
$this->messageBus->dispatch($message);
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'admin/backups/run', [
|
||||
'title' => __('Run Manual Backup'),
|
||||
'path' => $data['path'],
|
||||
'outputLog' => basename($tempFile),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'admin/backups/run',
|
||||
[
|
||||
'title' => __('Run Manual Backup'),
|
||||
'path' => $data['path'],
|
||||
'outputLog' => basename($tempFile),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'system/form_page', [
|
||||
'form' => $runForm,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Run Manual Backup'),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'system/form_page',
|
||||
[
|
||||
'form' => $runForm,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Run Manual Backup'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function logAction(
|
||||
|
@ -173,12 +196,12 @@ class BackupsController extends AbstractLogViewerController
|
|||
[$storageLocationId, $path] = explode('|', $pathStr);
|
||||
|
||||
$storageLocation = $this->storageLocationRepo->findByType(
|
||||
StorageLocation::TYPE_BACKUP,
|
||||
Entity\StorageLocation::TYPE_BACKUP,
|
||||
(int)$storageLocationId
|
||||
);
|
||||
|
||||
|
||||
if (!($storageLocation instanceof StorageLocation)) {
|
||||
if (!($storageLocation instanceof Entity\StorageLocation)) {
|
||||
throw new \InvalidArgumentException('Invalid storage location.');
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Repository\SettingsTableRepository;
|
||||
use App\Entity\Settings;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Form\GeoLiteSettingsForm;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
|
@ -27,13 +26,17 @@ class InstallGeoLiteController
|
|||
$flash = $request->getFlash();
|
||||
|
||||
try {
|
||||
$syncTask->updateDatabase();
|
||||
$settings = $form->getEntityRepository()->readSettings();
|
||||
$syncTask->updateDatabase($settings->getGeoliteLicenseKey() ?? '');
|
||||
$flash->addMessage(__('Changes saved.'), Flash::SUCCESS);
|
||||
} catch (Exception $e) {
|
||||
$flash->addMessage(__(
|
||||
'An error occurred while downloading the GeoLite database: %s',
|
||||
$e->getMessage() . ' (' . $e->getFile() . ' L' . $e->getLine() . ')'
|
||||
), Flash::ERROR);
|
||||
$flash->addMessage(
|
||||
__(
|
||||
'An error occurred while downloading the GeoLite database: %s',
|
||||
$e->getMessage() . ' (' . $e->getFile() . ' L' . $e->getLine() . ')'
|
||||
),
|
||||
Flash::ERROR
|
||||
);
|
||||
}
|
||||
|
||||
return $response->withRedirect($request->getUri()->getPath());
|
||||
|
@ -41,25 +44,29 @@ class InstallGeoLiteController
|
|||
|
||||
$version = GeoLite::getVersion();
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'admin/install_geolite/index', [
|
||||
'form' => $form,
|
||||
'title' => __('Install GeoLite IP Database'),
|
||||
'version' => $version,
|
||||
'csrf' => $request->getCsrf()->generate($this->csrf_namespace),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'admin/install_geolite/index',
|
||||
[
|
||||
'form' => $form,
|
||||
'title' => __('Install GeoLite IP Database'),
|
||||
'version' => $version,
|
||||
'csrf' => $request->getCsrf()->generate($this->csrf_namespace),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function uninstallAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
Settings $settings,
|
||||
SettingsTableRepository $settingsTableRepo,
|
||||
SettingsRepository $settingsRepo,
|
||||
$csrf
|
||||
): ResponseInterface {
|
||||
$request->getCsrf()->verify($csrf, $this->csrf_namespace);
|
||||
|
||||
$settings = $settingsRepo->readSettings();
|
||||
$settings->setGeoliteLicenseKey(null);
|
||||
$settingsTableRepo->writeSettings($settings);
|
||||
$settingsRepo->writeSettings($settings);
|
||||
|
||||
@unlink(GeoLite::getDatabasePath());
|
||||
|
||||
|
|
|
@ -20,23 +20,18 @@ class SettingsController
|
|||
|
||||
protected ValidatorInterface $validator;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->serializer = $serializer;
|
||||
$this->validator = $validator;
|
||||
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settings = $settings;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +50,8 @@ class SettingsController
|
|||
*/
|
||||
public function listAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
return $response->withJson($this->serializer->normalize($this->settings, null));
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
return $response->withJson($this->serializer->normalize($settings, null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,7 +75,7 @@ class SettingsController
|
|||
*/
|
||||
public function updateAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$this->settingsTableRepo->writeSettings($request->getParsedBody());
|
||||
$this->settingsRepo->writeSettings($request->getParsedBody());
|
||||
|
||||
return $response->withJson(new Entity\Api\Status());
|
||||
}
|
||||
|
|
|
@ -25,12 +25,12 @@ class NowplayingController implements EventSubscriberInterface
|
|||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
CacheInterface $cache,
|
||||
EventDispatcher $dispatcher
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->settings = $settings;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
$this->cache = $cache;
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
@ -122,9 +122,12 @@ class NowplayingController implements EventSubscriberInterface
|
|||
|
||||
// If unauthenticated, hide non-public stations from full view.
|
||||
if ($request->getAttribute('user') === null) {
|
||||
$np = array_filter($np, function ($np_row) {
|
||||
return $np_row->station->is_public;
|
||||
});
|
||||
$np = array_filter(
|
||||
$np,
|
||||
function ($np_row) {
|
||||
return $np_row->station->is_public;
|
||||
}
|
||||
);
|
||||
|
||||
// Prevent NP array from returning as an object.
|
||||
$np = array_values($np);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Controller\Frontend\Account;
|
||||
|
||||
use App\Entity\Settings;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Entity\User;
|
||||
use App\Exception\RateLimitExceededException;
|
||||
use App\Http\Response;
|
||||
|
@ -20,12 +20,14 @@ class LoginAction
|
|||
Response $response,
|
||||
EntityManagerInterface $em,
|
||||
RateLimit $rateLimit,
|
||||
Settings $settings
|
||||
SettingsRepository $settingsRepo
|
||||
): ResponseInterface {
|
||||
$auth = $request->getAuth();
|
||||
$acl = $request->getAcl();
|
||||
|
||||
// Check installation completion progress.
|
||||
$settings = $settingsRepo->readSettings();
|
||||
|
||||
if (!$settings->isSetupComplete()) {
|
||||
$num_users = (int)$em->createQuery(
|
||||
<<<'DQL'
|
||||
|
|
|
@ -34,14 +34,14 @@ class DashboardController
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Acl $acl,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
CacheInterface $cache,
|
||||
Adapters $adapter_manager,
|
||||
EventDispatcher $dispatcher
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->acl = $acl;
|
||||
$this->settings = $settings;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
$this->cache = $cache;
|
||||
$this->adapter_manager = $adapter_manager;
|
||||
$this->dispatcher = $dispatcher;
|
||||
|
@ -59,11 +59,14 @@ class DashboardController
|
|||
$stations = $this->em->getRepository(Entity\Station::class)->findAll();
|
||||
|
||||
// Don't show stations the user can't manage.
|
||||
$stations = array_filter($stations, function ($station) use ($user) {
|
||||
/** @var Entity\Station $station */
|
||||
return $station->isEnabled() &&
|
||||
$this->acl->userAllowed($user, Acl::STATION_VIEW, $station->getId());
|
||||
});
|
||||
$stations = array_filter(
|
||||
$stations,
|
||||
function ($station) use ($user) {
|
||||
/** @var Entity\Station $station */
|
||||
return $station->isEnabled() &&
|
||||
$this->acl->userAllowed($user, Acl::STATION_VIEW, $station->getId());
|
||||
}
|
||||
);
|
||||
|
||||
if (empty($stations) && !$show_admin) {
|
||||
return $view->renderToResponse($response, 'frontend/index/noaccess');
|
||||
|
@ -136,13 +139,17 @@ class DashboardController
|
|||
}
|
||||
}
|
||||
|
||||
return $view->renderToResponse($response, 'frontend/index/index', [
|
||||
'stations' => ['stations' => $view_stations],
|
||||
'station_ids' => $station_ids,
|
||||
'show_admin' => $show_admin,
|
||||
'metrics' => $metrics,
|
||||
'notifications' => $notifications,
|
||||
]);
|
||||
return $view->renderToResponse(
|
||||
$response,
|
||||
'frontend/index/index',
|
||||
[
|
||||
'stations' => ['stations' => $view_stations],
|
||||
'station_ids' => $station_ids,
|
||||
'show_admin' => $show_admin,
|
||||
'metrics' => $metrics,
|
||||
'notifications' => $notifications,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,9 +12,10 @@ class IndexController
|
|||
public function indexAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
Entity\Settings $settings
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
): ResponseInterface {
|
||||
// Redirect to complete setup, if it hasn't been completed yet.
|
||||
$settings = $settingsRepo->readSettings();
|
||||
if (!$settings->isSetupComplete()) {
|
||||
return $response->withRedirect($request->getRouter()->named('setup:index'));
|
||||
}
|
||||
|
|
|
@ -17,22 +17,18 @@ class SetupController
|
|||
{
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
protected Environment $environment;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Repository\SettingsTableRepository $settingsRepository,
|
||||
Environment $environment,
|
||||
Entity\Settings $settings
|
||||
Entity\Repository\SettingsRepository $settingsRepository,
|
||||
Environment $environment
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->settingsTableRepo = $settingsRepository;
|
||||
$this->settingsRepo = $settingsRepository;
|
||||
$this->environment = $environment;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,7 +50,8 @@ class SetupController
|
|||
*/
|
||||
protected function getSetupStep(ServerRequest $request): string
|
||||
{
|
||||
if ($this->settings->isSetupComplete()) {
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
if ($settings->isSetupComplete()) {
|
||||
return 'complete';
|
||||
}
|
||||
|
||||
|
@ -182,9 +179,13 @@ class SetupController
|
|||
return $response->withRedirect($request->getRouter()->named('setup:settings'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'frontend/setup/station', [
|
||||
'form' => $stationForm,
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'frontend/setup/station',
|
||||
[
|
||||
'form' => $stationForm,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,8 +209,9 @@ class SetupController
|
|||
}
|
||||
|
||||
if ($settingsForm->process($request)) {
|
||||
$this->settings->updateSetupComplete();
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->updateSetupComplete();
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
|
||||
// Notify the user and redirect to homepage.
|
||||
$request->getFlash()->addMessage(
|
||||
|
@ -224,8 +226,12 @@ class SetupController
|
|||
return $response->withRedirect($request->getRouter()->named('dashboard'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'frontend/setup/settings', [
|
||||
'form' => $settingsForm,
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'frontend/setup/settings',
|
||||
[
|
||||
'form' => $settingsForm,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,12 @@ class ListenersController
|
|||
public function __invoke(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
IpGeolocation $ipGeo
|
||||
): ResponseInterface {
|
||||
$view = $request->getView();
|
||||
|
||||
$settings = $settingsRepo->readSettings();
|
||||
$analytics_level = $settings->getAnalytics();
|
||||
|
||||
if ($analytics_level !== Entity\Analytics::LEVEL_ALL) {
|
||||
|
@ -25,8 +26,12 @@ class ListenersController
|
|||
}
|
||||
|
||||
$attribution = $ipGeo->getAttribution();
|
||||
return $view->renderToResponse($response, 'stations/reports/listeners', [
|
||||
'attribution' => $attribution,
|
||||
]);
|
||||
return $view->renderToResponse(
|
||||
$response,
|
||||
'stations/reports/listeners',
|
||||
[
|
||||
'attribution' => $attribution,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ class OverviewController
|
|||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\AnalyticsRepository $analyticsRepo
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->settings = $settings;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
$this->analyticsRepo = $analyticsRepo;
|
||||
}
|
||||
|
||||
|
@ -237,25 +237,32 @@ class OverviewController
|
|||
$songs[] = $song_row;
|
||||
}
|
||||
|
||||
usort($songs, function ($a_arr, $b_arr) {
|
||||
$a = $a_arr['stat_delta'];
|
||||
$b = $b_arr['stat_delta'];
|
||||
usort(
|
||||
$songs,
|
||||
function ($a_arr, $b_arr) {
|
||||
$a = $a_arr['stat_delta'];
|
||||
$b = $b_arr['stat_delta'];
|
||||
|
||||
return $a <=> $b;
|
||||
});
|
||||
return $a <=> $b;
|
||||
}
|
||||
);
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'stations/reports/overview', [
|
||||
'charts' => [
|
||||
'daily' => json_encode($daily_data, JSON_THROW_ON_ERROR),
|
||||
'daily_alt' => implode('', $daily_alt),
|
||||
'hourly' => json_encode($hourly_data, JSON_THROW_ON_ERROR),
|
||||
'hourly_alt' => implode('', $hourly_alt),
|
||||
'day_of_week' => json_encode($day_of_week_data, JSON_THROW_ON_ERROR),
|
||||
'day_of_week_alt' => implode('', $day_of_week_alt),
|
||||
],
|
||||
'song_totals' => $song_totals,
|
||||
'best_performing_songs' => array_reverse(array_slice($songs, -5)),
|
||||
'worst_performing_songs' => array_slice($songs, 0, 5),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'stations/reports/overview',
|
||||
[
|
||||
'charts' => [
|
||||
'daily' => json_encode($daily_data, JSON_THROW_ON_ERROR),
|
||||
'daily_alt' => implode('', $daily_alt),
|
||||
'hourly' => json_encode($hourly_data, JSON_THROW_ON_ERROR),
|
||||
'hourly_alt' => implode('', $hourly_alt),
|
||||
'day_of_week' => json_encode($day_of_week_data, JSON_THROW_ON_ERROR),
|
||||
'day_of_week_alt' => implode('', $day_of_week_alt),
|
||||
],
|
||||
'song_totals' => $song_totals,
|
||||
'best_performing_songs' => array_reverse(array_slice($songs, -5)),
|
||||
'worst_performing_songs' => array_slice($songs, 0, 5),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,11 +22,11 @@ class StreamersController
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
AzuraCastCentral $ac_central,
|
||||
Entity\Settings $settings
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->ac_central = $ac_central;
|
||||
$this->settings = $settings;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request, Response $response): ResponseInterface
|
||||
|
@ -60,12 +60,16 @@ class StreamersController
|
|||
|
||||
$be_settings = $station->getBackendConfig();
|
||||
|
||||
return $view->renderToResponse($response, 'stations/streamers/index', [
|
||||
'server_url' => $this->settings->getBaseUrl(),
|
||||
'stream_port' => $backend->getStreamPort($station),
|
||||
'ip' => $this->ac_central->getIp(),
|
||||
'dj_mount_point' => $be_settings['dj_mount_point'] ?? '/',
|
||||
'station_tz' => $station->getTimezone(),
|
||||
]);
|
||||
return $view->renderToResponse(
|
||||
$response,
|
||||
'stations/streamers/index',
|
||||
[
|
||||
'server_url' => $this->settings->getBaseUrl(),
|
||||
'stream_port' => $backend->getStreamPort($station),
|
||||
'ip' => $this->ac_central->getIp(),
|
||||
'dj_mount_point' => $be_settings['dj_mount_point'] ?? '/',
|
||||
'station_tz' => $station->getTimezone(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ class Customization
|
|||
protected string $instanceName = '';
|
||||
|
||||
public function __construct(
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
ServerRequestInterface $request
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
$this->environment = $environment;
|
||||
|
||||
$this->instanceName = $settings->getInstanceName() ?? '';
|
||||
$this->instanceName = $this->settings->getInstanceName() ?? '';
|
||||
|
||||
// Register current user
|
||||
$this->user = $request->getAttribute(ServerRequest::ATTR_USER);
|
||||
|
@ -52,7 +52,7 @@ class Customization
|
|||
if (!empty($queryParams['theme'])) {
|
||||
$this->publicTheme = $this->theme = $queryParams['theme'];
|
||||
} else {
|
||||
$this->publicTheme = $settings->getPublicTheme() ?? $this->publicTheme;
|
||||
$this->publicTheme = $this->settings->getPublicTheme() ?? $this->publicTheme;
|
||||
|
||||
if (null !== $this->user && !empty($this->user->getTheme())) {
|
||||
$this->theme = (string)$this->user->getTheme();
|
||||
|
|
|
@ -13,8 +13,10 @@ use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class SettingsTableRepository extends Repository
|
||||
class SettingsRepository extends Repository
|
||||
{
|
||||
protected static ?Entity\Settings $instance = null;
|
||||
|
||||
protected const CACHE_KEY = 'settings';
|
||||
|
||||
protected const CACHE_TTL = 600;
|
||||
|
@ -23,6 +25,8 @@ class SettingsTableRepository extends Repository
|
|||
|
||||
protected ValidatorInterface $validator;
|
||||
|
||||
protected string $entityClass = Entity\SettingsTable::class;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
|
@ -37,32 +41,18 @@ class SettingsTableRepository extends Repository
|
|||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
public function readSettings(): Entity\Settings
|
||||
public function readSettings(bool $reload = false): Entity\Settings
|
||||
{
|
||||
if (Entity\Settings::hasInstance()) {
|
||||
return Entity\Settings::getInstance();
|
||||
} else {
|
||||
$settings = $this->arrayToObject($this->readSettingsArray());
|
||||
Entity\Settings::setInstance($settings);
|
||||
|
||||
return $settings;
|
||||
if ($reload || null === self::$instance) {
|
||||
self::$instance = $this->arrayToObject($this->readSettingsArray());
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a long-running process, update the Settings entity to have the latest data.
|
||||
*
|
||||
* @param array|null $newData
|
||||
*
|
||||
*/
|
||||
public function updateSettings(?array $newData = null): Entity\Settings
|
||||
public function clearSettingsInstance(): void
|
||||
{
|
||||
if (null === $newData) {
|
||||
$newData = $this->readSettingsArray();
|
||||
}
|
||||
|
||||
$settings = $this->arrayToObject($newData, $this->readSettings());
|
||||
return $settings;
|
||||
self::$instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,6 +60,10 @@ class SettingsTableRepository extends Repository
|
|||
*/
|
||||
public function readSettingsArray(): array
|
||||
{
|
||||
if ($this->cache->has(self::CACHE_KEY)) {
|
||||
return $this->cache->get(self::CACHE_KEY);
|
||||
}
|
||||
|
||||
$allRecords = [];
|
||||
foreach ($this->repository->findAll() as $record) {
|
||||
/** @var Entity\SettingsTable $record */
|
||||
|
@ -87,7 +81,7 @@ class SettingsTableRepository extends Repository
|
|||
public function writeSettings($settingsObj): void
|
||||
{
|
||||
if (is_array($settingsObj)) {
|
||||
$settingsObj = $this->updateSettings($settingsObj);
|
||||
$settingsObj = $this->arrayToObject($settingsObj, $this->readSettings(true));
|
||||
}
|
||||
|
||||
$errors = $this->validator->validate($settingsObj);
|
||||
|
@ -155,9 +149,12 @@ class SettingsTableRepository extends Repository
|
|||
|
||||
protected function arrayToObject(array $settings, ?Entity\Settings $existingSettings = null): Entity\Settings
|
||||
{
|
||||
$settings = array_filter($settings, function ($value) {
|
||||
return null !== $value;
|
||||
});
|
||||
$settings = array_filter(
|
||||
$settings,
|
||||
function ($value) {
|
||||
return null !== $value;
|
||||
}
|
||||
);
|
||||
|
||||
$context = [];
|
||||
if (null !== $existingSettings) {
|
|
@ -34,28 +34,29 @@ class StationRepository extends Repository
|
|||
|
||||
protected StorageLocationRepository $storageLocationRepo;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
protected SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
Environment $environment,
|
||||
SettingsRepository $settingsRepo,
|
||||
StorageLocationRepository $storageLocationRepo,
|
||||
LoggerInterface $logger,
|
||||
CheckMediaTask $mediaSync,
|
||||
Adapters $adapters,
|
||||
Configuration $configuration,
|
||||
ValidatorInterface $validator,
|
||||
CacheInterface $cache,
|
||||
Entity\Settings $settings
|
||||
CacheInterface $cache
|
||||
) {
|
||||
$this->mediaSync = $mediaSync;
|
||||
$this->adapters = $adapters;
|
||||
$this->configuration = $configuration;
|
||||
$this->validator = $validator;
|
||||
$this->cache = $cache;
|
||||
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
$this->storageLocationRepo = $storageLocationRepo;
|
||||
$this->settings = $settings;
|
||||
|
||||
parent::__construct($em, $serializer, $environment, $logger);
|
||||
}
|
||||
|
@ -341,7 +342,8 @@ class StationRepository extends Repository
|
|||
}
|
||||
}
|
||||
|
||||
$custom_url = trim($this->settings->getDefaultAlbumArtUrl());
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$custom_url = trim($settings->getDefaultAlbumArtUrl());
|
||||
|
||||
if (!empty($custom_url)) {
|
||||
return new Uri($custom_url);
|
||||
|
|
|
@ -664,7 +664,9 @@ class Settings
|
|||
|
||||
public function getGeoliteLicenseKey(): ?string
|
||||
{
|
||||
return $this->geoliteLicenseKey;
|
||||
return (null === $this->geoliteLicenseKey)
|
||||
? null
|
||||
: trim($this->geoliteLicenseKey);
|
||||
}
|
||||
|
||||
public function setGeoliteLicenseKey(?string $geoliteLicenseKey): void
|
||||
|
|
|
@ -11,13 +11,13 @@ abstract class AbstractSettingsForm extends Form
|
|||
{
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
protected Environment $environment;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
array $formConfig
|
||||
) {
|
||||
|
@ -25,7 +25,7 @@ abstract class AbstractSettingsForm extends Form
|
|||
|
||||
$this->em = $em;
|
||||
$this->environment = $environment;
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
public function getEntityManager(): EntityManagerInterface
|
||||
|
@ -33,9 +33,9 @@ abstract class AbstractSettingsForm extends Form
|
|||
return $this->em;
|
||||
}
|
||||
|
||||
public function getEntityRepository(): Entity\Repository\SettingsTableRepository
|
||||
public function getEntityRepository(): Entity\Repository\SettingsRepository
|
||||
{
|
||||
return $this->settingsTableRepo;
|
||||
return $this->settingsRepo;
|
||||
}
|
||||
|
||||
public function getEnvironment(): Environment
|
||||
|
@ -46,7 +46,7 @@ abstract class AbstractSettingsForm extends Form
|
|||
public function process(ServerRequest $request): bool
|
||||
{
|
||||
// Populate the form with existing values (if they exist).
|
||||
$defaults = $this->settingsTableRepo->readSettingsArray();
|
||||
$defaults = $this->settingsRepo->readSettingsArray();
|
||||
|
||||
// Use current URI from request if the base URL isn't set.
|
||||
if (empty($defaults['baseUrl'])) {
|
||||
|
@ -59,7 +59,7 @@ abstract class AbstractSettingsForm extends Form
|
|||
// Handle submission.
|
||||
if ('POST' === $request->getMethod() && $this->isValid($request->getParsedBody())) {
|
||||
$data = $this->getValues();
|
||||
$this->settingsTableRepo->writeSettings($data);
|
||||
$this->settingsRepo->writeSettings($data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,19 +11,25 @@ class BackupSettingsForm extends AbstractSettingsForm
|
|||
{
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\StorageLocationRepository $storageLocationRepo,
|
||||
Environment $environment,
|
||||
Config $config
|
||||
) {
|
||||
$formConfig = $config->get('forms/backup', [
|
||||
'settings' => $environment,
|
||||
'storageLocations' => $storageLocationRepo->fetchSelectByType(Entity\StorageLocation::TYPE_BACKUP, true),
|
||||
]);
|
||||
$formConfig = $config->get(
|
||||
'forms/backup',
|
||||
[
|
||||
'settings' => $environment,
|
||||
'storageLocations' => $storageLocationRepo->fetchSelectByType(
|
||||
Entity\StorageLocation::TYPE_BACKUP,
|
||||
true
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
parent::__construct(
|
||||
$em,
|
||||
$settingsTableRepo,
|
||||
$settingsRepo,
|
||||
$environment,
|
||||
$formConfig
|
||||
);
|
||||
|
|
|
@ -11,13 +11,16 @@ class BrandingSettingsForm extends AbstractSettingsForm
|
|||
{
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Repository\SettingsTableRepository $settingsRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
Config $config
|
||||
) {
|
||||
$formConfig = $config->get('forms/branding', [
|
||||
'settings' => $environment,
|
||||
]);
|
||||
$formConfig = $config->get(
|
||||
'forms/branding',
|
||||
[
|
||||
'settings' => $environment,
|
||||
]
|
||||
);
|
||||
|
||||
parent::__construct(
|
||||
$em,
|
||||
|
|
|
@ -14,7 +14,7 @@ class GeoLiteSettingsForm extends AbstractSettingsForm
|
|||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Repository\SettingsTableRepository $settingsRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
Config $config,
|
||||
UpdateGeoLiteTask $syncTask
|
||||
|
|
|
@ -13,15 +13,18 @@ class SettingsForm extends AbstractSettingsForm
|
|||
{
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Repository\SettingsTableRepository $settingsRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
Version $version,
|
||||
Config $config
|
||||
) {
|
||||
$formConfig = $config->get('forms/settings', [
|
||||
'settings' => $environment,
|
||||
'version' => $version,
|
||||
]);
|
||||
$formConfig = $config->get(
|
||||
'forms/settings',
|
||||
[
|
||||
'settings' => $environment,
|
||||
'version' => $version,
|
||||
]
|
||||
);
|
||||
|
||||
parent::__construct(
|
||||
$em,
|
||||
|
|
|
@ -8,7 +8,8 @@ use App\Exception;
|
|||
use App\Exception\NotLoggedInException;
|
||||
use App\Exception\PermissionDeniedException;
|
||||
use App\Session\Flash;
|
||||
use App\ViewFactory;
|
||||
use App\View;
|
||||
use DI\FactoryInterface;
|
||||
use Gettext\Translator;
|
||||
use Mezzio\Session\SessionInterface;
|
||||
use Monolog\Logger;
|
||||
|
@ -31,21 +32,21 @@ class ErrorHandler extends \Slim\Handlers\ErrorHandler
|
|||
|
||||
protected Router $router;
|
||||
|
||||
protected ViewFactory $viewFactory;
|
||||
protected FactoryInterface $factory;
|
||||
|
||||
protected Environment $environment;
|
||||
|
||||
public function __construct(
|
||||
App $app,
|
||||
FactoryInterface $factory,
|
||||
Logger $logger,
|
||||
Router $router,
|
||||
ViewFactory $viewFactory,
|
||||
Environment $environment
|
||||
) {
|
||||
parent::__construct($app->getCallableResolver(), $app->getResponseFactory(), $logger);
|
||||
|
||||
$this->environment = $environment;
|
||||
$this->viewFactory = $viewFactory;
|
||||
$this->factory = $factory;
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
|
@ -130,12 +131,14 @@ class ErrorHandler extends \Slim\Handlers\ErrorHandler
|
|||
if (false !== stripos($ua, 'curl')) {
|
||||
$response = $this->responseFactory->createResponse($this->statusCode);
|
||||
|
||||
$response->getBody()->write(sprintf(
|
||||
'Error: %s on %s L%s',
|
||||
$this->exception->getMessage(),
|
||||
$this->exception->getFile(),
|
||||
$this->exception->getLine()
|
||||
));
|
||||
$response->getBody()->write(
|
||||
sprintf(
|
||||
'Error: %s on %s L%s',
|
||||
$this->exception->getMessage(),
|
||||
$this->exception->getFile(),
|
||||
$this->exception->getLine()
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
@ -150,7 +153,12 @@ class ErrorHandler extends \Slim\Handlers\ErrorHandler
|
|||
}
|
||||
|
||||
try {
|
||||
$view = $this->viewFactory->create($this->request);
|
||||
$view = $this->factory->make(
|
||||
View::class,
|
||||
[
|
||||
'request' => $this->request,
|
||||
]
|
||||
);
|
||||
|
||||
return $view->renderToResponse(
|
||||
$response,
|
||||
|
@ -238,7 +246,12 @@ class ErrorHandler extends \Slim\Handlers\ErrorHandler
|
|||
}
|
||||
|
||||
try {
|
||||
$view = $this->viewFactory->create($this->request);
|
||||
$view = $this->factory->make(
|
||||
View::class,
|
||||
[
|
||||
'request' => $this->request,
|
||||
]
|
||||
);
|
||||
|
||||
return $view->renderToResponse(
|
||||
$response,
|
||||
|
|
|
@ -9,6 +9,7 @@ use GuzzleHttp\Psr7\UriResolver;
|
|||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Slim\App;
|
||||
use Slim\Interfaces\RouteInterface;
|
||||
use Slim\Interfaces\RouteParserInterface;
|
||||
use Slim\Routing\RouteContext;
|
||||
|
@ -25,12 +26,12 @@ class Router implements RouterInterface
|
|||
|
||||
public function __construct(
|
||||
Environment $environment,
|
||||
RouteParserInterface $routeParser,
|
||||
Entity\Settings $settings
|
||||
App $app,
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->environment = $environment;
|
||||
$this->settings = $settings;
|
||||
$this->routeParser = $routeParser;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
$this->routeParser = $app->getRouteCollector()->getRouteParser();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
namespace App\MessageQueue;
|
||||
|
||||
use App\Entity\Repository\SettingsTableRepository;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
|
||||
|
||||
class ReloadSettingsMiddleware implements EventSubscriberInterface
|
||||
{
|
||||
protected SettingsTableRepository $settingsTableRepo;
|
||||
protected SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(SettingsTableRepository $settingsTableRepo)
|
||||
public function __construct(SettingsRepository $settingsRepo)
|
||||
{
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,6 +27,6 @@ class ReloadSettingsMiddleware implements EventSubscriberInterface
|
|||
|
||||
public function resetSettings(WorkerMessageReceivedEvent $event): void
|
||||
{
|
||||
$this->settingsTableRepo->updateSettings();
|
||||
$this->settingsRepo->clearSettingsInstance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
namespace App\Middleware;
|
||||
|
||||
use App\Http\ServerRequest;
|
||||
use App\ViewFactory;
|
||||
use App\View;
|
||||
use DI\FactoryInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
|
@ -14,16 +15,21 @@ use Psr\Http\Server\RequestHandlerInterface;
|
|||
*/
|
||||
class EnableView implements MiddlewareInterface
|
||||
{
|
||||
protected ViewFactory $viewFactory;
|
||||
protected FactoryInterface $factory;
|
||||
|
||||
public function __construct(ViewFactory $viewFactory)
|
||||
public function __construct(FactoryInterface $factory)
|
||||
{
|
||||
$this->viewFactory = $viewFactory;
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$view = $this->viewFactory->create($request);
|
||||
$view = $this->factory->make(
|
||||
View::class,
|
||||
[
|
||||
'request' => $request,
|
||||
]
|
||||
);
|
||||
|
||||
$request = $request->withAttribute(ServerRequest::ATTR_VIEW, $view);
|
||||
return $handler->handle($request);
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
namespace App\Middleware;
|
||||
|
||||
use App\Assets;
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use Psr\Http\Message\ResponseFactoryInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
@ -19,18 +17,14 @@ class EnforceSecurity implements MiddlewareInterface
|
|||
{
|
||||
protected ResponseFactoryInterface $responseFactory;
|
||||
|
||||
protected Assets $assets;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
App $app,
|
||||
Assets $assets,
|
||||
Entity\Settings $settings
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->responseFactory = $app->getResponseFactory();
|
||||
$this->assets = $assets;
|
||||
$this->settings = $settings;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,20 +33,17 @@ class EnforceSecurity implements MiddlewareInterface
|
|||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$always_use_ssl = $this->settings->getAlwaysUseSsl();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$always_use_ssl = $settings->getAlwaysUseSsl();
|
||||
|
||||
$internal_api_url = mb_stripos($request->getUri()->getPath(), '/api/internal') === 0;
|
||||
|
||||
// Assemble Content Security Policy (CSP)
|
||||
$csp = [];
|
||||
$add_hsts_header = false;
|
||||
|
||||
$addHstsHeader = false;
|
||||
if ('https' === $request->getUri()->getScheme()) {
|
||||
// Enforce secure cookies.
|
||||
ini_set('session.cookie_secure', '1');
|
||||
|
||||
$csp[] = 'upgrade-insecure-requests';
|
||||
|
||||
$add_hsts_header = true;
|
||||
$addHstsHeader = true;
|
||||
} elseif ($always_use_ssl && !$internal_api_url) {
|
||||
return $this->responseFactory->createResponse(307)
|
||||
->withHeader('Location', (string)$request->getUri()->withScheme('https'));
|
||||
|
@ -60,7 +51,7 @@ class EnforceSecurity implements MiddlewareInterface
|
|||
|
||||
$response = $handler->handle($request);
|
||||
|
||||
if ($add_hsts_header) {
|
||||
if ($addHstsHeader) {
|
||||
$response = $response->withHeader('Strict-Transport-Security', 'max-age=3600');
|
||||
}
|
||||
|
||||
|
@ -72,19 +63,6 @@ class EnforceSecurity implements MiddlewareInterface
|
|||
$response = $response->withHeader('X-Frame-Options', 'DENY');
|
||||
}
|
||||
|
||||
if (($response instanceof Response) && !$response->hasCacheLifetime()) {
|
||||
// CSP JavaScript policy
|
||||
// Note: unsafe-eval included for Vue template compiling
|
||||
$csp_script_src = $this->assets->getCspDomains();
|
||||
$csp_script_src[] = "'self'";
|
||||
$csp_script_src[] = "'unsafe-eval'";
|
||||
$csp_script_src[] = "'nonce-" . $this->assets->getCspNonce() . "'";
|
||||
|
||||
$csp[] = 'script-src ' . implode(' ', $csp_script_src);
|
||||
|
||||
$response = $response->withHeader('Content-Security-Policy', implode('; ', $csp));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ namespace App\Middleware;
|
|||
use App\Auth;
|
||||
use App\Customization;
|
||||
use App\Entity;
|
||||
use App\Environment;
|
||||
use App\Http\ServerRequest;
|
||||
use DI\FactoryInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
|
@ -17,29 +17,21 @@ use Psr\Http\Server\RequestHandlerInterface;
|
|||
*/
|
||||
class GetCurrentUser implements MiddlewareInterface
|
||||
{
|
||||
protected Entity\Repository\UserRepository $userRepo;
|
||||
protected FactoryInterface $factory;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
protected Environment $environment;
|
||||
|
||||
public function __construct(
|
||||
Entity\Repository\UserRepository $userRepo,
|
||||
Environment $environment,
|
||||
Entity\Settings $settings
|
||||
) {
|
||||
$this->userRepo = $userRepo;
|
||||
$this->environment = $environment;
|
||||
$this->settings = $settings;
|
||||
public function __construct(FactoryInterface $factory)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
// Initialize the Auth for this request.
|
||||
$auth = new Auth(
|
||||
$this->userRepo,
|
||||
$request->getAttribute(ServerRequest::ATTR_SESSION),
|
||||
$this->environment
|
||||
$auth = $this->factory->make(
|
||||
Auth::class,
|
||||
[
|
||||
'session' => $request->getAttribute(ServerRequest::ATTR_SESSION),
|
||||
]
|
||||
);
|
||||
$user = ($auth->isLoggedIn()) ? $auth->getLoggedInUser() : null;
|
||||
|
||||
|
@ -49,7 +41,12 @@ class GetCurrentUser implements MiddlewareInterface
|
|||
->withAttribute('is_logged_in', (null !== $user));
|
||||
|
||||
// Initialize Customization (timezones, locales, etc) based on the current logged in user.
|
||||
$customization = new Customization($this->settings, $this->environment, $request);
|
||||
$customization = $this->factory->make(
|
||||
Customization::class,
|
||||
[
|
||||
'request' => $request,
|
||||
]
|
||||
);
|
||||
|
||||
$request = $request
|
||||
->withAttribute('locale', $customization->getLocale())
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Middleware;
|
||||
|
||||
use App\Acl;
|
||||
use App\Entity\Repository\RolePermissionRepository;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
@ -15,12 +14,10 @@ use Psr\Http\Server\RequestHandlerInterface;
|
|||
*/
|
||||
class InjectAcl implements MiddlewareInterface
|
||||
{
|
||||
protected RolePermissionRepository $rolePermRepo;
|
||||
protected Acl $acl;
|
||||
|
||||
public function __construct(RolePermissionRepository $rolePermRepo, Acl $acl)
|
||||
public function __construct(Acl $acl)
|
||||
{
|
||||
$this->rolePermRepo = $rolePermRepo;
|
||||
$this->acl = $acl;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,14 +16,14 @@ class Api
|
|||
{
|
||||
protected Entity\Repository\ApiKeyRepository $api_repo;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
Entity\Repository\ApiKeyRepository $apiKeyRepository,
|
||||
Entity\Settings $settings
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->api_repo = $apiKeyRepository;
|
||||
$this->settings = $settings;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
|
@ -40,12 +40,14 @@ class Api
|
|||
}
|
||||
|
||||
// Set default cache control for API pages.
|
||||
$prefer_browser_url = $this->settings->getPreferBrowserUrl();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
$prefer_browser_url = $settings->getPreferBrowserUrl();
|
||||
|
||||
$response = $handler->handle($request);
|
||||
|
||||
// Check for a user-set CORS header override.
|
||||
$acao_header = trim($this->settings->getApiAccessControl());
|
||||
$acao_header = trim($settings->getApiAccessControl());
|
||||
if (!empty($acao_header)) {
|
||||
if ('*' === $acao_header) {
|
||||
$response = $response->withHeader('Access-Control-Allow-Origin', '*');
|
||||
|
@ -55,7 +57,7 @@ class Api
|
|||
|
||||
if (!empty($origin)) {
|
||||
$rawOrigins = array_map('trim', explode(',', $acao_header));
|
||||
$rawOrigins[] = $this->settings->getBaseUrl();
|
||||
$rawOrigins[] = $settings->getBaseUrl();
|
||||
|
||||
$origins = [];
|
||||
foreach ($rawOrigins as $rawOrigin) {
|
||||
|
|
|
@ -11,14 +11,16 @@ use Carbon\CarbonImmutable;
|
|||
|
||||
class RecentBackupCheck
|
||||
{
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
protected Environment $environment;
|
||||
|
||||
public function __construct(Entity\Settings $settings, Environment $environment)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
Environment $environment,
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->environment = $environment;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
public function __invoke(GetNotifications $event): void
|
||||
|
@ -37,27 +39,31 @@ class RecentBackupCheck
|
|||
$threshold = CarbonImmutable::now()->subWeeks(2)->getTimestamp();
|
||||
|
||||
// Don't show backup warning for freshly created installations.
|
||||
$setupComplete = $this->settings->getSetupCompleteTime();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
$setupComplete = $settings->getSetupCompleteTime();
|
||||
if ($setupComplete >= $threshold) {
|
||||
return;
|
||||
}
|
||||
|
||||
$backupLastRun = $this->settings->getBackupLastRun();
|
||||
$backupLastRun = $settings->getBackupLastRun();
|
||||
|
||||
if ($backupLastRun < $threshold) {
|
||||
$router = $request->getRouter();
|
||||
$backupUrl = $router->named('admin:backups:index');
|
||||
|
||||
$event->addNotification(new Notification(
|
||||
__('Installation Not Recently Backed Up'),
|
||||
// phpcs:disable Generic.Files.LineLength
|
||||
__(
|
||||
'This installation has not been backed up in the last two weeks. Visit the <a href="%s" target="_blank">Backups</a> page to run a new backup.',
|
||||
$backupUrl
|
||||
),
|
||||
// phpcs:enable
|
||||
Notification::INFO
|
||||
));
|
||||
$event->addNotification(
|
||||
new Notification(
|
||||
__('Installation Not Recently Backed Up'),
|
||||
// phpcs:disable Generic.Files.LineLength
|
||||
__(
|
||||
'This installation has not been backed up in the last two weeks. Visit the <a href="%s" target="_blank">Backups</a> page to run a new backup.',
|
||||
$backupUrl
|
||||
),
|
||||
// phpcs:enable
|
||||
Notification::INFO
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,14 +12,14 @@ class SyncTaskCheck
|
|||
{
|
||||
protected Runner $syncRunner;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
Runner $syncRunner,
|
||||
Entity\Settings $settings
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->syncRunner = $syncRunner;
|
||||
$this->settings = $settings;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
public function __invoke(GetNotifications $event): void
|
||||
|
@ -31,7 +31,9 @@ class SyncTaskCheck
|
|||
return;
|
||||
}
|
||||
|
||||
$setupComplete = $this->settings->isSetupComplete();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
$setupComplete = $settings->isSetupComplete();
|
||||
$syncTasks = $this->syncRunner->getSyncTimes();
|
||||
|
||||
foreach ($syncTasks as $taskKey => $task) {
|
||||
|
@ -48,17 +50,19 @@ class SyncTaskCheck
|
|||
$router = $request->getRouter();
|
||||
$backupUrl = $router->named('admin:debug:sync', ['type' => $taskKey]);
|
||||
|
||||
$event->addNotification(new Notification(
|
||||
__('Synchronized Task Not Recently Run'),
|
||||
// phpcs:disable Generic.Files.LineLength
|
||||
__(
|
||||
'The "%s" synchronization task has not run recently. This may indicate an error with your installation. <a href="%s" target="_blank">Manually run the task</a> to check for errors.',
|
||||
$task['name'],
|
||||
$backupUrl
|
||||
),
|
||||
// phpcs:enable
|
||||
Notification::ERROR
|
||||
));
|
||||
$event->addNotification(
|
||||
new Notification(
|
||||
__('Synchronized Task Not Recently Run'),
|
||||
// phpcs:disable Generic.Files.LineLength
|
||||
__(
|
||||
'The "%s" synchronization task has not run recently. This may indicate an error with your installation. <a href="%s" target="_blank">Manually run the task</a> to check for errors.',
|
||||
$task['name'],
|
||||
$backupUrl
|
||||
),
|
||||
// phpcs:enable
|
||||
Notification::ERROR
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,14 @@ use App\Version;
|
|||
|
||||
class UpdateCheck
|
||||
{
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
protected Version $version;
|
||||
|
||||
public function __construct(Entity\Settings $settings, Version $version)
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(Version $version, Entity\Repository\SettingsRepository $settingsRepo)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->version = $version;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
public function __invoke(GetNotifications $event): void
|
||||
|
@ -29,12 +29,14 @@ class UpdateCheck
|
|||
return;
|
||||
}
|
||||
|
||||
$checkForUpdates = $this->settings->getCheckForUpdates();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
$checkForUpdates = $settings->getCheckForUpdates();
|
||||
if (!$checkForUpdates) {
|
||||
return;
|
||||
}
|
||||
|
||||
$updateData = $this->settings->getUpdateResults();
|
||||
$updateData = $settings->getUpdateResults();
|
||||
if (empty($updateData)) {
|
||||
return;
|
||||
}
|
||||
|
@ -61,11 +63,13 @@ class UpdateCheck
|
|||
$instructions_string,
|
||||
];
|
||||
|
||||
$event->addNotification(new Notification(
|
||||
__('New AzuraCast Release Version Available'),
|
||||
implode(' ', $notification_parts),
|
||||
Notification::INFO
|
||||
));
|
||||
$event->addNotification(
|
||||
new Notification(
|
||||
__('New AzuraCast Release Version Available'),
|
||||
implode(' ', $notification_parts),
|
||||
Notification::INFO
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -73,10 +77,12 @@ class UpdateCheck
|
|||
$notification_parts = [];
|
||||
if ($updateData['rolling_updates_available'] < 15 && !empty($updateData['rolling_updates_list'])) {
|
||||
$notification_parts[] = __('The following improvements have been made since your last update:');
|
||||
$notification_parts[] = nl2br('<ul><li>' . implode(
|
||||
'</li><li>',
|
||||
$updateData['rolling_updates_list']
|
||||
) . '</li></ul>');
|
||||
$notification_parts[] = nl2br(
|
||||
'<ul><li>' . implode(
|
||||
'</li><li>',
|
||||
$updateData['rolling_updates_list']
|
||||
) . '</li></ul>'
|
||||
);
|
||||
} else {
|
||||
$notification_parts[] = '<b>' . __(
|
||||
'Your installation is currently %d update(s) behind the latest version.',
|
||||
|
@ -87,11 +93,13 @@ class UpdateCheck
|
|||
|
||||
$notification_parts[] = $instructions_string;
|
||||
|
||||
$event->addNotification(new Notification(
|
||||
__('New AzuraCast Updates Available'),
|
||||
implode(' ', $notification_parts),
|
||||
Notification::INFO
|
||||
));
|
||||
$event->addNotification(
|
||||
new Notification(
|
||||
__('New AzuraCast Updates Available'),
|
||||
implode(' ', $notification_parts),
|
||||
Notification::INFO
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ abstract class AbstractFrontend extends AbstractAdapter
|
|||
AdapterFactory $adapterFactory,
|
||||
Client $client,
|
||||
Router $router,
|
||||
Entity\Repository\StationMountRepository $stationMountRepo,
|
||||
Entity\Settings $settings
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\StationMountRepository $stationMountRepo
|
||||
) {
|
||||
parent::__construct($environment, $em, $supervisor, $dispatcher);
|
||||
|
||||
|
@ -49,7 +49,7 @@ abstract class AbstractFrontend extends AbstractAdapter
|
|||
$this->router = $router;
|
||||
|
||||
$this->stationMountRepo = $stationMountRepo;
|
||||
$this->settings = $settings;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,13 +25,13 @@ abstract class AbstractRemote
|
|||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Client $http_client,
|
||||
Logger $logger,
|
||||
AdapterFactory $adapterFactory
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->settings = $settings;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
$this->http_client = $http_client;
|
||||
$this->logger = $logger;
|
||||
$this->adapterFactory = $adapterFactory;
|
||||
|
|
|
@ -18,9 +18,7 @@ class AzuraCastCentral
|
|||
|
||||
protected Client $httpClient;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
protected Version $version;
|
||||
|
||||
|
@ -31,15 +29,13 @@ class AzuraCastCentral
|
|||
Version $version,
|
||||
Client $httpClient,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->environment = $environment;
|
||||
$this->version = $version;
|
||||
$this->httpClient = $httpClient;
|
||||
$this->logger = $logger;
|
||||
$this->settings = $settings;
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,13 +79,14 @@ class AzuraCastCentral
|
|||
|
||||
public function getUniqueIdentifier(): string
|
||||
{
|
||||
$appUuid = $this->settings->getAppUniqueIdentifier();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$appUuid = $settings->getAppUniqueIdentifier();
|
||||
|
||||
if (empty($appUuid)) {
|
||||
$appUuid = Uuid::uuid4()->toString();
|
||||
|
||||
$this->settings->setAppUniqueIdentifier($appUuid);
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings->setAppUniqueIdentifier($appUuid);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
||||
return $appUuid;
|
||||
|
@ -102,8 +99,9 @@ class AzuraCastCentral
|
|||
*/
|
||||
public function getIp(bool $cached = true): ?string
|
||||
{
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$ip = ($cached)
|
||||
? $this->settings->getExternalIp()
|
||||
? $settings->getExternalIp()
|
||||
: null;
|
||||
|
||||
if (empty($ip)) {
|
||||
|
@ -123,8 +121,8 @@ class AzuraCastCentral
|
|||
}
|
||||
|
||||
if (!empty($ip) && $cached) {
|
||||
$this->settings->setExternalIp($ip);
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings->setExternalIp($ip);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace App\Sync;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Repository\SettingsTableRepository;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Environment;
|
||||
use App\Event\GetSyncTasks;
|
||||
use App\EventDispatcher;
|
||||
|
@ -20,26 +19,22 @@ class Runner
|
|||
{
|
||||
protected Logger $logger;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
protected Environment $environment;
|
||||
|
||||
protected SettingsTableRepository $settingsTableRepo;
|
||||
protected SettingsRepository $settingsRepo;
|
||||
|
||||
protected LockFactory $lockFactory;
|
||||
|
||||
protected EventDispatcher $eventDispatcher;
|
||||
|
||||
public function __construct(
|
||||
SettingsTableRepository $settingsRepo,
|
||||
Entity\Settings $settings,
|
||||
SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
Logger $logger,
|
||||
LockFactory $lockFactory,
|
||||
EventDispatcher $eventDispatcher
|
||||
) {
|
||||
$this->settingsTableRepo = $settingsRepo;
|
||||
$this->settings = $settings;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
$this->environment = $environment;
|
||||
$this->logger = $logger;
|
||||
$this->lockFactory = $lockFactory;
|
||||
|
@ -67,7 +62,8 @@ class Runner
|
|||
public function runSyncTask(string $type, bool $force = false): void
|
||||
{
|
||||
// Immediately halt if setup is not complete.
|
||||
if (!$this->settings->isSetupComplete()) {
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
if (!$settings->isSetupComplete()) {
|
||||
$this->logger->notice(
|
||||
sprintf('Skipping sync task %s; setup not complete.', $type)
|
||||
);
|
||||
|
@ -123,15 +119,18 @@ class Runner
|
|||
$end_time = microtime(true);
|
||||
$time_diff = $end_time - $start_time;
|
||||
|
||||
$this->logger->debug(sprintf(
|
||||
'Timer "%s" completed in %01.3f second(s).',
|
||||
$taskClass,
|
||||
round($time_diff, 3)
|
||||
));
|
||||
$this->logger->debug(
|
||||
sprintf(
|
||||
'Timer "%s" completed in %01.3f second(s).',
|
||||
$taskClass,
|
||||
round($time_diff, 3)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->settings->updateSyncLastRunTime($type);
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings->updateSyncLastRunTime($type);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
|
@ -145,6 +144,8 @@ class Runner
|
|||
$shortTaskTimeout = $this->environment->getSyncShortExecutionTime();
|
||||
$longTaskTimeout = $this->environment->getSyncLongExecutionTime();
|
||||
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
$syncs = [
|
||||
GetSyncTasks::SYNC_NOWPLAYING => [
|
||||
'name' => __('Now Playing Data'),
|
||||
|
@ -152,7 +153,7 @@ class Runner
|
|||
__('Now Playing Data'),
|
||||
],
|
||||
'timeout' => $shortTaskTimeout,
|
||||
'latest' => $this->settings->getSyncNowplayingLastRun(),
|
||||
'latest' => $settings->getSyncNowplayingLastRun(),
|
||||
'interval' => 15,
|
||||
],
|
||||
GetSyncTasks::SYNC_SHORT => [
|
||||
|
@ -161,7 +162,7 @@ class Runner
|
|||
__('Song Requests Queue'),
|
||||
],
|
||||
'timeout' => $shortTaskTimeout,
|
||||
'latest' => $this->settings->getSyncShortLastRun(),
|
||||
'latest' => $settings->getSyncShortLastRun(),
|
||||
'interval' => 60,
|
||||
],
|
||||
GetSyncTasks::SYNC_MEDIUM => [
|
||||
|
@ -170,7 +171,7 @@ class Runner
|
|||
__('Check Media Folders'),
|
||||
],
|
||||
'timeout' => $shortTaskTimeout,
|
||||
'latest' => $this->settings->getSyncMediumLastRun(),
|
||||
'latest' => $settings->getSyncMediumLastRun(),
|
||||
'interval' => 300,
|
||||
],
|
||||
GetSyncTasks::SYNC_LONG => [
|
||||
|
@ -180,7 +181,7 @@ class Runner
|
|||
__('Cleanup'),
|
||||
],
|
||||
'timeout' => $longTaskTimeout,
|
||||
'latest' => $this->settings->getSyncLongLastRun(),
|
||||
'latest' => $settings->getSyncLongLastRun(),
|
||||
'interval' => 3600,
|
||||
],
|
||||
];
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Sync\Task;
|
||||
|
||||
use App\Entity;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
@ -12,16 +11,12 @@ abstract class AbstractTask
|
|||
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->logger = $logger;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
abstract public function run(bool $force = false): void;
|
||||
|
|
|
@ -17,11 +17,10 @@ class BuildQueueTask extends AbstractTask
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
AutoDJ $autoDJ,
|
||||
LockFactory $lockFactory
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->autoDJ = $autoDJ;
|
||||
$this->lockFactory = $lockFactory;
|
||||
|
@ -33,6 +32,7 @@ class BuildQueueTask extends AbstractTask
|
|||
->findBy(['is_enabled' => 1]);
|
||||
|
||||
foreach ($stations as $station) {
|
||||
/** @var Entity\Station $station */
|
||||
$this->processStation($station, $force);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,11 @@ class CheckFolderPlaylistsTask extends AbstractTask
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\StationPlaylistMediaRepository $spmRepo,
|
||||
Entity\Repository\StationPlaylistFolderRepository $folderRepo,
|
||||
FilesystemManager $filesystem
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->spmRepo = $spmRepo;
|
||||
$this->folderRepo = $folderRepo;
|
||||
|
@ -45,9 +44,12 @@ class CheckFolderPlaylistsTask extends AbstractTask
|
|||
foreach ($stations as $station) {
|
||||
/** @var Entity\Station $station */
|
||||
|
||||
$this->logger->info('Processing auto-assigning folders for station...', [
|
||||
'station' => $station->getName(),
|
||||
]);
|
||||
$this->logger->info(
|
||||
'Processing auto-assigning folders for station...',
|
||||
[
|
||||
'station' => $station->getName(),
|
||||
]
|
||||
);
|
||||
|
||||
$this->syncPlaylistFolders($station);
|
||||
gc_collect_cycles();
|
||||
|
@ -88,7 +90,7 @@ class CheckFolderPlaylistsTask extends AbstractTask
|
|||
SELECT sm
|
||||
FROM App\Entity\StationMedia sm
|
||||
WHERE sm.storage_location = :storageLocation
|
||||
AND sm.path LIKE :path
|
||||
AND sm.path LIKE :path
|
||||
DQL
|
||||
)->setParameter('storageLocation', $station->getMediaStorageLocation());
|
||||
|
||||
|
|
|
@ -32,14 +32,13 @@ class CheckMediaTask extends AbstractTask
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\StationMediaRepository $mediaRepo,
|
||||
Entity\Repository\StorageLocationRepository $storageLocationRepo,
|
||||
FilesystemManager $filesystem,
|
||||
MessageBus $messageBus,
|
||||
QueueManager $queueManager
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->storageLocationRepo = $storageLocationRepo;
|
||||
$this->mediaRepo = $mediaRepo;
|
||||
|
|
|
@ -21,12 +21,11 @@ class CheckRequests extends AbstractTask
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\StationRequestRepository $requestRepo,
|
||||
Adapters $adapters,
|
||||
EventDispatcher $dispatcher
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->requestRepo = $requestRepo;
|
||||
$this->dispatcher = $dispatcher;
|
||||
|
@ -67,10 +66,12 @@ class CheckRequests extends AbstractTask
|
|||
}
|
||||
|
||||
// Check for an existing SongHistory record and skip if one exists.
|
||||
$sq = $this->em->getRepository(Entity\StationQueue::class)->findOneBy([
|
||||
'station' => $station,
|
||||
'request' => $request,
|
||||
]);
|
||||
$sq = $this->em->getRepository(Entity\StationQueue::class)->findOneBy(
|
||||
[
|
||||
'station' => $station,
|
||||
'request' => $request,
|
||||
]
|
||||
);
|
||||
|
||||
if (!$sq instanceof Entity\StationQueue) {
|
||||
// Log the item in SongHistory.
|
||||
|
|
|
@ -15,25 +15,26 @@ class CheckUpdatesTask extends AbstractTask
|
|||
|
||||
protected AzuraCastCentral $azuracastCentral;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
AzuraCastCentral $azuracastCentral
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
$this->azuracastCentral = $azuracastCentral;
|
||||
}
|
||||
|
||||
public function run(bool $force = false): void
|
||||
{
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
if (!$force) {
|
||||
$update_last_run = $this->settings->getUpdateLastRun();
|
||||
$update_last_run = $settings->getUpdateLastRun();
|
||||
|
||||
if ($update_last_run > (time() - self::UPDATE_THRESHOLD)) {
|
||||
$this->logger->debug('Not checking for updates; checked too recently.');
|
||||
|
@ -50,8 +51,7 @@ class CheckUpdatesTask extends AbstractTask
|
|||
$updates = $this->azuracastCentral->checkForUpdates();
|
||||
|
||||
if (!empty($updates)) {
|
||||
$this->settings->setUpdateResults($updates);
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings->setUpdateResults($updates);
|
||||
|
||||
$this->logger->info('Successfully checked for updates.', ['results' => $updates]);
|
||||
} else {
|
||||
|
@ -62,7 +62,7 @@ class CheckUpdatesTask extends AbstractTask
|
|||
return;
|
||||
}
|
||||
|
||||
$this->settings->updateUpdateLastRun();
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings->updateUpdateLastRun();
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,22 +12,26 @@ class CleanupHistoryTask extends AbstractTask
|
|||
|
||||
protected Entity\Repository\ListenerRepository $listenerRepo;
|
||||
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\SongHistoryRepository $historyRepo,
|
||||
Entity\Repository\ListenerRepository $listenerRepo
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
$this->historyRepo = $historyRepo;
|
||||
$this->listenerRepo = $listenerRepo;
|
||||
}
|
||||
|
||||
public function run(bool $force = false): void
|
||||
{
|
||||
$daysToKeep = $this->settings->getHistoryKeepDays();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$daysToKeep = $settings->getHistoryKeepDays();
|
||||
|
||||
if ($daysToKeep !== 0) {
|
||||
$this->historyRepo->cleanup($daysToKeep);
|
||||
|
|
|
@ -16,10 +16,9 @@ class CleanupStorageTask extends AbstractTask
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
FilesystemManager $filesystem
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
|
||||
protected Entity\Repository\ListenerRepository $listenerRepo;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
protected LockFactory $lockFactory;
|
||||
|
||||
|
@ -49,12 +49,9 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
|
||||
protected RouterInterface $router;
|
||||
|
||||
protected string $analyticsLevel = Entity\Analytics::LEVEL_ALL;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Adapters $adapters,
|
||||
AutoDJ $autodj,
|
||||
CacheInterface $cache,
|
||||
|
@ -64,10 +61,10 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
RouterInterface $router,
|
||||
Entity\Repository\ListenerRepository $listenerRepository,
|
||||
Entity\Repository\StationQueueRepository $queueRepo,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\ApiGenerator\NowPlayingApiGenerator $nowPlayingApiGenerator
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->adapters = $adapters;
|
||||
$this->autodj = $autodj;
|
||||
|
@ -79,11 +76,9 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
|
||||
$this->listenerRepo = $listenerRepository;
|
||||
$this->queueRepo = $queueRepo;
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
|
||||
$this->nowPlayingApiGenerator = $nowPlayingApiGenerator;
|
||||
|
||||
$this->analyticsLevel = $settings->getAnalytics();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,8 +104,9 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
|
||||
$this->cache->set('nowplaying', $nowplaying, 120);
|
||||
|
||||
$this->settings->setNowplaying($nowplaying);
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings->setNowplaying($nowplaying);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,7 +114,7 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
*
|
||||
* @return Entity\Api\NowPlaying[]
|
||||
*/
|
||||
protected function loadNowPlaying($force = false): array
|
||||
protected function loadNowPlaying(bool $force = false): array
|
||||
{
|
||||
$stations = $this->em->getRepository(Entity\Station::class)
|
||||
->findBy(['is_enabled' => 1]);
|
||||
|
@ -131,16 +127,9 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
return $nowplaying;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Structured NowPlaying Data for a given station.
|
||||
*
|
||||
* @param Entity\Station $station
|
||||
* @param bool $standalone Whether the request is for this station alone or part of the regular sync process.
|
||||
*
|
||||
*/
|
||||
public function processStation(
|
||||
Entity\Station $station,
|
||||
$standalone = false
|
||||
bool $standalone = false
|
||||
): Entity\Api\NowPlaying {
|
||||
$lock = $this->getLockForStation($station);
|
||||
$lock->acquire(true);
|
||||
|
@ -149,15 +138,18 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
/** @var Logger $logger */
|
||||
$logger = $this->logger;
|
||||
|
||||
$logger->pushProcessor(function ($record) use ($station) {
|
||||
$record['extra']['station'] = [
|
||||
'id' => $station->getId(),
|
||||
'name' => $station->getName(),
|
||||
];
|
||||
return $record;
|
||||
});
|
||||
$logger->pushProcessor(
|
||||
function ($record) use ($station) {
|
||||
$record['extra']['station'] = [
|
||||
'id' => $station->getId(),
|
||||
'name' => $station->getName(),
|
||||
];
|
||||
return $record;
|
||||
}
|
||||
);
|
||||
|
||||
$include_clients = ($this->analyticsLevel === Entity\Analytics::LEVEL_ALL);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$include_clients = (Entity\Analytics::LEVEL_NONE !== $settings->getAnalytics());
|
||||
|
||||
$frontend_adapter = $this->adapters->getFrontendAdapter($station);
|
||||
$remote_adapters = $this->adapters->getRemoteAdapters($station);
|
||||
|
@ -174,20 +166,27 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
|
||||
$npResult = $event->getResult();
|
||||
} catch (Exception $e) {
|
||||
$this->logger->log(Logger::ERROR, $e->getMessage(), [
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'code' => $e->getCode(),
|
||||
]);
|
||||
$this->logger->log(
|
||||
Logger::ERROR,
|
||||
$e->getMessage(),
|
||||
[
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'code' => $e->getCode(),
|
||||
]
|
||||
);
|
||||
|
||||
$npResult = Result::blank();
|
||||
}
|
||||
|
||||
$this->logger->debug('Final NowPlaying Response for Station', [
|
||||
'id' => $station->getId(),
|
||||
'name' => $station->getName(),
|
||||
'np' => $npResult,
|
||||
]);
|
||||
$this->logger->debug(
|
||||
'Final NowPlaying Response for Station',
|
||||
[
|
||||
'id' => $station->getId(),
|
||||
'name' => $station->getName(),
|
||||
'np' => $npResult,
|
||||
]
|
||||
);
|
||||
|
||||
// Update detailed listener statistics, if they exist for the station
|
||||
if ($include_clients && null !== $npResult->clients) {
|
||||
|
@ -267,9 +266,12 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
$message = new Message\UpdateNowPlayingMessage();
|
||||
$message->station_id = $station->getId();
|
||||
|
||||
$this->messageBus->dispatch($message, [
|
||||
new DelayStamp(2000),
|
||||
]);
|
||||
$this->messageBus->dispatch(
|
||||
$message,
|
||||
[
|
||||
new DelayStamp(2000),
|
||||
]
|
||||
);
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
|
|
|
@ -13,10 +13,9 @@ class ReactivateStreamerTask extends AbstractTask
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\StationStreamerRepository $streamerRepo
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->streamerRepo = $streamerRepo;
|
||||
}
|
||||
|
|
|
@ -19,22 +19,26 @@ class RotateLogsTask extends AbstractTask
|
|||
|
||||
protected Supervisor $supervisor;
|
||||
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
protected Entity\Repository\StorageLocationRepository $storageLocationRepo;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Environment $environment,
|
||||
Adapters $adapters,
|
||||
Supervisor $supervisor,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\StorageLocationRepository $storageLocationRepo
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->environment = $environment;
|
||||
$this->adapters = $adapters;
|
||||
$this->supervisor = $supervisor;
|
||||
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
$this->storageLocationRepo = $storageLocationRepo;
|
||||
}
|
||||
|
||||
|
@ -63,10 +67,12 @@ class RotateLogsTask extends AbstractTask
|
|||
$rotate->run();
|
||||
|
||||
// Rotate the automated backups.
|
||||
$backups_to_keep = $this->settings->getBackupKeepCopies();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
$backups_to_keep = $settings->getBackupKeepCopies();
|
||||
|
||||
if ($backups_to_keep > 0) {
|
||||
$backupStorageId = (int)$this->settings->getBackupStorageLocation();
|
||||
$backupStorageId = (int)$settings->getBackupStorageLocation();
|
||||
|
||||
if ($backupStorageId > 0) {
|
||||
$storageLocation = $this->storageLocationRepo->findByType(
|
||||
|
|
|
@ -9,6 +9,8 @@ use Psr\Log\LoggerInterface;
|
|||
|
||||
class RunAnalyticsTask extends AbstractTask
|
||||
{
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
protected Entity\Repository\AnalyticsRepository $analyticsRepo;
|
||||
|
||||
protected Entity\Repository\ListenerRepository $listenerRepo;
|
||||
|
@ -18,13 +20,14 @@ class RunAnalyticsTask extends AbstractTask
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\AnalyticsRepository $analyticsRepo,
|
||||
Entity\Repository\ListenerRepository $listenerRepo,
|
||||
Entity\Repository\SongHistoryRepository $historyRepo
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
$this->analyticsRepo = $analyticsRepo;
|
||||
$this->listenerRepo = $listenerRepo;
|
||||
$this->historyRepo = $historyRepo;
|
||||
|
@ -32,7 +35,8 @@ class RunAnalyticsTask extends AbstractTask
|
|||
|
||||
public function run(bool $force = false): void
|
||||
{
|
||||
$analytics_level = $this->settings->getAnalytics();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$analytics_level = $settings->getAnalytics();
|
||||
|
||||
switch ($analytics_level) {
|
||||
case Entity\Analytics::LEVEL_NONE:
|
||||
|
|
|
@ -21,11 +21,10 @@ class RunAutomatedAssignmentTask extends AbstractTask
|
|||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\StationMediaRepository $mediaRepo,
|
||||
Adapters $adapters
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->mediaRepo = $mediaRepo;
|
||||
$this->adapters = $adapters;
|
||||
|
@ -125,9 +124,12 @@ class RunAutomatedAssignmentTask extends AbstractTask
|
|||
$mediaReport = $this->generateReport($station, $threshold_days);
|
||||
|
||||
// Remove songs that weren't already in auto-assigned playlists.
|
||||
$mediaReport = array_filter($mediaReport, function ($media) use ($mediaToUpdate) {
|
||||
return (isset($mediaToUpdate[$media['id']]));
|
||||
});
|
||||
$mediaReport = array_filter(
|
||||
$mediaReport,
|
||||
function ($media) use ($mediaToUpdate) {
|
||||
return (isset($mediaToUpdate[$media['id']]));
|
||||
}
|
||||
);
|
||||
|
||||
// Place all songs with 0 plays back in their original playlists.
|
||||
foreach ($mediaReport as $song_id => $media) {
|
||||
|
@ -137,9 +139,12 @@ class RunAutomatedAssignmentTask extends AbstractTask
|
|||
}
|
||||
|
||||
// Sort songs by ratio descending.
|
||||
uasort($mediaReport, function ($a_media, $b_media) {
|
||||
return (int)$b_media['ratio'] <=> (int)$a_media['ratio'];
|
||||
});
|
||||
uasort(
|
||||
$mediaReport,
|
||||
function ($a_media, $b_media) {
|
||||
return (int)$b_media['ratio'] <=> (int)$a_media['ratio'];
|
||||
}
|
||||
);
|
||||
|
||||
// Distribute media across the enabled playlists and assign media to playlist.
|
||||
$numSongs = count($mediaReport);
|
||||
|
|
|
@ -13,27 +13,24 @@ use Symfony\Component\Messenger\MessageBus;
|
|||
|
||||
class RunBackupTask extends AbstractTask
|
||||
{
|
||||
public const BASE_DIR = '/var/azuracast/backups';
|
||||
|
||||
protected MessageBus $messageBus;
|
||||
|
||||
protected Application $console;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
MessageBus $messageBus,
|
||||
Application $console,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->messageBus = $messageBus;
|
||||
$this->console = $console;
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,8 +41,10 @@ class RunBackupTask extends AbstractTask
|
|||
public function __invoke(Message\AbstractMessage $message): void
|
||||
{
|
||||
if ($message instanceof Message\BackupMessage) {
|
||||
$this->settings->updateBackupLastRun();
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings->updateBackupLastRun();
|
||||
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
|
||||
[$result_code, $result_output] = $this->runBackup(
|
||||
$message->path,
|
||||
|
@ -54,9 +53,10 @@ class RunBackupTask extends AbstractTask
|
|||
$message->storageLocationId
|
||||
);
|
||||
|
||||
$this->settings->setBackupLastResult($result_code);
|
||||
$this->settings->setBackupLastOutput($result_output);
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings->setBackupLastResult($result_code);
|
||||
$settings->setBackupLastOutput($result_output);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,9 @@ class RunBackupTask extends AbstractTask
|
|||
|
||||
public function run(bool $force = false): void
|
||||
{
|
||||
$backup_enabled = $this->settings->isBackupEnabled();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
$backup_enabled = $settings->isBackupEnabled();
|
||||
if (!$backup_enabled) {
|
||||
$this->logger->debug('Automated backups disabled; skipping...');
|
||||
return;
|
||||
|
@ -103,11 +105,11 @@ class RunBackupTask extends AbstractTask
|
|||
$now_utc = CarbonImmutable::now('UTC');
|
||||
|
||||
$threshold = $now_utc->subDay()->getTimestamp();
|
||||
$last_run = $this->settings->getBackupLastRun();
|
||||
$last_run = $settings->getBackupLastRun();
|
||||
|
||||
if ($last_run <= $threshold) {
|
||||
// Check if the backup time matches (if it's set).
|
||||
$backupTimecode = $this->settings->getBackupTimeCode();
|
||||
$backupTimecode = $settings->getBackupTimeCode();
|
||||
|
||||
if (null !== $backupTimecode && '' !== $backupTimecode) {
|
||||
$isWithinTimecode = false;
|
||||
|
@ -134,7 +136,7 @@ class RunBackupTask extends AbstractTask
|
|||
}
|
||||
|
||||
// Trigger a new backup.
|
||||
$storageLocationId = (int)($this->settings->getBackupStorageLocation() ?? 0);
|
||||
$storageLocationId = $settings->getBackupStorageLocation() ?? 0;
|
||||
if ($storageLocationId <= 0) {
|
||||
$storageLocationId = null;
|
||||
}
|
||||
|
@ -142,7 +144,7 @@ class RunBackupTask extends AbstractTask
|
|||
$message = new Message\BackupMessage();
|
||||
$message->storageLocationId = $storageLocationId;
|
||||
$message->path = 'automatic_backup.zip';
|
||||
$message->excludeMedia = $this->settings->getBackupExcludeMedia();
|
||||
$message->excludeMedia = $settings->getBackupExcludeMedia();
|
||||
|
||||
$this->messageBus->dispatch($message);
|
||||
}
|
||||
|
|
|
@ -21,28 +21,28 @@ class UpdateGeoLiteTask extends AbstractTask
|
|||
|
||||
protected IpGeolocation $geoLite;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
Entity\Settings $settings,
|
||||
Client $httpClient,
|
||||
IpGeolocation $geoLite,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
parent::__construct($em, $logger, $settings);
|
||||
parent::__construct($em, $logger);
|
||||
|
||||
$this->httpClient = $httpClient;
|
||||
$this->geoLite = $geoLite;
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
public function run(bool $force = false): void
|
||||
{
|
||||
if (!$force) {
|
||||
$lastRun = $this->settings->getGeoliteLastRun();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
if (!$force) {
|
||||
$lastRun = $settings->getGeoliteLastRun();
|
||||
if ($lastRun > (time() - self::UPDATE_THRESHOLD)) {
|
||||
$this->logger->debug('Not checking for updates; checked too recently.');
|
||||
return;
|
||||
|
@ -50,23 +50,25 @@ class UpdateGeoLiteTask extends AbstractTask
|
|||
}
|
||||
|
||||
try {
|
||||
$this->updateDatabase();
|
||||
$this->updateDatabase($settings->getGeoliteLicenseKey() ?? '');
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error('Error updating GeoLite database.', [
|
||||
'error' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
]);
|
||||
$this->logger->error(
|
||||
'Error updating GeoLite database.',
|
||||
[
|
||||
'error' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$this->settings->updateGeoliteLastRun();
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings->updateGeoliteLastRun();
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
||||
public function updateDatabase(): void
|
||||
public function updateDatabase(string $licenseKey): void
|
||||
{
|
||||
$licenseKey = trim($this->settings->getGeoliteLicenseKey());
|
||||
|
||||
if (empty($licenseKey)) {
|
||||
$this->logger->info('Not checking for GeoLite updates; no license key provided.');
|
||||
return;
|
||||
|
@ -77,28 +79,34 @@ class UpdateGeoLiteTask extends AbstractTask
|
|||
|
||||
set_time_limit(900);
|
||||
|
||||
$this->httpClient->get('https://download.maxmind.com/app/geoip_download', [
|
||||
RequestOptions::HTTP_ERRORS => true,
|
||||
RequestOptions::QUERY => [
|
||||
'license_key' => $licenseKey,
|
||||
'edition_id' => 'GeoLite2-City',
|
||||
'suffix' => 'tar.gz',
|
||||
],
|
||||
RequestOptions::DECODE_CONTENT => false,
|
||||
RequestOptions::SINK => $downloadPath,
|
||||
RequestOptions::TIMEOUT => 600,
|
||||
]);
|
||||
$this->httpClient->get(
|
||||
'https://download.maxmind.com/app/geoip_download',
|
||||
[
|
||||
RequestOptions::HTTP_ERRORS => true,
|
||||
RequestOptions::QUERY => [
|
||||
'license_key' => $licenseKey,
|
||||
'edition_id' => 'GeoLite2-City',
|
||||
'suffix' => 'tar.gz',
|
||||
],
|
||||
RequestOptions::DECODE_CONTENT => false,
|
||||
RequestOptions::SINK => $downloadPath,
|
||||
RequestOptions::TIMEOUT => 600,
|
||||
]
|
||||
);
|
||||
|
||||
if (!file_exists($downloadPath)) {
|
||||
throw new RuntimeException('New GeoLite database .tar.gz file not found.');
|
||||
}
|
||||
|
||||
$process = new Process([
|
||||
'tar',
|
||||
'xvzf',
|
||||
$downloadPath,
|
||||
'--strip-components=1',
|
||||
], $baseDir);
|
||||
$process = new Process(
|
||||
[
|
||||
'tar',
|
||||
'xvzf',
|
||||
$downloadPath,
|
||||
'--strip-components=1',
|
||||
],
|
||||
$baseDir
|
||||
);
|
||||
|
||||
$process->mustRun();
|
||||
|
||||
|
|
|
@ -11,10 +11,35 @@ class TaskLocator
|
|||
|
||||
protected array $tasks;
|
||||
|
||||
public function __construct(ContainerInterface $di, array $tasks)
|
||||
public function __construct(ContainerInterface $di)
|
||||
{
|
||||
$this->di = $di;
|
||||
$this->tasks = $tasks;
|
||||
|
||||
$this->tasks = [
|
||||
GetSyncTasks::SYNC_NOWPLAYING => [
|
||||
Task\BuildQueueTask::class,
|
||||
Task\NowPlayingTask::class,
|
||||
Task\ReactivateStreamerTask::class,
|
||||
],
|
||||
GetSyncTasks::SYNC_SHORT => [
|
||||
Task\CheckRequests::class,
|
||||
Task\RunBackupTask::class,
|
||||
Task\CleanupRelaysTask::class,
|
||||
],
|
||||
GetSyncTasks::SYNC_MEDIUM => [
|
||||
Task\CheckMediaTask::class,
|
||||
Task\CheckFolderPlaylistsTask::class,
|
||||
Task\CheckUpdatesTask::class,
|
||||
],
|
||||
GetSyncTasks::SYNC_LONG => [
|
||||
Task\RunAnalyticsTask::class,
|
||||
Task\RunAutomatedAssignmentTask::class,
|
||||
Task\CleanupHistoryTask::class,
|
||||
Task\CleanupStorageTask::class,
|
||||
Task\RotateLogsTask::class,
|
||||
Task\UpdateGeoLiteTask::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function __invoke(GetSyncTasks $event): void
|
||||
|
|
140
src/View.php
140
src/View.php
|
@ -2,12 +2,132 @@
|
|||
|
||||
namespace App;
|
||||
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use DI\FactoryInterface;
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use League\Plates\Engine;
|
||||
use League\Plates\Template\Data;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||
|
||||
class View extends Engine
|
||||
{
|
||||
public function __construct(
|
||||
FactoryInterface $factory,
|
||||
Environment $environment,
|
||||
EventDispatcher $dispatcher,
|
||||
Version $version,
|
||||
ServerRequestInterface $request
|
||||
) {
|
||||
parent::__construct($environment->getViewsDirectory(), 'phtml');
|
||||
|
||||
// Add non-request-dependent content.
|
||||
$this->addData(
|
||||
[
|
||||
'environment' => $environment,
|
||||
'version' => $version,
|
||||
]
|
||||
);
|
||||
|
||||
// Add request-dependent content.
|
||||
$assets = $factory->make(
|
||||
Assets::class,
|
||||
[
|
||||
'request' => $request,
|
||||
]
|
||||
);
|
||||
|
||||
$this->addData(
|
||||
[
|
||||
'request' => $request,
|
||||
'router' => $request->getAttribute(ServerRequest::ATTR_ROUTER),
|
||||
'auth' => $request->getAttribute(ServerRequest::ATTR_AUTH),
|
||||
'acl' => $request->getAttribute(ServerRequest::ATTR_ACL),
|
||||
'customization' => $request->getAttribute(ServerRequest::ATTR_CUSTOMIZATION),
|
||||
'flash' => $request->getAttribute(ServerRequest::ATTR_SESSION_FLASH),
|
||||
'assets' => $assets,
|
||||
]
|
||||
);
|
||||
|
||||
$this->registerFunction(
|
||||
'escapeJs',
|
||||
function ($string) {
|
||||
return json_encode($string, JSON_THROW_ON_ERROR, 512);
|
||||
}
|
||||
);
|
||||
|
||||
$this->registerFunction(
|
||||
'dump',
|
||||
function ($value) {
|
||||
if (class_exists(VarCloner::class)) {
|
||||
$varCloner = new VarCloner();
|
||||
|
||||
$dumper = new CliDumper();
|
||||
$dumpedValue = $dumper->dump($varCloner->cloneVar($value), true);
|
||||
} else {
|
||||
$dumpedValue = json_encode($value, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
return '<pre>' . htmlspecialchars($dumpedValue) . '</pre>';
|
||||
}
|
||||
);
|
||||
|
||||
$this->registerFunction(
|
||||
'mailto',
|
||||
function ($address, $link_text = null) {
|
||||
$address = substr(chunk_split(bin2hex(" $address"), 2, ';&#x'), 3, -3);
|
||||
$link_text = $link_text ?? $address;
|
||||
return '<a href="mailto:' . $address . '">' . $link_text . '</a>';
|
||||
}
|
||||
);
|
||||
|
||||
$this->registerFunction(
|
||||
'pluralize',
|
||||
function ($word, $num = 0) {
|
||||
if ((int)$num === 1) {
|
||||
return $word;
|
||||
}
|
||||
|
||||
$inflector = InflectorFactory::create()->build();
|
||||
return $inflector->pluralize($word);
|
||||
}
|
||||
);
|
||||
|
||||
$this->registerFunction(
|
||||
'truncate',
|
||||
function ($text, $length = 80) {
|
||||
return Utilities::truncateText($text, $length);
|
||||
}
|
||||
);
|
||||
|
||||
$this->registerFunction(
|
||||
'truncateUrl',
|
||||
function ($url) {
|
||||
return Utilities::truncateUrl($url);
|
||||
}
|
||||
);
|
||||
|
||||
$this->registerFunction(
|
||||
'link',
|
||||
function ($url, $external = true, $truncate = true) {
|
||||
$url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$a = ['href="' . $url . '"'];
|
||||
if ($external) {
|
||||
$a[] = 'target="_blank"';
|
||||
}
|
||||
|
||||
$a_body = ($truncate) ? Utilities::truncateUrl($url) : $url;
|
||||
return '<a ' . implode(' ', $a) . '>' . $a_body . '</a>';
|
||||
}
|
||||
);
|
||||
|
||||
$dispatcher->dispatch(new Event\BuildView($this));
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->data = new Data();
|
||||
|
@ -26,17 +146,25 @@ class View extends Engine
|
|||
* Trigger rendering of template and write it directly to the PSR-7 compatible Response object.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param string $template_name
|
||||
* @param array $template_args
|
||||
* @param string $templateName
|
||||
* @param array $templateArgs
|
||||
*/
|
||||
public function renderToResponse(
|
||||
ResponseInterface $response,
|
||||
$template_name,
|
||||
array $template_args = []
|
||||
string $templateName,
|
||||
array $templateArgs = []
|
||||
): ResponseInterface {
|
||||
$template = $this->render($template_name, $template_args);
|
||||
$template = $this->render($templateName, $templateArgs);
|
||||
|
||||
$response->getBody()->write($template);
|
||||
return $response->withHeader('Content-type', 'text/html; charset=utf-8');
|
||||
$response = $response->withHeader('Content-type', 'text/html; charset=utf-8');
|
||||
|
||||
if ($response instanceof Response && !$response->hasCacheLifetime()) {
|
||||
/** @var Assets $assets */
|
||||
$assets = $this->getData('assets');
|
||||
$response = $assets->writeCsp($response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Http\ServerRequest;
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||
|
||||
use const JSON_PRETTY_PRINT;
|
||||
|
||||
class ViewFactory
|
||||
{
|
||||
protected ContainerInterface $di;
|
||||
|
||||
protected Environment $environment;
|
||||
|
||||
protected EventDispatcher $dispatcher;
|
||||
|
||||
protected Version $version;
|
||||
|
||||
protected Assets $assets;
|
||||
|
||||
public function __construct(
|
||||
ContainerInterface $di,
|
||||
Environment $environment,
|
||||
EventDispatcher $dispatcher,
|
||||
Version $version,
|
||||
Assets $assets
|
||||
) {
|
||||
$this->di = $di;
|
||||
$this->environment = $environment;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->version = $version;
|
||||
$this->assets = $assets;
|
||||
}
|
||||
|
||||
public function create(ServerRequestInterface $request): View
|
||||
{
|
||||
$view = new View($this->environment->getViewsDirectory(), 'phtml');
|
||||
|
||||
// Add non-request-dependent content.
|
||||
$view->addData([
|
||||
'environment' => $this->environment,
|
||||
'version' => $this->version,
|
||||
]);
|
||||
|
||||
// Add request-dependent content.
|
||||
$assets = $this->assets->withRequest($request);
|
||||
|
||||
$view->addData([
|
||||
'request' => $request,
|
||||
'router' => $request->getAttribute(ServerRequest::ATTR_ROUTER),
|
||||
'auth' => $request->getAttribute(ServerRequest::ATTR_AUTH),
|
||||
'acl' => $request->getAttribute(ServerRequest::ATTR_ACL),
|
||||
'customization' => $request->getAttribute(ServerRequest::ATTR_CUSTOMIZATION),
|
||||
'flash' => $request->getAttribute(ServerRequest::ATTR_SESSION_FLASH),
|
||||
'assets' => $assets,
|
||||
]);
|
||||
|
||||
$view->registerFunction('service', function ($service) {
|
||||
return $this->di->get($service);
|
||||
});
|
||||
|
||||
$view->registerFunction('escapeJs', function ($string) {
|
||||
return json_encode($string, JSON_THROW_ON_ERROR, 512);
|
||||
});
|
||||
|
||||
$view->registerFunction('dump', function ($value) {
|
||||
if (class_exists(VarCloner::class)) {
|
||||
$varCloner = new VarCloner();
|
||||
|
||||
$dumper = new CliDumper();
|
||||
$dumpedValue = $dumper->dump($varCloner->cloneVar($value), true);
|
||||
} else {
|
||||
$dumpedValue = json_encode($value, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
return '<pre>' . htmlspecialchars($dumpedValue) . '</pre>';
|
||||
});
|
||||
|
||||
$view->registerFunction('mailto', function ($address, $link_text = null) {
|
||||
$address = substr(chunk_split(bin2hex(" $address"), 2, ';&#x'), 3, -3);
|
||||
$link_text = $link_text ?? $address;
|
||||
return '<a href="mailto:' . $address . '">' . $link_text . '</a>';
|
||||
});
|
||||
|
||||
$view->registerFunction('pluralize', function ($word, $num = 0) {
|
||||
if ((int)$num === 1) {
|
||||
return $word;
|
||||
}
|
||||
|
||||
$inflector = InflectorFactory::create()->build();
|
||||
return $inflector->pluralize($word);
|
||||
});
|
||||
|
||||
$view->registerFunction('truncate', function ($text, $length = 80) {
|
||||
return Utilities::truncateText($text, $length);
|
||||
});
|
||||
|
||||
$view->registerFunction('truncateUrl', function ($url) {
|
||||
return Utilities::truncateUrl($url);
|
||||
});
|
||||
|
||||
$view->registerFunction('link', function ($url, $external = true, $truncate = true) {
|
||||
$url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$a = ['href="' . $url . '"'];
|
||||
if ($external) {
|
||||
$a[] = 'target="_blank"';
|
||||
}
|
||||
|
||||
$a_body = ($truncate) ? Utilities::truncateUrl($url) : $url;
|
||||
return '<a ' . implode(' ', $a) . '>' . $a_body . '</a>';
|
||||
});
|
||||
|
||||
$this->dispatcher->dispatch(new Event\BuildView($view));
|
||||
|
||||
return $view;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Webhook;
|
||||
|
||||
use App\Config;
|
||||
use App\Webhook\Connector\ConnectorInterface;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
@ -12,8 +13,16 @@ class ConnectorLocator
|
|||
|
||||
protected array $connectors;
|
||||
|
||||
public function __construct(ContainerInterface $di, array $connectors)
|
||||
{
|
||||
public function __construct(
|
||||
ContainerInterface $di,
|
||||
Config $config
|
||||
) {
|
||||
$webhooks = $config->get('webhooks');
|
||||
$connectors = [];
|
||||
foreach ($webhooks['webhooks'] as $webhook_key => $webhook_info) {
|
||||
$connectors[$webhook_key] = $webhook_info['class'];
|
||||
}
|
||||
|
||||
$this->di = $di;
|
||||
$this->connectors = $connectors;
|
||||
}
|
||||
|
|
|
@ -23,22 +23,18 @@ class LocalWebhookHandler
|
|||
|
||||
protected CacheInterface $cache;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
Logger $logger,
|
||||
Client $httpClient,
|
||||
CacheInterface $cache,
|
||||
Entity\Settings $settings,
|
||||
Entity\Repository\SettingsTableRepository $settingsTableRepo
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
$this->httpClient = $httpClient;
|
||||
$this->cache = $cache;
|
||||
$this->settings = $settings;
|
||||
$this->settingsTableRepo = $settingsTableRepo;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
public function dispatch(SendWebhooks $event): void
|
||||
|
@ -65,8 +61,9 @@ class LocalWebhookHandler
|
|||
|
||||
$this->cache->set('nowplaying', $np_new, 120);
|
||||
|
||||
$this->settings->setNowplaying($np_new);
|
||||
$this->settingsTableRepo->writeSettings($this->settings);
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings->setNowplaying($np_new);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,10 +73,15 @@ class LocalWebhookHandler
|
|||
$config_dir = $station->getRadioConfigDir();
|
||||
$np_file = $config_dir . '/nowplaying.txt';
|
||||
|
||||
$np_text = implode(' - ', array_filter([
|
||||
$np->now_playing->song->artist ?? null,
|
||||
$np->now_playing->song->title ?? null,
|
||||
]));
|
||||
$np_text = implode(
|
||||
' - ',
|
||||
array_filter(
|
||||
[
|
||||
$np->now_playing->song->artist ?? null,
|
||||
$np->now_playing->song->title ?? null,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
if (empty($np_text)) {
|
||||
$np_text = $station->getName();
|
||||
|
@ -107,9 +109,12 @@ class LocalWebhookHandler
|
|||
if (NChan::isSupported()) {
|
||||
$this->logger->debug('Dispatching Nchan notification...');
|
||||
|
||||
$this->httpClient->post('http://localhost:9010/pub/' . urlencode($station->getShortName()), [
|
||||
'json' => $np,
|
||||
]);
|
||||
$this->httpClient->post(
|
||||
'http://localhost:9010/pub/' . urlencode($station->getShortName()),
|
||||
[
|
||||
'json' => $np,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ abstract class CestAbstract
|
|||
|
||||
protected App\Environment $environment;
|
||||
|
||||
protected Entity\Repository\SettingsTableRepository $settingsTableRepo;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
protected Entity\Repository\StationRepository $stationRepo;
|
||||
|
||||
|
@ -25,7 +25,7 @@ abstract class CestAbstract
|
|||
$this->di = $tests_module->container;
|
||||
$this->em = $tests_module->em;
|
||||
|
||||
$this->settingsTableRepo = $this->di->get(Entity\Repository\SettingsTableRepository::class);
|
||||
$this->settingsRepo = $this->di->get(Entity\Repository\SettingsRepository::class);
|
||||
$this->stationRepo = $this->di->get(Entity\Repository\StationRepository::class);
|
||||
$this->environment = $this->di->get(App\Environment::class);
|
||||
}
|
||||
|
@ -48,9 +48,10 @@ abstract class CestAbstract
|
|||
{
|
||||
$I->wantTo('Start with an incomplete setup.');
|
||||
|
||||
$settings = $this->settingsTableRepo->updateSettings();
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings->setSetupCompleteTime(0);
|
||||
$this->settingsTableRepo->writeSettings($settings);
|
||||
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
|
||||
$this->_cleanTables();
|
||||
}
|
||||
|
@ -92,10 +93,10 @@ abstract class CestAbstract
|
|||
$this->test_station = $this->stationRepo->create($test_station);
|
||||
|
||||
// Set settings.
|
||||
$settings = $this->settingsTableRepo->updateSettings();
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings->updateSetupComplete();
|
||||
$settings->setBaseUrl('localhost');
|
||||
$this->settingsTableRepo->writeSettings($settings);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
||||
protected function getTestStation(): Entity\Station
|
||||
|
@ -149,10 +150,13 @@ abstract class CestAbstract
|
|||
$I->amOnPage('/');
|
||||
$I->seeInCurrentUrl('/login');
|
||||
|
||||
$I->submitForm('#login-form', [
|
||||
'username' => $this->login_username,
|
||||
'password' => $this->login_password,
|
||||
]);
|
||||
$I->submitForm(
|
||||
'#login-form',
|
||||
[
|
||||
'username' => $this->login_username,
|
||||
'password' => $this->login_password,
|
||||
]
|
||||
);
|
||||
|
||||
$I->seeInSource('Logged In');
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue