Switch Settings to be a flat single entity to use EntityManager built-in functions. (#4045)
This commit is contained in:
parent
3930070637
commit
2dc41d080a
|
@ -56,6 +56,7 @@
|
|||
"psr/http-factory": "^1.0",
|
||||
"psr/simple-cache": "^1.0",
|
||||
"ramsey/uuid": "^4.0",
|
||||
"ramsey/uuid-doctrine": "^1.6",
|
||||
"rlanvin/php-ip": "^2.0",
|
||||
"slim/http": "^1.1",
|
||||
"slim/slim": "^4.2",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "86025d9340610c6ae8f5853b3fa5e2bf",
|
||||
"content-hash": "17f74c9a9115bff2e514f58d32a7f93f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
|
@ -5670,6 +5670,58 @@
|
|||
],
|
||||
"time": "2020-08-18T17:17:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid-doctrine",
|
||||
"version": "1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid-doctrine.git",
|
||||
"reference": "9facc4689547e72e03c1e18df4a0ee162b2778b0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid-doctrine/zipball/9facc4689547e72e03c1e18df4a0ee162b2778b0",
|
||||
"reference": "9facc4689547e72e03c1e18df4a0ee162b2778b0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/orm": "^2.5",
|
||||
"php": "^5.4 | ^7 | ^8",
|
||||
"ramsey/uuid": "^3.5 | ^4"
|
||||
},
|
||||
"require-dev": {
|
||||
"jakub-onderka/php-parallel-lint": "^1",
|
||||
"mockery/mockery": "^0.9 | ^1",
|
||||
"phpunit/phpunit": "^4.8.36 | ^5.7 | ^6.5 | ^7",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ramsey\\Uuid\\Doctrine\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Allow the use of ramsey/uuid as a Doctrine field type.",
|
||||
"homepage": "https://github.com/ramsey/uuid-doctrine",
|
||||
"keywords": [
|
||||
"database",
|
||||
"doctrine",
|
||||
"guid",
|
||||
"identifier",
|
||||
"uuid"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/uuid-doctrine/issues",
|
||||
"rss": "https://github.com/ramsey/uuid-doctrine/releases.atom",
|
||||
"source": "https://github.com/ramsey/uuid-doctrine",
|
||||
"wiki": "https://github.com/ramsey/uuid/wiki"
|
||||
},
|
||||
"time": "2020-01-27T05:09:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rlanvin/php-ip",
|
||||
"version": "v2.1.0",
|
||||
|
|
|
@ -8,11 +8,13 @@ return [
|
|||
|
||||
'elements' => [
|
||||
|
||||
'backupEnabled' => [
|
||||
'backup_enabled' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Run Automatic Nightly Backups'),
|
||||
'description' => __('Enable to have AzuraCast automatically run nightly backups at the time specified.'),
|
||||
'description' => __(
|
||||
'Enable to have AzuraCast automatically run nightly backups at the time specified.'
|
||||
),
|
||||
'selected_text' => __('Yes'),
|
||||
'deselected_text' => __('No'),
|
||||
'default' => false,
|
||||
|
@ -20,7 +22,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'backupTimeCode' => [
|
||||
'backup_time_code' => [
|
||||
'PlaylistTime',
|
||||
[
|
||||
'label' => __('Scheduled Backup Time'),
|
||||
|
@ -29,11 +31,13 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'backupExcludeMedia' => [
|
||||
'backup_exclude_media' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Exclude Media from Backups'),
|
||||
'description' => __('Excluding media from automated backups will save space, but you should make sure to back up your media elsewhere. Note that only locally stored media will be backed up.'),
|
||||
'description' => __(
|
||||
'Excluding media from automated backups will save space, but you should make sure to back up your media elsewhere. Note that only locally stored media will be backed up.'
|
||||
),
|
||||
'selected_text' => __('Yes'),
|
||||
'deselected_text' => __('No'),
|
||||
'default' => false,
|
||||
|
@ -41,11 +45,13 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'backupKeepCopies' => [
|
||||
'backup_keep_copies' => [
|
||||
'number',
|
||||
[
|
||||
'label' => __('Number of Backup Copies to Keep'),
|
||||
'description' => __('Copies older than the specified number of days will automatically be deleted. Set to zero to disable automatic deletion.'),
|
||||
'description' => __(
|
||||
'Copies older than the specified number of days will automatically be deleted. Set to zero to disable automatic deletion.'
|
||||
),
|
||||
'min' => 0,
|
||||
'max' => 365,
|
||||
'default' => 0,
|
||||
|
@ -53,7 +59,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'backupStorageLocation' => [
|
||||
'backup_storage_location' => [
|
||||
'select',
|
||||
[
|
||||
'label' => __('Storage Location'),
|
||||
|
|
|
@ -8,11 +8,13 @@ return [
|
|||
'use_grid' => true,
|
||||
'elements' => [
|
||||
|
||||
'publicTheme' => [
|
||||
'public_theme' => [
|
||||
'radio',
|
||||
[
|
||||
'label' => __('Base Theme for Public Pages'),
|
||||
'description' => __('Select a theme to use as a base for station public pages and the login page.'),
|
||||
'description' => __(
|
||||
'Select a theme to use as a base for station public pages and the login page.'
|
||||
),
|
||||
'choices' => [
|
||||
'light' => __('Light') . ' (' . __('Default') . ')',
|
||||
'dark' => __('Dark'),
|
||||
|
@ -22,7 +24,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'hideAlbumArt' => [
|
||||
'hide_album_art' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Hide Album Art on Public Pages'),
|
||||
|
@ -34,31 +36,37 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'homepageRedirectUrl' => [
|
||||
'homepage_redirect_url' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('Homepage Redirect URL'),
|
||||
'description' => __('If a visitor is not signed in and visits the AzuraCast homepage, you can automatically redirect them to the URL specified here. Leave blank to redirect them to the login screen by default.'),
|
||||
'description' => __(
|
||||
'If a visitor is not signed in and visits the AzuraCast homepage, you can automatically redirect them to the URL specified here. Leave blank to redirect them to the login screen by default.'
|
||||
),
|
||||
'default' => '',
|
||||
'form_group_class' => 'col-md-6',
|
||||
],
|
||||
],
|
||||
|
||||
'defaultAlbumArtUrl' => [
|
||||
'default_album_art_url' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('Default Album Art URL'),
|
||||
'description' => __('If a song has no album art, this URL will be listed instead. Leave blank to use the standard placeholder art.'),
|
||||
'description' => __(
|
||||
'If a song has no album art, this URL will be listed instead. Leave blank to use the standard placeholder art.'
|
||||
),
|
||||
'default' => '',
|
||||
'form_group_class' => 'col-md-6',
|
||||
],
|
||||
],
|
||||
|
||||
'hideProductName' => [
|
||||
'hide_product_name' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Hide AzuraCast Branding on Public Pages'),
|
||||
'description' => __('If selected, this will remove the AzuraCast branding from public-facing pages.'),
|
||||
'description' => __(
|
||||
'If selected, this will remove the AzuraCast branding from public-facing pages.'
|
||||
),
|
||||
'selected_text' => __('Yes'),
|
||||
'deselected_text' => __('No'),
|
||||
'default' => false,
|
||||
|
@ -66,7 +74,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'publicCustomCss' => [
|
||||
'public_custom_css' => [
|
||||
'textarea',
|
||||
[
|
||||
'label' => __('Custom CSS for Public Pages'),
|
||||
|
@ -80,11 +88,13 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'publicCustomJs' => [
|
||||
'public_custom_js' => [
|
||||
'textarea',
|
||||
[
|
||||
'label' => __('Custom JS for Public Pages'),
|
||||
'description' => __('This javascript code will be applied to the station public pages and login page.'),
|
||||
'description' => __(
|
||||
'This javascript code will be applied to the station public pages and login page.'
|
||||
),
|
||||
'spellcheck' => 'false',
|
||||
'class' => 'js-editor',
|
||||
'filter' => function ($val) {
|
||||
|
@ -94,7 +104,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'internalCustomCss' => [
|
||||
'internal_custom_css' => [
|
||||
'textarea',
|
||||
[
|
||||
'label' => __('Custom CSS for Internal Pages'),
|
||||
|
|
|
@ -28,7 +28,7 @@ return [
|
|||
'tab' => 'system',
|
||||
|
||||
'elements' => [
|
||||
'baseUrl' => [
|
||||
'base_url' => [
|
||||
'url',
|
||||
[
|
||||
'label' => __('Site Base URL'),
|
||||
|
@ -40,7 +40,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'instanceName' => [
|
||||
'instance_name' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('AzuraCast Instance Name'),
|
||||
|
@ -51,7 +51,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'preferBrowserUrl' => [
|
||||
'prefer_browser_url' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Prefer Browser URL (If Available)'),
|
||||
|
@ -65,7 +65,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'useRadioProxy' => [
|
||||
'use_radio_proxy' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Use Web Proxy for Radio'),
|
||||
|
@ -79,7 +79,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'historyKeepDays' => [
|
||||
'history_keep_days' => [
|
||||
'radio',
|
||||
[
|
||||
'label' => __('Days of Playback History to Keep'),
|
||||
|
@ -99,7 +99,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'enableWebsockets' => [
|
||||
'enable_websockets' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Use WebSockets for Now Playing Updates'),
|
||||
|
@ -113,7 +113,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'enableAdvancedFeatures' => [
|
||||
'enable_advanced_features' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Enable Advanced Features'),
|
||||
|
@ -136,7 +136,7 @@ return [
|
|||
|
||||
'elements' => [
|
||||
|
||||
'alwaysUseSsl' => [
|
||||
'always_use_ssl' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Always Use HTTPS'),
|
||||
|
@ -150,7 +150,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'apiAccessControl' => [
|
||||
'api_access_control' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('API "Access-Control-Allow-Origin" header'),
|
||||
|
@ -212,7 +212,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'checkForUpdates' => [
|
||||
'check_for_updates' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Show Update Announcements'),
|
||||
|
@ -232,7 +232,7 @@ return [
|
|||
|
||||
'elements' => [
|
||||
|
||||
'mailEnabled' => [
|
||||
'mail_enabled' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Enable Mail Delivery'),
|
||||
|
@ -243,7 +243,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'mailSenderName' => [
|
||||
'mail_sender_name' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('Sender Name'),
|
||||
|
@ -252,7 +252,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'mailSenderEmail' => [
|
||||
'mail_sender_email' => [
|
||||
'email',
|
||||
[
|
||||
'label' => __('Sender E-mail Address'),
|
||||
|
@ -262,7 +262,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'mailSmtpHost' => [
|
||||
'mail_smtp_host' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('SMTP Host'),
|
||||
|
@ -271,7 +271,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'mailSmtpPort' => [
|
||||
'mail_smtp_port' => [
|
||||
'number',
|
||||
[
|
||||
'label' => __('SMTP Port'),
|
||||
|
@ -280,7 +280,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'mailSmtpSecure' => [
|
||||
'mail_smtp_secure' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Use Secure (TLS) SMTP Connection'),
|
||||
|
@ -293,7 +293,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'mailSmtpUsername' => [
|
||||
'mail_smtp_username' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('SMTP Username'),
|
||||
|
@ -302,7 +302,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'mailSmtpPassword' => [
|
||||
'mail_smtp_password' => [
|
||||
'password',
|
||||
[
|
||||
'label' => __('SMTP Password'),
|
||||
|
@ -320,7 +320,7 @@ return [
|
|||
|
||||
'elements' => [
|
||||
|
||||
'avatarService' => [
|
||||
'avatar_service' => [
|
||||
'radio',
|
||||
[
|
||||
'label' => __('Avatar Service'),
|
||||
|
@ -335,7 +335,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'avatarDefaultUrl' => [
|
||||
'avatar_default_url' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('Default Avatar URL'),
|
||||
|
@ -354,7 +354,7 @@ return [
|
|||
|
||||
'elements' => [
|
||||
|
||||
'useExternalAlbumArtInApis' => [
|
||||
'use_external_album_art_in_apis' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Check Web Services for Album Art for "Now Playing" Tracks'),
|
||||
|
@ -365,7 +365,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'useExternalAlbumArtWhenProcessingMedia' => [
|
||||
'use_external_album_art_when_processing_media' => [
|
||||
'toggle',
|
||||
[
|
||||
'label' => __('Check Web Services for Album Art When Uploading Media'),
|
||||
|
@ -376,7 +376,7 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'lastFmApiKey' => [
|
||||
'last_fm_api_key' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('Last.fm API Key'),
|
||||
|
|
|
@ -108,6 +108,10 @@ return [
|
|||
|
||||
$config->addCustomNumericFunction('RAND', DoctrineExtensions\Query\Mysql\Rand::class);
|
||||
|
||||
if (!Doctrine\DBAL\Types\Type::hasType('uuid')) {
|
||||
Doctrine\DBAL\Types\Type::addType('uuid', Ramsey\Uuid\Doctrine\UuidType::class);
|
||||
}
|
||||
|
||||
if (!Doctrine\DBAL\Types\Type::hasType('carbon_immutable')) {
|
||||
Doctrine\DBAL\Types\Type::addType('carbon_immutable', Carbon\Doctrine\CarbonImmutableType::class);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use App\Environment;
|
|||
use App\EventDispatcher;
|
||||
use App\MessageQueue\LogWorkerExceptionSubscriber;
|
||||
use App\MessageQueue\QueueManager;
|
||||
use App\MessageQueue\ReloadSettingsMiddleware;
|
||||
use App\MessageQueue\ResetArrayCacheMiddleware;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Messenger\EventListener\StopWorkerOnTimeLimitListener;
|
||||
|
@ -42,7 +41,6 @@ class ProcessCommand extends CommandAbstract
|
|||
|
||||
$eventDispatcher->addServiceSubscriber(ClearEntityManagerSubscriber::class);
|
||||
$eventDispatcher->addServiceSubscriber(LogWorkerExceptionSubscriber::class);
|
||||
$eventDispatcher->addServiceSubscriber(ReloadSettingsMiddleware::class);
|
||||
$eventDispatcher->addServiceSubscriber(ResetArrayCacheMiddleware::class);
|
||||
|
||||
if ($runtime <= 0) {
|
||||
|
|
|
@ -21,7 +21,9 @@ class ListCommand extends CommandAbstract
|
|||
];
|
||||
$rows = [];
|
||||
|
||||
$all_settings = $settingsTableRepo->readSettingsArray();
|
||||
$settings = $settingsTableRepo->readSettings();
|
||||
$all_settings = $settingsTableRepo->toArray($settings);
|
||||
|
||||
foreach ($all_settings as $setting_key => $setting_value) {
|
||||
$value = print_r($setting_value, true);
|
||||
$value = Utilities\Strings::truncateText($value, 600);
|
||||
|
|
|
@ -73,7 +73,7 @@ class SetupCommand extends CommandAbstract
|
|||
|
||||
$this->runCommand($output, 'queue:clear');
|
||||
|
||||
$settings = $settingsRepo->readSettings(true);
|
||||
$settings = $settingsRepo->readSettings();
|
||||
$settings->setNowplaying(null);
|
||||
|
||||
$stationRepo->clearNowPlaying();
|
||||
|
@ -92,10 +92,6 @@ class SetupCommand extends CommandAbstract
|
|||
$settings->setExternalIp(null);
|
||||
}
|
||||
|
||||
if (!$update) {
|
||||
$settings->setAppUniqueIdentifier(null);
|
||||
}
|
||||
|
||||
$settingsRepo->writeSettings($settings);
|
||||
|
||||
$storageLocationRepo->createDefaultStorageLocations();
|
||||
|
|
|
@ -26,7 +26,7 @@ class InstallGeoLiteController
|
|||
$flash = $request->getFlash();
|
||||
|
||||
try {
|
||||
$settings = $form->getEntityRepository()->readSettings();
|
||||
$settings = $form->getSettingsRepository()->readSettings();
|
||||
$syncTask->updateDatabase($settings->getGeoliteLicenseKey() ?? '');
|
||||
$flash->addMessage(__('Changes saved.'), Flash::SUCCESS);
|
||||
} catch (Exception $e) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Controller\Api\AbstractApiCrudController;
|
||||
use App\Entity;
|
||||
use App\Exception\ValidationException;
|
||||
use App\Http\Response;
|
||||
|
@ -12,25 +13,18 @@ use Psr\Http\Message\ResponseInterface;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class SettingsController
|
||||
class SettingsController extends AbstractApiCrudController
|
||||
{
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
protected Serializer $serializer;
|
||||
|
||||
protected ValidatorInterface $validator;
|
||||
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator
|
||||
ValidatorInterface $validator,
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->serializer = $serializer;
|
||||
$this->validator = $validator;
|
||||
parent::__construct($em, $serializer, $validator);
|
||||
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
|
@ -51,7 +45,7 @@ class SettingsController
|
|||
public function listAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
return $response->withJson($this->serializer->normalize($settings, null));
|
||||
return $response->withJson($this->toArray($settings));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,7 +69,8 @@ class SettingsController
|
|||
*/
|
||||
public function updateAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$this->settingsRepo->writeSettings($request->getParsedBody());
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$this->editRecord($request->getParsedBody(), $settings);
|
||||
|
||||
return $response->withJson(new Entity\Api\Status());
|
||||
}
|
||||
|
|
|
@ -10,38 +10,41 @@ class Settings extends AbstractFixture
|
|||
{
|
||||
public function load(ObjectManager $em): void
|
||||
{
|
||||
$settings = [
|
||||
'baseUrl' => getenv('INIT_BASE_URL') ?? 'docker.local',
|
||||
'instanceName' => getenv('INIT_INSTANCE_NAME') ?? 'local test',
|
||||
'geoliteLicenseKey' => getenv('INIT_GEOLITE_LICENSE_KEY') ?? '',
|
||||
'setupCompleteTime' => time(),
|
||||
'preferBrowserUrl' => true,
|
||||
'useRadioProxy' => true,
|
||||
'checkForUpdates' => true,
|
||||
'externalIp' => '127.0.0.1',
|
||||
'enableAdvancedFeatures' => true,
|
||||
];
|
||||
$existingSettings = $em->getRepository(Entity\Settings::class)->findAll();
|
||||
foreach ($existingSettings as $row) {
|
||||
$em->remove($row);
|
||||
}
|
||||
|
||||
$settings = new Entity\Settings();
|
||||
$settings->setBaseUrl(getenv('INIT_BASE_URL') ?? 'docker.local');
|
||||
$settings->setInstanceName(getenv('INIT_INSTANCE_NAME') ?? 'local test');
|
||||
$settings->setGeoliteLicenseKey(getenv('INIT_GEOLITE_LICENSE_KEY') ?? '');
|
||||
|
||||
$settings->setSetupCompleteTime(time());
|
||||
$settings->setPreferBrowserUrl(true);
|
||||
$settings->setUseRadioProxy(true);
|
||||
$settings->setCheckForUpdates(true);
|
||||
$settings->setExternalIp('127.0.0.1');
|
||||
$settings->setEnableAdvancedFeatures(true);
|
||||
|
||||
$isDemoMode = (!empty(getenv('INIT_DEMO_API_KEY') ?? ''));
|
||||
if ($isDemoMode) {
|
||||
$settings['analytics'] = Entity\Analytics::LEVEL_NO_IP;
|
||||
$settings['checkForUpdates'] = false;
|
||||
$settings['publicCustomJs'] = <<<'JS'
|
||||
$settings->setAnalytics(Entity\Analytics::LEVEL_NO_IP);
|
||||
$settings->setCheckForUpdates(false);
|
||||
|
||||
$settings->setPublicCustomJs(
|
||||
<<<'JS'
|
||||
$(function() {
|
||||
if ($('body').hasClass('login-content')) {
|
||||
$('input[name="username"]').val('demo@azuracast.com');
|
||||
$('input[name="password"]').val('demo');
|
||||
}
|
||||
});
|
||||
JS;
|
||||
}
|
||||
|
||||
foreach ($settings as $setting_key => $setting_value) {
|
||||
$record = new Entity\SettingsTable($setting_key);
|
||||
$record->setSettingValue($setting_value);
|
||||
$em->persist($record);
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
$em->persist($settings);
|
||||
$em->flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Migration;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210419033245 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Settings entity migration, part 1';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE new_settings (app_unique_identifier CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', base_url VARCHAR(255) DEFAULT NULL, instance_name VARCHAR(255) DEFAULT NULL, prefer_browser_url TINYINT(1) NOT NULL, use_radio_proxy TINYINT(1) NOT NULL, history_keep_days SMALLINT NOT NULL, always_use_ssl TINYINT(1) NOT NULL, api_access_control VARCHAR(255) DEFAULT NULL, enable_websockets TINYINT(1) NOT NULL, analytics VARCHAR(50) DEFAULT NULL, check_for_updates TINYINT(1) NOT NULL, update_results LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:json)\', update_last_run INT NOT NULL, public_theme VARCHAR(50) DEFAULT NULL, hide_album_art TINYINT(1) NOT NULL, homepage_redirect_url VARCHAR(255) DEFAULT NULL, default_album_art_url VARCHAR(255) DEFAULT NULL, use_external_album_art_when_processing_media TINYINT(1) NOT NULL, use_external_album_art_in_apis TINYINT(1) NOT NULL, last_fm_api_key VARCHAR(255) DEFAULT NULL, hide_product_name TINYINT(1) NOT NULL, public_custom_css LONGTEXT DEFAULT NULL, public_custom_js LONGTEXT DEFAULT NULL, internal_custom_css LONGTEXT DEFAULT NULL, backup_enabled TINYINT(1) NOT NULL, backup_time_code VARCHAR(4) DEFAULT NULL, backup_exclude_media TINYINT(1) NOT NULL, backup_keep_copies SMALLINT NOT NULL, backup_storage_location INT DEFAULT NULL, backup_last_run INT NOT NULL, backup_last_result LONGTEXT DEFAULT NULL, backup_last_output LONGTEXT DEFAULT NULL, setup_complete_time INT NOT NULL, nowplaying LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:json)\', sync_nowplaying_last_run INT NOT NULL, sync_short_last_run INT NOT NULL, sync_medium_last_run INT NOT NULL, sync_long_last_run INT NOT NULL, external_ip VARCHAR(45) DEFAULT NULL, geolite_license_key VARCHAR(255) DEFAULT NULL, geolite_last_run INT NOT NULL, enable_advanced_features TINYINT(1) NOT NULL, mail_enabled TINYINT(1) NOT NULL, mail_sender_name VARCHAR(255) DEFAULT NULL, mail_sender_email VARCHAR(255) DEFAULT NULL, mail_smtp_host VARCHAR(255) DEFAULT NULL, mail_smtp_port SMALLINT NOT NULL, mail_smtp_username VARCHAR(255) DEFAULT NULL, mail_smtp_password VARCHAR(255) DEFAULT NULL, mail_smtp_secure TINYINT(1) NOT NULL, avatar_service VARCHAR(25) DEFAULT NULL, avatar_default_url VARCHAR(255) DEFAULT NULL, PRIMARY KEY(app_unique_identifier)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_general_ci` ENGINE = InnoDB');
|
||||
$this->addSql('RENAME TABLE settings TO old_settings');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('DROP TABLE new_settings');
|
||||
$this->addSql('RENAME TABLE old_settings TO settings');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Migration;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210419043231 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Settings entity migration, part 2';
|
||||
}
|
||||
|
||||
public function preUp(Schema $schema): void
|
||||
{
|
||||
$oldSettings = [];
|
||||
|
||||
$oldSettingsRaw = $this->connection->fetchAllAssociative(
|
||||
'SELECT setting_key, setting_value FROM old_settings'
|
||||
);
|
||||
|
||||
foreach ($oldSettingsRaw as $row) {
|
||||
$key = $row['setting_key'];
|
||||
$key = preg_replace('~(?<=\\w)([A-Z])~u', '_$1', $key);
|
||||
$key = mb_strtolower($key);
|
||||
|
||||
$value = $row['setting_value'];
|
||||
$value = ($value === null || $value === '')
|
||||
? null
|
||||
: json_decode($value, true);
|
||||
|
||||
$oldSettings[$key] = $value;
|
||||
}
|
||||
|
||||
$newSettings = [];
|
||||
|
||||
$appUniqueIdentifier = $oldSettings['app_unique_identifier'] ?? null;
|
||||
if (empty($appUniqueIdentifier)) {
|
||||
$appUniqueIdentifier = Uuid::uuid4()->toString();
|
||||
}
|
||||
$newSettings['app_unique_identifier'] = $appUniqueIdentifier;
|
||||
|
||||
$textFields = [
|
||||
'public_custom_css',
|
||||
'public_custom_js',
|
||||
'internal_custom_css',
|
||||
'backup_last_result',
|
||||
'backup_last_output',
|
||||
];
|
||||
|
||||
$stringFields = [
|
||||
'base_url' => 255,
|
||||
'instance_name' => 255,
|
||||
'api_access_control' => 255,
|
||||
'analytics' => 50,
|
||||
'public_theme' => 50,
|
||||
'homepage_redirect_url' => 255,
|
||||
'default_album_art_url' => 255,
|
||||
'last_fm_api_key' => 255,
|
||||
'backup_time_code' => 4,
|
||||
'external_ip' => 45,
|
||||
'geolite_license_key' => 255,
|
||||
'mail_sender_name' => 255,
|
||||
'mail_sender_email' => 255,
|
||||
'mail_smtp_host' => 255,
|
||||
'mail_smtp_username' => 255,
|
||||
'mail_smtp_password' => 255,
|
||||
'avatar_service' => 25,
|
||||
'avatar_default_url' => 255,
|
||||
];
|
||||
|
||||
$boolFields = [
|
||||
'prefer_browser_url',
|
||||
'use_radio_proxy',
|
||||
'always_use_ssl',
|
||||
'enable_websockets',
|
||||
'check_for_updates',
|
||||
'hide_album_art',
|
||||
'use_external_album_art_when_processing_media',
|
||||
'use_external_album_art_in_apis',
|
||||
'hide_product_name',
|
||||
'backup_enabled',
|
||||
'backup_exclude_media',
|
||||
'enable_advanced_features',
|
||||
'mail_enabled',
|
||||
'mail_smtp_secure',
|
||||
];
|
||||
|
||||
$smallIntFields = [
|
||||
'history_keep_days',
|
||||
'backup_keep_copies',
|
||||
'mail_smtp_port',
|
||||
];
|
||||
|
||||
$intFields = [
|
||||
'update_last_run',
|
||||
'backup_storage_location',
|
||||
'backup_last_run',
|
||||
'setup_complete_time',
|
||||
'sync_nowplaying_last_run',
|
||||
'sync_short_last_run',
|
||||
'sync_medium_last_run',
|
||||
'sync_long_last_run',
|
||||
'geolite_last_run',
|
||||
];
|
||||
|
||||
foreach ($textFields as $field) {
|
||||
$value = $oldSettings[$field] ?? null;
|
||||
if (null === $value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newSettings[$field] = $value;
|
||||
}
|
||||
|
||||
foreach ($stringFields as $field => $length) {
|
||||
$value = $oldSettings[$field] ?? null;
|
||||
if (null === $value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newSettings[$field] = mb_substr($value, 0, $length, 'UTF-8');
|
||||
}
|
||||
|
||||
foreach ($boolFields as $field) {
|
||||
$value = $oldSettings[$field] ?? null;
|
||||
if (null === $value) {
|
||||
$newSettings[$field] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
$newSettings[$field] = $value ? 1 : 0;
|
||||
}
|
||||
|
||||
foreach ($smallIntFields as $field) {
|
||||
$value = $oldSettings[$field] ?? null;
|
||||
if (null === $value) {
|
||||
$newSettings[$field] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = (int)$value;
|
||||
if ($value > 32767) {
|
||||
$value = 32767;
|
||||
}
|
||||
|
||||
$newSettings[$field] = $value;
|
||||
}
|
||||
|
||||
foreach ($intFields as $field) {
|
||||
$value = $oldSettings[$field] ?? null;
|
||||
if (null === $value) {
|
||||
$value = 0;
|
||||
}
|
||||
|
||||
$newSettings[$field] = (int)$value;
|
||||
}
|
||||
|
||||
$this->connection->executeQuery('DELETE FROM new_settings');
|
||||
$this->connection->insert('new_settings', $newSettings);
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('RENAME TABLE new_settings TO settings');
|
||||
$this->addSql('DROP TABLE old_settings');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('RENAME TABLE settings TO new_settings');
|
||||
$this->addSql('CREATE TABLE old_settings (setting_key VARCHAR(64) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_general_ci`, setting_value LONGTEXT CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_general_ci` COMMENT \'(DC2Type:json)\', PRIMARY KEY(setting_key)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
|
||||
}
|
||||
}
|
|
@ -2,84 +2,44 @@
|
|||
|
||||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Annotations\AuditLog\AuditIgnore;
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Environment;
|
||||
use App\Exception\ValidationException;
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use ReflectionObject;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class SettingsRepository extends Repository
|
||||
{
|
||||
protected static ?Entity\Settings $instance = null;
|
||||
|
||||
protected const CACHE_KEY = 'settings';
|
||||
|
||||
protected const CACHE_TTL = 600;
|
||||
|
||||
protected CacheInterface $cache;
|
||||
|
||||
protected ValidatorInterface $validator;
|
||||
|
||||
protected Reader $annotationReader;
|
||||
|
||||
protected string $entityClass = Entity\SettingsTable::class;
|
||||
protected string $entityClass = Entity\Settings::class;
|
||||
|
||||
public function __construct(
|
||||
ReloadableEntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
Environment $environment,
|
||||
LoggerInterface $logger,
|
||||
CacheInterface $cache,
|
||||
ValidatorInterface $validator,
|
||||
Reader $annotationReader
|
||||
ValidatorInterface $validator
|
||||
) {
|
||||
parent::__construct($em, $serializer, $environment, $logger);
|
||||
|
||||
$this->cache = $cache;
|
||||
$this->validator = $validator;
|
||||
$this->annotationReader = $annotationReader;
|
||||
}
|
||||
|
||||
public function readSettings(bool $reload = false): Entity\Settings
|
||||
public function readSettings(): Entity\Settings
|
||||
{
|
||||
if ($reload || null === self::$instance) {
|
||||
self::$instance = $this->arrayToObject($this->readSettingsArray());
|
||||
$settings = $this->repository->findOneBy([]);
|
||||
|
||||
if (!($settings instanceof Entity\Settings)) {
|
||||
$settings = new Entity\Settings();
|
||||
$this->em->persist($settings);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function clearSettingsInstance(): void
|
||||
{
|
||||
self::$instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function readSettingsArray(bool $reload = false): array
|
||||
{
|
||||
$allRecords = $this->cache->get(self::CACHE_KEY);
|
||||
|
||||
if ($reload || null === $allRecords) {
|
||||
$allRecords = [];
|
||||
foreach ($this->repository->findAll() as $record) {
|
||||
/** @var Entity\SettingsTable $record */
|
||||
$allRecords[$record->getSettingKey()] = $record->getSettingValue();
|
||||
}
|
||||
|
||||
$this->cache->set(self::CACHE_KEY, $allRecords, self::CACHE_TTL);
|
||||
}
|
||||
|
||||
return $allRecords;
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,7 +48,10 @@ class SettingsRepository extends Repository
|
|||
public function writeSettings($settingsObj): void
|
||||
{
|
||||
if (is_array($settingsObj)) {
|
||||
$settingsObj = $this->arrayToObject($settingsObj, $this->readSettings(true));
|
||||
$settings = $this->readSettings();
|
||||
$settings = $this->fromArray($settingsObj, $settings);
|
||||
} else {
|
||||
$settings = $settingsObj;
|
||||
}
|
||||
|
||||
$errors = $this->validator->validate($settingsObj);
|
||||
|
@ -98,102 +61,7 @@ class SettingsRepository extends Repository
|
|||
throw $e;
|
||||
}
|
||||
|
||||
$settings = $this->objectToArray($settingsObj);
|
||||
|
||||
$currentRecords = $this->repository->findAll();
|
||||
$allRecords = [];
|
||||
foreach ($currentRecords as $record) {
|
||||
/** @var Entity\SettingsTable $record */
|
||||
$allRecords[$record->getSettingKey()] = $record;
|
||||
}
|
||||
|
||||
$changes = [];
|
||||
foreach ($settings as $settingKey => $settingValue) {
|
||||
if (isset($allRecords[$settingKey])) {
|
||||
$record = $allRecords[$settingKey];
|
||||
$prev = $record->getSettingValue();
|
||||
} else {
|
||||
$record = new Entity\SettingsTable($settingKey);
|
||||
$prev = null;
|
||||
}
|
||||
|
||||
$record->setSettingValue($settingValue);
|
||||
$this->em->persist($record);
|
||||
|
||||
// Include change in audit log.
|
||||
if ($prev !== $settingValue) {
|
||||
$changes[$settingKey] = [$prev, $settingValue];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($changes)) {
|
||||
// Ignore any properties tagged with "AuditIgnore".
|
||||
$reflectionClass = new ReflectionObject($settingsObj);
|
||||
$loggableChanges = array_filter(
|
||||
$changes,
|
||||
function ($settingKey) use ($reflectionClass) {
|
||||
$reflectionProp = $reflectionClass->getProperty($settingKey);
|
||||
$ignoreAnnotation = $this->annotationReader->getPropertyAnnotation(
|
||||
$reflectionProp,
|
||||
AuditIgnore::class
|
||||
);
|
||||
return (null === $ignoreAnnotation);
|
||||
},
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
|
||||
if (!empty($loggableChanges)) {
|
||||
$auditLog = new Entity\AuditLog(
|
||||
Entity\AuditLog::OPER_UPDATE,
|
||||
Entity\SettingsTable::class,
|
||||
'Settings',
|
||||
null,
|
||||
null,
|
||||
$loggableChanges
|
||||
);
|
||||
|
||||
$this->em->persist($auditLog);
|
||||
}
|
||||
}
|
||||
|
||||
$this->em->persist($settings);
|
||||
$this->em->flush();
|
||||
$this->cache->delete(self::CACHE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Settings $settings
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
protected function objectToArray(Entity\Settings $settings): array
|
||||
{
|
||||
$reflectionClass = new ReflectionObject($settings);
|
||||
$array = $this->serializer->normalize($settings, null);
|
||||
|
||||
// Prevent serializer from returning things that aren't actually properties on the class.
|
||||
return array_filter(
|
||||
$array,
|
||||
function ($key) use ($reflectionClass) {
|
||||
return $reflectionClass->hasProperty($key);
|
||||
},
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
}
|
||||
|
||||
protected function arrayToObject(array $settings, ?Entity\Settings $existingSettings = null): Entity\Settings
|
||||
{
|
||||
$settings = array_filter(
|
||||
$settings,
|
||||
function ($value) {
|
||||
return null !== $value;
|
||||
}
|
||||
);
|
||||
|
||||
$context = [];
|
||||
if (null !== $existingSettings) {
|
||||
$context[ObjectNormalizer::OBJECT_TO_POPULATE] = $existingSettings;
|
||||
}
|
||||
|
||||
return $this->serializer->denormalize($settings, Entity\Settings::class, null, $context);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table(name="settings")
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
class SettingsTable
|
||||
{
|
||||
/**
|
||||
* @ORM\Column(name="setting_key", type="string", length=64)
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="NONE")
|
||||
* @var string
|
||||
*/
|
||||
protected $setting_key;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="setting_value", type="json", nullable=true)
|
||||
* @var mixed
|
||||
*/
|
||||
protected $setting_value;
|
||||
|
||||
public function __construct(string $setting_key)
|
||||
{
|
||||
$this->setting_key = $setting_key;
|
||||
}
|
||||
|
||||
public function getSettingKey(): string
|
||||
{
|
||||
return $this->setting_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSettingValue()
|
||||
{
|
||||
return $this->setting_value;
|
||||
}
|
||||
|
||||
public function setSettingValue($setting_value): void
|
||||
{
|
||||
$this->setting_value = $setting_value;
|
||||
}
|
||||
}
|
|
@ -6,34 +6,32 @@ use App\Entity;
|
|||
use App\Environment;
|
||||
use App\Http\ServerRequest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
abstract class AbstractSettingsForm extends Form
|
||||
abstract class AbstractSettingsForm extends EntityForm
|
||||
{
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
protected Environment $environment;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
array $formConfig
|
||||
array $options = [],
|
||||
?array $defaults = null
|
||||
) {
|
||||
parent::__construct($formConfig);
|
||||
parent::__construct($em, $serializer, $validator, $options, $defaults);
|
||||
|
||||
$this->em = $em;
|
||||
$this->environment = $environment;
|
||||
$this->entityClass = Entity\Settings::class;
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
$this->environment = $environment;
|
||||
}
|
||||
|
||||
public function getEntityManager(): EntityManagerInterface
|
||||
{
|
||||
return $this->em;
|
||||
}
|
||||
|
||||
public function getEntityRepository(): Entity\Repository\SettingsRepository
|
||||
public function getSettingsRepository(): Entity\Repository\SettingsRepository
|
||||
{
|
||||
return $this->settingsRepo;
|
||||
}
|
||||
|
@ -43,26 +41,19 @@ abstract class AbstractSettingsForm extends Form
|
|||
return $this->environment;
|
||||
}
|
||||
|
||||
public function process(ServerRequest $request): bool
|
||||
/** @inheritDoc */
|
||||
public function process(ServerRequest $request, $record = null)
|
||||
{
|
||||
// Populate the form with existing values (if they exist).
|
||||
$defaults = $this->settingsRepo->readSettingsArray();
|
||||
if (null === $record) {
|
||||
$record = $this->settingsRepo->readSettings();
|
||||
}
|
||||
|
||||
// Use current URI from request if the base URL isn't set.
|
||||
if (empty($defaults['baseUrl'])) {
|
||||
/** @var Entity\Settings $record */
|
||||
if (empty($record->getBaseUrl())) {
|
||||
$currentUri = $request->getUri()->withPath('');
|
||||
$defaults['baseUrl'] = (string)$currentUri;
|
||||
$record->setBaseUrl((string)$currentUri);
|
||||
}
|
||||
|
||||
$this->populate($defaults);
|
||||
|
||||
// Handle submission.
|
||||
if ('POST' === $request->getMethod() && $this->isValid($request->getParsedBody())) {
|
||||
$data = $this->getValues();
|
||||
$this->settingsRepo->writeSettings($data);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return parent::process($request, $record);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,18 @@ use App\Config;
|
|||
use App\Entity;
|
||||
use App\Environment;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class BackupSettingsForm extends AbstractSettingsForm
|
||||
{
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Entity\Repository\StorageLocationRepository $storageLocationRepo,
|
||||
Environment $environment,
|
||||
Entity\Repository\StorageLocationRepository $storageLocationRepo,
|
||||
Config $config
|
||||
) {
|
||||
$formConfig = $config->get(
|
||||
|
@ -28,11 +32,6 @@ class BackupSettingsForm extends AbstractSettingsForm
|
|||
]
|
||||
);
|
||||
|
||||
parent::__construct(
|
||||
$em,
|
||||
$settingsRepo,
|
||||
$environment,
|
||||
$formConfig
|
||||
);
|
||||
parent::__construct($em, $serializer, $validator, $settingsRepo, $environment, $formConfig);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,15 @@ use App\Config;
|
|||
use App\Entity;
|
||||
use App\Environment;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class BrandingSettingsForm extends AbstractSettingsForm
|
||||
{
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
Config $config
|
||||
|
@ -22,11 +26,6 @@ class BrandingSettingsForm extends AbstractSettingsForm
|
|||
]
|
||||
);
|
||||
|
||||
parent::__construct(
|
||||
$em,
|
||||
$settingsRepo,
|
||||
$environment,
|
||||
$formConfig
|
||||
);
|
||||
parent::__construct($em, $serializer, $validator, $settingsRepo, $environment, $formConfig);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ use App\Entity;
|
|||
use App\Environment;
|
||||
use App\Sync\Task\UpdateGeoLiteTask;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class GeoLiteSettingsForm extends AbstractSettingsForm
|
||||
{
|
||||
|
@ -14,6 +16,8 @@ class GeoLiteSettingsForm extends AbstractSettingsForm
|
|||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
Config $config,
|
||||
|
@ -21,12 +25,7 @@ class GeoLiteSettingsForm extends AbstractSettingsForm
|
|||
) {
|
||||
$formConfig = $config->get('forms/install_geolite');
|
||||
|
||||
parent::__construct(
|
||||
$em,
|
||||
$settingsRepo,
|
||||
$environment,
|
||||
$formConfig
|
||||
);
|
||||
parent::__construct($em, $serializer, $validator, $settingsRepo, $environment, $formConfig);
|
||||
|
||||
$this->syncTask = $syncTask;
|
||||
}
|
||||
|
|
|
@ -8,11 +8,15 @@ use App\Environment;
|
|||
use App\Http\ServerRequest;
|
||||
use App\Version;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class SettingsForm extends AbstractSettingsForm
|
||||
{
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
Environment $environment,
|
||||
Version $version,
|
||||
|
@ -26,18 +30,14 @@ class SettingsForm extends AbstractSettingsForm
|
|||
]
|
||||
);
|
||||
|
||||
parent::__construct(
|
||||
$em,
|
||||
$settingsRepo,
|
||||
$environment,
|
||||
$formConfig
|
||||
);
|
||||
parent::__construct($em, $serializer, $validator, $settingsRepo, $environment, $formConfig);
|
||||
}
|
||||
|
||||
public function process(ServerRequest $request): bool
|
||||
/** @inheritDoc */
|
||||
public function process(ServerRequest $request, $record = null)
|
||||
{
|
||||
if ('https' !== $request->getUri()->getScheme()) {
|
||||
$alwaysUseSsl = $this->getField('alwaysUseSsl');
|
||||
$alwaysUseSsl = $this->getField('always_use_ssl');
|
||||
$alwaysUseSsl->setAttribute('disabled', 'disabled');
|
||||
$alwaysUseSsl->setOption(
|
||||
'description',
|
||||
|
@ -45,6 +45,6 @@ class SettingsForm extends AbstractSettingsForm
|
|||
);
|
||||
}
|
||||
|
||||
return parent::process($request);
|
||||
return parent::process($request, $record);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class Router implements RouterInterface
|
|||
|
||||
protected ?ServerRequestInterface $currentRequest = null;
|
||||
|
||||
protected Entity\Settings $settings;
|
||||
protected Entity\Repository\SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(
|
||||
Environment $environment,
|
||||
|
@ -30,7 +30,7 @@ class Router implements RouterInterface
|
|||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
) {
|
||||
$this->environment = $environment;
|
||||
$this->settings = $settingsRepo->readSettings();
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
$this->routeParser = $app->getRouteCollector()->getRouteParser();
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,9 @@ class Router implements RouterInterface
|
|||
|
||||
public function getBaseUrl(bool $useRequest = true): UriInterface
|
||||
{
|
||||
$settingsBaseUrl = $this->settings->getBaseUrl();
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
|
||||
$settingsBaseUrl = $settings->getBaseUrl();
|
||||
if (!empty($settingsBaseUrl)) {
|
||||
if (strpos($settingsBaseUrl, 'http') !== 0) {
|
||||
$settingsBaseUrl = 'http://' . $settingsBaseUrl;
|
||||
|
@ -166,7 +168,7 @@ class Router implements RouterInterface
|
|||
$baseUrl = new Uri('');
|
||||
}
|
||||
|
||||
$useHttps = $this->settings->getAlwaysUseSsl();
|
||||
$useHttps = $settings->getAlwaysUseSsl();
|
||||
|
||||
if ($useRequest && $this->currentRequest instanceof ServerRequestInterface) {
|
||||
$currentUri = $this->currentRequest->getUri();
|
||||
|
@ -175,7 +177,7 @@ class Router implements RouterInterface
|
|||
$useHttps = true;
|
||||
}
|
||||
|
||||
$preferBrowserUrl = $this->settings->getPreferBrowserUrl();
|
||||
$preferBrowserUrl = $settings->getPreferBrowserUrl();
|
||||
if ($preferBrowserUrl || $baseUrl->getHost() === '') {
|
||||
$ignoredHosts = ['web', 'nginx', 'localhost'];
|
||||
if (!in_array($currentUri->getHost(), $ignoredHosts, true)) {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\MessageQueue;
|
||||
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
|
||||
|
||||
class ReloadSettingsMiddleware implements EventSubscriberInterface
|
||||
{
|
||||
protected SettingsRepository $settingsRepo;
|
||||
|
||||
public function __construct(SettingsRepository $settingsRepo)
|
||||
{
|
||||
$this->settingsRepo = $settingsRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
WorkerMessageReceivedEvent::class => 'resetSettings',
|
||||
];
|
||||
}
|
||||
|
||||
public function resetSettings(WorkerMessageReceivedEvent $event): void
|
||||
{
|
||||
$this->settingsRepo->clearSettingsInstance();
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ use App\Version;
|
|||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
class AzuraCastCentral
|
||||
{
|
||||
|
@ -59,6 +58,13 @@ class AzuraCastCentral
|
|||
$request_body['release'] = Version::FALLBACK_VERSION;
|
||||
}
|
||||
|
||||
$this->logger->debug(
|
||||
'Update request body',
|
||||
[
|
||||
'body' => $request_body,
|
||||
]
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request(
|
||||
'POST',
|
||||
|
@ -80,16 +86,7 @@ class AzuraCastCentral
|
|||
public function getUniqueIdentifier(): string
|
||||
{
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$appUuid = $settings->getAppUniqueIdentifier();
|
||||
|
||||
if (empty($appUuid)) {
|
||||
$appUuid = Uuid::uuid4()->toString();
|
||||
|
||||
$settings->setAppUniqueIdentifier($appUuid);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
||||
return $appUuid;
|
||||
return (string)$settings->getAppUniqueIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -145,7 +145,7 @@ class Runner
|
|||
gc_collect_cycles();
|
||||
}
|
||||
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->updateSyncLastRunTime($type);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
} finally {
|
||||
|
|
|
@ -102,7 +102,7 @@ class NowPlayingTask extends AbstractTask implements EventSubscriberInterface
|
|||
|
||||
$this->cache->set('nowplaying', $nowplaying, 120);
|
||||
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->setNowplaying($nowplaying);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ class RunBackupTask extends AbstractTask
|
|||
public function __invoke(Message\AbstractMessage $message): void
|
||||
{
|
||||
if ($message instanceof Message\BackupMessage) {
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->updateBackupLastRun();
|
||||
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
|
@ -53,7 +53,7 @@ class RunBackupTask extends AbstractTask
|
|||
$message->storageLocationId
|
||||
);
|
||||
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->setBackupLastResult($result_code);
|
||||
$settings->setBackupLastOutput($result_output);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
|
|
|
@ -62,7 +62,7 @@ class UpdateGeoLiteTask extends AbstractTask
|
|||
);
|
||||
}
|
||||
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->updateGeoliteLastRun();
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ class LocalWebhookHandler
|
|||
|
||||
$this->cache->set('nowplaying', $np_new, 120);
|
||||
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->setNowplaying($np_new);
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
|
|
@ -48,12 +48,12 @@ abstract class CestAbstract
|
|||
{
|
||||
$I->wantTo('Start with an incomplete setup.');
|
||||
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$this->_cleanTables();
|
||||
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->setSetupCompleteTime(0);
|
||||
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
|
||||
$this->_cleanTables();
|
||||
}
|
||||
|
||||
protected function setupComplete(FunctionalTester $I): void
|
||||
|
@ -93,9 +93,9 @@ abstract class CestAbstract
|
|||
$this->test_station = $this->stationRepo->create($test_station);
|
||||
|
||||
// Set settings.
|
||||
$settings = $this->settingsRepo->readSettings(true);
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$settings->updateSetupComplete();
|
||||
$settings->setBaseUrl('localhost');
|
||||
$settings->setBaseUrl('http://localhost');
|
||||
$this->settingsRepo->writeSettings($settings);
|
||||
}
|
||||
|
||||
|
@ -136,11 +136,14 @@ abstract class CestAbstract
|
|||
Entity\User::class,
|
||||
Entity\Role::class,
|
||||
Entity\Station::class,
|
||||
Entity\Settings::class,
|
||||
];
|
||||
|
||||
foreach ($clean_tables as $clean_table) {
|
||||
$this->em->createQuery('DELETE FROM ' . $clean_table . ' t')->execute();
|
||||
}
|
||||
|
||||
$this->em->clear();
|
||||
}
|
||||
|
||||
protected function login(FunctionalTester $I): void
|
||||
|
|
Loading…
Reference in New Issue