System-Wide Strict Types (#4405)
This commit is contained in:
parent
64b7d83258
commit
5cbacd5df6
|
@ -1,7 +1,10 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
class Spinner
|
||||
{
|
||||
|
|
|
@ -102,17 +102,19 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/AzuraCast/azuraforms.git",
|
||||
"reference": "6fb50189f7286bdf6bca63047bc145867051c0a1"
|
||||
"reference": "8a32a97e4d633eed0dca09ea1107d88256281aed"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/AzuraCast/azuraforms/zipball/6fb50189f7286bdf6bca63047bc145867051c0a1",
|
||||
"reference": "6fb50189f7286bdf6bca63047bc145867051c0a1",
|
||||
"url": "https://api.github.com/repos/AzuraCast/azuraforms/zipball/8a32a97e4d633eed0dca09ea1107d88256281aed",
|
||||
"reference": "8a32a97e4d633eed0dca09ea1107d88256281aed",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": ">=7.4"
|
||||
"league/mime-type-detection": "^1.7",
|
||||
"php": ">=7.4",
|
||||
"psr/http-message": ">1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-console-highlighter": "^0.5.0",
|
||||
|
@ -165,7 +167,7 @@
|
|||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-04-26T10:41:32+00:00"
|
||||
"time": "2021-07-18T17:02:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "azuracast/flysystem-v2-extensions",
|
||||
|
|
|
@ -148,12 +148,12 @@ return [
|
|||
return '$(function () { ' . implode('', $notifies) . ' });';
|
||||
},
|
||||
function (Request $request) {
|
||||
/** @var Locale|null $locale */
|
||||
/** @var App\Locale|null $locale */
|
||||
$localeObj = $request->getAttribute(ServerRequest::ATTR_LOCALE);
|
||||
|
||||
$locale = ($localeObj instanceof App\Locale)
|
||||
? (string)$localeObj
|
||||
: Locale::DEFAULT_LOCALE;
|
||||
: App\Locale::DEFAULT_LOCALE;
|
||||
|
||||
$locale = explode('.', $locale, 2)[0];
|
||||
$localeShort = substr($locale, 0, 2);
|
||||
|
|
|
@ -17,32 +17,32 @@ return function (App\Event\BuildAdminMenu $e) {
|
|||
'items' => [
|
||||
'settings' => [
|
||||
'label' => __('System Settings'),
|
||||
'url' => $router->named('admin:settings:index'),
|
||||
'url' => (string)$router->named('admin:settings:index'),
|
||||
'permission' => Acl::GLOBAL_SETTINGS,
|
||||
],
|
||||
'branding' => [
|
||||
'label' => __('Custom Branding'),
|
||||
'url' => $router->named('admin:branding:index'),
|
||||
'url' => (string)$router->named('admin:branding:index'),
|
||||
'permission' => Acl::GLOBAL_SETTINGS,
|
||||
],
|
||||
'logs' => [
|
||||
'label' => __('System Logs'),
|
||||
'url' => $router->named('admin:logs:index'),
|
||||
'url' => (string)$router->named('admin:logs:index'),
|
||||
'permission' => Acl::GLOBAL_LOGS,
|
||||
],
|
||||
'storage_locations' => [
|
||||
'label' => __('Storage Locations'),
|
||||
'url' => $router->named('admin:storage_locations:index'),
|
||||
'url' => (string)$router->named('admin:storage_locations:index'),
|
||||
'permission' => Acl::GLOBAL_STORAGE_LOCATIONS,
|
||||
],
|
||||
'backups' => [
|
||||
'label' => __('Backups'),
|
||||
'url' => $router->named('admin:backups:index'),
|
||||
'url' => (string)$router->named('admin:backups:index'),
|
||||
'permission' => Acl::GLOBAL_BACKUPS,
|
||||
],
|
||||
'debug' => [
|
||||
'label' => __('System Debugger'),
|
||||
'url' => $router->named('admin:debug:index'),
|
||||
'url' => (string)$router->named('admin:debug:index'),
|
||||
'permission' => Acl::GLOBAL_ALL,
|
||||
],
|
||||
],
|
||||
|
@ -53,22 +53,22 @@ return function (App\Event\BuildAdminMenu $e) {
|
|||
'items' => [
|
||||
'manage_users' => [
|
||||
'label' => __('User Accounts'),
|
||||
'url' => $router->named('admin:users:index'),
|
||||
'url' => (string)$router->named('admin:users:index'),
|
||||
'permission' => Acl::GLOBAL_ALL,
|
||||
],
|
||||
'permissions' => [
|
||||
'label' => __('Permissions'),
|
||||
'url' => $router->named('admin:permissions:index'),
|
||||
'url' => (string)$router->named('admin:permissions:index'),
|
||||
'permission' => Acl::GLOBAL_ALL,
|
||||
],
|
||||
'auditlog' => [
|
||||
'label' => __('Audit Log'),
|
||||
'url' => $router->named('admin:auditlog:index'),
|
||||
'url' => (string)$router->named('admin:auditlog:index'),
|
||||
'permission' => Acl::GLOBAL_LOGS,
|
||||
],
|
||||
'api_keys' => [
|
||||
'label' => __('API Keys'),
|
||||
'url' => $router->named('admin:api:index'),
|
||||
'url' => (string)$router->named('admin:api:index'),
|
||||
'permission' => Acl::GLOBAL_API_KEYS,
|
||||
],
|
||||
],
|
||||
|
@ -79,27 +79,27 @@ return function (App\Event\BuildAdminMenu $e) {
|
|||
'items' => [
|
||||
'manage_stations' => [
|
||||
'label' => __('Stations'),
|
||||
'url' => $router->named('admin:stations:index'),
|
||||
'url' => (string)$router->named('admin:stations:index'),
|
||||
'permission' => Acl::GLOBAL_STATIONS,
|
||||
],
|
||||
'custom_fields' => [
|
||||
'label' => __('Custom Fields'),
|
||||
'url' => $router->named('admin:custom_fields:index'),
|
||||
'url' => (string)$router->named('admin:custom_fields:index'),
|
||||
'permission' => Acl::GLOBAL_CUSTOM_FIELDS,
|
||||
],
|
||||
'relays' => [
|
||||
'label' => __('Connected AzuraRelays'),
|
||||
'url' => $router->named('admin:relays:index'),
|
||||
'url' => (string)$router->named('admin:relays:index'),
|
||||
'permission' => Acl::GLOBAL_STATIONS,
|
||||
],
|
||||
'shoutcast' => [
|
||||
'label' => __('Install SHOUTcast'),
|
||||
'url' => $router->named('admin:install_shoutcast:index'),
|
||||
'url' => (string)$router->named('admin:install_shoutcast:index'),
|
||||
'permission' => Acl::GLOBAL_ALL,
|
||||
],
|
||||
'geolite' => [
|
||||
'label' => __('Install GeoLite IP Database'),
|
||||
'url' => $router->named('admin:install_geolite:index'),
|
||||
'url' => (string)$router->named('admin:install_geolite:index'),
|
||||
'permission' => Acl::GLOBAL_ALL,
|
||||
],
|
||||
],
|
||||
|
|
|
@ -21,7 +21,7 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'label' => __('Start Station'),
|
||||
'title' => __('Ready to start broadcasting? Click to start your station.'),
|
||||
'icon' => 'refresh',
|
||||
'url' => $router->fromHere('api:stations:restart'),
|
||||
'url' => (string)$router->fromHere('api:stations:restart'),
|
||||
'class' => 'api-call text-success',
|
||||
'confirm' => __('Restart broadcasting? This will disconnect any current listeners.'),
|
||||
'visible' => !$station->getHasStarted(),
|
||||
|
@ -31,7 +31,7 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'label' => __('Restart to Apply Changes'),
|
||||
'title' => __('Click to restart your station and apply configuration changes.'),
|
||||
'icon' => 'refresh',
|
||||
'url' => $router->fromHere('api:stations:restart'),
|
||||
'url' => (string)$router->fromHere('api:stations:restart'),
|
||||
'class' => 'api-call text-warning',
|
||||
'confirm' => __('Restart broadcasting? This will disconnect any current listeners.'),
|
||||
'visible' => $station->getHasStarted() && $station->getNeedsRestart(),
|
||||
|
@ -40,53 +40,53 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'profile' => [
|
||||
'label' => __('Profile'),
|
||||
'icon' => 'image',
|
||||
'url' => $router->fromHere('stations:profile:index'),
|
||||
'url' => (string)$router->fromHere('stations:profile:index'),
|
||||
],
|
||||
'public' => [
|
||||
'label' => __('Public Page'),
|
||||
'icon' => 'public',
|
||||
'url' => $router->named('public:index', ['station_id' => $station->getShortName()]),
|
||||
'url' => (string)$router->named('public:index', ['station_id' => $station->getShortName()]),
|
||||
'external' => true,
|
||||
'visible' => $station->getEnablePublicPage(),
|
||||
],
|
||||
'ondemand' => [
|
||||
'label' => __('On-Demand Media'),
|
||||
'icon' => 'cloud_download',
|
||||
'url' => $router->named('public:ondemand', ['station_id' => $station->getShortName()]),
|
||||
'url' => (string)$router->named('public:ondemand', ['station_id' => $station->getShortName()]),
|
||||
'external' => true,
|
||||
'visible' => $station->getEnableOnDemand(),
|
||||
],
|
||||
'files' => [
|
||||
'label' => __('Music Files'),
|
||||
'icon' => 'library_music',
|
||||
'url' => $router->fromHere('stations:files:index'),
|
||||
'url' => (string)$router->fromHere('stations:files:index'),
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'permission' => Acl::STATION_MEDIA,
|
||||
],
|
||||
'playlists' => [
|
||||
'label' => __('Playlists'),
|
||||
'icon' => 'queue_music',
|
||||
'url' => $router->fromHere('stations:playlists:index'),
|
||||
'url' => (string)$router->fromHere('stations:playlists:index'),
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'permission' => Acl::STATION_MEDIA,
|
||||
],
|
||||
'podcasts' => [
|
||||
'label' => __('Podcasts (Beta)'),
|
||||
'icon' => 'cast',
|
||||
'url' => $router->fromHere('stations:podcasts:index'),
|
||||
'url' => (string)$router->fromHere('stations:podcasts:index'),
|
||||
'permission' => Acl::STATION_PODCASTS,
|
||||
],
|
||||
'streamers' => [
|
||||
'label' => __('Streamer/DJ Accounts'),
|
||||
'icon' => 'mic',
|
||||
'url' => $router->fromHere('stations:streamers:index'),
|
||||
'url' => (string)$router->fromHere('stations:streamers:index'),
|
||||
'visible' => $backend->supportsStreamers(),
|
||||
'permission' => Acl::STATION_STREAMERS,
|
||||
],
|
||||
'web_dj' => [
|
||||
'label' => __('Web DJ'),
|
||||
'icon' => 'surround_sound',
|
||||
'url' => $router->named('public:dj', ['station_id' => $station->getShortName()], [], true)
|
||||
'url' => (string)$router->named('public:dj', ['station_id' => $station->getShortName()], [], true)
|
||||
->withScheme('https'),
|
||||
'visible' => $station->getEnablePublicPage() && $station->getEnableStreamers(),
|
||||
'external' => true,
|
||||
|
@ -94,20 +94,20 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'mounts' => [
|
||||
'label' => __('Mount Points'),
|
||||
'icon' => 'wifi_tethering',
|
||||
'url' => $router->fromHere('stations:mounts:index'),
|
||||
'url' => (string)$router->fromHere('stations:mounts:index'),
|
||||
'visible' => $frontend->supportsMounts(),
|
||||
'permission' => Acl::STATION_MOUNTS,
|
||||
],
|
||||
'remotes' => [
|
||||
'label' => __('Remote Relays'),
|
||||
'icon' => 'router',
|
||||
'url' => $router->fromHere('stations:remotes:index'),
|
||||
'url' => (string)$router->fromHere('stations:remotes:index'),
|
||||
'permission' => Acl::STATION_REMOTES,
|
||||
],
|
||||
'webhooks' => [
|
||||
'label' => __('Web Hooks'),
|
||||
'icon' => 'code',
|
||||
'url' => $router->fromHere('stations:webhooks:index'),
|
||||
'url' => (string)$router->fromHere('stations:webhooks:index'),
|
||||
'permission' => Acl::STATION_WEB_HOOKS,
|
||||
],
|
||||
'reports' => [
|
||||
|
@ -117,40 +117,40 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'items' => [
|
||||
'reports_overview' => [
|
||||
'label' => __('Statistics Overview'),
|
||||
'url' => $router->fromHere('stations:reports:overview'),
|
||||
'url' => (string)$router->fromHere('stations:reports:overview'),
|
||||
],
|
||||
'reports_listeners' => [
|
||||
'label' => __('Listeners'),
|
||||
'url' => $router->fromHere('stations:reports:listeners'),
|
||||
'url' => (string)$router->fromHere('stations:reports:listeners'),
|
||||
'visible' => $frontend->supportsListenerDetail(),
|
||||
],
|
||||
'reports_requests' => [
|
||||
'label' => __('Song Requests'),
|
||||
'url' => $router->fromHere('stations:reports:requests'),
|
||||
'url' => (string)$router->fromHere('stations:reports:requests'),
|
||||
'visible' => $station->getEnableRequests(),
|
||||
],
|
||||
'reports_timeline' => [
|
||||
'label' => __('Song Playback Timeline'),
|
||||
'url' => $router->fromHere('stations:reports:timeline'),
|
||||
'url' => (string)$router->fromHere('stations:reports:timeline'),
|
||||
],
|
||||
'reports_performance' => [
|
||||
'label' => __('Song Listener Impact'),
|
||||
'url' => $router->fromHere('stations:reports:performance'),
|
||||
'url' => (string)$router->fromHere('stations:reports:performance'),
|
||||
'visible' => $backend->supportsMedia(),
|
||||
],
|
||||
'reports_duplicates' => [
|
||||
'label' => __('Duplicate Songs'),
|
||||
'url' => $router->fromHere('stations:files:index') . '#special:duplicates',
|
||||
'url' => (string)$router->fromHere('stations:files:index') . '#special:duplicates',
|
||||
'visible' => $backend->supportsMedia(),
|
||||
],
|
||||
'reports_unprocessable' => [
|
||||
'label' => __('Unprocessable Files'),
|
||||
'url' => $router->fromHere('stations:files:index') . '#special:unprocessable',
|
||||
'url' => (string)$router->fromHere('stations:files:index') . '#special:unprocessable',
|
||||
'visible' => $backend->supportsMedia(),
|
||||
],
|
||||
'reports_soundexchange' => [
|
||||
'label' => __('SoundExchange Royalties'),
|
||||
'url' => $router->fromHere('stations:reports:soundexchange'),
|
||||
'url' => (string)$router->fromHere('stations:reports:soundexchange'),
|
||||
'visible' => $frontend->supportsListenerDetail(),
|
||||
],
|
||||
],
|
||||
|
@ -161,36 +161,36 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'items' => [
|
||||
'sftp_users' => [
|
||||
'label' => __('SFTP Users'),
|
||||
'url' => $router->fromHere('stations:sftp_users:index'),
|
||||
'url' => (string)$router->fromHere('stations:sftp_users:index'),
|
||||
'visible' => App\Service\SftpGo::isSupportedForStation($station),
|
||||
'permission' => Acl::STATION_MEDIA,
|
||||
],
|
||||
'automation' => [
|
||||
'label' => __('Automated Assignment'),
|
||||
'url' => $router->fromHere('stations:automation:index'),
|
||||
'url' => (string)$router->fromHere('stations:automation:index'),
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'permission' => Acl::STATION_AUTOMATION,
|
||||
],
|
||||
'ls_config' => [
|
||||
'label' => __('Edit Liquidsoap Configuration'),
|
||||
'url' => $router->fromHere('stations:util:ls_config'),
|
||||
'url' => (string)$router->fromHere('stations:util:ls_config'),
|
||||
'visible' => $settings->getEnableAdvancedFeatures()
|
||||
&& $backend instanceof App\Radio\Backend\Liquidsoap,
|
||||
'permission' => Acl::STATION_BROADCASTING,
|
||||
],
|
||||
'logs' => [
|
||||
'label' => __('Log Viewer'),
|
||||
'url' => $router->fromHere('stations:logs:index'),
|
||||
'url' => (string)$router->fromHere('stations:logs:index'),
|
||||
'permission' => Acl::STATION_LOGS,
|
||||
],
|
||||
'queue' => [
|
||||
'label' => __('Upcoming Song Queue'),
|
||||
'url' => $router->fromHere('stations:queue:index'),
|
||||
'url' => (string)$router->fromHere('stations:queue:index'),
|
||||
'permission' => Acl::STATION_BROADCASTING,
|
||||
],
|
||||
'restart' => [
|
||||
'label' => __('Restart Broadcasting'),
|
||||
'url' => $router->fromHere('api:stations:restart'),
|
||||
'url' => (string)$router->fromHere('api:stations:restart'),
|
||||
'class' => 'api-call',
|
||||
'confirm' => __('Restart broadcasting? This will disconnect any current listeners.'),
|
||||
'permission' => Acl::STATION_BROADCASTING,
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
<exclude-pattern>src/Installer/EnvFiles/*.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification">
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification"/>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Arrays.TrailingArrayComma"/>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint">
|
||||
|
|
12
phpstan.neon
12
phpstan.neon
|
@ -1,5 +1,8 @@
|
|||
parameters:
|
||||
level: 3
|
||||
level: 8
|
||||
|
||||
checkGenericClassInNonGenericObjectType: false
|
||||
checkMissingIterableValueType: false
|
||||
|
||||
paths:
|
||||
- src
|
||||
|
@ -15,6 +18,13 @@ parameters:
|
|||
# Caused by Symfony Validator (perhaps wrongly) returning the interface.
|
||||
- '#Cannot cast Symfony\\Component\\Validator\\ConstraintViolationListInterface to string.#'
|
||||
|
||||
# Some doctrine migrations fail because of these
|
||||
- '#Parameter \#3 \$criteria of method Doctrine\\DBAL\\Connection::update\(\) expects array<string, mixed>, array<int, int> given.#'
|
||||
- '#Parameter \#2 \$criteria of method Doctrine\\DBAL\\Connection::delete\(\) expects array<string, mixed>, array<int, int> given.#'
|
||||
|
||||
# Known upstream issue with Plates template engine
|
||||
- '#Parameter \#2 \$callback of method League\\Plates\\Engine::registerFunction\(\) expects League\\Plates\\callback, Closure given.#'
|
||||
|
||||
parallel:
|
||||
maximumNumberOfProcesses: 1
|
||||
|
||||
|
|
14
src/Acl.php
14
src/Acl.php
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -74,6 +76,7 @@ class Acl
|
|||
public function listPermissions(): array
|
||||
{
|
||||
if (!isset($this->permissions)) {
|
||||
/** @var array<string,array> $permissions */
|
||||
$permissions = [
|
||||
'global' => [
|
||||
self::GLOBAL_ALL => __('All Permissions'),
|
||||
|
@ -118,7 +121,7 @@ class Acl
|
|||
* @param array|string $action
|
||||
* @param int|Entity\Station|null $stationId
|
||||
*/
|
||||
public function isAllowed(array|string $action, $stationId = null): bool
|
||||
public function isAllowed(array|string $action, Entity\Station|int $stationId = null): bool
|
||||
{
|
||||
if ($this->request instanceof ServerRequestInterface) {
|
||||
$user = $this->request->getAttribute(ServerRequest::ATTR_USER);
|
||||
|
@ -135,8 +138,11 @@ class Acl
|
|||
* @param array|string $action
|
||||
* @param int|Entity\Station|null $stationId
|
||||
*/
|
||||
public function userAllowed(?Entity\User $user = null, array|string $action, $stationId = null): bool
|
||||
{
|
||||
public function userAllowed(
|
||||
?Entity\User $user = null,
|
||||
array|string $action,
|
||||
Entity\Station|int $stationId = null
|
||||
): bool {
|
||||
if (null === $user) {
|
||||
return false;
|
||||
}
|
||||
|
@ -172,7 +178,7 @@ class Acl
|
|||
* @param array|string $action
|
||||
* @param int|Entity\Station|null $station_id
|
||||
*/
|
||||
public function roleAllowed(array|int $role_id, array|string $action, $station_id = null): bool
|
||||
public function roleAllowed(array|int $role_id, array|string $action, Entity\Station|int $station_id = null): bool
|
||||
{
|
||||
if ($station_id instanceof Entity\Station) {
|
||||
$station_id = $station_id->getId();
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Console\Application;
|
||||
use App\Http\Factory\ResponseFactory;
|
||||
use App\Http\Factory\ServerRequestFactory;
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use DI;
|
||||
use DI\Bridge\Slim\ControllerInvoker;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
|
@ -26,14 +29,32 @@ use const E_USER_ERROR;
|
|||
|
||||
class AppFactory
|
||||
{
|
||||
public static function createApp($autoloader = null, $appEnvironment = [], $diDefinitions = []): App
|
||||
{
|
||||
/**
|
||||
* @param ClassLoader|null $autoloader
|
||||
* @param array<string, mixed> $appEnvironment
|
||||
* @param array<string, mixed> $diDefinitions
|
||||
*
|
||||
*/
|
||||
public static function createApp(
|
||||
?ClassLoader $autoloader = null,
|
||||
array $appEnvironment = [],
|
||||
array $diDefinitions = []
|
||||
): App {
|
||||
$di = self::buildContainer($autoloader, $appEnvironment, $diDefinitions);
|
||||
return self::buildAppFromContainer($di);
|
||||
}
|
||||
|
||||
public static function createCli($autoloader = null, $appEnvironment = [], $diDefinitions = []): Application
|
||||
{
|
||||
/**
|
||||
* @param ClassLoader|null $autoloader
|
||||
* @param array<string, mixed> $appEnvironment
|
||||
* @param array<string, mixed> $diDefinitions
|
||||
*
|
||||
*/
|
||||
public static function createCli(
|
||||
?ClassLoader $autoloader = null,
|
||||
array $appEnvironment = [],
|
||||
array $diDefinitions = []
|
||||
): Application {
|
||||
$di = self::buildContainer($autoloader, $appEnvironment, $diDefinitions);
|
||||
self::buildAppFromContainer($di);
|
||||
|
||||
|
@ -83,11 +104,18 @@ class AppFactory
|
|||
return $app;
|
||||
}
|
||||
|
||||
/** @noinspection SummerTimeUnsafeTimeManipulationInspection */
|
||||
/**
|
||||
* @param ClassLoader|null $autoloader
|
||||
* @param array<string, mixed> $appEnvironment
|
||||
* @param array<string, mixed> $diDefinitions
|
||||
*
|
||||
* @noinspection SummerTimeUnsafeTimeManipulationInspection
|
||||
*
|
||||
*/
|
||||
public static function buildContainer(
|
||||
$autoloader = null,
|
||||
$appEnvironment = [],
|
||||
$diDefinitions = []
|
||||
?ClassLoader $autoloader = null,
|
||||
array $appEnvironment = [],
|
||||
array $diDefinitions = []
|
||||
): DI\Container {
|
||||
// Register Annotation autoloader
|
||||
if (null !== $autoloader) {
|
||||
|
@ -165,7 +193,10 @@ class AppFactory
|
|||
return $di;
|
||||
}
|
||||
|
||||
public static function buildEnvironment(array $environment): Environment
|
||||
/**
|
||||
* @param array<string, mixed> $environment
|
||||
*/
|
||||
public static function buildEnvironment(array $environment = []): Environment
|
||||
{
|
||||
if (!isset($environment[Environment::BASE_DIR])) {
|
||||
throw new Exception\BootstrapException('No base directory specified!');
|
||||
|
@ -180,7 +211,10 @@ class AppFactory
|
|||
$environment[Environment::VIEWS_DIR] ??= $environment[Environment::BASE_DIR] . '/templates';
|
||||
|
||||
if (file_exists($environment[Environment::BASE_DIR] . '/env.ini')) {
|
||||
$_ENV = array_merge($_ENV, parse_ini_file($environment[Environment::BASE_DIR] . '/env.ini'));
|
||||
$envIni = parse_ini_file($environment[Environment::BASE_DIR] . '/env.ini');
|
||||
if (false !== $envIni) {
|
||||
$_ENV = array_merge($_ENV, $envIni);
|
||||
}
|
||||
} else {
|
||||
$_ENV = getenv();
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Traits\RequestAwareTrait;
|
||||
use App\Utilities\Json;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
use function base64_encode;
|
||||
use function is_array;
|
||||
|
@ -22,13 +25,13 @@ class Assets
|
|||
{
|
||||
use RequestAwareTrait;
|
||||
|
||||
/** @var array Known libraries loaded in initialization. */
|
||||
/** @var array<string, array> Known libraries loaded in initialization. */
|
||||
protected array $libraries = [];
|
||||
|
||||
/** @var array An optional array lookup for versioned files. */
|
||||
/** @var array<string, string> An optional array lookup for versioned files. */
|
||||
protected array $versioned_files = [];
|
||||
|
||||
/** @var array Loaded libraries. */
|
||||
/** @var array<string, array> Loaded libraries. */
|
||||
protected array $loaded = [];
|
||||
|
||||
/** @var bool Whether the current loaded libraries have been sorted by order. */
|
||||
|
@ -40,9 +43,6 @@ class Assets
|
|||
/** @var array The loaded domains that should be included in the CSP header. */
|
||||
protected array $csp_domains;
|
||||
|
||||
/** @var ServerRequestInterface|null The current request (if it's available) */
|
||||
protected ?ServerRequestInterface $request = null;
|
||||
|
||||
public function __construct(
|
||||
protected Environment $environment,
|
||||
Config $config
|
||||
|
@ -51,18 +51,10 @@ class Assets
|
|||
$this->addLibrary($library, $library_name);
|
||||
}
|
||||
|
||||
$versioned_files = [];
|
||||
$assets_file = $environment->getBaseDirectory() . '/web/static/assets.json';
|
||||
if (is_file($assets_file)) {
|
||||
$versioned_files = json_decode(file_get_contents($assets_file), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
$versioned_files = Json::loadFromFile($environment->getBaseDirectory() . '/web/static/assets.json');
|
||||
$this->versioned_files = $versioned_files;
|
||||
|
||||
$vueComponents = [];
|
||||
$assets_file = $environment->getBaseDirectory() . '/web/static/webpack.json';
|
||||
if (is_file($assets_file)) {
|
||||
$vueComponents = json_decode(file_get_contents($assets_file), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
$vueComponents = Json::loadFromFile($environment->getBaseDirectory() . '/web/static/webpack.json');
|
||||
$this->addVueComponents($vueComponents);
|
||||
|
||||
$this->csp_nonce = (string)preg_replace('/[^A-Za-z0-9\+\/=]/', '', base64_encode(random_bytes(18)));
|
||||
|
@ -538,10 +530,9 @@ class Assets
|
|||
*/
|
||||
protected function addDomainToCsp(string $src): void
|
||||
{
|
||||
$src_parts = parse_url($src);
|
||||
|
||||
$domain = $src_parts['scheme'] . '://' . $src_parts['host'];
|
||||
$uri = new Uri($src);
|
||||
|
||||
$domain = $uri->getScheme() . '://' . $uri->getHost();
|
||||
if (!isset($this->csp_domains[$domain])) {
|
||||
$this->csp_domains[$domain] = $domain;
|
||||
}
|
||||
|
@ -550,7 +541,7 @@ class Assets
|
|||
public function writeCsp(ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
$csp = [];
|
||||
if ('https' === $this->request->getUri()->getScheme()) {
|
||||
if (null !== $this->request && 'https' === $this->request->getUri()->getScheme()) {
|
||||
$csp[] = 'upgrade-insecure-requests';
|
||||
}
|
||||
|
||||
|
|
11
src/Auth.php
11
src/Auth.php
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Entity\Repository\UserRepository;
|
||||
|
@ -52,7 +54,7 @@ class Auth
|
|||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getLoggedInUser($real_user_only = false): ?User
|
||||
public function getLoggedInUser(bool $real_user_only = false): ?User
|
||||
{
|
||||
if (!$real_user_only && $this->isMasqueraded()) {
|
||||
return $this->getMasquerade();
|
||||
|
@ -193,13 +195,16 @@ class Auth
|
|||
*/
|
||||
public function getMasquerade(): ?User
|
||||
{
|
||||
return $this->masqueraded_user;
|
||||
if ($this->masqueraded_user instanceof User) {
|
||||
return $this->masqueraded_user;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Become a different user across the application.
|
||||
*
|
||||
* @param array|User $user_info
|
||||
* @param array<string, mixed>|User $user_info
|
||||
*/
|
||||
public function masqueradeAsUser(User|array $user_info): void
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
use const EXTR_OVERWRITE;
|
||||
|
@ -17,7 +19,7 @@ class Config
|
|||
* @param string $name
|
||||
* @param array $inject_vars Variables to pass into the scope of the configuration.
|
||||
*
|
||||
* @return mixed[]
|
||||
* @return array<mixed>
|
||||
* @noinspection PhpIncludeInspection
|
||||
* @noinspection UselessUnsetInspection
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
|
@ -22,6 +24,10 @@ class Application extends \Silly\Edition\PhpDi\Application
|
|||
$input->setInteractive(false);
|
||||
|
||||
$temp_stream = fopen($outputFile, 'wb+');
|
||||
if (false === $temp_stream) {
|
||||
throw new \RuntimeException(sprintf('Could not open output file: "%s"', $outputFile));
|
||||
}
|
||||
|
||||
$output = new StreamOutput($temp_stream);
|
||||
|
||||
$command = $this->find($command);
|
||||
|
@ -31,7 +37,7 @@ class Application extends \Silly\Edition\PhpDi\Application
|
|||
$result_output = stream_get_contents($temp_stream);
|
||||
fclose($temp_stream);
|
||||
|
||||
$result_output = trim($result_output);
|
||||
$result_output = trim((string)$result_output);
|
||||
|
||||
return [
|
||||
$result_code,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Backup;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
@ -118,7 +120,7 @@ class BackupCommand extends CommandAbstract
|
|||
|
||||
// Strip leading slashes from backup paths.
|
||||
$files_to_backup = array_map(
|
||||
static function ($val) {
|
||||
static function (string $val) {
|
||||
if (str_starts_with($val, '/')) {
|
||||
return substr($val, 1);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Backup;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Console\Application;
|
||||
|
@ -20,7 +22,7 @@ abstract class CommandAbstract
|
|||
return $this->application;
|
||||
}
|
||||
|
||||
protected function runCommand(OutputInterface $output, $command_name, $command_args = []): void
|
||||
protected function runCommand(OutputInterface $output, string $command_name, array $command_args = []): void
|
||||
{
|
||||
$command = $this->getApplication()->find($command_name);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Debug;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Environment;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Internal;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Internal;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Internal;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Internal;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Internal;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
@ -12,7 +14,7 @@ class GetIpCommand extends CommandAbstract
|
|||
SymfonyStyle $io,
|
||||
AzuraCastCentral $acCentral
|
||||
): int {
|
||||
$io->write($acCentral->getIp());
|
||||
$io->write($acCentral->getIp() ?? 'Unknown');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Internal;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Internal;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
@ -18,9 +20,9 @@ class SftpAuthCommand extends CommandAbstract
|
|||
SymfonyStyle $io,
|
||||
EntityManagerInterface $em
|
||||
): int {
|
||||
$username = getenv('SFTPGO_AUTHD_USERNAME');
|
||||
$password = getenv('SFTPGO_AUTHD_PASSWORD');
|
||||
$pubKey = getenv('SFTPGO_AUTHD_PUBLIC_KEY');
|
||||
$username = getenv('SFTPGO_AUTHD_USERNAME') ?: null;
|
||||
$password = getenv('SFTPGO_AUTHD_PASSWORD') ?: null;
|
||||
$pubKey = getenv('SFTPGO_AUTHD_PUBLIC_KEY') ?: null;
|
||||
|
||||
$sftpUser = $em->getRepository(SftpUser::class)->findOneBy(['username' => $username]);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Internal;
|
||||
|
||||
use App\Console\Application;
|
||||
|
@ -63,6 +65,11 @@ class SftpEventCommand extends CommandAbstract
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (null === $path) {
|
||||
$this->logger->error('No path specified for action.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
return match ($action) {
|
||||
'upload' => $this->handleNewUpload($storageLocation, $path),
|
||||
'pre-delete' => $this->handleDelete($storageLocation, $path),
|
||||
|
@ -99,7 +106,7 @@ class SftpEventCommand extends CommandAbstract
|
|||
);
|
||||
|
||||
$message = new Message\AddNewMediaMessage();
|
||||
$message->storage_location_id = $storageLocation->getId();
|
||||
$message->storage_location_id = $storageLocation->getIdRequired();
|
||||
$message->path = $relativePath;
|
||||
|
||||
$this->messageBus->dispatch($message);
|
||||
|
@ -148,8 +155,13 @@ class SftpEventCommand extends CommandAbstract
|
|||
protected function handleRename(
|
||||
Entity\StorageLocation $storageLocation,
|
||||
string $path,
|
||||
string $newPath
|
||||
?string $newPath
|
||||
): int {
|
||||
if (null === $newPath) {
|
||||
$this->logger->error('No new path specified for rename.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$pathPrefixer = new PathPrefixer($storageLocation->getPath(), DIRECTORY_SEPARATOR);
|
||||
|
||||
$from = $pathPrefixer->stripPrefix($path);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Locale;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Locale;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\MessageQueue;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\MessageQueue;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Environment;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Entity\Repository\StationRepository;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Settings;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Settings;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App\Environment;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command;
|
||||
|
||||
use App;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Traits;
|
||||
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
@ -9,8 +11,8 @@ trait PassThruProcess
|
|||
{
|
||||
protected function passThruProcess(
|
||||
SymfonyStyle $io,
|
||||
$cmd,
|
||||
$cwd = null,
|
||||
string|array $cmd,
|
||||
?string $cwd = null,
|
||||
array $env = [],
|
||||
int $timeout = 14400
|
||||
): Process {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Users;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Users;
|
||||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Command\Users;
|
||||
|
||||
use App\Acl;
|
||||
|
@ -25,11 +27,19 @@ class SetAdministratorCommand extends CommandAbstract
|
|||
$admin_role = $em->getRepository(Entity\Role::class)
|
||||
->find(Entity\Role::SUPER_ADMINISTRATOR_ROLE_ID);
|
||||
|
||||
$perms_repo->setActionsForRole($admin_role, [
|
||||
'actions_global' => [
|
||||
Acl::GLOBAL_ALL,
|
||||
],
|
||||
]);
|
||||
if (null === $admin_role) {
|
||||
$io->error('Administrator role not found.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$perms_repo->setActionsForRole(
|
||||
$admin_role,
|
||||
[
|
||||
'actions_global' => [
|
||||
Acl::GLOBAL_ALL,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$user_roles = $user->getRoles();
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -16,8 +18,8 @@ abstract class AbstractLogViewerController
|
|||
protected function view(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
$log_path,
|
||||
$tail_file = true
|
||||
string $log_path,
|
||||
bool $tail_file = true
|
||||
): ResponseInterface {
|
||||
clearstatcache();
|
||||
|
||||
|
@ -26,7 +28,7 @@ abstract class AbstractLogViewerController
|
|||
}
|
||||
|
||||
if (!$tail_file) {
|
||||
$log = file_get_contents($log_path);
|
||||
$log = file_get_contents($log_path) ?: '';
|
||||
$log_contents = $this->processLog($request, $log);
|
||||
|
||||
return $response->withJson([
|
||||
|
@ -55,8 +57,12 @@ abstract class AbstractLogViewerController
|
|||
|
||||
if ($log_visible_size > 0) {
|
||||
$fp = fopen($log_path, 'rb');
|
||||
if (false === $fp) {
|
||||
throw new \RuntimeException(sprintf('Could not open file at path "%s".', $log_path));
|
||||
}
|
||||
|
||||
fseek($fp, -$log_visible_size, SEEK_END);
|
||||
$log_contents_raw = fread($fp, $log_visible_size);
|
||||
$log_contents_raw = fread($fp, $log_visible_size) ?: '';
|
||||
fclose($fp);
|
||||
|
||||
$log_contents = $this->processLog($request, $log_contents_raw, $cut_first_line, true);
|
||||
|
@ -91,7 +97,7 @@ abstract class AbstractLogViewerController
|
|||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
* @return array<string, array>
|
||||
*/
|
||||
protected function getStationLogs(Entity\Station $station): array
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Exception\NotFoundException;
|
||||
|
@ -28,19 +30,19 @@ abstract class AbstractAdminCrudController
|
|||
|
||||
/**
|
||||
* @param ServerRequest $request
|
||||
* @param string|int|null $id
|
||||
* @param int|string|null $id
|
||||
*
|
||||
*/
|
||||
protected function doEdit(ServerRequest $request, $id = null): object|bool|null
|
||||
protected function doEdit(ServerRequest $request, int|string $id = null): object|bool|null
|
||||
{
|
||||
$record = $this->getRecord($id);
|
||||
return $this->form->process($request, $record);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int|null $id
|
||||
* @param int|string|null $id
|
||||
*/
|
||||
protected function getRecord($id = null): ?object
|
||||
protected function getRecord(int|string $id = null): ?object
|
||||
{
|
||||
if (null === $id) {
|
||||
return null;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Form\ApiKeyForm;
|
||||
|
@ -33,25 +35,33 @@ class ApiController extends AbstractAdminCrudController
|
|||
]);
|
||||
}
|
||||
|
||||
public function editAction(ServerRequest $request, Response $response, $id): ResponseInterface
|
||||
public function editAction(ServerRequest $request, Response $response, string $id): ResponseInterface
|
||||
{
|
||||
if (false !== $this->doEdit($request, $id)) {
|
||||
$request->getFlash()->addMessage(__('API Key updated.'), Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:api:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:api:index'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'system/form_page', [
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Edit API Key'),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'system/form_page',
|
||||
[
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Edit API Key'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteAction(ServerRequest $request, Response $response, $id, $csrf): ResponseInterface
|
||||
{
|
||||
public function deleteAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
string $id,
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$this->doDelete($request, $id, $csrf);
|
||||
|
||||
$request->getFlash()->addMessage(__('API Key deleted.'), Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:api:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:api:index'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Http\Response;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Config;
|
||||
|
@ -91,7 +93,7 @@ class BackupsController extends AbstractLogViewerController
|
|||
|
||||
if (false !== $settingsForm->process($request)) {
|
||||
$request->getFlash()->addMessage(__('Changes saved.'), Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->fromHere('admin:backups:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->fromHere('admin:backups:index'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse(
|
||||
|
@ -123,7 +125,7 @@ class BackupsController extends AbstractLogViewerController
|
|||
);
|
||||
|
||||
// Handle submission.
|
||||
if ($request->isPost() && $runForm->isValid($request->getParsedBody())) {
|
||||
if ($runForm->isValid($request)) {
|
||||
$data = $runForm->getValues();
|
||||
|
||||
$tempFile = File::generateTempPath('backup.log');
|
||||
|
@ -176,7 +178,7 @@ class BackupsController extends AbstractLogViewerController
|
|||
public function downloadAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
$path
|
||||
string $path
|
||||
): ResponseInterface {
|
||||
[$path, $fs] = $this->getFile($path);
|
||||
|
||||
|
@ -186,8 +188,12 @@ class BackupsController extends AbstractLogViewerController
|
|||
->streamFilesystemFile($fs, $path);
|
||||
}
|
||||
|
||||
public function deleteAction(ServerRequest $request, Response $response, $path, $csrf): ResponseInterface
|
||||
{
|
||||
public function deleteAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
string $path,
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$request->getCsrf()->verify($csrf, $this->csrfNamespace);
|
||||
|
||||
[$path, $fs] = $this->getFile($path);
|
||||
|
@ -196,7 +202,7 @@ class BackupsController extends AbstractLogViewerController
|
|||
$fs->delete($path);
|
||||
|
||||
$request->getFlash()->addMessage('<b>' . __('Backup deleted.') . '</b>', Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:backups:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:backups:index'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Form\BrandingSettingsForm;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -33,29 +35,37 @@ class CustomFieldsController extends AbstractAdminCrudController
|
|||
]);
|
||||
}
|
||||
|
||||
public function editAction(ServerRequest $request, Response $response, $id = null): ResponseInterface
|
||||
public function editAction(ServerRequest $request, Response $response, int $id = null): ResponseInterface
|
||||
{
|
||||
if (false !== $this->doEdit($request, $id)) {
|
||||
$request->getFlash()->addMessage(
|
||||
($id ? __('Custom Field updated.') : __('Custom Field added.')),
|
||||
Flash::SUCCESS
|
||||
);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:custom_fields:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:custom_fields:index'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'system/form_page', [
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => $id ? __('Edit Custom Field') : __('Add Custom Field'),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'system/form_page',
|
||||
[
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => $id ? __('Edit Custom Field') : __('Add Custom Field'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteAction(ServerRequest $request, Response $response, $id, $csrf): ResponseInterface
|
||||
{
|
||||
public function deleteAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
int $id,
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$this->doDelete($request, $id, $csrf);
|
||||
|
||||
$request->getFlash()->addMessage('<b>' . __('Custom Field deleted.') . '</b>', Flash::SUCCESS);
|
||||
|
||||
return $response->withRedirect($request->getRouter()->named('admin:custom_fields:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:custom_fields:index'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Console\Application;
|
||||
|
@ -169,7 +171,7 @@ class DebugController extends AbstractLogViewerController
|
|||
// Flash an update to ensure the session is recreated.
|
||||
$request->getFlash()->addMessage($resultOutput, Flash::SUCCESS);
|
||||
|
||||
return $response->withRedirect($request->getRouter()->fromHere('admin:debug:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->fromHere('admin:debug:index'));
|
||||
}
|
||||
|
||||
public function clearQueueAction(
|
||||
|
@ -187,6 +189,6 @@ class DebugController extends AbstractLogViewerController
|
|||
// Flash an update to ensure the session is recreated.
|
||||
$request->getFlash()->addMessage($resultOutput, Flash::SUCCESS);
|
||||
|
||||
return $response->withRedirect($request->getRouter()->fromHere('admin:debug:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->fromHere('admin:debug:index'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Acl;
|
||||
|
@ -50,7 +52,7 @@ class IndexController
|
|||
$spaceUsed = $spaceTotal->minus($spaceFree);
|
||||
|
||||
// Get memory info.
|
||||
$meminfoRaw = file("/proc/meminfo", FILE_IGNORE_NEW_LINES);
|
||||
$meminfoRaw = file("/proc/meminfo", FILE_IGNORE_NEW_LINES) ?: [];
|
||||
$meminfo = [];
|
||||
foreach ($meminfoRaw as $line) {
|
||||
if (str_contains($line, ':')) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
|
@ -63,7 +65,7 @@ class InstallGeoLiteController
|
|||
ServerRequest $request,
|
||||
Response $response,
|
||||
SettingsRepository $settingsRepo,
|
||||
$csrf
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$request->getCsrf()->verify($csrf, $this->csrf_namespace);
|
||||
|
||||
|
@ -74,6 +76,6 @@ class InstallGeoLiteController
|
|||
@unlink(GeoLite::getDatabasePath());
|
||||
|
||||
$request->getFlash()->addMessage(__('GeoLite database uninstalled.'), Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->fromHere('admin:install_geolite:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->fromHere('admin:install_geolite:index'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Config;
|
||||
|
@ -13,8 +15,6 @@ use Psr\Http\Message\ResponseInterface;
|
|||
use Psr\Http\Message\UploadedFileInterface;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
use const UPLOAD_ERR_OK;
|
||||
|
||||
class InstallShoutcastController
|
||||
{
|
||||
protected array $form_config;
|
||||
|
@ -44,15 +44,14 @@ class InstallShoutcastController
|
|||
|
||||
$form = new Form($form_config, []);
|
||||
|
||||
if ($request->isPost() && $form->isValid($request->getParsedBody())) {
|
||||
if ($form->isValid($request)) {
|
||||
try {
|
||||
$sc_base_dir = $environment->getParentDirectory() . '/servers/shoutcast2';
|
||||
|
||||
$files = $request->getUploadedFiles();
|
||||
/** @var UploadedFileInterface $import_file */
|
||||
$import_file = $files['binary'];
|
||||
$values = $form->getValues();
|
||||
|
||||
if (UPLOAD_ERR_OK === $import_file->getError()) {
|
||||
$import_file = $values['binary'] ?? null;
|
||||
if ($import_file instanceof UploadedFileInterface) {
|
||||
$sc_tgz_path = $sc_base_dir . '/sc_serv.tar.gz';
|
||||
if (is_file($sc_tgz_path)) {
|
||||
unlink($sc_tgz_path);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Controller\AbstractLogViewerController;
|
||||
|
@ -43,7 +45,7 @@ class LogsController extends AbstractLogViewerController
|
|||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
* @return array<string, array>
|
||||
*/
|
||||
protected function getGlobalLogs(): array
|
||||
{
|
||||
|
@ -82,8 +84,12 @@ class LogsController extends AbstractLogViewerController
|
|||
return $logPaths;
|
||||
}
|
||||
|
||||
public function viewAction(ServerRequest $request, Response $response, $station_id, $log): ResponseInterface
|
||||
{
|
||||
public function viewAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
string|int $station_id,
|
||||
string $log
|
||||
): ResponseInterface {
|
||||
if ('global' === $station_id) {
|
||||
$log_areas = $this->getGlobalLogs();
|
||||
} else {
|
||||
|
@ -94,7 +100,7 @@ class LogsController extends AbstractLogViewerController
|
|||
throw new Exception('Invalid log file specified.');
|
||||
}
|
||||
|
||||
$log = $log_areas[$log];
|
||||
return $this->view($request, $response, $log['path'], $log['tail'] ?? true);
|
||||
$logArea = $log_areas[$log];
|
||||
return $this->view($request, $response, $logArea['path'], $logArea['tail'] ?? true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Form\PermissionsForm;
|
||||
|
@ -59,28 +61,36 @@ class PermissionsController extends AbstractAdminCrudController
|
|||
]);
|
||||
}
|
||||
|
||||
public function editAction(ServerRequest $request, Response $response, $id = null): ResponseInterface
|
||||
public function editAction(ServerRequest $request, Response $response, int $id = null): ResponseInterface
|
||||
{
|
||||
if (false !== $this->doEdit($request, $id)) {
|
||||
$request->getFlash()->addMessage(
|
||||
'<b>' . ($id ? __('Permission updated.') : __('Permission added.')) . '</b>',
|
||||
Flash::SUCCESS
|
||||
);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:permissions:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:permissions:index'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'system/form_page', [
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => $id ? __('Edit Permission') : __('Add Permission'),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'system/form_page',
|
||||
[
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => $id ? __('Edit Permission') : __('Add Permission'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteAction(ServerRequest $request, Response $response, $id, $csrf): ResponseInterface
|
||||
{
|
||||
public function deleteAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
int $id,
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$this->doDelete($request, $id, $csrf);
|
||||
|
||||
$request->getFlash()->addMessage('<b>' . __('Permission deleted.') . '</b>', Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:permissions:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:permissions:index'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Form\SettingsForm;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -33,53 +35,61 @@ class StationsController extends AbstractAdminCrudController
|
|||
]);
|
||||
}
|
||||
|
||||
public function editAction(ServerRequest $request, Response $response, $id = null): ResponseInterface
|
||||
public function editAction(ServerRequest $request, Response $response, int $id = null): ResponseInterface
|
||||
{
|
||||
if (false !== $this->doEdit($request, $id)) {
|
||||
$request->getFlash()->addMessage(($id ? __('Station updated.') : __('Station added.')), Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:stations:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:stations:index'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'admin/stations/edit', [
|
||||
'form' => $this->form,
|
||||
'title' => $id ? __('Edit Station') : 'Add Station',
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'admin/stations/edit',
|
||||
[
|
||||
'form' => $this->form,
|
||||
'title' => $id ? __('Edit Station') : 'Add Station',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteAction(ServerRequest $request, Response $response, $id, $csrf): ResponseInterface
|
||||
{
|
||||
public function deleteAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
int $id,
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$request->getCsrf()->verify($csrf, $this->csrf_namespace);
|
||||
|
||||
$record = $this->record_repo->find((int)$id);
|
||||
$record = $this->record_repo->find($id);
|
||||
if ($record instanceof Entity\Station) {
|
||||
$this->stationRepo->destroy($record);
|
||||
}
|
||||
|
||||
$request->getFlash()->addMessage(__('Station deleted.'), Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:stations:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:stations:index'));
|
||||
}
|
||||
|
||||
public function cloneAction(ServerRequest $request, Response $response, $id): ResponseInterface
|
||||
public function cloneAction(ServerRequest $request, Response $response, int $id): ResponseInterface
|
||||
{
|
||||
$cloneForm = $this->factory->make(Form\StationCloneForm::class);
|
||||
|
||||
$record = $this->record_repo->find((int)$id);
|
||||
$record = $this->record_repo->find($id);
|
||||
if (!($record instanceof Entity\Station)) {
|
||||
throw new NotFoundException(__('Station not found.'));
|
||||
}
|
||||
|
||||
if (false !== $cloneForm->process($request, $record)) {
|
||||
$request->getFlash()->addMessage(__('Changes saved.'), Flash::SUCCESS);
|
||||
return $response->withRedirect($request->getRouter()->named('admin:stations:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:stations:index'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'system/form_page',
|
||||
[
|
||||
'form' => $cloneForm,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Clone Station: %s', $record->getName()),
|
||||
'form' => $cloneForm,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Clone Station: %s', $record->getName()),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Http\Response;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -39,13 +41,13 @@ class UsersController extends AbstractAdminCrudController
|
|||
]);
|
||||
}
|
||||
|
||||
public function editAction(ServerRequest $request, Response $response, $id = null): ResponseInterface
|
||||
public function editAction(ServerRequest $request, Response $response, int $id = null): ResponseInterface
|
||||
{
|
||||
try {
|
||||
if (false !== $this->doEdit($request, $id)) {
|
||||
$request->getFlash()->addMessage(($id ? __('User updated.') : __('User added.')), Flash::SUCCESS);
|
||||
|
||||
return $response->withRedirect($request->getRouter()->named('admin:users:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:users:index'));
|
||||
}
|
||||
} catch (UniqueConstraintViolationException) {
|
||||
$request->getFlash()->addMessage(
|
||||
|
@ -54,18 +56,26 @@ class UsersController extends AbstractAdminCrudController
|
|||
);
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'system/form_page', [
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => $id ? __('Edit User') : __('Add User'),
|
||||
]);
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'system/form_page',
|
||||
[
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => $id ? __('Edit User') : __('Add User'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteAction(ServerRequest $request, Response $response, $id, $csrf): ResponseInterface
|
||||
{
|
||||
public function deleteAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
int $id,
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$request->getCsrf()->verify($csrf, $this->csrf_namespace);
|
||||
|
||||
$user = $this->record_repo->find((int)$id);
|
||||
$user = $this->record_repo->find($id);
|
||||
|
||||
$current_user = $request->getUser();
|
||||
|
||||
|
@ -78,18 +88,18 @@ class UsersController extends AbstractAdminCrudController
|
|||
$request->getFlash()->addMessage('<b>' . __('User deleted.') . '</b>', Flash::SUCCESS);
|
||||
}
|
||||
|
||||
return $response->withRedirect($request->getRouter()->named('admin:users:index'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:users:index'));
|
||||
}
|
||||
|
||||
public function impersonateAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
$id,
|
||||
$csrf
|
||||
int $id,
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$request->getCsrf()->verify($csrf, $this->csrf_namespace);
|
||||
|
||||
$user = $this->record_repo->find((int)$id);
|
||||
$user = $this->record_repo->find($id);
|
||||
|
||||
if (!($user instanceof Entity\User)) {
|
||||
throw new NotFoundException(__('User not found.'));
|
||||
|
@ -103,6 +113,6 @@ class UsersController extends AbstractAdminCrudController
|
|||
Flash::SUCCESS
|
||||
);
|
||||
|
||||
return $response->withRedirect($request->getRouter()->named('dashboard'));
|
||||
return $response->withRedirect((string)$request->getRouter()->named('dashboard'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api;
|
||||
|
||||
use App\Entity\Interfaces\IdentifiableEntityInterface;
|
||||
use App\Exception\ValidationException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Paginator;
|
||||
use App\Utilities;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\OptimisticLockException;
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Doctrine\ORM\Query;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
@ -17,9 +18,12 @@ use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @template TEntity as object
|
||||
*/
|
||||
abstract class AbstractApiCrudController
|
||||
{
|
||||
/** @var string The fully-qualified (::class) class name of the entity being managed. */
|
||||
/** @var class-string<TEntity> The fully-qualified (::class) class name of the entity being managed. */
|
||||
protected string $entityClass;
|
||||
|
||||
/** @var string The route name used to generate the "self" links for each record. */
|
||||
|
@ -59,7 +63,7 @@ abstract class AbstractApiCrudController
|
|||
}
|
||||
|
||||
/**
|
||||
* @param object $record
|
||||
* @param TEntity $record
|
||||
* @param ServerRequest $request
|
||||
*
|
||||
*/
|
||||
|
@ -74,21 +78,28 @@ abstract class AbstractApiCrudController
|
|||
$isInternal = ('true' === $request->getParam('internal', 'false'));
|
||||
$router = $request->getRouter();
|
||||
|
||||
$return['links'] = [
|
||||
'self' => $router->fromHere($this->resourceRouteName, ['id' => $record->getId()], [], !$isInternal),
|
||||
];
|
||||
if ($record instanceof IdentifiableEntityInterface) {
|
||||
$return['links'] = [
|
||||
'self' => (string)$router->fromHere(
|
||||
$this->resourceRouteName,
|
||||
['id' => $record->getIdRequired()],
|
||||
[],
|
||||
!$isInternal
|
||||
),
|
||||
];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $record
|
||||
* @param array $context
|
||||
* @param TEntity $record
|
||||
* @param array<string, mixed> $context
|
||||
*
|
||||
* @return mixed[]
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function toArray(object $record, array $context = []): array
|
||||
{
|
||||
return $this->serializer->normalize(
|
||||
return (array)$this->serializer->normalize(
|
||||
$record,
|
||||
null,
|
||||
array_merge(
|
||||
|
@ -126,15 +137,25 @@ abstract class AbstractApiCrudController
|
|||
return $object->getName();
|
||||
}
|
||||
|
||||
return $object->getId();
|
||||
if ($object instanceof IdentifiableEntityInterface) {
|
||||
return $object->getIdRequired();
|
||||
}
|
||||
|
||||
if ($object instanceof \Stringable) {
|
||||
return (string)$object;
|
||||
}
|
||||
|
||||
return get_class($object) . ': ' . spl_object_hash($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|null $data
|
||||
* @param object|null $record
|
||||
* @param array $context
|
||||
* @param array<mixed>|null $data
|
||||
* @param TEntity|null $record
|
||||
* @param array<string, mixed> $context
|
||||
*
|
||||
* @return TEntity
|
||||
*/
|
||||
protected function editRecord(?array $data, $record = null, array $context = []): object
|
||||
protected function editRecord(?array $data, ?object $record = null, array $context = []): object
|
||||
{
|
||||
if (null === $data) {
|
||||
throw new InvalidArgumentException('Could not parse input data.');
|
||||
|
@ -156,11 +177,13 @@ abstract class AbstractApiCrudController
|
|||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param object|null $record
|
||||
* @param array $context
|
||||
* @param array<mixed> $data
|
||||
* @param TEntity|null $record
|
||||
* @param array<string, mixed> $context
|
||||
*
|
||||
* @return TEntity
|
||||
*/
|
||||
protected function fromArray(array $data, $record = null, array $context = []): object
|
||||
protected function fromArray(array $data, ?object $record = null, array $context = []): object
|
||||
{
|
||||
if (null !== $record) {
|
||||
$context[ObjectNormalizer::OBJECT_TO_POPULATE] = $record;
|
||||
|
@ -170,10 +193,7 @@ abstract class AbstractApiCrudController
|
|||
}
|
||||
|
||||
/**
|
||||
* @param object $record
|
||||
*
|
||||
* @throws ORMException
|
||||
* @throws OptimisticLockException
|
||||
* @param TEntity $record
|
||||
*/
|
||||
protected function deleteRecord(object $record): void
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Controller\Api\AbstractApiCrudController;
|
||||
|
@ -7,11 +9,12 @@ use App\Entity;
|
|||
use App\Exception;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Doctrine\ORM\OptimisticLockException;
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Doctrine\ORM\TransactionRequiredException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @template TEntity as object
|
||||
* @extends AbstractApiCrudController<TEntity>
|
||||
*/
|
||||
abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
|
||||
{
|
||||
public function listAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
|
@ -29,7 +32,7 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
|
|||
*/
|
||||
public function createAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$row = $this->createRecord($request->getParsedBody());
|
||||
$row = $this->createRecord((array)$request->getParsedBody());
|
||||
|
||||
$return = $this->viewRecord($row, $request);
|
||||
return $response->withJson($return);
|
||||
|
@ -37,6 +40,8 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
|
|||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TEntity
|
||||
*/
|
||||
protected function createRecord(array $data): object
|
||||
{
|
||||
|
@ -54,7 +59,7 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
|
|||
|
||||
if (null === $record) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found!')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$return = $this->viewRecord($record, $request);
|
||||
|
@ -64,9 +69,7 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
|
|||
/**
|
||||
* @param mixed $id
|
||||
*
|
||||
* @throws ORMException
|
||||
* @throws OptimisticLockException
|
||||
* @throws TransactionRequiredException
|
||||
* @return TEntity|null
|
||||
*/
|
||||
protected function getRecord(mixed $id): ?object
|
||||
{
|
||||
|
@ -84,10 +87,10 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
|
|||
|
||||
if (null === $record) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found!')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$this->editRecord($request->getParsedBody(), $record);
|
||||
$this->editRecord((array)$request->getParsedBody(), $record);
|
||||
|
||||
return $response->withJson(new Entity\Api\Status(true, __('Changes saved successfully.')));
|
||||
}
|
||||
|
@ -103,7 +106,7 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
|
|||
|
||||
if (null === $record) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found!')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$this->deleteRecord($record);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Entity;
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
/**
|
||||
* @extends AbstractAdminApiCrudController<Entity\CustomField>
|
||||
*/
|
||||
class CustomFieldsController extends AbstractAdminApiCrudController
|
||||
{
|
||||
protected string $entityClass = Entity\CustomField::class;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Acl;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Acl;
|
||||
|
@ -45,7 +47,7 @@ class RelaysController
|
|||
$fa = $this->adapters->getFrontendAdapter($station);
|
||||
|
||||
$row = new Entity\Api\Admin\Relay();
|
||||
$row->id = $station->getId();
|
||||
$row->id = $station->getIdRequired();
|
||||
$row->name = $station->getName();
|
||||
$row->shortcode = $station->getShortName();
|
||||
$row->description = $station->getDescription();
|
||||
|
@ -108,14 +110,13 @@ class RelaysController
|
|||
{
|
||||
$relay_repo = $this->em->getRepository(Entity\Relay::class);
|
||||
|
||||
$body = $request->getParsedBody();
|
||||
$body = (array)$request->getParsedBody();
|
||||
|
||||
if (!empty($body['base_url'])) {
|
||||
$base_url = $body['base_url'];
|
||||
} else {
|
||||
$serverParams = $request->getServerParams();
|
||||
/** @noinspection HttpUrlsUsage */
|
||||
$base_url = 'http://' . $serverParams('REMOTE_ADDR');
|
||||
$base_url = 'http://' . $request->getIp();
|
||||
}
|
||||
|
||||
$relay = $relay_repo->findOneBy(['base_url' => $base_url]);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Acl;
|
||||
|
@ -10,6 +12,9 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractAdminApiCrudController<Entity\Role>
|
||||
*/
|
||||
class RolesController extends AbstractAdminApiCrudController
|
||||
{
|
||||
protected string $entityClass = Entity\Role::class;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Controller\Api\AbstractApiCrudController;
|
||||
|
@ -13,6 +15,9 @@ use Psr\Http\Message\ResponseInterface;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractApiCrudController<Entity\Settings>
|
||||
*/
|
||||
class SettingsController extends AbstractApiCrudController
|
||||
{
|
||||
public function __construct(
|
||||
|
@ -66,7 +71,7 @@ class SettingsController extends AbstractApiCrudController
|
|||
public function updateAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$settings = $this->settingsRepo->readSettings();
|
||||
$this->editRecord($request->getParsedBody(), $settings);
|
||||
$this->editRecord((array)$request->getParsedBody(), $settings);
|
||||
|
||||
return $response->withJson(new Entity\Api\Status());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -11,6 +13,9 @@ use OpenApi\Annotations as OA;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractAdminApiCrudController<Entity\Station>
|
||||
*/
|
||||
class StationsController extends AbstractAdminApiCrudController
|
||||
{
|
||||
protected string $entityClass = Entity\Station::class;
|
||||
|
@ -104,7 +109,12 @@ class StationsController extends AbstractAdminApiCrudController
|
|||
* )
|
||||
*/
|
||||
|
||||
/** @inheritDoc */
|
||||
/**
|
||||
* @param Entity\Station $record
|
||||
* @param array<string, mixed> $context
|
||||
*
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function toArray(object $record, array $context = []): array
|
||||
{
|
||||
return parent::toArray(
|
||||
|
@ -122,8 +132,14 @@ class StationsController extends AbstractAdminApiCrudController
|
|||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
protected function editRecord(?array $data, $record = null, array $context = []): object
|
||||
/**
|
||||
* @param array<mixed>|null $data
|
||||
* @param Entity\Station|null $record
|
||||
* @param array<string, mixed> $context
|
||||
*
|
||||
* @return Entity\Station
|
||||
*/
|
||||
protected function editRecord(?array $data, object $record = null, array $context = []): object
|
||||
{
|
||||
$create_mode = (null === $record);
|
||||
|
||||
|
@ -150,7 +166,9 @@ class StationsController extends AbstractAdminApiCrudController
|
|||
return $this->station_repo->edit($record);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
/**
|
||||
* @param Entity\Station $record
|
||||
*/
|
||||
protected function deleteRecord(object $record): void
|
||||
{
|
||||
$this->station_repo->destroy($record);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -13,6 +15,9 @@ use RuntimeException;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractAdminApiCrudController<Entity\StorageLocation>
|
||||
*/
|
||||
class StorageLocationsController extends AbstractAdminApiCrudController
|
||||
{
|
||||
protected string $entityClass = Entity\StorageLocation::class;
|
||||
|
@ -125,9 +130,8 @@ class StorageLocationsController extends AbstractAdminApiCrudController
|
|||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
protected function viewRecord(object $record, ServerRequest $request): Entity\Api\Admin\StorageLocation
|
||||
protected function viewRecord(object $record, ServerRequest $request): object
|
||||
{
|
||||
/** @var Entity\StorageLocation $record */
|
||||
$original = parent::viewRecord($record, $request);
|
||||
|
||||
$return = new Entity\Api\Admin\StorageLocation();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -8,6 +10,9 @@ use App\Http\ServerRequest;
|
|||
use OpenApi\Annotations as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractAdminApiCrudController<Entity\User>
|
||||
*/
|
||||
class UsersController extends AbstractAdminApiCrudController
|
||||
{
|
||||
protected string $entityClass = Entity\User::class;
|
||||
|
@ -97,12 +102,11 @@ class UsersController extends AbstractAdminApiCrudController
|
|||
*/
|
||||
public function deleteAction(ServerRequest $request, Response $response, mixed $id): ResponseInterface
|
||||
{
|
||||
/** @var Entity\User|null $record */
|
||||
$record = $this->getRecord($id);
|
||||
|
||||
if (null === $record) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found!')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$current_user = $request->getUser();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Frontend\Account;
|
||||
|
||||
use App\Controller\Api\Admin\UsersController;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Frontend\Account;
|
||||
|
||||
use App\Controller\Api\Admin\UsersController;
|
||||
|
@ -17,7 +19,7 @@ class PutMeAction extends UsersController
|
|||
public function __invoke(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$user = $request->getUser();
|
||||
$this->editRecord($request->getParsedBody(), $user);
|
||||
$this->editRecord((array)$request->getParsedBody(), $user);
|
||||
|
||||
return $response->withJson(new Entity\Api\Status(true, __('Changes saved successfully.')));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Frontend\Dashboard;
|
||||
|
||||
use App\Acl;
|
||||
|
@ -83,7 +85,7 @@ class ChartsAction
|
|||
$sortableKey = $moment->format('Y-m-d');
|
||||
$jsTimestamp = $moment->getTimestamp() * 1000;
|
||||
|
||||
$average = round($row['number_avg'], 2);
|
||||
$average = round((float)$row['number_avg'], 2);
|
||||
$unique = $row['number_unique'];
|
||||
|
||||
$rawStats['average'][$stationId][$sortableKey] = [
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Frontend\Dashboard;
|
||||
|
||||
use App\Event;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Frontend\Dashboard;
|
||||
|
||||
use App\Acl;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api;
|
||||
|
||||
use App\Acl;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -80,8 +82,11 @@ class NowplayingController implements EventSubscriberInterface
|
|||
* @param Response $response
|
||||
* @param int|string|null $station_id
|
||||
*/
|
||||
public function __invoke(ServerRequest $request, Response $response, $station_id = null): ResponseInterface
|
||||
{
|
||||
public function __invoke(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
$station_id = null
|
||||
): ResponseInterface {
|
||||
$router = $request->getRouter();
|
||||
|
||||
// Pull NP data from the fastest/first available source using the EventDispatcher.
|
||||
|
@ -101,7 +106,7 @@ class NowplayingController implements EventSubscriberInterface
|
|||
}
|
||||
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, 'Station not found.'));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
// If unauthenticated, hide non-public stations from full view.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api;
|
||||
|
||||
use App\Environment;
|
||||
|
@ -20,7 +22,7 @@ class OpenApiController
|
|||
|
||||
public function __invoke(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$api_base_url = $request->getRouter()->fromHere(null, [], [], true);
|
||||
$api_base_url = (string)$request->getRouter()->fromHere(absolute: true);
|
||||
$api_base_url = str_replace('/openapi.yml', '', $api_base_url);
|
||||
|
||||
define('AZURACAST_API_URL', $api_base_url);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -14,6 +16,10 @@ use Psr\Http\Message\ResponseInterface;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @template TEntity as Entity\StationPlaylist|Entity\StationStreamer
|
||||
* @extends AbstractStationApiCrudController<TEntity>
|
||||
*/
|
||||
abstract class AbstractScheduledEntityController extends AbstractStationApiCrudController
|
||||
{
|
||||
public function __construct(
|
||||
|
@ -37,11 +43,21 @@ abstract class AbstractScheduledEntityController extends AbstractStationApiCrudC
|
|||
$params = $request->getQueryParams();
|
||||
|
||||
$startDateStr = substr($params['start'], 0, 10);
|
||||
$startDate = CarbonImmutable::createFromFormat('Y-m-d', $startDateStr, $tz)->subDay();
|
||||
$startDate = CarbonImmutable::createFromFormat('Y-m-d', $startDateStr, $tz);
|
||||
|
||||
if (false === $startDate) {
|
||||
throw new \InvalidArgumentException(sprintf('Could not parse start date: "%s"', $startDateStr));
|
||||
}
|
||||
|
||||
$startDate = $startDate->subDay();
|
||||
|
||||
$endDateStr = substr($params['end'], 0, 10);
|
||||
$endDate = CarbonImmutable::createFromFormat('Y-m-d', $endDateStr, $tz);
|
||||
|
||||
if (false === $endDate) {
|
||||
throw new \InvalidArgumentException(sprintf('Could not parse end date: "%s"', $endDateStr));
|
||||
}
|
||||
|
||||
$events = [];
|
||||
|
||||
foreach ($scheduleItems as $scheduleItem) {
|
||||
|
@ -73,13 +89,13 @@ abstract class AbstractScheduledEntityController extends AbstractStationApiCrudC
|
|||
return $response->withJson($events);
|
||||
}
|
||||
|
||||
protected function editRecord(?array $data, $record = null, array $context = []): object
|
||||
protected function editRecord(?array $data, object $record = null, array $context = []): object
|
||||
{
|
||||
if (null === $data) {
|
||||
throw new InvalidArgumentException('Could not parse input data.');
|
||||
}
|
||||
|
||||
$scheduleItems = $data['schedule_items'] ?? null;
|
||||
$scheduleItems = $data['schedule_items'] ?? [];
|
||||
unset($data['schedule_items']);
|
||||
|
||||
$record = $this->fromArray($data, $record, $context);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations;
|
||||
|
||||
use App\Controller\Api\AbstractApiCrudController;
|
||||
|
@ -10,6 +12,10 @@ use App\Http\ServerRequest;
|
|||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
|
||||
/**
|
||||
* @template TEntity as object
|
||||
* @extends AbstractApiCrudController<TEntity>
|
||||
*/
|
||||
abstract class AbstractStationApiCrudController extends AbstractApiCrudController
|
||||
{
|
||||
/**
|
||||
|
@ -46,7 +52,7 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
|
|||
public function createAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$station = $this->getStation($request);
|
||||
$row = $this->createRecord($request->getParsedBody(), $station);
|
||||
$row = $this->createRecord((array)$request->getParsedBody(), $station);
|
||||
|
||||
$return = $this->viewRecord($row, $request);
|
||||
|
||||
|
@ -56,6 +62,8 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
|
|||
/**
|
||||
* @param array $data
|
||||
* @param Entity\Station $station
|
||||
*
|
||||
* @return TEntity
|
||||
*/
|
||||
protected function createRecord(array $data, Entity\Station $station): object
|
||||
{
|
||||
|
@ -75,23 +83,23 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
|
|||
/**
|
||||
* @param ServerRequest $request
|
||||
* @param Response $response
|
||||
* @param int|string $station_id
|
||||
* @param int|string $id
|
||||
* @param int $station_id
|
||||
* @param int $id
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
int|string $station_id,
|
||||
int|string $id
|
||||
int $station_id,
|
||||
int $id
|
||||
): ResponseInterface {
|
||||
$station = $this->getStation($request);
|
||||
$record = $this->getRecord($station, $id);
|
||||
|
||||
if (null === $record) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found!')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$return = $this->viewRecord($record, $request);
|
||||
|
@ -101,6 +109,8 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
|
|||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param int|string $id
|
||||
*
|
||||
* @return TEntity
|
||||
*/
|
||||
protected function getRecord(Entity\Station $station, int|string $id): ?object
|
||||
{
|
||||
|
@ -115,23 +125,23 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
|
|||
/**
|
||||
* @param ServerRequest $request
|
||||
* @param Response $response
|
||||
* @param int|string $station_id
|
||||
* @param int|string $id
|
||||
* @param int $station_id
|
||||
* @param int $id
|
||||
*/
|
||||
public function editAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
int|string $station_id,
|
||||
int|string $id
|
||||
int $station_id,
|
||||
int $id
|
||||
): ResponseInterface {
|
||||
$record = $this->getRecord($this->getStation($request), $id);
|
||||
|
||||
if (null === $record) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found!')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$this->editRecord($request->getParsedBody(), $record);
|
||||
$this->editRecord((array)$request->getParsedBody(), $record);
|
||||
|
||||
return $response->withJson(new Entity\Api\Status(true, __('Changes saved successfully.')));
|
||||
}
|
||||
|
@ -139,20 +149,20 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
|
|||
/**
|
||||
* @param ServerRequest $request
|
||||
* @param Response $response
|
||||
* @param int|string $station_id
|
||||
* @param int|string $id
|
||||
* @param int $station_id
|
||||
* @param int $id
|
||||
*/
|
||||
public function deleteAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
int|string $station_id,
|
||||
int|string $id
|
||||
int $station_id,
|
||||
int $id
|
||||
): ResponseInterface {
|
||||
$record = $this->getRecord($this->getStation($request), $id);
|
||||
|
||||
if (null === $record) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found!')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$this->deleteRecord($record);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Art;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -9,6 +11,14 @@ use Psr\Http\Message\ResponseInterface;
|
|||
|
||||
class DeleteArtAction
|
||||
{
|
||||
/**
|
||||
* @param ServerRequest $request
|
||||
* @param Response $response
|
||||
* @param Entity\Repository\StationMediaRepository $mediaRepo
|
||||
* @param int|string $media_id
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function __invoke(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
|
@ -20,7 +30,7 @@ class DeleteArtAction
|
|||
$media = $mediaRepo->find($media_id, $station);
|
||||
if (!($media instanceof Entity\StationMedia)) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found.')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$mediaRepo->removeAlbumArt($media);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Art;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -46,7 +48,7 @@ class GetArtAction
|
|||
|
||||
$fsMedia = (new StationFilesystems($station))->getMediaFilesystem();
|
||||
|
||||
$defaultArtRedirect = $response->withRedirect($stationRepo->getDefaultAlbumArtUrl($station), 302);
|
||||
$defaultArtRedirect = $response->withRedirect((string)$stationRepo->getDefaultAlbumArtUrl($station), 302);
|
||||
|
||||
// If a timestamp delimiter is added, strip it automatically.
|
||||
$media_id = explode('-', $media_id, 2)[0];
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Art;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -11,6 +13,16 @@ use Psr\Http\Message\ResponseInterface;
|
|||
|
||||
class PostArtAction
|
||||
{
|
||||
/**
|
||||
* @param ServerRequest $request
|
||||
* @param Response $response
|
||||
* @param Entity\Repository\StationMediaRepository $mediaRepo
|
||||
* @param EntityManagerInterface $em
|
||||
* @param int|string $media_id
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws \App\Exception\NoFileUploadedException
|
||||
*/
|
||||
public function __invoke(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
|
@ -23,7 +35,7 @@ class PostArtAction
|
|||
$media = $mediaRepo->find($media_id, $station);
|
||||
if (!($media instanceof Entity\StationMedia)) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found.')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$flowResponse = Flow::process($request, $response, $station->getRadioTempDir());
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
|
@ -157,6 +159,7 @@ class BatchAction
|
|||
$this->em->flush();
|
||||
|
||||
foreach ($playlists as $playlistRecord) {
|
||||
/** @var Entity\StationPlaylist $playlist */
|
||||
$playlist = $this->em->refetchAsReference($playlistRecord);
|
||||
|
||||
$playlistWeights[$playlist->getId()]++;
|
||||
|
@ -170,6 +173,7 @@ class BatchAction
|
|||
}
|
||||
}
|
||||
|
||||
/** @var Entity\Station $station */
|
||||
$station = $this->em->refetch($station);
|
||||
|
||||
foreach ($result->directories as $dir) {
|
||||
|
@ -226,7 +230,7 @@ class BatchAction
|
|||
$toMove = [
|
||||
$this->batchUtilities->iterateMediaInDirectory($storageLocation, $dirPath),
|
||||
$this->batchUtilities->iterateUnprocessableMediaInDirectory($storageLocation, $dirPath),
|
||||
$this->batchUtilities->iteratePlaylistFoldersInDirectory($station, $dirPath),
|
||||
$this->batchUtilities->iteratePlaylistFoldersInDirectory($storageLocation, $dirPath),
|
||||
];
|
||||
|
||||
foreach ($toMove as $iterator) {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
|
@ -23,7 +25,7 @@ class DownloadAction
|
|||
|
||||
if (!$fsMedia->fileExists($path)) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Error(404, 'File not found.'));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
return $response->streamFilesystemFile($fsMedia, $path);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -129,7 +131,7 @@ class ListAction
|
|||
|
||||
if (!$playlist instanceof Entity\StationPlaylist) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Error('Playlist not found.'));
|
||||
->withJson(new Entity\Api\Error(400, 'Playlist not found.'));
|
||||
}
|
||||
|
||||
$mediaQueryBuilder->andWhere(
|
||||
|
@ -177,7 +179,7 @@ class ListAction
|
|||
$media->genre = (string)$row['genre'];
|
||||
|
||||
$media->is_playable = ($row['length'] !== 0);
|
||||
$media->length = $row['length'];
|
||||
$media->length = (int)$row['length'];
|
||||
$media->length_text = $row['length_text'];
|
||||
|
||||
$media->media_id = $row['id'];
|
||||
|
@ -315,7 +317,7 @@ class ListAction
|
|||
$paginator = Paginator::fromArray($result, $request);
|
||||
|
||||
// Add processor-intensive data for just this page.
|
||||
$stationId = $station->getId();
|
||||
$stationId = $station->getIdRequired();
|
||||
$isInternal = (bool)$request->getParam('internal', false);
|
||||
$defaultAlbumArtUrl = (string)$stationRepo->getDefaultAlbumArtUrl($station);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -24,7 +26,7 @@ class PlayAction
|
|||
|
||||
if (!$media instanceof Entity\StationMedia) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, 'Not Found'));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$fsMedia = (new StationFilesystems($station))->getMediaFilesystem();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations;
|
||||
|
||||
use App\Entity;
|
||||
|
@ -19,6 +21,9 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
|||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationApiCrudController<Entity\StationMedia>
|
||||
*/
|
||||
class FilesController extends AbstractStationApiCrudController
|
||||
{
|
||||
protected string $entityClass = Entity\StationMedia::class;
|
||||
|
@ -179,19 +184,19 @@ class FilesController extends AbstractStationApiCrudController
|
|||
public function editAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
int|string $station_id,
|
||||
int|string $id
|
||||
int $station_id,
|
||||
int $id
|
||||
): ResponseInterface {
|
||||
$station = $this->getStation($request);
|
||||
$record = $this->getRecord($station, $id);
|
||||
|
||||
if (null === $record) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(new Entity\Api\Error(404, __('Record not found!')));
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
}
|
||||
|
||||
$data = $request->getParsedBody();
|
||||
if (null === $data) {
|
||||
if (!is_array($data)) {
|
||||
throw new InvalidArgumentException('Could not parse input data.');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Stations;
|
||||
|
||||
use App;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue