Slim PHP Framework 4 Update (#1822)

Implement an upgrade of the codebase to use Slim Framework version 4, which includes the following changes:
 - Updating to Slim version 4 and the corresponding AzuraCore updates.
 - Making all objects PSR-7 Request/Response agnostic (and creating RequestHelper and ResponseHelper objects to interact with the PSR-7 Req/Resp objects).
 - Moving to PHP-DI as a DI container and implementing its autowiring support.
This commit is contained in:
Buster "Silver Eagle" Neece 2019-08-06 23:33:55 -05:00 committed by GitHub
parent f9c7e1f533
commit 639dddf989
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
291 changed files with 3689 additions and 4349 deletions

View File

@ -1,3 +1,3 @@
#!/usr/bin/env php
<?php
include('azuracast.php');
include dirname(__DIR__).'/util/cli.php';

View File

@ -1,24 +1,2 @@
<?php
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
ini_set('display_errors', 1);
$autoloader = require dirname(__DIR__).'/vendor/autoload.php';
// Placeholder locale functions
\App\Customization::setGlobalValues();
$translator = new \Gettext\Translator();
$translator->register();
$app = \App\App::create([
'autoloader' => $autoloader,
'settings' => [
\Azura\Settings::BASE_DIR => dirname(__DIR__),
],
]);
$di = $app->getContainer();
/** @var \Azura\Console\Application $cli */
$cli = $di[\Azura\Console\Application::class];
$cli->run();
include dirname(__DIR__).'/util/cli.php';

View File

@ -1,3 +1,3 @@
#!/usr/bin/env php
<?php
include('azuracast.php');
include dirname(__DIR__).'/util/cli.php';

View File

@ -41,15 +41,16 @@
"spomky-labs/otphp": "^9.1",
"studio24/rotate": "^1.0",
"supervisorphp/supervisor": "^3.0",
"symfony/finder": "^4.1",
"symfony/process": "^4.1",
"symfony/property-access": "^4.2",
"symfony/finder": "^4.3",
"symfony/process": "^4.3",
"symfony/property-access": "^4.3",
"ramsey/uuid": "^3.8",
"wikimedia/composer-merge-plugin": "^1.4",
"zircote/swagger-php": "^3.0"
},
"require-dev": {
"codeception/codeception": "^2.2",
"filp/whoops": "dev-master",
"flow/jsonpath": "^0.3.4",
"mockery/mockery": "^1.0",
"phpstan/phpstan": "^0.11.1",
@ -68,7 +69,8 @@
],
"phplint": "phplint",
"phpstan": "phpstan analyze",
"codeception": "codecept run --no-interaction --coverage --coverage-xml --fail-fast"
"codeception": "codecept run --no-interaction --coverage --coverage-xml --fail-fast",
"codeception-no-coverage": "codecept run --no-interaction"
},
"authors": [
{

1157
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<?php
use App\Http\Request;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* Static assets referenced in AzuraCast.
@ -232,7 +232,7 @@ return [
'inline' => [
'js' => [
function(Request $request) {
if (!$request->hasAttribute('locale')) {
if ('' !== $request->getAttribute('locale', '')) {
return '';
}

View File

@ -5,7 +5,7 @@ use App\Console\Command;
return function (\Azura\EventDispatcher $dispatcher)
{
// Build default routes and middleware
$dispatcher->addListener(Azura\Event\BuildRoutes::NAME, function(Azura\Event\BuildRoutes $event) {
$dispatcher->addListener(Azura\Event\BuildRoutes::class, function(Azura\Event\BuildRoutes $event) {
$app = $event->getApp();
if (file_exists(__DIR__.'/routes.dev.php')) {
@ -13,27 +13,25 @@ return function (\Azura\EventDispatcher $dispatcher)
$dev_routes($app);
}
// Get the current user entity object and assign it into the request if it exists.
$app->add(Middleware\GetCurrentUser::class);
// Check HTTPS setting and enforce Content Security Policy accordingly.
$app->add(Middleware\EnforceSecurity::class);
$app->add(Middleware\InjectAcl::class);
$app->add(Middleware\GetCurrentUser::class);
}, 2);
// Build default menus
$dispatcher->addListener(App\Event\BuildAdminMenu::NAME, function(\App\Event\BuildAdminMenu $e) {
$dispatcher->addListener(App\Event\BuildAdminMenu::class, function(\App\Event\BuildAdminMenu $e) {
$callable = require(__DIR__.'/menus/admin.php');
$callable($e);
});
$dispatcher->addListener(App\Event\BuildStationMenu::NAME, function(\App\Event\BuildStationMenu $e) {
$dispatcher->addListener(App\Event\BuildStationMenu::class, function(\App\Event\BuildStationMenu $e) {
$callable = require(__DIR__.'/menus/station.php');
$callable($e);
});
// Build CLI commands
$dispatcher->addListener(Azura\Event\BuildConsoleCommands::NAME, function(Azura\Event\BuildConsoleCommands $event) {
$dispatcher->addListener(Azura\Event\BuildConsoleCommands::class, function(Azura\Event\BuildConsoleCommands $event) {
$event->getConsole()->addCommands([
// Liquidsoap Internal CLI Commands
new Command\Internal\NextSong,

View File

@ -2,249 +2,234 @@
use App\Controller;
use App\Middleware;
use App\Acl;
use Azura\App;
use Slim\App;
use Azura\Middleware as AzuraMiddleware;
use Slim\Routing\RouteCollectorProxy;
return function(App $app)
{
$app->group('/admin', function () {
/** @var App $this */
$this->get('', Controller\Admin\IndexController::class.':indexAction')
$app->group('/admin', function (RouteCollectorProxy $group) {
$group->get('', Controller\Admin\IndexController::class.':indexAction')
->setName('admin:index:index');
$this->get('/sync/{type}', Controller\Admin\IndexController::class.':syncAction')
$group->get('/sync/{type}', Controller\Admin\IndexController::class.':syncAction')
->setName('admin:index:sync')
->add([Middleware\Permissions::class, Acl::GLOBAL_ALL]);
->add(new Middleware\Permissions(Acl::GLOBAL_ALL));
$this->group('/install', function () {
/** @var App $this */
$group->group('/install', function (RouteCollectorProxy $group) {
$this->map(['GET', 'POST'], '/shoutcast', Controller\Admin\InstallShoutcastController::class)
$group->map(['GET', 'POST'], '/shoutcast', Controller\Admin\InstallShoutcastController::class)
->setName('admin:install:shoutcast');
})->add([Middleware\Permissions::class, Acl::GLOBAL_ALL]);
})->add(new Middleware\Permissions(Acl::GLOBAL_ALL));
$this->group('/api', function () {
/** @var App $this */
$group->group('/api', function (RouteCollectorProxy $group) {
$this->get('', Controller\Admin\ApiController::class.':indexAction')
$group->get('', Controller\Admin\ApiController::class.':indexAction')
->setName('admin:api:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\ApiController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\ApiController::class.':editAction')
->setName('admin:api:edit');
$this->get('/delete/{id}/{csrf}', Controller\Admin\ApiController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Admin\ApiController::class.':deleteAction')
->setName('admin:api:delete');
})->add([Middleware\Permissions::class, Acl::GLOBAL_API_KEYS]);
})->add(new Middleware\Permissions(Acl::GLOBAL_API_KEYS));
$this->group('/backups', function() {
/** @var App $this */
$group->group('/backups', function(RouteCollectorProxy $group) {
$this->get('', Controller\Admin\BackupsController::class)
$group->get('', Controller\Admin\BackupsController::class)
->setName('admin:backups:index');
$this->map(['GET', 'POST'], '/configure', Controller\Admin\BackupsController::class.':configureAction')
$group->map(['GET', 'POST'], '/configure', Controller\Admin\BackupsController::class.':configureAction')
->setName('admin:backups:configure');
$this->map(['GET', 'POST'], '/run', Controller\Admin\BackupsController::class.':runAction')
$group->map(['GET', 'POST'], '/run', Controller\Admin\BackupsController::class.':runAction')
->setName('admin:backups:run');
$this->get('/delete/{path}', Controller\Admin\BackupsController::class.':downloadAction')
$group->get('/delete/{path}', Controller\Admin\BackupsController::class.':downloadAction')
->setName('admin:backups:download');
$this->get('/delete/{path}/{csrf}', Controller\Admin\BackupsController::class.':deleteAction')
$group->get('/delete/{path}/{csrf}', Controller\Admin\BackupsController::class.':deleteAction')
->setName('admin:backups:delete');
})->add([Middleware\Permissions::class, Acl::GLOBAL_BACKUPS]);
})->add(new Middleware\Permissions(Acl::GLOBAL_BACKUPS));
$this->map(['GET', 'POST'], '/branding', Controller\Admin\BrandingController::class.':indexAction')
$group->map(['GET', 'POST'], '/branding', Controller\Admin\BrandingController::class.':indexAction')
->setName('admin:branding:index')
->add([Middleware\Permissions::class, Acl::GLOBAL_SETTINGS]);
->add(new Middleware\Permissions(Acl::GLOBAL_SETTINGS));
$this->group('/custom_fields', function() {
/** @var App $this */
$group->group('/custom_fields', function(RouteCollectorProxy $group) {
$this->get('', Controller\Admin\CustomFieldsController::class.':indexAction')
$group->get('', Controller\Admin\CustomFieldsController::class.':indexAction')
->setName('admin:custom_fields:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\CustomFieldsController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\CustomFieldsController::class.':editAction')
->setName('admin:custom_fields:edit');
$this->map(['GET', 'POST'], '/add', Controller\Admin\CustomFieldsController::class.':editAction')
$group->map(['GET', 'POST'], '/add', Controller\Admin\CustomFieldsController::class.':editAction')
->setName('admin:custom_fields:add');
$this->get('/delete/{id}/{csrf}', Controller\Admin\CustomFieldsController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Admin\CustomFieldsController::class.':deleteAction')
->setName('admin:custom_fields:delete');
})->add([Middleware\Permissions::class, Acl::GLOBAL_CUSTOM_FIELDS]);
})->add(new Middleware\Permissions(Acl::GLOBAL_CUSTOM_FIELDS));
$this->group('/logs', function () {
/** @var App $this */
$group->group('/logs', function (RouteCollectorProxy $group) {
$this->get('', Controller\Admin\LogsController::class)
$group->get('', Controller\Admin\LogsController::class)
->setName('admin:logs:index');
$this->get('/view/{station}/{log}', Controller\Admin\LogsController::class.':viewAction')
$group->get('/view/{station}/{log}', Controller\Admin\LogsController::class.':viewAction')
->setName('admin:logs:view')
->add([Middleware\GetStation::class, false]);
->add(Middleware\GetStation::class);
})
->add([Middleware\Permissions::class, Acl::GLOBAL_LOGS]);
})->add(new Middleware\Permissions(Acl::GLOBAL_LOGS));
$this->group('/permissions', function () {
/** @var App $this */
$group->group('/permissions', function (RouteCollectorProxy $group) {
$this->get('', Controller\Admin\PermissionsController::class.':indexAction')
$group->get('', Controller\Admin\PermissionsController::class.':indexAction')
->setName('admin:permissions:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\PermissionsController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\PermissionsController::class.':editAction')
->setName('admin:permissions:edit');
$this->map(['GET', 'POST'], '/add', Controller\Admin\PermissionsController::class.':editAction')
$group->map(['GET', 'POST'], '/add', Controller\Admin\PermissionsController::class.':editAction')
->setName('admin:permissions:add');
$this->get('/delete/{id}/{csrf}', Controller\Admin\PermissionsController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Admin\PermissionsController::class.':deleteAction')
->setName('admin:permissions:delete');
})->add([Middleware\Permissions::class, Acl::GLOBAL_PERMISSIONS]);
})->add(new Middleware\Permissions(Acl::GLOBAL_PERMISSIONS));
$this->get('/relays', Controller\Admin\RelaysController::class)
$group->get('/relays', Controller\Admin\RelaysController::class)
->setName('admin:relays:index')
->add([Middleware\Permissions::class, Acl::GLOBAL_STATIONS]);
->add(new Middleware\Permissions(Acl::GLOBAL_STATIONS));
$this->map(['GET', 'POST'], '/settings', Controller\Admin\SettingsController::class.':indexAction')
$group->map(['GET', 'POST'], '/settings', Controller\Admin\SettingsController::class.':indexAction')
->setName('admin:settings:index')
->add([Middleware\Permissions::class, Acl::GLOBAL_SETTINGS]);
->add(new Middleware\Permissions(Acl::GLOBAL_SETTINGS));
$this->group('/stations', function () {
/** @var App $this */
$group->group('/stations', function (RouteCollectorProxy $group) {
$this->get('', Controller\Admin\StationsController::class)
$group->get('', Controller\Admin\StationsController::class)
->setName('admin:stations:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\StationsController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\StationsController::class.':editAction')
->setName('admin:stations:edit');
$this->map(['GET', 'POST'], '/add', Controller\Admin\StationsController::class.':editAction')
$group->map(['GET', 'POST'], '/add', Controller\Admin\StationsController::class.':editAction')
->setName('admin:stations:add');
$this->map(['GET', 'POST'], '/clone/{id}', Controller\Admin\StationsController::class.':cloneAction')
$group->map(['GET', 'POST'], '/clone/{id}', Controller\Admin\StationsController::class.':cloneAction')
->setName('admin:stations:clone');
$this->get('/delete/{id}/{csrf}', Controller\Admin\StationsController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Admin\StationsController::class.':deleteAction')
->setName('admin:stations:delete');
})->add([Middleware\Permissions::class, Acl::GLOBAL_STATIONS]);
})->add(new Middleware\Permissions(Acl::GLOBAL_STATIONS));
$this->group('/users', function () {
/** @var App $this */
$group->group('/users', function (RouteCollectorProxy $group) {
$this->get('', Controller\Admin\UsersController::class.':indexAction')
$group->get('', Controller\Admin\UsersController::class.':indexAction')
->setName('admin:users:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\UsersController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\UsersController::class.':editAction')
->setName('admin:users:edit');
$this->map(['GET', 'POST'], '/add', Controller\Admin\UsersController::class.':editAction')
$group->map(['GET', 'POST'], '/add', Controller\Admin\UsersController::class.':editAction')
->setName('admin:users:add');
$this->get('/delete/{id}/{csrf}', Controller\Admin\UsersController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Admin\UsersController::class.':deleteAction')
->setName('admin:users:delete');
$this->get('/login-as/{id}/{csrf}', Controller\Admin\UsersController::class.':impersonateAction')
$group->get('/login-as/{id}/{csrf}', Controller\Admin\UsersController::class.':impersonateAction')
->setName('admin:users:impersonate');
})->add([Middleware\Permissions::class, Acl::GLOBAL_USERS]);
})->add(new Middleware\Permissions(Acl::GLOBAL_USERS));
// END /admin GROUP
})
->add(Middleware\Module\Admin::class)
->add(AzuraMiddleware\EnableView::class)
->add([Middleware\Permissions::class, Acl::GLOBAL_VIEW])
->add(new Middleware\Permissions(Acl::GLOBAL_VIEW))
->add(Middleware\RequireLogin::class);
$app->group('/api', function () {
/** @var App $this */
$app->group('/api', function (RouteCollectorProxy $group) {
$this->options('/{routes:.+}', function (\App\Http\Request $request, \App\Http\Response $response) {
$group->options('/{routes:.+}', function (\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response) {
return $response
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Access-Control-Allow-Headers', 'x-requested-with, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Origin', '*');
});
$this->get('', Controller\Api\IndexController::class.':indexAction')
$group->get('', Controller\Api\IndexController::class.':indexAction')
->setName('api:index:index');
$this->get('/openapi.yml', Controller\Api\OpenApiController::class)
$group->get('/openapi.yml', Controller\Api\OpenApiController::class)
->setName('api:openapi');
$this->get('/status', Controller\Api\IndexController::class.':statusAction')
$group->get('/status', Controller\Api\IndexController::class.':statusAction')
->setName('api:index:status');
$this->get('/time', Controller\Api\IndexController::class.':timeAction')
$group->get('/time', Controller\Api\IndexController::class.':timeAction')
->setName('api:index:time');
$this->group('/internal', function () {
/** @var App $this */
$group->group('/internal', function (RouteCollectorProxy $group) {
$this->group('/{station}', function() {
/** @var App $this */
$group->group('/{station}', function(RouteCollectorProxy $group) {
// Liquidsoap internal authentication functions
$this->map(['GET', 'POST'], '/auth', Controller\Api\InternalController::class.':authAction')
$group->map(['GET', 'POST'], '/auth', Controller\Api\InternalController::class.':authAction')
->setName('api:internal:auth');
$this->map(['GET', 'POST'], '/nextsong', Controller\Api\InternalController::class.':nextsongAction')
$group->map(['GET', 'POST'], '/nextsong', Controller\Api\InternalController::class.':nextsongAction')
->setName('api:internal:nextsong');
$this->map(['GET', 'POST'], '/djon', Controller\Api\InternalController::class.':djonAction')
$group->map(['GET', 'POST'], '/djon', Controller\Api\InternalController::class.':djonAction')
->setName('api:internal:djon');
$this->map(['GET', 'POST'], '/djoff', Controller\Api\InternalController::class.':djoffAction')
$group->map(['GET', 'POST'], '/djoff', Controller\Api\InternalController::class.':djoffAction')
->setName('api:internal:djoff');
$this->map(['GET', 'POST'], '/feedback', Controller\Api\InternalController::class.':feedbackAction')
$group->map(['GET', 'POST'], '/feedback', Controller\Api\InternalController::class.':feedbackAction')
->setName('api:internal:feedback');
})->add(Middleware\GetStation::class);
$this->get('/relays', Controller\Api\Admin\RelaysController::class)
$group->get('/relays', Controller\Api\Admin\RelaysController::class)
->setName('api:internal:relays')
->add(Middleware\RequireLogin::class);
$this->post('/relays', Controller\Api\Admin\RelaysController::class.':updateAction')
$group->post('/relays', Controller\Api\Admin\RelaysController::class.':updateAction')
->add(Middleware\RequireLogin::class);
});
$this->get('/nowplaying[/{station}]', Controller\Api\NowplayingController::class)
$group->get('/nowplaying[/{station}]', Controller\Api\NowplayingController::class)
->setName('api:nowplaying:index');
$this->get('/stations', Controller\Api\Stations\IndexController::class.':listAction')
$group->get('/stations', Controller\Api\Stations\IndexController::class.':listAction')
->setName('api:stations:list')
->add([AzuraMiddleware\RateLimit::class, 'api', 5, 2]);
->add(new AzuraMiddleware\RateLimit('api'));
$this->group('/admin', function() {
/** @var App $this */
$group->group('/admin', function(RouteCollectorProxy $group) {
$this->get('/permissions', Controller\Api\Admin\PermissionsController::class)
->add([Middleware\Permissions::class, Acl::GLOBAL_PERMISSIONS]);
$group->get('/permissions', Controller\Api\Admin\PermissionsController::class)
->add(new Middleware\Permissions(Acl::GLOBAL_PERMISSIONS));
$this->map(['GET', 'POST'], '/relays', function (\App\Http\Request $request, \App\Http\Response $response) {
return $response->withRedirect($request->getRouter()->fromHere('api:internal:relays'));
$group->map(['GET', 'POST'], '/relays', function (\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response) {
return \App\Http\ResponseHelper::withRedirect($response, \App\Http\RequestHelper::getRouter($request)->fromHere('api:internal:relays'));
});
$this->group('', function() {
/** @var App $this */
$this->get('/settings', Controller\Api\Admin\SettingsController::class.':listAction')
$group->group('', function(RouteCollectorProxy $group) {
$group->get('/settings', Controller\Api\Admin\SettingsController::class.':listAction')
->setName('api:admin:settings');
$this->put('/settings', Controller\Api\Admin\SettingsController::class.':updateAction');
})->add([Middleware\Permissions::class, Acl::GLOBAL_SETTINGS]);
$group->put('/settings', Controller\Api\Admin\SettingsController::class.':updateAction');
})->add(new Middleware\Permissions(Acl::GLOBAL_SETTINGS));
$admin_api_endpoints = [
['custom_field', 'custom_fields', Controller\Api\Admin\CustomFieldsController::class, Acl::GLOBAL_CUSTOM_FIELDS],
@ -254,59 +239,56 @@ return function(App $app)
];
foreach($admin_api_endpoints as [$singular, $plural, $class, $permission]) {
$this->group('', function() use ($singular, $plural, $class) {
/** @var App $this */
$this->get('/'.$plural, $class.':listAction')
$group->group('', function(RouteCollectorProxy $group) use ($singular, $plural, $class) {
$group->get('/'.$plural, $class.':listAction')
->setName('api:admin:'.$plural);
$this->post('/'.$plural, $class.':createAction');
$group->post('/'.$plural, $class.':createAction');
$this->get('/'.$singular.'/{id}', $class.':getAction')
$group->get('/'.$singular.'/{id}', $class.':getAction')
->setName('api:admin:'.$singular);
$this->put('/'.$singular.'/{id}', $class.':editAction');
$this->delete('/'.$singular.'/{id}', $class.':deleteAction');
})->add([Middleware\Permissions::class, $permission]);
$group->put('/'.$singular.'/{id}', $class.':editAction');
$group->delete('/'.$singular.'/{id}', $class.':deleteAction');
})->add(new Middleware\Permissions($permission));
}
});
$this->group('/station/{station}', function () {
/** @var App $this */
$group->group('/station/{station}', function (RouteCollectorProxy $group) {
$this->get('', Controller\Api\Stations\IndexController::class.':indexAction')
$group->get('', Controller\Api\Stations\IndexController::class.':indexAction')
->setName('api:stations:index')
->add([AzuraMiddleware\RateLimit::class, 'api', 5, 2]);
->add(new AzuraMiddleware\RateLimit('api', 5, 2));
$this->get('/nowplaying', Controller\Api\NowplayingController::class.':indexAction');
$group->get('/nowplaying', Controller\Api\NowplayingController::class.':indexAction');
$this->get('/history', Controller\Api\Stations\HistoryController::class)
$group->get('/history', Controller\Api\Stations\HistoryController::class)
->setName('api:stations:history')
->add([Middleware\Permissions::class, Acl::STATION_REPORTS, true]);
->add(new Middleware\Permissions(Acl::STATION_REPORTS, true));
$this->group('/queue', function() {
/** @var App $this */
$this->get('', Controller\Api\Stations\QueueController::class.':listAction')
$group->group('/queue', function(RouteCollectorProxy $group) {
$group->get('', Controller\Api\Stations\QueueController::class.':listAction')
->setName('api:stations:queue');
$this->get('/{id}', Controller\Api\Stations\QueueController::class.':getAction')
$group->get('/{id}', Controller\Api\Stations\QueueController::class.':getAction')
->setName('api:stations:queue:record');
$this->delete('/{id}', Controller\Api\Stations\QueueController::class.':deleteAction');
})->add([Middleware\Permissions::class, Acl::STATION_BROADCASTING, true]);
$group->delete('/{id}', Controller\Api\Stations\QueueController::class.':deleteAction');
})->add(new Middleware\Permissions(Acl::STATION_BROADCASTING, true));
$this->get('/requests', Controller\Api\Stations\RequestsController::class.':listAction')
$group->get('/requests', Controller\Api\Stations\RequestsController::class.':listAction')
->setName('api:requests:list');
$this->map(['GET', 'POST'], '/request/{media_id}', Controller\Api\Stations\RequestsController::class.':submitAction')
$group->map(['GET', 'POST'], '/request/{media_id}', Controller\Api\Stations\RequestsController::class.':submitAction')
->setName('api:requests:submit')
->add([AzuraMiddleware\RateLimit::class, 'api', 5, 2]);
->add(new AzuraMiddleware\RateLimit('api', 5, 2));
$this->get('/listeners', Controller\Api\Stations\ListenersController::class.':indexAction')
$group->get('/listeners', Controller\Api\Stations\ListenersController::class.':indexAction')
->setName('api:listeners:index')
->add([Middleware\Permissions::class, Acl::STATION_REPORTS, true]);
->add(new Middleware\Permissions(Acl::STATION_REPORTS, true));
$this->get('/art/{media_id:[a-zA-Z0-9]+}.jpg', Controller\Api\Stations\ArtController::class)
$group->get('/art/{media_id:[a-zA-Z0-9]+}.jpg', Controller\Api\Stations\ArtController::class)
->setName('api:stations:media:art');
$this->get('/art/{media_id:[a-zA-Z0-9]+}', Controller\Api\Stations\ArtController::class);
$group->get('/art/{media_id:[a-zA-Z0-9]+}', Controller\Api\Stations\ArtController::class);
$station_api_endpoints = [
['file', 'files', Controller\Api\Stations\FilesController::class, Acl::STATION_MEDIA],
@ -318,36 +300,36 @@ return function(App $app)
];
foreach($station_api_endpoints as [$singular, $plural, $class, $permission]) {
$this->group('', function() use ($singular, $plural, $class) {
/** @var App $this */
$this->get('/'.$plural, $class.':listAction')
$group->group('', function(RouteCollectorProxy $group) use ($singular, $plural, $class) {
$group->get('/'.$plural, $class.':listAction')
->setName('api:stations:'.$plural);
$this->post('/'.$plural, $class.':createAction');
$group->post('/'.$plural, $class.':createAction');
$this->get('/'.$singular.'/{id}', $class.':getAction')
$group->get('/'.$singular.'/{id}', $class.':getAction')
->setName('api:stations:'.$singular);
$this->put('/'.$singular.'/{id}', $class.':editAction');
$this->delete('/'.$singular.'/{id}', $class.':deleteAction');
})->add([Middleware\Permissions::class, $permission, true]);
$group->put('/'.$singular.'/{id}', $class.':editAction');
$group->delete('/'.$singular.'/{id}', $class.':deleteAction');
})->add(new Middleware\Permissions($permission, true));
}
$this->get('/status', Controller\Api\Stations\ServicesController::class.':statusAction')
$group->get('/status', Controller\Api\Stations\ServicesController::class.':statusAction')
->setName('api:stations:status')
->add([Middleware\Permissions::class, Acl::STATION_VIEW, true]);
->add(new Middleware\Permissions(Acl::STATION_VIEW, true));
$this->post('/backend/{do}', Controller\Api\Stations\ServicesController::class.':backendAction')
$group->post('/backend/{do}', Controller\Api\Stations\ServicesController::class.':backendAction')
->setName('api:stations:backend')
->add([Middleware\Permissions::class, Acl::STATION_BROADCASTING, true]);
->add(new Middleware\Permissions(Acl::STATION_BROADCASTING, true));
$this->post('/frontend/{do}', Controller\Api\Stations\ServicesController::class.':frontendAction')
$group->post('/frontend/{do}', Controller\Api\Stations\ServicesController::class.':frontendAction')
->setName('api:stations:frontend')
->add([Middleware\Permissions::class, Acl::STATION_BROADCASTING, true]);
->add(new Middleware\Permissions(Acl::STATION_BROADCASTING, true));
$this->post('/restart', Controller\Api\Stations\ServicesController::class.':restartAction')
$group->post('/restart', Controller\Api\Stations\ServicesController::class.':restartAction')
->setName('api:stations:restart')
->add([Middleware\Permissions::class, Acl::STATION_BROADCASTING, true]);
->add(new Middleware\Permissions(Acl::STATION_BROADCASTING, true));
})->add(Middleware\GetStation::class);
})->add(Middleware\GetStation::class)
->add(Middleware\RequireStation::class);
// END /api GROUP
@ -357,43 +339,42 @@ return function(App $app)
$app->get('/', Controller\Frontend\IndexController::class.':indexAction')
->setName('home');
$app->group('', function() {
/** @var App $this */
$app->group('', function(RouteCollectorProxy $group) {
$this->get('/dashboard', Controller\Frontend\DashboardController::class.':indexAction')
$group->get('/dashboard', Controller\Frontend\DashboardController::class.':indexAction')
->setName('dashboard');
$this->get('/logout', Controller\Frontend\AccountController::class.':logoutAction')
$group->get('/logout', Controller\Frontend\AccountController::class.':logoutAction')
->setName('account:logout');
$this->get('/endsession', Controller\Frontend\AccountController::class.':endmasqueradeAction')
$group->get('/endsession', Controller\Frontend\AccountController::class.':endmasqueradeAction')
->setName('account:endmasquerade');
$this->get('/profile', Controller\Frontend\ProfileController::class.':indexAction')
$group->get('/profile', Controller\Frontend\ProfileController::class.':indexAction')
->setName('profile:index');
$this->map(['GET', 'POST'], '/profile/edit', Controller\Frontend\ProfileController::class.':editAction')
$group->map(['GET', 'POST'], '/profile/edit', Controller\Frontend\ProfileController::class.':editAction')
->setName('profile:edit');
$this->map(['GET', 'POST'], '/profile/2fa/enable', Controller\Frontend\ProfileController::class.':enableTwoFactorAction')
$group->map(['GET', 'POST'], '/profile/2fa/enable', Controller\Frontend\ProfileController::class.':enableTwoFactorAction')
->setName('profile:2fa:enable');
$this->map(['GET', 'POST'], '/profile/2fa/disable', Controller\Frontend\ProfileController::class.':disableTwoFactorAction')
$group->map(['GET', 'POST'], '/profile/2fa/disable', Controller\Frontend\ProfileController::class.':disableTwoFactorAction')
->setName('profile:2fa:disable');
$this->get('/profile/theme', Controller\Frontend\ProfileController::class.':themeAction')
$group->get('/profile/theme', Controller\Frontend\ProfileController::class.':themeAction')
->setName('profile:theme');
$this->get('/api_keys', Controller\Frontend\ApiKeysController::class.':indexAction')
$group->get('/api_keys', Controller\Frontend\ApiKeysController::class.':indexAction')
->setName('api_keys:index');
$this->map(['GET', 'POST'], '/api_keys/edit/{id}', Controller\Frontend\ApiKeysController::class.':editAction')
$group->map(['GET', 'POST'], '/api_keys/edit/{id}', Controller\Frontend\ApiKeysController::class.':editAction')
->setName('api_keys:edit');
$this->map(['GET', 'POST'], '/api_keys/add', Controller\Frontend\ApiKeysController::class.':editAction')
$group->map(['GET', 'POST'], '/api_keys/add', Controller\Frontend\ApiKeysController::class.':editAction')
->setName('api_keys:add');
$this->get('/api_keys/delete/{id}/{csrf}', Controller\Frontend\ApiKeysController::class.':deleteAction')
$group->get('/api_keys/delete/{id}/{csrf}', Controller\Frontend\ApiKeysController::class.':deleteAction')
->setName('api_keys:delete');
})
->add(AzuraMiddleware\EnableView::class)
@ -407,267 +388,255 @@ return function(App $app)
->setName('account:login:2fa')
->add(AzuraMiddleware\EnableView::class);
$app->group('/setup', function () {
/** @var App $this */
$app->group('/setup', function (RouteCollectorProxy $group) {
$this->map(['GET', 'POST'], '', Controller\Frontend\SetupController::class.':indexAction')
$group->map(['GET', 'POST'], '', Controller\Frontend\SetupController::class.':indexAction')
->setName('setup:index');
$this->map(['GET', 'POST'], '/complete', Controller\Frontend\SetupController::class.':completeAction')
$group->map(['GET', 'POST'], '/complete', Controller\Frontend\SetupController::class.':completeAction')
->setName('setup:complete');
$this->map(['GET', 'POST'], '/register', Controller\Frontend\SetupController::class.':registerAction')
$group->map(['GET', 'POST'], '/register', Controller\Frontend\SetupController::class.':registerAction')
->setName('setup:register');
$this->map(['GET', 'POST'], '/station', Controller\Frontend\SetupController::class.':stationAction')
$group->map(['GET', 'POST'], '/station', Controller\Frontend\SetupController::class.':stationAction')
->setName('setup:station');
$this->map(['GET', 'POST'], '/settings', Controller\Frontend\SetupController::class.':settingsAction')
$group->map(['GET', 'POST'], '/settings', Controller\Frontend\SetupController::class.':settingsAction')
->setName('setup:settings');
})
->add(AzuraMiddleware\EnableView::class);
$app->group('/public/{station}', function () {
/** @var App $this */
$app->group('/public/{station}', function (RouteCollectorProxy $group) {
$this->get('', Controller\Frontend\PublicController::class.':indexAction')
$group->get('', Controller\Frontend\PublicController::class.':indexAction')
->setName('public:index');
$this->get('/embed', Controller\Frontend\PublicController::class.':embedAction')
$group->get('/embed', Controller\Frontend\PublicController::class.':embedAction')
->setName('public:embed');
$this->get('/embed-requests', Controller\Frontend\PublicController::class.':embedrequestsAction')
$group->get('/embed-requests', Controller\Frontend\PublicController::class.':embedrequestsAction')
->setName('public:embedrequests');
$this->get('/playlist[/{format}]', Controller\Frontend\PublicController::class.':playlistAction')
$group->get('/playlist[/{format}]', Controller\Frontend\PublicController::class.':playlistAction')
->setName('public:playlist');
$this->get('/dj', Controller\Frontend\PublicController::class.':djAction')
$group->get('/dj', Controller\Frontend\PublicController::class.':djAction')
->setName('public:dj');
})
->add(Middleware\GetStation::class)
->add(AzuraMiddleware\EnableView::class);
$app->group('/station/{station}', function () {
/** @var App $this */
$app->group('/station/{station}', function (RouteCollectorProxy $group) {
$this->get('', function (\App\Http\Request $request, \App\Http\Response $response) {
return $response->withRedirect($request->getRouter()->fromHere('stations:profile:index'));
$group->get('', function (\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response) {
return \App\Http\ResponseHelper::withRedirect($response, \App\Http\RequestHelper::getRouter($request)->fromHere('stations:profile:index'));
})->setName('stations:index:index');
$this->group('/automation', function () {
/** @var App $this */
$group->group('/automation', function (RouteCollectorProxy $group) {
$this->map(['GET', 'POST'], '', Controller\Stations\AutomationController::class.':indexAction')
$group->map(['GET', 'POST'], '', Controller\Stations\AutomationController::class.':indexAction')
->setName('stations:automation:index');
$this->get('/run', Controller\Stations\AutomationController::class.':runAction')
$group->get('/run', Controller\Stations\AutomationController::class.':runAction')
->setName('stations:automation:run');
})->add([Middleware\Permissions::class, Acl::STATION_AUTOMATION, true]);
})->add(new Middleware\Permissions(Acl::STATION_AUTOMATION, true));
$this->group('/files', function () {
/** @var App $this */
$group->group('/files', function (RouteCollectorProxy $group) {
$this->get('', Controller\Stations\Files\FilesController::class)
$group->get('', Controller\Stations\Files\FilesController::class)
->setName('stations:files:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\Files\EditController::class)
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\Files\EditController::class)
->setName('stations:files:edit');
$this->map(['GET', 'POST'], '/rename', Controller\Stations\Files\FilesController::class.':renameAction')
$group->map(['GET', 'POST'], '/rename', Controller\Stations\Files\FilesController::class.':renameAction')
->setName('stations:files:rename');
$this->map(['GET', 'POST'], '/list', Controller\Stations\Files\ListController::class)
$group->map(['GET', 'POST'], '/list', Controller\Stations\Files\ListController::class)
->setName('stations:files:list');
$this->map(['GET', 'POST'], '/directories', Controller\Stations\Files\FilesController::class.':listDirectoriesAction')
$group->map(['GET', 'POST'], '/directories', Controller\Stations\Files\FilesController::class.':listDirectoriesAction')
->setName('stations:files:directories');
$this->map(['GET', 'POST'], '/batch', Controller\Stations\Files\BatchController::class)
$group->map(['GET', 'POST'], '/batch', Controller\Stations\Files\BatchController::class)
->setName('stations:files:batch');
$this->map(['GET', 'POST'], '/mkdir', Controller\Stations\Files\FilesController::class.':mkdirAction')
$group->map(['GET', 'POST'], '/mkdir', Controller\Stations\Files\FilesController::class.':mkdirAction')
->setName('stations:files:mkdir');
$this->map(['GET', 'POST'], '/upload', Controller\Stations\Files\FilesController::class.':uploadAction')
$group->map(['GET', 'POST'], '/upload', Controller\Stations\Files\FilesController::class.':uploadAction')
->setName('stations:files:upload');
$this->map(['GET', 'POST'], '/download', Controller\Stations\Files\FilesController::class.':downloadAction')
$group->map(['GET', 'POST'], '/download', Controller\Stations\Files\FilesController::class.':downloadAction')
->setName('stations:files:download');
})
->add(Middleware\Module\StationFiles::class)
->add([Middleware\Permissions::class, Acl::STATION_MEDIA, true]);
->add(new Middleware\Permissions(Acl::STATION_MEDIA, true));
$this->group('/logs', function () {
/** @var App $this */
$group->group('/logs', function (RouteCollectorProxy $group) {
$this->get('', Controller\Stations\LogsController::class)
$group->get('', Controller\Stations\LogsController::class)
->setName('stations:logs:index');
$this->get('/view/{log}', Controller\Stations\LogsController::class.':viewAction')
$group->get('/view/{log}', Controller\Stations\LogsController::class.':viewAction')
->setName('stations:logs:view');
})
->add([Middleware\Permissions::class, Acl::STATION_LOGS, true]);
})->add(new Middleware\Permissions(Acl::STATION_LOGS, true));
$this->group('/playlists', function () {
/** @var App $this */
$group->group('/playlists', function (RouteCollectorProxy $group) {
$this->get('', Controller\Stations\PlaylistsController::class.':indexAction')
$group->get('', Controller\Stations\PlaylistsController::class.':indexAction')
->setName('stations:playlists:index');
$this->get('/schedule', Controller\Stations\PlaylistsController::class.':scheduleAction')
$group->get('/schedule', Controller\Stations\PlaylistsController::class.':scheduleAction')
->setName('stations:playlists:schedule');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\PlaylistsController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\PlaylistsController::class.':editAction')
->setName('stations:playlists:edit');
$this->map(['GET', 'POST'], '/add', Controller\Stations\PlaylistsController::class.':editAction')
$group->map(['GET', 'POST'], '/add', Controller\Stations\PlaylistsController::class.':editAction')
->setName('stations:playlists:add');
$this->get('/delete/{id}/{csrf}', Controller\Stations\PlaylistsController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Stations\PlaylistsController::class.':deleteAction')
->setName('stations:playlists:delete');
$this->map(['GET', 'POST'], '/reorder/{id}', Controller\Stations\PlaylistsController::class.':reorderAction')
$group->map(['GET', 'POST'], '/reorder/{id}', Controller\Stations\PlaylistsController::class.':reorderAction')
->setName('stations:playlists:reorder');
$this->get('/toggle/{id}', Controller\Stations\PlaylistsController::class.':toggleAction')
$group->get('/toggle/{id}', Controller\Stations\PlaylistsController::class.':toggleAction')
->setName('stations:playlists:toggle');
$this->get('/export/{id}[/{format}]', Controller\Stations\PlaylistsController::class.':exportAction')
$group->get('/export/{id}[/{format}]', Controller\Stations\PlaylistsController::class.':exportAction')
->setName('stations:playlists:export');
})->add([Middleware\Permissions::class, Acl::STATION_MEDIA, true]);
})->add(new Middleware\Permissions(Acl::STATION_MEDIA, true));
$this->group('/mounts', function () {
/** @var App $this */
$group->group('/mounts', function (RouteCollectorProxy $group) {
$this->get('', Controller\Stations\MountsController::class.':indexAction')
$group->get('', Controller\Stations\MountsController::class.':indexAction')
->setName('stations:mounts:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\MountsController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\MountsController::class.':editAction')
->setName('stations:mounts:edit');
$this->map(['GET', 'POST'], '/add', Controller\Stations\MountsController::class.':editAction')
$group->map(['GET', 'POST'], '/add', Controller\Stations\MountsController::class.':editAction')
->setName('stations:mounts:add');
$this->get('/delete/{id}/{csrf}', Controller\Stations\MountsController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Stations\MountsController::class.':deleteAction')
->setName('stations:mounts:delete');
})->add([Middleware\Permissions::class, Acl::STATION_MOUNTS, true]);
})->add(new Middleware\Permissions(Acl::STATION_MOUNTS, true));
$this->get('/profile', Controller\Stations\ProfileController::class)
$group->get('/profile', Controller\Stations\ProfileController::class)
->setName('stations:profile:index');
$this->get('/profile/toggle/{feature}/{csrf}', Controller\Stations\ProfileController::class.':toggleAction')
$group->get('/profile/toggle/{feature}/{csrf}', Controller\Stations\ProfileController::class.':toggleAction')
->setName('stations:profile:toggle')
->add([Middleware\Permissions::class, Acl::STATION_PROFILE, true]);
->add(new Middleware\Permissions(Acl::STATION_PROFILE, true));
$this->map(['GET', 'POST'], '/profile/edit', Controller\Stations\ProfileController::class.':editAction')
$group->map(['GET', 'POST'], '/profile/edit', Controller\Stations\ProfileController::class.':editAction')
->setName('stations:profile:edit')
->add([Middleware\Permissions::class, Acl::STATION_PROFILE, true]);
->add(new Middleware\Permissions(Acl::STATION_PROFILE, true));
$this->get('/queue', Controller\Stations\QueueController::class)
$group->get('/queue', Controller\Stations\QueueController::class)
->setName('stations:queue:index');
$this->group('/remotes', function () {
/** @var App $this */
$group->group('/remotes', function (RouteCollectorProxy $group) {
$this->get('', Controller\Stations\RemotesController::class.':indexAction')
$group->get('', Controller\Stations\RemotesController::class.':indexAction')
->setName('stations:remotes:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\RemotesController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\RemotesController::class.':editAction')
->setName('stations:remotes:edit');
$this->map(['GET', 'POST'], '/add', Controller\Stations\RemotesController::class.':editAction')
$group->map(['GET', 'POST'], '/add', Controller\Stations\RemotesController::class.':editAction')
->setName('stations:remotes:add');
$this->get('/delete/{id}/{csrf}', Controller\Stations\RemotesController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Stations\RemotesController::class.':deleteAction')
->setName('stations:remotes:delete');
})->add([Middleware\Permissions::class, Acl::STATION_REMOTES, true]);
})->add(new Middleware\Permissions(Acl::STATION_REMOTES, true));
$this->group('/reports', function () {
/** @var App $this */
$group->group('/reports', function (RouteCollectorProxy $group) {
$this->get('/overview', Controller\Stations\Reports\OverviewController::class)
$group->get('/overview', Controller\Stations\Reports\OverviewController::class)
->setName('stations:reports:overview');
$this->get('/timeline[/format/{format}]', Controller\Stations\Reports\TimelineController::class)
$group->get('/timeline[/format/{format}]', Controller\Stations\Reports\TimelineController::class)
->setName('stations:reports:timeline');
$this->get('/performance[/format/{format}]', Controller\Stations\Reports\PerformanceController::class)
$group->get('/performance[/format/{format}]', Controller\Stations\Reports\PerformanceController::class)
->setName('stations:reports:performance');
$this->get('/duplicates', Controller\Stations\Reports\DuplicatesController::class)
$group->get('/duplicates', Controller\Stations\Reports\DuplicatesController::class)
->setName('stations:reports:duplicates');
$this->get('/duplicates/delete/{media_id}', Controller\Stations\Reports\DuplicatesController::class.':deleteAction')
$group->get('/duplicates/delete/{media_id}', Controller\Stations\Reports\DuplicatesController::class.':deleteAction')
->setName('stations:reports:duplicates:delete');
$this->map(['GET', 'POST'], '/listeners', Controller\Stations\Reports\ListenersController::class)
$group->map(['GET', 'POST'], '/listeners', Controller\Stations\Reports\ListenersController::class)
->setName('stations:reports:listeners');
$this->map(['GET', 'POST'], '/soundexchange', Controller\Stations\Reports\SoundExchangeController::class)
$group->map(['GET', 'POST'], '/soundexchange', Controller\Stations\Reports\SoundExchangeController::class)
->setName('stations:reports:soundexchange');
$this->get('/requests', Controller\Stations\Reports\RequestsController::class)
$group->get('/requests', Controller\Stations\Reports\RequestsController::class)
->setName('stations:reports:requests');
$this->get('/requests/delete/{request_id}/{csrf}', Controller\Stations\Reports\RequestsController::class.':deleteAction')
$group->get('/requests/delete/{request_id}/{csrf}', Controller\Stations\Reports\RequestsController::class.':deleteAction')
->setName('stations:reports:requests:delete');
})->add([Middleware\Permissions::class, Acl::STATION_REPORTS, true]);
})->add(new Middleware\Permissions(Acl::STATION_REPORTS, true));
$this->group('/streamers', function () {
/** @var App $this */
$group->group('/streamers', function (RouteCollectorProxy $group) {
$this->get('', Controller\Stations\StreamersController::class.':indexAction')
$group->get('', Controller\Stations\StreamersController::class.':indexAction')
->setName('stations:streamers:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\StreamersController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\StreamersController::class.':editAction')
->setName('stations:streamers:edit');
$this->map(['GET', 'POST'], '/add', Controller\Stations\StreamersController::class.':editAction')
$group->map(['GET', 'POST'], '/add', Controller\Stations\StreamersController::class.':editAction')
->setName('stations:streamers:add');
$this->get('/delete/{id}/{csrf}', Controller\Stations\StreamersController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Stations\StreamersController::class.':deleteAction')
->setName('stations:streamers:delete');
})->add([Middleware\Permissions::class, Acl::STATION_STREAMERS, true]);
})->add(new Middleware\Permissions(Acl::STATION_STREAMERS, true));
$this->group('/webhooks', function () {
/** @var App $this */
$group->group('/webhooks', function (RouteCollectorProxy $group) {
$this->get('', Controller\Stations\WebhooksController::class.':indexAction')
$group->get('', Controller\Stations\WebhooksController::class.':indexAction')
->setName('stations:webhooks:index');
$this->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\WebhooksController::class.':editAction')
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Stations\WebhooksController::class.':editAction')
->setName('stations:webhooks:edit');
$this->map(['GET', 'POST'], '/add[/{type}]', Controller\Stations\WebhooksController::class.':addAction')
$group->map(['GET', 'POST'], '/add[/{type}]', Controller\Stations\WebhooksController::class.':addAction')
->setName('stations:webhooks:add');
$this->get('/toggle/{id}/{csrf}', Controller\Stations\WebhooksController::class.':toggleAction')
$group->get('/toggle/{id}/{csrf}', Controller\Stations\WebhooksController::class.':toggleAction')
->setName('stations:webhooks:toggle');
$this->get('/test/{id}/{csrf}', Controller\Stations\WebhooksController::class.':testAction')
$group->get('/test/{id}/{csrf}', Controller\Stations\WebhooksController::class.':testAction')
->setName('stations:webhooks:test');
$this->get('/delete/{id}/{csrf}', Controller\Stations\WebhooksController::class.':deleteAction')
$group->get('/delete/{id}/{csrf}', Controller\Stations\WebhooksController::class.':deleteAction')
->setName('stations:webhooks:delete');
})->add([Middleware\Permissions::class, Acl::STATION_WEB_HOOKS, true]);
})->add(new Middleware\Permissions(Acl::STATION_WEB_HOOKS, true));
// END /stations GROUP
})
->add(Middleware\Module\Stations::class)
->add([Middleware\Permissions::class, Acl::STATION_VIEW, true])
->add(new Middleware\Permissions(Acl::STATION_VIEW, true))
->add(Middleware\RequireStation::class)
->add(Middleware\GetStation::class)
->add(AzuraMiddleware\EnableView::class)
->add(Middleware\RequireLogin::class);

View File

@ -1,155 +1,48 @@
<?php
return function (\Azura\Container $di)
{
// Override Slim handlers.
$di['request'] = function (\Azura\Container $di) {
return \App\Http\Request::createFromEnvironment($di->get('environment'));
};
/**
* PHP-DI Services
*/
$di['response'] = function (\Azura\Container $di) {
$headers = new \Slim\Http\Headers(['Content-Type' => 'text/html; charset=UTF-8']);
$response = new \App\Http\Response(200, $headers, null);
use Azura\Settings;
use Doctrine\ORM\EntityManager;
use Psr\Container\ContainerInterface;
return $response->withProtocolVersion($di->get('settings')['httpVersion']);
};
return [
$di['router'] = function(\Azura\Container $container) {
$routerCacheFile = $container->get('settings')[\Azura\Settings::SLIM_ROUTER_CACHE_FILE];
$router = new \App\Http\Router();
$router->setCacheFile($routerCacheFile);
$router->setContainer($container);
return $router;
};
/*
* Slim Component Overrides
*/
$di[\App\Http\ErrorHandler::class] = function($di) {
return new \App\Http\ErrorHandler(
$di[\App\Acl::class],
$di[\Monolog\Logger::class],
$di['router'],
$di[\Azura\Session::class],
$di[\Azura\View::class],
$di[\App\Service\Sentry::class]
);
};
$di->addAlias('phpErrorHandler', \App\Http\ErrorHandler::class);
$di->addAlias('errorHandler', \App\Http\ErrorHandler::class);
// URL Router helper
App\Http\Router::class => function(
Settings $settings,
\Slim\App $app,
EntityManager $em
) {
$route_parser = $app->getRouteCollector()->getRouteParser();
return new App\Http\Router($settings, $route_parser, $em);
},
Azura\Http\RouterInterface::class => DI\Get(App\Http\Router::class),
$di['notFoundHandler'] = function ($di) {
return function (\App\Http\Request $request, \App\Http\Response $response) use ($di) {
/** @var \Azura\View $view */
$view = $di[\Azura\View::class];
// Error Handler
App\Http\ErrorHandler::class => DI\autowire(),
Slim\Interfaces\ErrorHandlerInterface::class => DI\Get(App\Http\ErrorHandler::class),
return $view->renderToResponse($response->withStatus(404), 'system/error_pagenotfound');
};
};
/*
* Doctrine Database
*/
$di[\App\Entity\Repository\SettingsRepository::class] = function($di) {
/** @var \Doctrine\ORM\EntityManager $em */
$em = $di[\Doctrine\ORM\EntityManager::class];
return new \App\Entity\Repository\SettingsRepository(
$em,
$em->getClassMetadata(\App\Entity\Settings::class)
);
};
$di[\App\Entity\Repository\StationRepository::class] = function($di) {
/** @var \Doctrine\ORM\EntityManager $em */
$em = $di[\Doctrine\ORM\EntityManager::class];
return new \App\Entity\Repository\StationRepository(
$em,
$em->getClassMetadata(\App\Entity\Station::class),
$di[\App\Sync\Task\Media::class],
$di[\App\Radio\Adapters::class],
$di[\App\Radio\Configuration::class],
$di[\Azura\Cache::class],
$di[\Symfony\Component\Validator\Validator\ValidatorInterface::class]
);
};
$di[\App\Entity\Repository\StationMediaRepository::class] = function($di) {
/** @var \Doctrine\ORM\EntityManager $em */
$em = $di[\Doctrine\ORM\EntityManager::class];
return new \App\Entity\Repository\StationMediaRepository(
$em,
$em->getClassMetadata(\App\Entity\StationMedia::class),
$di[\App\Radio\Filesystem::class]
);
};
$di[\App\Entity\Repository\StationPlaylistMediaRepository::class] = function($di) {
/** @var \Doctrine\ORM\EntityManager $em */
$em = $di[\Doctrine\ORM\EntityManager::class];
return new \App\Entity\Repository\StationPlaylistMediaRepository(
$em,
$em->getClassMetadata(\App\Entity\StationPlaylistMedia::class),
$di[\Azura\Cache::class]
);
};
$di[\App\Auth::class] = function ($di) {
/** @var \Doctrine\ORM\EntityManager $em */
$em = $di[\Doctrine\ORM\EntityManager::class];
/** @var App\Entity\Repository\UserRepository $user_repo */
$user_repo = $em->getRepository(App\Entity\User::class);
return new \App\Auth($di[\Azura\Session::class], $user_repo);
};
$di[\App\Acl::class] = function ($di) {
/** @var \Doctrine\ORM\EntityManager $em */
$em = $di[\Doctrine\ORM\EntityManager::class];
/** @var App\Entity\Repository\RolePermissionRepository $permissions_repo */
$permissions_repo = $em->getRepository(App\Entity\RolePermission::class);
return new \App\Acl($permissions_repo);
};
$di[\InfluxDB\Database::class] = function ($di) {
$opts = [
'host' => (APP_INSIDE_DOCKER) ? 'influxdb' : 'localhost',
'port' => 8086,
];
$influx = new \InfluxDB\Client($opts['host'], $opts['port']);
return $influx->selectDB('stations');
};
$di[\Supervisor\Supervisor::class] = function ($di) {
$guzzle_client = new \GuzzleHttp\Client();
$client = new \fXmlRpc\Client(
'http://' . (APP_INSIDE_DOCKER ? 'stations' : '127.0.0.1') . ':9001/RPC2',
new \fXmlRpc\Transport\HttpAdapterTransport(
new \Http\Message\MessageFactory\GuzzleMessageFactory(),
new \Http\Adapter\Guzzle6\Client($guzzle_client)
)
);
$connector = new \Supervisor\Connector\XmlRpc($client);
$supervisor = new \Supervisor\Supervisor($connector);
if (!$supervisor->isConnected()) {
throw new \Azura\Exception(sprintf('Could not connect to supervisord.'));
}
return $supervisor;
};
$di->extend(\Doctrine\ORM\EntityManager::class, function(\Doctrine\ORM\EntityManager $em, \Azura\Container $di) {
EntityManager::class => DI\decorate(function(EntityManager $em, ContainerInterface $di) {
$event_manager = $em->getEventManager();
$event_manager->addEventSubscriber(new \App\Doctrine\Event\StationRequiresRestart);
$event_manager->addEventSubscriber(new App\Doctrine\Event\StationRequiresRestart);
return $em;
});
$di->extend(\Azura\View::class, function(\Azura\View $view, \Azura\Container $di) {
}),
/*
* View
*/
Azura\View::class => DI\decorate(function(Azura\View $view, ContainerInterface $di) {
$view->registerFunction('mailto', function ($address, $link_text = null) {
$address = substr(chunk_split(bin2hex(" $address"), 2, ";&#x"), 3, -3);
$link_text = $link_text ?? $address;
@ -158,15 +51,14 @@ return function (\Azura\Container $di)
$view->registerFunction('pluralize', function ($word, $num = 0) {
if ((int)$num === 1) {
return $word;
} else {
return \Doctrine\Common\Inflector\Inflector::pluralize($word);
}
return Doctrine\Common\Inflector\Inflector::pluralize($word);
});
$view->registerFunction('truncate', function ($text, $length = 80) {
return \App\Utilities::truncateText($text, $length);
return App\Utilities::truncateText($text, $length);
});
$view->registerFunction('truncateUrl', function($url) {
return \App\Utilities::truncateUrl($url);
return App\Utilities::truncateUrl($url);
});
$view->registerFunction('link', function($url, $external = true, $truncate = true) {
$url = htmlspecialchars($url, \ENT_QUOTES, 'UTF-8');
@ -176,177 +68,331 @@ return function (\Azura\Container $di)
$a[] = 'target="_blank"';
}
$a_body = ($truncate) ? \App\Utilities::truncateUrl($url) : $url;
$a_body = ($truncate) ? App\Utilities::truncateUrl($url) : $url;
return '<a '.implode(' ', $a).'>'.$a_body.'</a>';
});
$view->addData([
'assets' => $di[\Azura\Assets::class],
'auth' => $di[\App\Auth::class],
'acl' => $di[\App\Acl::class],
'customization' => $di[\App\Customization::class],
'version' => $di[\App\Version::class],
'assets' => $di->get(Azura\Assets::class),
'auth' => $di->get(App\Auth::class),
'acl' => $di->get(App\Acl::class),
'customization' => $di->get(App\Customization::class),
'version' => $di->get(App\Version::class),
]);
return $view;
});
}),
// MaxMind (IP Geolocation database for listener metadata)
$di[\MaxMind\Db\Reader::class] = function($di) {
$mmdb_path = dirname(APP_INCLUDE_ROOT).'/geoip/GeoLite2-City.mmdb';
return new \MaxMind\Db\Reader($mmdb_path);
};
/*
* Event Dispatcher
*/
$di->extend(\Azura\EventDispatcher::class, function(\Azura\EventDispatcher $dispatcher, \Azura\Container $di) {
if (isset($di[\App\Plugins::class])) {
/** @var \App\Plugins $plugins */
$plugins = $di[\App\Plugins::class];
Azura\EventDispatcher::class => DI\decorate(function(Azura\EventDispatcher $dispatcher, ContainerInterface $di) {
if ($di->has(App\Plugins::class)) {
/** @var App\Plugins $plugins */
$plugins = $di->get(App\Plugins::class);
// Register plugin-provided events.
$plugins->registerEvents($dispatcher);
}
return $dispatcher;
});
}),
$di->extend(\Azura\Console\Application::class, function(\Azura\Console\Application $console, $di) {
/** @var \App\Version $version */
$version = $di[\App\Version::class];
/*
* Console
*/
/** @var \Azura\Settings $settings */
$settings = $di['settings'];
Azura\Console\Application::class => DI\decorate(function(Azura\Console\Application $console, ContainerInterface $di) {
/** @var App\Version $version */
$version = $di->get(App\Version::class);
$console->setName($settings[\Azura\Settings::APP_NAME].' Command Line Tools ('.$settings[\Azura\Settings::APP_ENV].')');
/** @var Settings $settings */
$settings = $di->get(Settings::class);
$console->setName($settings[Settings::APP_NAME].' Command Line Tools ('.$settings[Settings::APP_ENV].')');
$console->setVersion($version->getVersion());
return $console;
});
}),
$di[\App\MessageQueue::class] = function($di) {
/*
* AzuraCast-specific dependencies
*/
App\Acl::class => DI\autowire(),
App\Auth::class => DI\autowire(),
App\ApiUtilities::class => DI\autowire(),
App\Customization::class => DI\autowire(),
App\Version::class => DI\autowire(),
App\Service\Sentry::class => DI\autowire(),
App\Service\NChan::class => DI\autowire(),
App\Validator\Constraints\StationPortCheckerValidator::class => DI\autowire(),
// Message queue manager class
App\MessageQueue::class => function(
DI\FactoryInterface $factory,
ContainerInterface $di,
Monolog\Logger $logger
) {
// Build QueueFactory
/** @var \Redis $redis */
$redis = $di[\Redis::class];
$redis->select(4);
$driver = new \Bernard\Driver\PhpRedis\Driver($redis);
/** @var Redis $redis */
$redis = $factory->make(Redis::class);
$normalizer = new \Normalt\Normalizer\AggregateNormalizer([
new \Bernard\Normalizer\EnvelopeNormalizer,
new \Symfony\Component\Serializer\Normalizer\PropertyNormalizer
$redis->select(4);
$driver = new Bernard\Driver\PhpRedis\Driver($redis);
$normalizer = new Normalt\Normalizer\AggregateNormalizer([
new Bernard\Normalizer\EnvelopeNormalizer,
new Symfony\Component\Serializer\Normalizer\PropertyNormalizer
]);
$symfony_serializer = new \Symfony\Component\Serializer\Serializer([$normalizer]);
$serializer = new \Bernard\Serializer($normalizer);
$symfony_serializer = new Symfony\Component\Serializer\Serializer([$normalizer]);
$serializer = new Bernard\Serializer($normalizer);
$queue_factory = new \Bernard\QueueFactory\PersistentFactory($driver, $serializer);
$queue_factory = new Bernard\QueueFactory\PersistentFactory($driver, $serializer);
// Event dispatcher
$dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher;
$dispatcher = new Symfony\Component\EventDispatcher\EventDispatcher;
// Build Producer
$producer = new \Bernard\Producer($queue_factory, $dispatcher);
$producer = new Bernard\Producer($queue_factory, $dispatcher);
// Build Consumer
$receivers = require __DIR__.'/messagequeue.php';
$router = new \Bernard\Router\ReceiverMapRouter($receivers, new \Bernard\Router\ContainerReceiverResolver($di));
$receivers = require __DIR__ . '/messagequeue.php';
$router = new Bernard\Router\ReceiverMapRouter($receivers, new Bernard\Router\ContainerReceiverResolver($di));
$consumer = new Bernard\Consumer($router, $dispatcher);
$mq = new \App\MessageQueue(
$mq = new App\MessageQueue(
$queue_factory,
$producer,
$consumer,
$di[\Monolog\Logger::class]
$logger
);
$dispatcher->addSubscriber($mq);
return $mq;
};
},
//
// AzuraCast-specific dependencies
//
// MaxMind (IP Geolocation database for listener metadata)
MaxMind\Db\Reader::class => function(Settings $settings) {
$mmdb_path = dirname($settings[Settings::BASE_DIR]).'/geoip/GeoLite2-City.mmdb';
return new MaxMind\Db\Reader($mmdb_path);
},
$di[\App\ApiUtilities::class] = function($di) {
return new \App\ApiUtilities(
$di[\Doctrine\ORM\EntityManager::class],
$di['router'],
$di[\App\Customization::class]
// InfluxDB
InfluxDB\Database::class => function(Settings $settings) {
$opts = [
'host' => $settings->isDocker() ? 'influxdb' : 'localhost',
'port' => 8086,
];
$influx = new InfluxDB\Client($opts['host'], $opts['port']);
return $influx->selectDB('stations');
},
// Supervisor manager
Supervisor\Supervisor::class => function(Settings $settings) {
$guzzle_client = new GuzzleHttp\Client();
$client = new fXmlRpc\Client(
'http://' . ($settings->isDocker() ? 'stations' : '127.0.0.1') . ':9001/RPC2',
new fXmlRpc\Transport\HttpAdapterTransport(
new Http\Message\MessageFactory\GuzzleMessageFactory(),
new Http\Adapter\Guzzle6\Client($guzzle_client)
)
);
};
$di[\Azura\Assets::class] = function ($di) {
/** @var \Azura\Config $config */
$config = $di[\Azura\Config::class];
$connector = new Supervisor\Connector\XmlRpc($client);
$supervisor = new Supervisor\Supervisor($connector);
if (!$supervisor->isConnected()) {
throw new \Azura\Exception(sprintf('Could not connect to supervisord.'));
}
return $supervisor;
},
Azura\Assets::class => function(Azura\Config $config, Settings $settings) {
$libraries = $config->get('assets');
$versioned_files = [];
$assets_file = APP_INCLUDE_ROOT.'/web/static/assets.json';
$assets_file = $settings[Settings::BASE_DIR].'/web/static/assets.json';
if (file_exists($assets_file)) {
$versioned_files = json_decode(file_get_contents($assets_file), true);
}
return new \Azura\Assets($libraries, $versioned_files);
};
return new Azura\Assets($libraries, $versioned_files);
},
$di[\App\Customization::class] = function ($di) {
return new \App\Customization(
$di['settings'],
$di[\App\Entity\Repository\SettingsRepository::class]
/*
* Radio Components
*/
App\Radio\Adapters::class => DI\autowire(),
App\Radio\AutoDJ::class => DI\autowire(),
App\Radio\Configuration::class => DI\autowire(),
App\Radio\Filesystem::class => function(DI\FactoryInterface $factory) {
/** @var Redis $redis */
$redis = $factory->make(Redis::class);
$redis->select(5);
return new App\Radio\Filesystem($redis);
},
App\Radio\Backend\Liquidsoap::class => DI\autowire(),
App\Radio\Backend\None::class => DI\autowire(),
App\Radio\Frontend\Icecast::class => DI\autowire(),
App\Radio\Frontend\Remote::class => DI\autowire(),
App\Radio\Frontend\SHOUTcast::class => DI\autowire(),
App\Radio\Remote\AzuraRelay::class => DI\autowire(),
App\Radio\Remote\Icecast::class => DI\autowire(),
App\Radio\Remote\SHOUTcast1::class => DI\autowire(),
App\Radio\Remote\SHOUTcast2::class => DI\autowire(),
/*
* Synchronized (Cron) Tasks
*/
App\Sync\Runner::class => function(
ContainerInterface $di,
EntityManager $em,
Monolog\Logger $logger
) {
/** @var App\Entity\Repository\SettingsRepository $settingsRepo */
$settingsRepo = $em->getRepository(App\Entity\Settings::class);
return new App\Sync\Runner(
$settingsRepo,
$logger,
[
$di->get(App\Sync\Task\NowPlaying::class),
$di->get(App\Sync\Task\ReactivateStreamer::class),
],
[ // Every minute tasks
$di->get(App\Sync\Task\RadioRequests::class),
$di->get(App\Sync\Task\Backup::class),
$di->get(App\Sync\Task\RelayCleanup::class),
],
[ // Every 5 minutes tasks
$di->get(App\Sync\Task\Media::class),
$di->get(App\Sync\Task\CheckForUpdates::class),
],
[ // Every hour tasks
$di->get(App\Sync\Task\Analytics::class),
$di->get(App\Sync\Task\RadioAutomation::class),
$di->get(App\Sync\Task\HistoryCleanup::class),
$di->get(App\Sync\Task\RotateLogs::class),
]
);
};
},
$di[\App\Version::class] = function($di) {
return new \App\Version(
$di[\Azura\Cache::class],
$di['settings']
);
};
App\Sync\Task\Analytics::class => DI\autowire(),
App\Sync\Task\Backup::class => DI\autowire(),
App\Sync\Task\CheckForUpdates::class => DI\autowire(),
App\Sync\Task\HistoryCleanup::class => DI\autowire(),
App\Sync\Task\Media::class => DI\autowire(),
App\Sync\Task\ReactivateStreamer::class => DI\autowire(),
App\Sync\Task\NowPlaying::class => DI\autowire(),
App\Sync\Task\RadioAutomation::class => DI\autowire(),
App\Sync\Task\RadioRequests::class => DI\autowire(),
App\Sync\Task\RelayCleanup::class => DI\autowire(),
App\Sync\Task\RotateLogs::class => DI\autowire(),
$di[\App\Service\Sentry::class] = function($di) {
return new \App\Service\Sentry(
$di[\App\Entity\Repository\SettingsRepository::class],
$di['settings'],
$di[\App\Version::class],
$di[\GuzzleHttp\Client::class]
);
};
/**
* Web Hooks
*/
$di[\App\Service\NChan::class] = function($di) {
return new \App\Service\NChan(
$di[\GuzzleHttp\Client::class]
);
};
App\Webhook\Dispatcher::class => function(
ContainerInterface $di,
Azura\Config $config,
Monolog\Logger $logger
){
$webhooks = $config->get('webhooks');
$services = [];
foreach($webhooks['webhooks'] as $webhook_key => $webhook_info) {
$services[$webhook_key] = $di->get($webhook_info['class']);
}
$di[\App\Validator\Constraints\StationPortCheckerValidator::class] = function($di) {
return new \App\Validator\Constraints\StationPortCheckerValidator(
$di[\App\Radio\Configuration::class]
);
};
return new App\Webhook\Dispatcher($logger, $services);
},
// Radio management
$di->register(new \App\Provider\RadioProvider);
App\Webhook\Connector\Discord::class => DI\autowire(),
App\Webhook\Connector\Generic::class => DI\autowire(),
App\Webhook\Connector\Local::class => DI\autowire(),
App\Webhook\Connector\TuneIn::class => DI\autowire(),
App\Webhook\Connector\Telegram::class => DI\autowire(),
App\Webhook\Connector\Twitter::class => DI\autowire(),
// Synchronization tasks
$di->register(new \App\Provider\SyncProvider);
/*
* Middleware
*/
// Web Hooks
$di->register(new \App\Provider\WebhookProvider);
App\Middleware\EnforceSecurity::class => DI\autowire(),
App\Middleware\GetCurrentUser::class => DI\autowire(),
App\Middleware\GetStation::class => DI\autowire(),
App\Middleware\Permissions::class => DI\create(),
App\Middleware\InjectAcl::class => DI\autowire(),
App\Middleware\RequireStation::class => DI\create(),
App\Middleware\RequireLogin::class => DI\create(),
// Middleware
$di->register(new \App\Provider\MiddlewareProvider);
// Module-specific middleware
App\Middleware\Module\Admin::class => DI\autowire(),
App\Middleware\Module\Api::class => DI\autowire(),
App\Middleware\Module\Stations::class => DI\autowire(),
App\Middleware\Module\StationFiles::class => DI\autowire(),
// Notifications
$di->register(new \App\Provider\NotificationProvider);
/*
* Notifications
*/
// Forms
$di->register(new \App\Provider\FormProvider);
App\Notification\Manager::class => DI\autowire(),
// Controller groups
$di->register(new \App\Provider\AdminProvider);
$di->register(new \App\Provider\ApiProvider);
$di->register(new \App\Provider\FrontendProvider);
$di->register(new \App\Provider\StationsProvider);
/*
* Forms
*/
return $di;
};
App\Form\EntityFormManager::class => function(
EntityManager $em,
Symfony\Component\Serializer\Serializer $serializer,
Symfony\Component\Validator\Validator\ValidatorInterface $validator,
ContainerInterface $di
) {
$custom_forms = [
App\Entity\Station::class => $di->get(App\Form\StationForm::class),
App\Entity\User::class => $di->get(App\Form\UserForm::class),
App\Entity\RolePermission::class => $di->get(App\Form\PermissionsForm::class),
App\Entity\StationPlaylist::class => $di->get(App\Form\StationPlaylistForm::class),
App\Entity\StationMount::class => $di->get(App\Form\StationMountForm::class),
App\Entity\StationWebhook::class => $di->get(App\Form\StationWebhookForm::class),
];
return new App\Form\EntityFormManager($em, $serializer, $validator, $custom_forms);
},
App\Form\PermissionsForm::class => DI\autowire(),
App\Form\StationForm::class => DI\autowire(),
App\Form\StationCloneForm::class => DI\autowire(),
App\Form\StationMountForm::class => DI\autowire(),
App\Form\StationPlaylistForm::class => DI\autowire(),
App\Form\StationWebhookForm::class => DI\autowire(),
App\Form\UserForm::class => DI\autowire(),
/*
* Controller Groups
*/
'App\Controller\Admin\*Controller' => DI\autowire(),
'App\Controller\Api\*Controller' => DI\autowire(),
'App\Controller\Api\Admin\*Controller' => DI\autowire(),
'App\Controller\Api\Stations\*Controller' => DI\autowire(),
'App\Controller\Frontend\*Controller' => DI\autowire(),
'App\Controller\Stations\*Controller' => DI\autowire(),
'App\Controller\Stations\Files\*Controller' => DI\autowire(),
'App\Controller\Stations\Reports\*Controller' => DI\autowire(),
];

View File

@ -1,9 +1,6 @@
<?php
/**
* Webhook Configuration
*
* Web hooks should also be registered in:
* @see \App\Provider\WebhookProvider
*/
use App\Webhook\Connector;

View File

@ -2,6 +2,7 @@
namespace App;
use App\Entity;
use Doctrine\ORM\EntityManager;
class Acl
{
@ -35,9 +36,9 @@ class Acl
/** @var array|null An array of actions enabled by each role. */
protected $_actions = null;
public function __construct(Entity\Repository\RolePermissionRepository $permission_repo)
public function __construct(EntityManager $em)
{
$this->permission_repo = $permission_repo;
$this->permission_repo = $em->getRepository(Entity\RolePermission::class);
$this->reload();
}

View File

@ -3,14 +3,10 @@ namespace App;
use App\Http\Router;
use Doctrine\ORM\EntityManager;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriResolver;
use Psr\Http\Message\UriInterface;
/**
* Class ApiSupport
* @package AzuraCast
*
* A dependency-injection-supported class for providing necessary data to API generator
* functions that they can't provide from their own internal data sources.
*/
@ -26,9 +22,9 @@ class ApiUtilities
protected $customization;
/**
* ApiUtilities constructor.
* @param EntityManager $em
* @param Router $router
* @param Customization $customization
*/
public function __construct(EntityManager $em, Router $router, Customization $customization)
{
@ -59,11 +55,12 @@ class ApiUtilities
$base_url = $this->router->getBaseUrl();
}
$path = $this->router->relativePathFor('api:stations:media:art', ['station' => $station_id, 'media_id' => $media_unique_id], []);
return UriResolver::resolve($base_url, new Uri($path));
$path = $this->router->named('api:stations:media:art', ['station' => $station_id, 'media_id' => $media_unique_id], []);
return UriResolver::resolve($base_url, $path);
}
/**
* @param UriInterface|null $base_url
* @return UriInterface
*/
public function getDefaultAlbumArtUrl(UriInterface $base_url = null): UriInterface

View File

@ -1,15 +1,16 @@
<?php
namespace App;
use Azura\Settings;
use Azura\Exception;
use Azura\Settings;
class App extends \Azura\App
{
public static function create(array $values): \Azura\App
/**
* @inheritDoc
*/
public static function create($autoloader = null, $settings = [], $diDefinitions = []): \Slim\App
{
$settings = $values['settings'] ?? [];
if (!isset($settings[Settings::BASE_DIR])) {
throw new Exception\Bootstrap('No base directory specified!');
}
@ -33,30 +34,24 @@ class App extends \Azura\App
define('SAMPLE_TIMESTAMP', rand(time() - 86400, time() + 86400));
// Register the plugins engine.
if (isset($values['autoloader'])) {
if ($autoloader) {
$plugins = new Plugins($settings[Settings::BASE_DIR] . '/plugins');
$plugins->registerAutoloaders($values['autoloader']);
$plugins->registerAutoloaders($autoloader);
$values[Plugins::class] = $plugins;
$diDefinitions[Plugins::class] = $plugins;
$diDefinitions = $plugins->registerServices($diDefinitions);
} else {
$plugins = null;
}
$values['settings'] = $settings;
$app = \Azura\App::create($values);
$app = parent::create($autoloader, $settings, $diDefinitions);
$di = $app->getContainer();
/** @var Settings $settings */
$settings = $di['settings'];
$settings = $di->get(Settings::class);
define('APP_APPLICATION_ENV', $settings[Settings::APP_ENV]);
define('APP_IN_PRODUCTION', $settings->isProduction());
if (null !== $plugins) {
$plugins->registerServices($di);
}
return $app;
}
}

View File

@ -5,6 +5,7 @@ use App\Entity\Repository\UserRepository;
use App\Entity\User;
use Azura\Session;
use Azura\Session\NamespaceInterface;
use Doctrine\ORM\EntityManager;
class Auth
{
@ -12,23 +13,27 @@ class Auth
public const TOTP_WINDOW = 5;
/** @var NamespaceInterface */
protected $_session;
protected $session;
/** @var UserRepository */
protected $_user_repo;
protected $user_repo;
/** @var User|bool|null */
protected $_user;
protected $user;
/** @var User|bool|null */
protected $_masqueraded_user;
protected $masqueraded_user;
public function __construct(Session $session, UserRepository $user_repo)
/**
* @param Session $session
* @param EntityManager $em
*/
public function __construct(Session $session, EntityManager $em)
{
$this->_user_repo = $user_repo;
$this->user_repo = $em->getRepository(User::class);
$class_name = strtolower(str_replace(['\\', '_'], ['', ''], get_called_class()));
$this->_session = $session->get('auth_' . $class_name . '_user');
$class_name = strtolower(str_replace(['\\', '_'], ['', ''], static::class));
$this->session = $session->get('auth_' . $class_name . '_user');
}
/**
@ -40,7 +45,7 @@ class Auth
*/
public function authenticate($username, $password): ?User
{
$user_auth = $this->_user_repo->authenticate($username, $password);
$user_auth = $this->user_repo->authenticate($username, $password);
if ($user_auth instanceof User) {
$this->setUser($user_auth);
@ -55,12 +60,12 @@ class Auth
*/
public function logout(): void
{
$this->_session->login_complete = false;
$this->session->login_complete = false;
unset($this->_session->user_id);
unset($this->_session->masquerade_user_id);
unset($this->session->user_id);
unset($this->session->masquerade_user_id);
$this->_user = null;
$this->user = null;
@session_unset();
}
@ -112,28 +117,28 @@ class Auth
*/
public function getUser(): ?User
{
if ($this->_user === null) {
$user_id = (int)$this->_session->user_id;
if ($this->user === null) {
$user_id = (int)$this->session->user_id;
if (0 === $user_id) {
$this->_user = false;
$this->user = false;
return null;
}
$user = $this->_user_repo->find($user_id);
$user = $this->user_repo->find($user_id);
if ($user instanceof User) {
$this->_user = $user;
$this->user = $user;
} else {
unset($this->_session->user_id);
$this->_user = false;
unset($this->session->user_id);
$this->user = false;
$this->logout();
throw new \Azura\Exception('Invalid user!');
}
}
return ($this->_user instanceof User)
? $this->_user
return ($this->user instanceof User)
? $this->user
: null;
}
@ -144,9 +149,9 @@ class Auth
*/
public function setUser(User $user): void
{
$this->_session->login_complete = (null === $user->getTwoFactorSecret());
$this->_session->user_id = $user->getId();
$this->_user = $user;
$this->session->login_complete = (null === $user->getTwoFactorSecret());
$this->session->user_id = $user->getId();
$this->user = $user;
}
/**
@ -156,20 +161,20 @@ class Auth
/**
* Become a different user across the application.
*
* @param array $user_info
* @param User|array $user_info
*/
public function masqueradeAsUser($user_info): void
{
if (!($user_info instanceof User)) {
$user_info = $this->_user_repo->findOneBy($user_info);
$user_info = $this->user_repo->findOneBy($user_info);
}
if (!($user_info instanceof User)) {
throw new \Azura\Exception('Invalid user!');
}
$this->_session->masquerade_user_id = $user_info->getId();
$this->_masqueraded_user = $user_info;
$this->session->masquerade_user_id = $user_info->getId();
$this->masqueraded_user = $user_info;
}
/**
@ -177,8 +182,8 @@ class Auth
*/
public function endMasquerade(): void
{
unset($this->_session->masquerade_user_id);
$this->_masqueraded_user = null;
unset($this->session->masquerade_user_id);
$this->masqueraded_user = null;
}
/**
@ -188,7 +193,7 @@ class Auth
*/
public function getMasquerade(): ?User
{
return $this->_masqueraded_user;
return $this->masqueraded_user;
}
/**
@ -199,31 +204,31 @@ class Auth
public function isMasqueraded(): bool
{
if (!$this->isLoggedIn()) {
$this->_masqueraded_user = false;
$this->masqueraded_user = false;
return false;
}
if ($this->_masqueraded_user === null) {
if (!$this->_session->masquerade_user_id) {
$this->_masqueraded_user = false;
if ($this->masqueraded_user === null) {
if (!$this->session->masquerade_user_id) {
$this->masqueraded_user = false;
} else {
$mask_user_id = (int)$this->_session->masquerade_user_id;
$mask_user_id = (int)$this->session->masquerade_user_id;
if (0 !== $mask_user_id) {
$user = $this->_user_repo->find($mask_user_id);
$user = $this->user_repo->find($mask_user_id);
} else {
$user = null;
}
if ($user instanceof User) {
$this->_masqueraded_user = $user;
$this->masqueraded_user = $user;
} else {
unset($this->_session->user_id, $this->_session->masquerade_user_id);
$this->_masqueraded_user = false;
unset($this->session->user_id, $this->session->masquerade_user_id);
$this->masqueraded_user = false;
}
}
}
return ($this->_masqueraded_user instanceof User);
return ($this->masqueraded_user instanceof User);
}
/**
@ -234,7 +239,7 @@ class Auth
*/
public function isLoginComplete(): bool
{
return $this->_session->login_complete ?? false;
return $this->session->login_complete ?? false;
}
/**
@ -252,7 +257,7 @@ class Auth
}
if ($user->verifyTwoFactor($otp)) {
$this->_session->login_complete = true;
$this->session->login_complete = true;
return true;
}

View File

@ -2,7 +2,6 @@
namespace App\Console\Command;
use App\Entity;
use App\Version;
use Azura\Console\Command\CommandAbstract;
use Azura\Settings;

View File

@ -1,11 +1,11 @@
<?php
namespace App\Console\Command\Internal;
use App\Entity;
use App\Radio\Adapters;
use App\Radio\Backend\Liquidsoap;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use App\Entity;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;

View File

@ -1,11 +1,11 @@
<?php
namespace App\Console\Command\Internal;
use App\Entity;
use App\Radio\Adapters;
use App\Radio\Backend\Liquidsoap;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use App\Entity;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

View File

@ -1,11 +1,11 @@
<?php
namespace App\Console\Command\Internal;
use App\Entity;
use App\Radio\Adapters;
use App\Radio\Backend\Liquidsoap;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use App\Entity;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

View File

@ -1,11 +1,10 @@
<?php
namespace App\Console\Command\Internal;
use App\Radio\AutoDJ;
use App\Entity;
use App\Sync\Task\NowPlaying;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use App\Entity;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;

View File

@ -1,10 +1,8 @@
<?php
namespace App\Console\Command\Internal;
use App\Radio\Adapters;
use App\Radio\AutoDJ;
use App\Radio\Backend\Liquidsoap;
use App\Entity;
use App\Radio\AutoDJ;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Input\InputArgument;

View File

@ -5,7 +5,6 @@ use App\Entity;
use App\Utilities;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -1,9 +1,7 @@
<?php
namespace App\Console\Command;
use App\Entity;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

View File

@ -1,11 +1,11 @@
<?php
namespace App\Console\Command;
use App\Entity;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use App\Entity;
class ReprocessMedia extends CommandAbstract
{

View File

@ -1,10 +1,10 @@
<?php
namespace App\Console\Command;
use App\Entity\Station;
use App\Radio\Configuration;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use App\Entity\Station;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

View File

@ -1,7 +1,6 @@
<?php
namespace App\Console\Command;
use App\Entity;
use App\Utilities;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;

View File

@ -9,7 +9,6 @@ use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\EntityManager;
use InfluxDB\Database;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

View File

@ -4,7 +4,6 @@ namespace App\Console\Command;
use App;
use Azura\Console\Command\CommandAbstract;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

View File

@ -2,8 +2,9 @@
namespace App\Controller\Admin;
use App\Form\EntityForm;
use App\Http\Request;
use App\Http\RequestHelper;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ServerRequestInterface;
abstract class AbstractAdminCrudController
{
@ -32,23 +33,23 @@ abstract class AbstractAdminCrudController
}
/**
* @param Request $request
* @param ServerRequestInterface $request
* @param string|int|null $id
* @return object|bool|null
*/
protected function _doEdit(Request $request, $id = null)
protected function _doEdit(ServerRequestInterface $request, $id = null)
{
$record = $this->_getRecord($id);
return $this->form->process($request, $record);
}
/**
* @param Request $request
* @param ServerRequestInterface $request
* @param string|int $id
*/
protected function _doDelete(Request $request, $id, $csrf_token): void
protected function _doDelete(ServerRequestInterface $request, $id, $csrf_token): void
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$record = $this->_getRecord($id);

View File

@ -1,55 +1,61 @@
<?php
namespace App\Controller\Admin;
use App\Form\EntityForm;
use App\Http\Request;
use App\Http\Response;
use App\Entity;
use App\Form\EntityFormManager;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ApiController extends AbstractAdminCrudController
{
/**
* @param EntityForm $form
*
* @see \App\Provider\AdminProvider
* @param Config $config
* @param EntityFormManager $formManager
*/
public function __construct(EntityForm $form)
{
public function __construct(
Config $config,
EntityFormManager $formManager
) {
$form = $formManager->getForm(Entity\ApiKey::class , $config->get('forms/api_key'));
parent::__construct($form);
$this->csrf_namespace = 'admin_api';
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$records = $this->em->createQuery(/** @lang DQL */'SELECT
a, u FROM App\Entity\ApiKey a JOIN a.user u')
->getArrayResult();
return $request->getView()->renderToResponse($response, 'admin/api/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/api/index', [
'records' => $records,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function editAction(Request $request, Response $response, $id): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $id): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash(__('%s updated.', __('API Key')), 'green');
return $response->withRedirect($request->getRouter()->named('admin:api:index'));
RequestHelper::getSession($request)->flash(__('%s updated.', __('API Key')), 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:api:index'));
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => __('Edit %s', __('API Key'))
]);
}
public function deleteAction(Request $request, Response $response, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $id, $csrf_token): ResponseInterface
{
$this->_doDelete($request, $id, $csrf_token);
$request->getSession()->flash(__('%s deleted.', __('API Key')), 'green');
return $response->withRedirect($request->getRouter()->named('admin:api:index'));
RequestHelper::getSession($request)->flash(__('%s deleted.', __('API Key')), 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:api:index'));
}
}

View File

@ -5,12 +5,15 @@ use App\Entity\Repository\SettingsRepository;
use App\Entity\Settings;
use App\Form\Form;
use App\Form\SettingsForm;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Sync\Task\Backup;
use Azura\Config;
use Doctrine\ORM\EntityManager;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class BackupsController
{
@ -33,18 +36,18 @@ class BackupsController
protected $csrf_namespace = 'admin_backups';
/**
* @param SettingsForm $settings_form
* @param Form $backup_run_form
* @param EntityManager $em
* @param Config $config
* @param Backup $backup_task
*
* @see \App\Provider\AdminProvider
*/
public function __construct(
SettingsForm $settings_form,
Form $backup_run_form,
EntityManager $em,
Config $config,
Backup $backup_task
)
{
) {
$settings_form = new SettingsForm($em, $config->get('forms/backup'));
$backup_run_form = new Form($config->get('forms/backup_run'));
$this->settings_form = $settings_form;
$this->settings_repo = $settings_form->getEntityRepository();
@ -54,43 +57,43 @@ class BackupsController
$this->backup_fs = new Filesystem(new Local(Backup::BASE_DIR));
}
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $request->getView()->renderToResponse($response, 'admin/backups/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/backups/index', [
'backups' => $this->backup_fs->listContents('', false),
'is_enabled' => (bool)$this->settings_repo->getSetting(Settings::BACKUP_ENABLED, false),
'last_run' => $this->settings_repo->getSetting(Settings::BACKUP_LAST_RUN, 0),
'last_result' => $this->settings_repo->getSetting(Settings::BACKUP_LAST_RESULT, 0),
'last_output' => $this->settings_repo->getSetting(Settings::BACKUP_LAST_OUTPUT, ''),
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function configureAction(Request $request, Response $response): ResponseInterface
public function configureAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
if (false !== $this->settings_form->process($request)) {
$request->getSession()->flash(__('Changes saved.'), 'green');
return $response->withRedirect($request->getRouter()->fromHere('admin:backups:index'));
RequestHelper::getSession($request)->flash(__('Changes saved.'), 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('admin:backups:index'));
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->settings_form,
'render_mode' => 'edit',
'title' => __('Configure Backups'),
]);
}
public function runAction(Request $request, Response $response): ResponseInterface
public function runAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
// Handle submission.
if ($request->isPost() && $this->backup_run_form->isValid($request->getParsedBody())) {
if ('POST' === $request->getMethod() && $this->backup_run_form->isValid($request->getParsedBody())) {
$data = $this->backup_run_form->getValues();
[$result_code, $result_output] = $this->backup_task->runBackup($data['path'], $data['exclude_media']);
$is_successful = (0 === $result_code);
return $request->getView()->renderToResponse($response, 'admin/backups/run', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/backups/run', [
'title' => __('Run Manual Backup'),
'path' => $data['path'],
'is_successful' => $is_successful,
@ -98,14 +101,14 @@ class BackupsController
]);
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->backup_run_form,
'render_mode' => 'edit',
'title' => __('Run Manual Backup'),
]);
}
public function downloadAction(Request $request, Response $response, $path): ResponseInterface
public function downloadAction(ServerRequestInterface $request, ResponseInterface $response, $path): ResponseInterface
{
$path = $this->getFilePath($path);
@ -118,25 +121,24 @@ class BackupsController
$file_mime = 'application/octet-stream';
}
return $response
->withNoCache()
return ResponseHelper::withNoCache($response)
->withHeader('Content-Type', $file_mime)
->withHeader('Content-Length', $file_meta['size'])
->withHeader('Content-Disposition', sprintf('attachment; filename=%s',
strpos('MSIE', $_SERVER['HTTP_REFERER']) ? rawurlencode($path) : "\"$path\""))
->withHeader('X-Accel-Buffering', 'no')
->withBody(new \Slim\Http\Stream($fh));
->withBody(new \Slim\Psr7\Stream($fh));
}
public function deleteAction(Request $request, Response $response, $path, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $path, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$path = $this->getFilePath($path);
$this->backup_fs->delete($path);
$request->getSession()->flash('<b>' . __('%s deleted.', __('Backup')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->named('admin:backups:index'));
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('Backup')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:backups:index'));
}
protected function getFilePath($raw_path)

View File

@ -2,9 +2,13 @@
namespace App\Controller\Admin;
use App\Form\SettingsForm;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Azura\Settings;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class BrandingController
{
@ -12,23 +16,27 @@ class BrandingController
protected $form;
/**
* @param SettingsForm $form
*
* @see \App\Provider\AdminProvider
* @param EntityManager $em
* @param Config $config
* @param Settings $settings
*/
public function __construct(SettingsForm $form)
{
$this->form = $form;
public function __construct(
EntityManager $em,
Config $config,
Settings $settings
) {
$form_config = $config->get('forms/branding', ['settings' => $settings]);
$this->form = new SettingsForm($em, $form_config);
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
if (false !== $this->form->process($request)) {
$request->getSession()->flash(__('Changes saved.'), 'green');
return $response->withRedirect($request->getUri()->getPath());
RequestHelper::getSession($request)->flash(__('Changes saved.'), 'green');
return ResponseHelper::withRedirect($response, $request->getUri()->getPath());
}
return $request->getView()->renderToResponse($response, 'admin/branding/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/branding/index', [
'form' => $this->form,
]);
}

View File

@ -1,55 +1,58 @@
<?php
namespace App\Controller\Admin;
use App\Form\EntityForm;
use App\Http\Request;
use App\Http\Response;
use App\Entity;
use App\Form\EntityFormManager;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class CustomFieldsController extends AbstractAdminCrudController
{
/**
* @param EntityForm $form
*
* @see \App\Provider\AdminProvider
* @param Config $config
* @param EntityFormManager $formManager
*/
public function __construct(EntityForm $form)
public function __construct(Config $config, EntityFormManager $formManager)
{
$form = $formManager->getForm(Entity\CustomField::class, $config->get('forms/custom_field'));
parent::__construct($form);
$this->csrf_namespace = 'admin_custom_fields';
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$records = $this->record_repo->fetchArray(true, 'name');
return $request->getView()->renderToResponse($response, 'admin/custom_fields/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/custom_fields/index', [
'records' => $records,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace)
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace)
]);
}
public function editAction(Request $request, Response $response, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $id = null): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash(sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Custom Field')), 'green');
return $response->withRedirect($request->getRouter()->named('admin:custom_fields:index'));
RequestHelper::getSession($request)->flash(sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Custom Field')), 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:custom_fields:index'));
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => sprintf(($id) ? __('Edit %s') : __('Add %s'), __('Custom Field'))
]);
}
public function deleteAction(Request $request, Response $response, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $id, $csrf_token): ResponseInterface
{
$this->_doDelete($request, $id, $csrf_token);
$request->getSession()->flash('<b>' . __('%s deleted.', __('Custom Field')) . '</b>', 'green');
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('Custom Field')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->named('admin:custom_fields:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:custom_fields:index'));
}
}

View File

@ -2,20 +2,17 @@
namespace App\Controller\Admin;
use App\Acl;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Radio\Quota;
use App\Sync\Runner;
use Brick\Math\BigInteger;
use Monolog\Handler\TestHandler;
use Monolog\Logger;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class IndexController
{
/** @var Acl */
protected $acl;
/** @var Logger */
protected $logger;
@ -23,32 +20,38 @@ class IndexController
protected $sync;
/**
* @param Acl $acl
* @param Logger $logger
* @param Runner $sync
* @see \App\Provider\AdminProvider
*/
public function __construct(Acl $acl, Logger $logger, Runner $sync)
public function __construct(Logger $logger, Runner $sync)
{
$this->acl = $acl;
$this->logger = $logger;
$this->sync = $sync;
}
/**
* Main display.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
*
* @return ResponseInterface
*/
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$view = $request->getView();
$user = $request->getUser();
$view = RequestHelper::getView($request);
$user = RequestHelper::getUser($request);
// Remove the sidebar on the homepage.
$view->sidebar = null;
$view->addData(['sidebar' => null]);
// Synchronization statuses
if ($this->acl->userAllowed($user, Acl::GLOBAL_ALL)) {
$view->sync_times = $this->sync->getSyncTimes();
$acl = RequestHelper::getAcl($request);
if ($acl->userAllowed($user, Acl::GLOBAL_ALL)) {
$view->addData([
'sync_times' => $this->sync->getSyncTimes()
]);
}
$stations_base_dir = dirname(APP_INCLUDE_ROOT) . '/stations';
@ -65,9 +68,9 @@ class IndexController
]);
}
public function syncAction(Request $request, Response $response, $type): ResponseInterface
public function syncAction(ServerRequestInterface $request, ResponseInterface $response, $type): ResponseInterface
{
$view = $request->getView();
$view = RequestHelper::getView($request);
$handler = new TestHandler(Logger::DEBUG, false);
$this->logger->pushHandler($handler);

View File

@ -2,11 +2,13 @@
namespace App\Controller\Admin;
use App\Form\Form;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Frontend\SHOUTcast;
use Azura\Config;
use Psr\Http\Message\ResponseInterface;
use Slim\Http\UploadedFile;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UploadedFileInterface;
use Symfony\Component\Process\Process;
class InstallShoutcastController
@ -15,15 +17,14 @@ class InstallShoutcastController
protected $form_config;
/**
* @param array $form_config
* @see \App\Provider\AdminProvider
* @param Config $config
*/
public function __construct(array $form_config)
public function __construct(Config $config)
{
$this->form_config = $form_config;
$this->form_config = $config->get('forms/install_shoutcast');
}
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$form_config = $this->form_config;
@ -35,13 +36,13 @@ class InstallShoutcastController
$form = new Form($form_config, []);
if ($request->isPost() && $form->isValid($_POST)) {
if ('POST' === $request->getMethod() && $form->isValid($_POST)) {
try
{
$sc_base_dir = dirname(APP_INCLUDE_ROOT) . '/servers/shoutcast2';
$files = $request->getUploadedFiles();
/** @var UploadedFile $import_file */
/** @var UploadedFileInterface $import_file */
$import_file = $files['binary'];
if ($import_file->getError() === \UPLOAD_ERR_OK) {
@ -61,7 +62,7 @@ class InstallShoutcastController
$process->mustRun();
}
return $response->withRedirect($request->getUri()->getPath());
return ResponseHelper::withRedirect($response, $request->getUri()->getPath());
} catch(\Exception $e) {
$form
->getField('binary')
@ -69,7 +70,7 @@ class InstallShoutcastController
}
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $form,
'render_mode' => 'edit',
'title' => __('Install SHOUTcast'),

View File

@ -3,11 +3,11 @@ namespace App\Controller\Admin;
use App\Controller\Traits\LogViewerTrait;
use App\Entity;
use App\Http\RequestHelper;
use Azura\Exception;
use App\Http\Request;
use App\Http\Response;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class LogsController
{
@ -18,15 +18,13 @@ class LogsController
/**
* @param EntityManager $em
*
* @see \App\Provider\AdminProvider
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$stations = $this->em->getRepository(Entity\Station::class)->findAll();
$station_logs = [];
@ -39,18 +37,18 @@ class LogsController
];
}
return $request->getView()->renderToResponse($response, 'admin/logs/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/logs/index', [
'global_logs' => $this->_getGlobalLogs(),
'station_logs' => $station_logs,
]);
}
public function viewAction(Request $request, Response $response, $station_id, $log_key): ResponseInterface
public function viewAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $log_key): ResponseInterface
{
if ('global' === $station_id) {
$log_areas = $this->_getGlobalLogs();
} else {
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$log_areas = $this->_getStationLogs($station);
}

View File

@ -2,28 +2,24 @@
namespace App\Controller\Admin;
use App\Acl;
use App\Form\EntityForm;
use App\Form\PermissionsForm;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class PermissionsController extends AbstractAdminCrudController
{
/**
* @param EntityForm $form
*
* @see \App\Provider\AdminProvider
* @param PermissionsForm $form
*/
public function __construct(EntityForm $form)
public function __construct(PermissionsForm $form)
{
parent::__construct($form);
$this->csrf_namespace = 'admin_permissions';
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$all_roles = $this->em->createQuery(/** @lang DQL */'SELECT
r, rp, s
@ -53,31 +49,31 @@ class PermissionsController extends AbstractAdminCrudController
$roles[] = $role;
}
return $request->getView()->renderToResponse($response, 'admin/permissions/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/permissions/index', [
'roles' => $roles,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function editAction(Request $request, Response $response, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $id = null): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Permission')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->named('admin:permissions:index'));
RequestHelper::getSession($request)->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Permission')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:permissions:index'));
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => sprintf(($id) ? __('Edit %s') : __('Add %s'), __('Permission')),
]);
}
public function deleteAction(Request $request, Response $response, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $id, $csrf_token): ResponseInterface
{
$this->_doDelete($request, $id, $csrf_token);
$request->getSession()->flash('<b>' . __('%s deleted.', __('Permission')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->named('admin:permissions:index'));
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('Permission')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:permissions:index'));
}
}

View File

@ -1,13 +1,11 @@
<?php
namespace App\Controller\Admin;
use App\Controller\Traits\LogViewerTrait;
use App\Entity;
use Azura\Exception;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class RelaysController
{
@ -16,20 +14,18 @@ class RelaysController
/**
* @param EntityManager $em
*
* @see \App\Provider\AdminProvider
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$record_repo = $this->em->getRepository(Entity\Relay::class);
$relays = $record_repo->fetchArray(false);
return $request->getView()->renderToResponse($response, 'admin/relays/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/relays/index', [
'relays' => $relays,
]);
}

View File

@ -1,12 +1,13 @@
<?php
namespace App\Controller\Admin;
use App\Entity;
use App\Form\Form;
use App\Form\SettingsForm;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class SettingsController
{
@ -14,23 +15,24 @@ class SettingsController
protected $form;
/**
* @param SettingsForm $form
*
* @see \App\Provider\AdminProvider
* SettingsController constructor.
* @param Config $config
* @param EntityManager $em
*/
public function __construct(SettingsForm $form)
public function __construct(Config $config, EntityManager $em)
{
$form = new SettingsForm($em, $config->get('forms/settings'));
$this->form = $form;
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
if (false !== $this->form->process($request)) {
$request->getSession()->flash(__('Changes saved.'), 'green');
return $response->withRedirect($request->getUri()->getPath());
RequestHelper::getSession($request)->flash(__('Changes saved.'), 'green');
return ResponseHelper::withRedirect($response, $request->getUri()->getPath());
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => __('System Settings'),

View File

@ -1,12 +1,12 @@
<?php
namespace App\Controller\Admin;
use App\Form;
use App\Entity;
use App\Form\EntityForm;
use App\Http\Request;
use App\Http\Response;
use App\Form;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class StationsController extends AbstractAdminCrudController
{
@ -14,12 +14,10 @@ class StationsController extends AbstractAdminCrudController
protected $clone_form;
/**
* @param EntityForm $form
* @param EntityForm $clone_form
*
* @see \App\Provider\AdminProvider
* @param Form\StationForm $form
* @param Form\StationCloneForm $clone_form
*/
public function __construct(EntityForm $form, EntityForm $clone_form)
public function __construct(Form\StationForm $form, Form\StationCloneForm $clone_form)
{
parent::__construct($form);
@ -27,32 +25,32 @@ class StationsController extends AbstractAdminCrudController
$this->csrf_namespace = 'admin_stations';
}
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$stations = $this->record_repo->fetchArray(false, 'name');
return $request->getView()->renderToResponse($response, 'admin/stations/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/stations/index', [
'stations' => $stations,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function editAction(Request $request, Response $response, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $id = null): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash(sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Station')), 'green');
return $response->withRedirect($request->getRouter()->named('admin:stations:index'));
RequestHelper::getSession($request)->flash(sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Station')), 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:stations:index'));
}
return $request->getView()->renderToResponse($response, 'admin/stations/edit', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/stations/edit', [
'form' => $this->form,
'title' => sprintf(($id) ? __('Edit %s') : __('Add %s'), __('Station')),
]);
}
public function deleteAction(Request $request, Response $response, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $id, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$record = $this->record_repo->find((int)$id);
if ($record instanceof Entity\Station) {
@ -61,11 +59,11 @@ class StationsController extends AbstractAdminCrudController
$record_repo->destroy($record);
}
$request->getSession()->flash(__('%s deleted.', __('Station')), 'green');
return $response->withRedirect($request->getRouter()->named('admin:stations:index'));
RequestHelper::getSession($request)->flash(__('%s deleted.', __('Station')), 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:stations:index'));
}
public function cloneAction(Request $request, Response $response, $id): ResponseInterface
public function cloneAction(ServerRequestInterface $request, ResponseInterface $response, $id): ResponseInterface
{
$record = $this->record_repo->find((int)$id);
if (!($record instanceof Entity\Station)) {
@ -73,11 +71,11 @@ class StationsController extends AbstractAdminCrudController
}
if (false !== $this->clone_form->process($request, $record)) {
$request->getSession()->flash(__('Changes saved.'), 'green');
return $response->withRedirect($request->getRouter()->named('admin:stations:index'));
RequestHelper::getSession($request)->flash(__('Changes saved.'), 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:stations:index'));
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->clone_form,
'render_mode' => 'edit',
'title' => __('Clone Station: %s', $record->getName())

View File

@ -2,12 +2,13 @@
namespace App\Controller\Admin;
use App\Auth;
use App\Form\EntityForm;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Form\UserForm;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class UsersController extends AbstractAdminCrudController
{
@ -15,13 +16,11 @@ class UsersController extends AbstractAdminCrudController
protected $auth;
/**
* @param EntityForm $form
* @param UserForm $form
* @param Auth $auth
*
* @see \App\Provider\AdminProvider
*/
public function __construct(
EntityForm $form,
UserForm $form,
Auth $auth
) {
parent::__construct($form);
@ -30,7 +29,7 @@ class UsersController extends AbstractAdminCrudController
$this->csrf_namespace = 'admin_users';
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$users = $this->em->createQuery(/** @lang DQL */'SELECT
u, r
@ -39,56 +38,56 @@ class UsersController extends AbstractAdminCrudController
ORDER BY u.name ASC')
->execute();
return $request->getView()->renderToResponse($response, 'admin/users/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'admin/users/index', [
'user' => $request->getAttribute('user'),
'users' => $users,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace)
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace)
]);
}
public function editAction(Request $request, Response $response, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $id = null): ResponseInterface
{
try {
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash(sprintf(($id) ? __('%s updated.') : __('%s added.'), __('User')),
RequestHelper::getSession($request)->flash(sprintf(($id) ? __('%s updated.') : __('%s added.'), __('User')),
'green');
return $response->withRedirect($request->getRouter()->named('admin:users:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:users:index'));
}
} catch(UniqueConstraintViolationException $e) {
$request->getSession()->flash(__('Another user already exists with this e-mail address. Please update the e-mail address.'), 'red');
RequestHelper::getSession($request)->flash(__('Another user already exists with this e-mail address. Please update the e-mail address.'), 'red');
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => sprintf(($id) ? __('Edit %s') : __('Add %s'), __('User'))
]);
}
public function deleteAction(Request $request, Response $response, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $id, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$user = $this->record_repo->find((int)$id);
$current_user = $request->getUser();
$current_user = RequestHelper::getUser($request);
if ($user === $current_user) {
$request->getSession()->flash('<b>'.__('You cannot delete your own account.').'</b>', 'red');
RequestHelper::getSession($request)->flash('<b>'.__('You cannot delete your own account.').'</b>', 'red');
} elseif ($user instanceof Entity\User) {
$this->em->remove($user);
$this->em->flush();
$request->getSession()->flash('<b>' . __('%s deleted.', __('User')) . '</b>', 'green');
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('User')) . '</b>', 'green');
}
return $response->withRedirect($request->getRouter()->named('admin:users:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:users:index'));
}
public function impersonateAction(Request $request, Response $response, $id, $csrf_token): ResponseInterface
public function impersonateAction(ServerRequestInterface $request, ResponseInterface $response, $id, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$user = $this->record_repo->find((int)$id);
@ -98,8 +97,8 @@ class UsersController extends AbstractAdminCrudController
$this->auth->masqueradeAsUser($user);
$request->getSession()->flash('<b>' . __('Logged in successfully.') . '</b><br>' . $user->getEmail(), 'green');
RequestHelper::getSession($request)->flash('<b>' . __('Logged in successfully.') . '</b><br>' . $user->getEmail(), 'green');
return $response->withRedirect($request->getRouter()->named('dashboard'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('dashboard'));
}
}

View File

@ -1,7 +1,7 @@
<?php
namespace App\Controller\Api;
use Azura\Http\Router;
use Azura\Http\RouterInterface;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
@ -38,10 +38,10 @@ abstract class AbstractApiCrudController
/**
* @param object $record
* @param Router $router
* @param RouterInterface $router
* @return mixed
*/
protected function _viewRecord($record, Router $router)
protected function _viewRecord($record, RouterInterface $router)
{
if (!($record instanceof $this->entityClass)) {
throw new \InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));

View File

@ -3,15 +3,16 @@ namespace App\Controller\Api\Admin;
use App\Controller\Api\AbstractApiCrudController;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Utilities;
use Azura\Doctrine\Paginator;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
{
public function listAction(Request $request, Response $response): ResponseInterface
public function listAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$query = $this->em->createQuery('SELECT e FROM ' . $this->entityClass . ' e');
@ -19,7 +20,7 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
$paginator->setFromRequest($request);
$is_bootgrid = $paginator->isFromBootgrid();
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$paginator->setPostprocessor(function($row) use ($is_bootgrid, $router) {
$return = $this->_viewRecord($row, $router);
@ -35,31 +36,31 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
* @throws \Azura\Exception
*/
public function createAction(Request $request, Response $response): ResponseInterface
public function createAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$row = $this->_createRecord($request->getParsedBody());
$return = $this->_viewRecord($row, $request->getRouter());
return $response->withJson($return);
$return = $this->_viewRecord($row, RequestHelper::getRouter($request));
return ResponseHelper::withJson($response, $return);
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param mixed $record_id
* @return ResponseInterface
*/
public function getAction(Request $request, Response $response, $record_id): ResponseInterface
public function getAction(ServerRequestInterface $request, ResponseInterface $response, $record_id): ResponseInterface
{
$record = $this->_getRecord($record_id);
$return = $this->_viewRecord($record, $request->getRouter());
return $response->withJson($return);
$return = $this->_viewRecord($record, RequestHelper::getRouter($request));
return ResponseHelper::withJson($response, $return);
}
/**
@ -72,45 +73,47 @@ abstract class AbstractAdminApiCrudController extends AbstractApiCrudController
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param mixed $record_id
* @return ResponseInterface
*/
public function editAction(Request $request, Response $response, $record_id): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $record_id): ResponseInterface
{
$record = $this->_getRecord($record_id);
if (null === $record) {
return $response
->withStatus(404)
->withJson(new Entity\Api\Error(404, 'Record not found!'));
return ResponseHelper::withJson(
$response->withStatus(404),
new Entity\Api\Error(404, 'Record not found!')
);
}
$this->_editRecord($request->getParsedBody(), $record);
return $response->withJson(new Entity\Api\Status(true, 'Changes saved successfully.'));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, 'Changes saved successfully.'));
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param mixed $record_id
* @return ResponseInterface
*/
public function deleteAction(Request $request, Response $response, $record_id): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $record_id): ResponseInterface
{
$record = $this->_getRecord($record_id);
if (null === $record) {
return $response
->withStatus(404)
->withJson(new Entity\Api\Error(404, 'Record not found!'));
return ResponseHelper::withJson(
$response->withStatus(404),
new Entity\Api\Error(404, 'Record not found!')
);
}
$this->_deleteRecord($record);
return $response->withJson(new Entity\Api\Status(true, 'Record deleted successfully.'));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, 'Record deleted successfully.'));
}
/**

View File

@ -4,9 +4,6 @@ namespace App\Controller\Api\Admin;
use App\Entity;
use OpenApi\Annotations as OA;
/**
* @see \App\Provider\ApiProvider
*/
class CustomFieldsController extends AbstractAdminApiCrudController
{
protected $entityClass = Entity\CustomField::class;

View File

@ -2,14 +2,11 @@
namespace App\Controller\Api\Admin;
use App\Acl;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use App\Http\ResponseHelper;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* @see \App\Provider\ApiProvider
*/
class PermissionsController
{
/**
@ -24,11 +21,11 @@ class PermissionsController
* security={{"api_key": {}}},
* )
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$permissions = [];
foreach(Acl::listPermissions() as $group => $actions) {
@ -40,6 +37,6 @@ class PermissionsController
}
}
return $response->withJson($permissions);
return ResponseHelper::withJson($response, $permissions);
}
}

View File

@ -3,13 +3,14 @@ namespace App\Controller\Api\Admin;
use App\Acl;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Adapters;
use Azura\Doctrine\Repository;
use Doctrine\ORM\EntityManager;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class RelaysController
{
@ -26,8 +27,6 @@ class RelaysController
* @param Acl $acl
* @param EntityManager $em
* @param Adapters $adapters
*
* @see \App\Provider\ApiProvider
*/
public function __construct(
Acl $acl,
@ -40,7 +39,7 @@ class RelaysController
}
/**
* @OA\Get(path="/admin/relays",
* @OA\Get(path="/internal/relays",
* tags={"Administration: Relays"},
* description="Returns all necessary information to relay all 'relayable' stations.",
* parameters={},
@ -51,15 +50,15 @@ class RelaysController
* )
* )
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$stations = $this->getManageableStations($request);
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$return = [];
foreach($stations as $station) {
@ -94,10 +93,10 @@ class RelaysController
$return[] = $row;
}
return $response->withJson($return);
return ResponseHelper::withJson($response, $return);
}
public function updateAction(Request $request, Response $response): ResponseInterface
public function updateAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
/** @var Repository $relay_repo */
$relay_repo = $this->em->getRepository(Entity\Relay::class);
@ -107,7 +106,8 @@ class RelaysController
if (!empty($body['base_url'])) {
$base_url = $body['base_url'];
} else {
$base_url = 'http://'.$request->getServerParam('REMOTE_ADDR');
$serverParams = $request->getServerParams();
$base_url = 'http://'.$serverParams('REMOTE_ADDR');
}
$relay = $relay_repo->findOneBy(['base_url' => $base_url]);
@ -168,14 +168,14 @@ class RelaysController
$this->em->flush();
return $response->withJson(new Entity\Api\Status);
return ResponseHelper::withJson($response, new Entity\Api\Status);
}
/**
* @param Request $request
* @param ServerRequestInterface $request
* @return Entity\Station[]
*/
protected function getManageableStations(Request $request): array
protected function getManageableStations(ServerRequestInterface $request): array
{
$all_stations = $this->em->createQuery(/** @lang DQL */'SELECT s, sm
FROM App\Entity\Station s
@ -185,7 +185,7 @@ class RelaysController
->setParameter('remote_frontend', Adapters::FRONTEND_REMOTE)
->execute();
$user = $request->getUser();
$user = RequestHelper::getUser($request);
return array_filter($all_stations, function(Entity\Station $station) use ($user) {
return $this->acl->userAllowed($user, Acl::STATION_BROADCASTING, $station->getId());

View File

@ -3,12 +3,9 @@ namespace App\Controller\Api\Admin;
use App\Acl;
use App\Entity;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use OpenApi\Annotations as OA;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
/**
* @see \App\Provider\ApiProvider
*/
class RolesController extends AbstractAdminApiCrudController
{
protected $entityClass = Entity\Role::class;

View File

@ -2,14 +2,14 @@
namespace App\Controller\Api\Admin;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\ResponseHelper;
use Doctrine\ORM\EntityManager;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use OpenApi\Annotations as OA;
class SettingsController
{
@ -32,8 +32,6 @@ class SettingsController
* @param EntityManager $em
* @param Serializer $serializer
* @param ValidatorInterface $validator
*
* @see \App\Provider\ApiProvider
*/
public function __construct(EntityManager $em, Serializer $serializer, ValidatorInterface $validator)
{
@ -63,13 +61,13 @@ class SettingsController
* security={{"api_key": {}}},
* )
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function listAction(Request $request, Response $response): ResponseInterface
public function listAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $response->withJson($this->api_settings);
return ResponseHelper::withJson($response, $this->api_settings);
}
/**
@ -86,12 +84,12 @@ class SettingsController
* security={{"api_key": {}}},
* )
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
* @throws \App\Exception\Validation
*/
public function updateAction(Request $request, Response $response): ResponseInterface
public function updateAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$api_settings_obj = $this->serializer->denormalize($request->getParsedBody(), Entity\Api\Admin\Settings::class, null, [
AbstractNormalizer::OBJECT_TO_POPULATE => $this->api_settings,
@ -106,6 +104,6 @@ class SettingsController
$this->settings_repo->setSettings($api_settings);
return $response->withJson(new Entity\Api\Status());
return ResponseHelper::withJson($response, new Entity\Api\Status());
}
}

View File

@ -8,9 +8,6 @@ use OpenApi\Annotations as OA;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* @see \App\Provider\ApiProvider
*/
class StationsController extends AbstractAdminApiCrudController
{
protected $entityClass = Entity\Station::class;

View File

@ -2,14 +2,12 @@
namespace App\Controller\Api\Admin;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* @see \App\Provider\ApiProvider
*/
class UsersController extends AbstractAdminApiCrudController
{
protected $entityClass = Entity\User::class;
@ -97,27 +95,29 @@ class UsersController extends AbstractAdminApiCrudController
*
* @inheritdoc
*/
public function deleteAction(Request $request, Response $response, $record_id): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $record_id): ResponseInterface
{
/** @var Entity\User $record */
$record = $this->_getRecord($record_id);
if (null === $record) {
return $response
->withStatus(404)
->withJson(new Entity\Api\Error(404, 'Record not found!'));
return ResponseHelper::withJson(
$response->withStatus(404),
new Entity\Api\Error(404, 'Record not found!')
);
}
$current_user = $request->getUser();
$current_user = RequestHelper::getUser($request);
if ($record->getId() === $current_user->getId()) {
return $response
->withStatus(403)
->withJson(new Entity\Api\Error(403, 'You cannot remove yourself.'));
return ResponseHelper::withJson(
$response->withStatus(403),
new Entity\Api\Error(403, 'You cannot remove yourself.')
);
}
$this->_deleteRecord($record);
return $response->withJson(new Entity\Api\Status(true, 'Record deleted successfully.'));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, 'Record deleted successfully.'));
}
}

View File

@ -2,18 +2,22 @@
namespace App\Controller\Api;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\ResponseHelper;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class IndexController
{
/**
* Public index for API.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $response->withRedirect('/static/api/index.html');
return \App\Http\ResponseHelper::withRedirect($response, '/static/api/index.html');
}
/**
@ -27,10 +31,14 @@ class IndexController
* @OA\JsonContent(ref="#/components/schemas/Api_SystemStatus")
* )
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function statusAction(Request $request, Response $response): ResponseInterface
public function statusAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $response->withJson(new Entity\Api\SystemStatus);
return ResponseHelper::withJson($response, new Entity\Api\SystemStatus);
}
/**
@ -44,10 +52,14 @@ class IndexController
* @OA\JsonContent(ref="#/components/schemas/Api_Time")
* )
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function timeAction(Request $request, Response $response): ResponseInterface
public function timeAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$tz_info = \Azura\Timezone::getInfo();
return $response->withJson(new Entity\Api\Time($tz_info));
return ResponseHelper::withJson($response, new Entity\Api\Time($tz_info));
}
}

View File

@ -2,14 +2,14 @@
namespace App\Controller\Api;
use App\Acl;
use App\Entity;
use App\Http\RequestHelper;
use App\Radio\AutoDJ;
use App\Radio\Backend\Liquidsoap;
use App\Sync\Task\NowPlaying;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Monolog\Logger;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class InternalController
{
@ -30,8 +30,6 @@ class InternalController
* @param NowPlaying $sync_nowplaying
* @param AutoDJ $autodj
* @param Logger $logger
*
* @see \App\Provider\ApiProvider
*/
public function __construct(
Acl $acl,
@ -45,47 +43,58 @@ class InternalController
$this->logger = $logger;
}
public function authAction(Request $request, Response $response): ResponseInterface
/**
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function authAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$this->_checkStationAuth($request);
$station = $request->getStation();
$station = RequestHelper::getStation($request);
if (!$station->getEnableStreamers()) {
$this->logger->error('Attempted DJ authentication when streamers are disabled on this station.', [
'station_id' => $station->getId(),
'station_name' => $station->getName(),
]);
return $response->write('false');
$response->getBody()->write('false');
return $response;
}
$user = $request->getParam('dj_user');
$pass = $request->getParam('dj_password');
$params = RequestHelper::getParams($request);
$user = $params['dj_user'] ?? '';
$pass = $params['dj_password'] ?? '';
$adapter = $request->getStationBackend();
$adapter = RequestHelper::getStationBackend($request);
if ($adapter instanceof Liquidsoap) {
return $response->write($adapter->authenticateStreamer($station, $user, $pass));
$response->getBody()->write($adapter->authenticateStreamer($station, $user, $pass));
return $response;
}
return $response->write('false');
$response->getBody()->write('false');
return $response;
}
public function nextsongAction(Request $request, Response $response): ResponseInterface
public function nextsongAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$this->_checkStationAuth($request);
$as_autodj = $request->hasParam('api_auth');
$params = RequestHelper::getParams($request);
$as_autodj = isset($params['api_auth']);
return $response->write($this->autodj->annotateNextSong($request->getStation(), $as_autodj));
$response->getBody()->write($this->autodj->annotateNextSong(RequestHelper::getStation($request), $as_autodj));
return $response;
}
public function djonAction(Request $request, Response $response): ResponseInterface
public function djonAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$this->_checkStationAuth($request);
$adapter = $request->getStationBackend();
$adapter = RequestHelper::getStationBackend($request);
if ($adapter instanceof Liquidsoap) {
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$this->logger->info('Received "DJ connected" ping from Liquidsoap.', [
'station_id' => $station->getId(),
@ -95,16 +104,17 @@ class InternalController
$adapter->toggleLiveStatus($station, true);
}
return $response->write('received');
$response->getBody()->write('received');
return $response;
}
public function djoffAction(Request $request, Response $response): ResponseInterface
public function djoffAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$this->_checkStationAuth($request);
$adapter = $request->getStationBackend();
$adapter = RequestHelper::getStationBackend($request);
if ($adapter instanceof Liquidsoap) {
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$this->logger->info('Received "DJ disconnected" ping from Liquidsoap.', [
'station_id' => $station->getId(),
@ -114,16 +124,17 @@ class InternalController
$adapter->toggleLiveStatus($station, false);
}
return $response->write('received');
$response->getBody()->write('received');
return $response;
}
public function feedbackAction(Request $request, Response $response): ResponseInterface
public function feedbackAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$this->_checkStationAuth($request);
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$body = $request->getParsedBody();
$body = RequestHelper::getParams($request);
$this->sync_nowplaying->queueStation($station, [
'song_id' => $body['song'] ?? null,
@ -131,26 +142,26 @@ class InternalController
'playlist_id' => $body['playlist'] ?? null,
]);
return $response->write('OK');
$response->getBody()->write('OK');
return $response;
}
/**
* @param Request $request
* @throws \Azura\Exception
* @throws \App\Exception\PermissionDenied
* @param ServerRequestInterface $request
*/
protected function _checkStationAuth(Request $request): void
protected function _checkStationAuth(ServerRequestInterface $request): void
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
/** @var Entity\User $user */
$user = $request->getAttribute(Request::ATTRIBUTE_USER);
$user = $request->getAttribute(RequestHelper::ATTR_USER);
if ($this->acl->userAllowed($user, Acl::GLOBAL_VIEW, $station->getId())) {
return;
}
$auth_key = $request->getParam('api_auth');
$params = RequestHelper::getParams($request);
$auth_key = $params['api_auth'];
if (!$station->validateAdapterApiKey($auth_key)) {
$this->logger->error('Invalid API key supplied for internal API call.', [
'station_id' => $station->getId(),

View File

@ -1,16 +1,17 @@
<?php
namespace App\Controller\Api;
use Azura\Cache;
use App\Entity;
use App\Event\Radio\LoadNowPlaying;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Cache;
use Azura\EventDispatcher;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class NowplayingController implements EventSubscriberInterface
{
@ -27,8 +28,6 @@ class NowplayingController implements EventSubscriberInterface
* @param EntityManager $em
* @param Cache $cache
* @param EventDispatcher $dispatcher
*
* @see \App\Provider\ApiProvider
*/
public function __construct(EntityManager $em, Cache $cache, EventDispatcher $dispatcher)
{
@ -58,7 +57,7 @@ class NowplayingController implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return [
LoadNowPlaying::NAME => [
LoadNowPlaying::class => [
['loadFromCache', 5],
['loadFromSettings', 0],
['loadFromStations', -5],
@ -89,17 +88,25 @@ class NowplayingController implements EventSubscriberInterface
* ),
* @OA\Response(response=404, description="Station not found")
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $id
* @return ResponseInterface
*/
public function __invoke(Request $request, Response $response, $id = null): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $id = null): ResponseInterface
{
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
// Pull NP data from the fastest/first available source using the EventDispatcher.
$event = new LoadNowPlaying();
$this->dispatcher->dispatch(LoadNowPlaying::NAME, $event);
$this->dispatcher->dispatch($event);
if (!$event->hasNowPlaying()) {
return $response->withJson('Now Playing data has not loaded yet. Please try again later.', 408);
return ResponseHelper::withJson(
$response->withStatus(408),
new Entity\Api\Error(408, 'Now Playing data has not loaded yet. Please try again later.')
);
}
$np = $event->getNowPlaying();
@ -109,11 +116,14 @@ class NowplayingController implements EventSubscriberInterface
if ($np_row->station->id == (int)$id || $np_row->station->shortcode === $id) {
$np_row->resolveUrls($router->getBaseUrl());
$np_row->now_playing->recalculate();
return $response->withJson($np_row);
return ResponseHelper::withJson($response, $np_row);
}
}
return $response->withJson('Station not found.', 404);
return ResponseHelper::withJson(
$response->withStatus(404),
new Entity\Api\Error(404, 'Station not found.')
);
}
// If unauthenticated, hide non-public stations from full view.
@ -128,7 +138,7 @@ class NowplayingController implements EventSubscriberInterface
$np_row->now_playing->recalculate();
}
return $response->withJson($np);
return ResponseHelper::withJson($response, $np);
}
public function loadFromCache(LoadNowPlaying $event)

View File

@ -1,11 +1,11 @@
<?php
namespace App\Controller\Api;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Version;
use Azura\Settings;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class OpenApiController
{
@ -18,8 +18,6 @@ class OpenApiController
/**
* @param Settings $settings
* @param Version $version
*
* @see \App\Provider\ApiProvider
*/
public function __construct(Settings $settings, Version $version)
{
@ -27,9 +25,9 @@ class OpenApiController
$this->version = $version;
}
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$api_base_url = (string)$router->fromHere(null, [], [], true);
$api_base_url = str_replace('/openapi.yml', '', $api_base_url);
@ -52,8 +50,7 @@ class OpenApiController
$yaml = $oa->toYaml();
return $response
->withHeader('Content-Type', 'text/x-yaml')
->write($yaml);
$response->getBody()->write($yaml);
return $response->withHeader('Content-Type', 'text/x-yaml');
}
}

View File

@ -3,22 +3,23 @@ namespace App\Controller\Api\Stations;
use App\Controller\Api\AbstractApiCrudController;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Utilities;
use Azura\Doctrine\Paginator;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
abstract class AbstractStationApiCrudController extends AbstractApiCrudController
{
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $station_id
* @return ResponseInterface
*/
public function listAction(Request $request, Response $response, $station_id): ResponseInterface
public function listAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $this->_getStation($request);
@ -31,7 +32,7 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
$paginator->setFromRequest($request);
$is_bootgrid = $paginator->isFromBootgrid();
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$paginator->setPostprocessor(function($row) use ($is_bootgrid, $router) {
$return = $this->_viewRecord($row, $router);
@ -46,79 +47,81 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $station_id
* @return ResponseInterface
*/
public function createAction(Request $request, Response $response, $station_id): ResponseInterface
public function createAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $this->_getStation($request);
$row = $this->_createRecord($request->getParsedBody(), $station);
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$return = $this->_viewRecord($row, $router);
return $response->withJson($return);
return ResponseHelper::withJson($response, $return);
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $record_id
* @return ResponseInterface
*/
public function getAction(Request $request, Response $response, $station_id, $record_id): ResponseInterface
public function getAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $record_id): ResponseInterface
{
$station = $this->_getStation($request);
$record = $this->_getRecord($station, $record_id);
$return = $this->_viewRecord($record, $request->getRouter());
return $response->withJson($return);
$return = $this->_viewRecord($record, RequestHelper::getRouter($request));
return ResponseHelper::withJson($response, $return);
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $station_id
* @param int|string $record_id
* @return ResponseInterface
*/
public function editAction(Request $request, Response $response, $station_id, $record_id): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $record_id): ResponseInterface
{
$record = $this->_getRecord($this->_getStation($request), $record_id);
if (null === $record) {
return $response
->withStatus(404)
->withJson(new Entity\Api\Error(404, 'Record not found!'));
return ResponseHelper::withJson(
$response->withStatus(404),
new Entity\Api\Error(404, 'Record not found!')
);
}
$this->_editRecord($request->getParsedBody(), $record);
return $response->withJson(new Entity\Api\Status(true, 'Changes saved successfully.'));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, 'Changes saved successfully.'));
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $station_id
* @param int|string $record_id
* @return ResponseInterface
*/
public function deleteAction(Request $request, Response $response, $station_id, $record_id): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $record_id): ResponseInterface
{
$record = $this->_getRecord($this->_getStation($request), $record_id);
if (null === $record) {
return $response
->withStatus(404)
->withJson(new Entity\Api\Error(404, 'Record not found!'));
return ResponseHelper::withJson(
$response->withStatus(404),
new Entity\Api\Error(404, 'Record not found!')
);
}
$this->_deleteRecord($record);
return $response->withJson(new Entity\Api\Status(true, 'Record deleted successfully.'));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, 'Record deleted successfully.'));
}
/**
@ -155,11 +158,11 @@ abstract class AbstractStationApiCrudController extends AbstractApiCrudControlle
* A placeholder function to retrieve the current station that some controllers can
* override to verify that the station can perform the specified task.
*
* @param Request $request
* @param ServerRequestInterface $request
* @return Entity\Station
*/
protected function _getStation(Request $request): Entity\Station
protected function _getStation(ServerRequestInterface $request): Entity\Station
{
return $request->getStation();
return RequestHelper::getStation($request);
}
}

View File

@ -1,12 +1,14 @@
<?php
namespace App\Controller\Api\Stations;
use App\Radio\Filesystem;
use App\Customization;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Filesystem;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Psr7\Stream;
class ArtController
{
@ -19,8 +21,6 @@ class ArtController
/**
* @param Customization $customization
* @param Filesystem $filesystem
*
* @see \App\Provider\ApiProvider
*/
public function __construct(Customization $customization, Filesystem $filesystem)
{
@ -45,10 +45,17 @@ class ArtController
* @OA\Response(response=200, description="The requested album artwork"),
* @OA\Response(response=404, description="Image not found; generic filler image.")
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param string|int $station_id
* @param string $media_id
*
* @return ResponseInterface
*/
public function __invoke(Request $request, Response $response, $station_id, $media_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id, $media_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$filesystem = $this->filesystem->getForStation($station);
$media_path = 'albumart://'.$media_id.'.jpg';
@ -58,14 +65,13 @@ class ArtController
$art = $filesystem->readStream($media_path);
if (is_resource($art)) {
return $response
return ResponseHelper::withCacheLifetime($response, ResponseHelper::CACHE_ONE_YEAR)
->withHeader('Content-Type', 'image/jpeg')
->withHeader('Content-Length', $file_meta['size'])
->withCacheLifetime(Response::CACHE_ONE_YEAR)
->withBody(new \Slim\Http\Stream($art));
->withBody(new Stream($art));
}
}
return $response->withRedirect($this->customization->getDefaultAlbumArtUrl(), 302);
return ResponseHelper::withRedirect($response, $this->customization->getDefaultAlbumArtUrl(), 302);
}
}

View File

@ -2,8 +2,8 @@
namespace App\Controller\Api\Stations;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Adapters;
use App\Radio\Backend\Liquidsoap;
use App\Radio\Filesystem;
@ -11,8 +11,8 @@ use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
@ -42,8 +42,6 @@ class FilesController extends AbstractStationApiCrudController
* @param ValidatorInterface $validator
* @param Filesystem $filesystem
* @param Adapters $adapters
*
* @see \App\Provider\ApiProvider
*/
public function __construct(
EntityManager $em,
@ -89,8 +87,13 @@ class FilesController extends AbstractStationApiCrudController
* @OA\Response(response=403, description="Access denied"),
* security={{"api_key": {}}},
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $station_id
* @return ResponseInterface
*/
public function createAction(Request $request, Response $response, $station_id): ResponseInterface
public function createAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $this->_getStation($request);
@ -117,10 +120,10 @@ class FilesController extends AbstractStationApiCrudController
// Process temp path as regular media record.
$record = $this->media_repo->uploadFile($station, $temp_path, $sanitized_path);
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$return = $this->_viewRecord($record, $router);
return $response->withJson($return);
return ResponseHelper::withJson($response, $return);
}
/**

View File

@ -2,15 +2,15 @@
namespace App\Controller\Api\Stations;
use App;
use App\Entity;
use App\Http\RequestHelper;
use Azura\Doctrine\Paginator;
use Azura\Utilities\Csv;
use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class HistoryController
{
@ -65,20 +65,20 @@ class HistoryController
* security={{"api_key": {}}},
* )
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $station_id
* @return ResponseInterface
*/
public function __invoke(Request $request, Response $response, $station_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$station_tz = new \DateTimeZone($station->getTimezone());
$start_param = $request->getParam('start');
if (!empty($start_param)) {
$start = Chronos::parse($start_param . ' 00:00:00', $station_tz);
$end = Chronos::parse($request->getParam('end', $start_param) . ' 23:59:59', $station_tz);
$params = $request->getQueryParams();
if (!empty($params['start'])) {
$start = Chronos::parse($params['start']. ' 00:00:00', $station_tz);
$end = Chronos::parse(($params['end'] ?? $params['start']) . ' 23:59:59', $station_tz);
} else {
$start = Chronos::parse('-2 weeks', $station_tz);
$end = Chronos::now($station_tz);
@ -98,7 +98,9 @@ class HistoryController
->setParameter('start', $start->getTimestamp())
->setParameter('end', $end->getTimestamp());
if ($request->getParam('format', 'json') === 'csv') {
$format = $params['format'] ?? 'json';
if ('csv' === $format) {
$export_all = [];
$export_all[] = [
'Date',
@ -128,10 +130,10 @@ class HistoryController
$csv_file = Csv::arrayToCsv($export_all);
$csv_filename = $station->getShortName() . '_timeline_' . $start->format('Ymd') . '_to_' . $end->format('Ymd') . '.csv';
return $response->renderStringAsFile($csv_file, 'text/csv', $csv_filename);
return App\Http\ResponseHelper::renderStringAsFile($response, $csv_file, 'text/csv', $csv_filename);
}
$search_phrase = trim($request->getParam('searchPhrase'));
$search_phrase = trim($params['searchPhrase']);
if (!empty($search_phrase)) {
$qb->andWhere('(s.title LIKE :query OR s.artist LIKE :query)')
->setParameter('query', '%'.$search_phrase.'%');
@ -143,7 +145,7 @@ class HistoryController
$paginator->setFromRequest($request);
$is_bootgrid = $paginator->isFromBootgrid();
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$paginator->setPostprocessor(function($sh_row) use ($is_bootgrid, $router) {

View File

@ -1,13 +1,14 @@
<?php
namespace App\Controller\Api\Stations;
use App\Entity;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Adapters;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class IndexController
{
@ -40,7 +41,7 @@ class IndexController
* )
* )
*/
public function listAction(Request $request, Response $response): ResponseInterface
public function listAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$stations_raw = $this->em->getRepository(Entity\Station::class)
->findBy(['is_enabled' => 1]);
@ -53,14 +54,14 @@ class IndexController
$this->adapters->getRemoteAdapters($row)
);
$api_row->resolveUrls($request->getRouter()->getBaseUrl());
$api_row->resolveUrls(RequestHelper::getRouter($request)->getBaseUrl());
if ($api_row->is_public) {
$stations[] = $api_row;
}
}
return $response->withJson($stations);
return ResponseHelper::withJson($response, $stations);
}
/**
@ -74,11 +75,11 @@ class IndexController
* @OA\Response(response=404, description="Station not found")
* )
*/
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$api_response = $request->getStation()->api($request->getStationFrontend());
$api_response->resolveUrls($request->getRouter()->getBaseUrl());
$api_response = RequestHelper::getStation($request)->api(RequestHelper::getStationFrontend($request));
$api_response->resolveUrls(RequestHelper::getRouter($request)->getBaseUrl());
return $response->withJson($api_response);
return ResponseHelper::withJson($response, $api_response);
}
}

View File

@ -1,16 +1,17 @@
<?php
namespace App\Controller\Api\Stations;
use App\Entity;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Cache;
use Azura\Utilities\Csv;
use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use MaxMind\Db\Reader;
use Psr\Http\Message\ResponseInterface;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ListenersController
{
@ -27,7 +28,6 @@ class ListenersController
* @param EntityManager $em
* @param Cache $cache
* @param Reader $geoip
* @see \App\Provider\ApiProvider
*/
public function __construct(EntityManager $em, Cache $cache, Reader $geoip)
{
@ -51,16 +51,18 @@ class ListenersController
* security={{"api_key": {}}},
* )
*/
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$station_tz = new \DateTimeZone($station->getTimezone());
if ($request->getParam('start') !== null) {
$start = Chronos::parse($request->getParam('start').' 00:00:00', $station_tz);
$params = $request->getQueryParams();
if (!empty($params['start'])) {
$start = Chronos::parse($params['start'].' 00:00:00', $station_tz);
$start_timestamp = $start->getTimestamp();
$end = Chronos::parse($request->getParam('end', $request->getParam('start')).' 23:59:59', $station_tz);
$end = Chronos::parse(($params['end'] ?? $params['start']).' 23:59:59', $station_tz);
$end_timestamp = $end->getTimestamp();
$range = $start->format('Ymd').'_to_'.$end->format('Ymd');
@ -112,7 +114,9 @@ class ListenersController
$detect = new \Mobile_Detect;
$locale = $request->getAttribute('locale');
if ('csv' === $request->getParam('format', 'json')) {
$format = $params['format'] ?? 'json';
if ('csv' === $format) {
$export_all = [
[
'IP',
@ -154,7 +158,7 @@ class ListenersController
$csv_file = Csv::arrayToCsv($export_all);
$csv_filename = $station->getShortName() . '_listeners_' . $range . '.csv';
return $response->renderStringAsFile($csv_file, 'text/csv', $csv_filename);
return ResponseHelper::renderStringAsFile($response, $csv_file, 'text/csv', $csv_filename);
}
$listeners = [];
@ -170,7 +174,7 @@ class ListenersController
$listeners[] = $api;
}
return $response->withJson($listeners);
return ResponseHelper::withJson($response, $listeners);
}
protected function _getLocationInfo($ip, $locale): array

View File

@ -2,12 +2,10 @@
namespace App\Controller\Api\Stations;
use App\Entity;
use App\Http\Request;
use App\Http\RequestHelper;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ServerRequestInterface;
/**
* @see \App\Provider\ApiProvider
*/
class MountsController extends AbstractStationApiCrudController
{
protected $entityClass = Entity\StationMount::class;
@ -100,11 +98,11 @@ class MountsController extends AbstractStationApiCrudController
/**
* @inheritDoc
*/
protected function _getStation(Request $request): Entity\Station
protected function _getStation(ServerRequestInterface $request): Entity\Station
{
$station = parent::_getStation($request);
$frontend = $request->getStationFrontend();
$frontend = RequestHelper::getStationFrontend($request);
if (!$frontend::supportsMounts()) {
throw new \App\Exception\StationUnsupported;
}

View File

@ -2,12 +2,8 @@
namespace App\Controller\Api\Stations;
use App\Entity;
use App\Http\Request;
use OpenApi\Annotations as OA;
/**
* @see \App\Provider\ApiProvider
*/
class PlaylistsController extends AbstractStationApiCrudController
{
protected $entityClass = Entity\StationPlaylist::class;

View File

@ -2,20 +2,17 @@
namespace App\Controller\Api\Stations;
use App;
use Azura\Doctrine\Paginator;
use Azura\Http\Router;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use Azura\Doctrine\Paginator;
use Azura\Http\RouterInterface;
use Doctrine\ORM\EntityManager;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use OpenApi\Annotations as OA;
/**
* @see \App\Provider\ApiProvider
*/
class QueueController extends AbstractStationApiCrudController
{
protected $entityClass = Entity\SongHistory::class;
@ -48,7 +45,7 @@ class QueueController extends AbstractStationApiCrudController
*
* @inheritdoc
*/
public function listAction(Request $request, Response $response, $station_id): ResponseInterface
public function listAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$query = $this->em->createQuery(/** @lang DQL */'SELECT sh, sp, s, sm
FROM App\Entity\SongHistory sh
@ -66,7 +63,7 @@ class QueueController extends AbstractStationApiCrudController
$paginator->setFromRequest($request);
$is_bootgrid = $paginator->isFromBootgrid();
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$paginator->setPostprocessor(function($row) use ($is_bootgrid, $router) {
$return = $this->_viewRecord($row, $router);
@ -121,7 +118,7 @@ class QueueController extends AbstractStationApiCrudController
/**
* @inheritdoc
*/
protected function _viewRecord($record, Router $router)
protected function _viewRecord($record, RouterInterface $router)
{
if (!($record instanceof $this->entityClass)) {
throw new \InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));

View File

@ -3,12 +3,8 @@ namespace App\Controller\Api\Stations;
use App\Entity;
use App\Entity\StationRemote;
use App\Http\Request;
use OpenApi\Annotations as OA;
/**
* @see \App\Provider\ApiProvider
*/
class RemotesController extends AbstractStationApiCrudController
{
protected $entityClass = Entity\StationRemote::class;

View File

@ -1,15 +1,16 @@
<?php
namespace App\Controller\Api\Stations;
use Azura\Doctrine\Paginator;
use App\Utilities;
use App\ApiUtilities;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Utilities;
use Azura\Doctrine\Paginator;
use Doctrine\ORM\EntityManager;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class RequestsController
{
@ -22,7 +23,6 @@ class RequestsController
/**
* @param EntityManager $em
* @param ApiUtilities $api_utils
* @see \App\Provider\ApiProvider
*/
public function __construct(EntityManager $em, ApiUtilities $api_utils)
{
@ -46,15 +46,20 @@ class RequestsController
* @OA\Response(response=404, description="Station not found"),
* @OA\Response(response=403, description="Station does not support requests")
* )
*
* @inheritDoc
*/
public function listAction(Request $request, Response $response, $station_id): ResponseInterface
public function listAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
// Verify that the station supports requests.
$ba = $request->getStationBackend();
$ba = RequestHelper::getStationBackend($request);
if (!$ba::supportsRequests() || !$station->getEnableRequests()) {
return $response->withJson('This station does not accept requests currently.', 403);
return ResponseHelper::withJson(
$response->withStatus(403),
new Entity\Api\Error(403, 'This station does not accept requests currently.')
);
}
$qb = $this->em->createQueryBuilder();
@ -70,14 +75,16 @@ class RequestsController
->andWhere('sp.include_in_requests = 1')
->setParameter('station_id', $station_id);
if ($request->hasParam('sort')) {
$params = $request->getQueryParams();
if (!empty($params['sort'])) {
$sort_fields = [
'song_title' => 'sm.title',
'song_artist' => 'sm.artist',
'song_album' => 'sm.album',
];
foreach($request->getParam('sort') as $sort_key => $sort_direction)
foreach($params['sort'] as $sort_key => $sort_direction)
{
if (isset($sort_fields[$sort_key])) {
$qb->addOrderBy($sort_fields[$sort_key], $sort_direction);
@ -88,7 +95,7 @@ class RequestsController
->addOrderBy('sm.title', 'ASC');
}
$search_phrase = trim($request->getParam('searchPhrase'));
$search_phrase = trim($params['searchPhrase']);
if (!empty($search_phrase)) {
$qb->andWhere('(sm.title LIKE :query OR sm.artist LIKE :query OR sm.album LIKE :query)')
->setParameter('query', '%'.$search_phrase.'%');
@ -98,7 +105,7 @@ class RequestsController
$paginator->setFromRequest($request);
$is_bootgrid = $paginator->isFromBootgrid();
$router = $request->getRouter();
$router = RequestHelper::getRouter($request);
$paginator->setPostprocessor(function($media_row) use ($station_id, $is_bootgrid, $router) {
/** @var Entity\StationMedia $media_row */
@ -140,27 +147,38 @@ class RequestsController
* @OA\Response(response=404, description="Station not found"),
* @OA\Response(response=403, description="Station does not support requests")
* )
*
* @inheritDoc
*/
public function submitAction(Request $request, Response $response, $station_id, $media_id): ResponseInterface
public function submitAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $media_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
// Verify that the station supports requests.
$ba = $request->getStationBackend();
$ba = RequestHelper::getStationBackend($request);
if (!$ba::supportsRequests() || !$station->getEnableRequests()) {
return $response->withJson('This station does not accept requests currently.', 403);
return ResponseHelper::withJson(
$response->withStatus(403),
new Entity\Api\Error(403, 'This station does not accept requests currently.')
);
}
$is_authenticated = !empty($request->getAttribute(Request::ATTRIBUTE_USER));
$is_authenticated = !empty($request->getAttribute(RequestHelper::ATTR_USER));
try {
/** @var Entity\Repository\StationRequestRepository $request_repo */
$request_repo = $this->em->getRepository(Entity\StationRequest::class);
$request_repo->submit($station, $media_id, $is_authenticated);
return $response->withJson('Request submitted successfully.');
return ResponseHelper::withJson(
$response,
new Entity\Api\Status(true, 'Request submitted successfully.')
);
} catch (\Azura\Exception $e) {
return $response->withJson($e->getMessage(), 400);
return ResponseHelper::withJson(
$response->withStatus(400),
new Entity\Api\Error(400, $e->getMessage())
);
}
}
}

View File

@ -1,14 +1,14 @@
<?php
namespace App\Controller\Api\Stations;
use App\Http\Request;
use App\Http\Response;
use App\Radio;
use App\Entity;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Configuration;
use Doctrine\ORM\EntityManager;
use App\Entity;
use Psr\Http\Message\ResponseInterface;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ServicesController
{
@ -33,15 +33,19 @@ class ServicesController
* @OA\Response(response=403, description="Access Forbidden", @OA\Schema(ref="#/components/schemas/Api_Error")),
* security={{"api_key": {}}}
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function statusAction(Request $request, Response $response): ResponseInterface
public function statusAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$backend = $request->getStationBackend();
$frontend = $request->getStationFrontend();
$backend = RequestHelper::getStationBackend($request);
$frontend = RequestHelper::getStationFrontend($request);
return $response->withJson(new Entity\Api\StationServiceStatus(
return ResponseHelper::withJson($response, new Entity\Api\StationServiceStatus(
$backend->isRunning($station),
$frontend->isRunning($station)
));
@ -56,13 +60,17 @@ class ServicesController
* @OA\Response(response=403, description="Access Forbidden", @OA\Schema(ref="#/components/schemas/Api_Error")),
* security={{"api_key": {}}}
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function restartAction(Request $request, Response $response): ResponseInterface
public function restartAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$this->configuration->writeConfiguration($station, false, true);
return $response->withJson(new Entity\Api\Status(true, __('%s restarted.', __('Station'))));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('%s restarted.', __('Station'))));
}
/**
@ -84,26 +92,32 @@ class ServicesController
* @OA\Response(response=403, description="Access Forbidden", @OA\Schema(ref="#/components/schemas/Api_Error")),
* security={{"api_key": {}}}
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param string|int $station_id
* @param string $do
* @return ResponseInterface
*/
public function frontendAction(Request $request, Response $response, $station_id, $do = 'restart'): ResponseInterface
public function frontendAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $do = 'restart'): ResponseInterface
{
$station = $request->getStation();
$frontend = $request->getStationFrontend();
$station = RequestHelper::getStation($request);
$frontend = RequestHelper::getStationFrontend($request);
switch ($do) {
case "stop":
case 'stop':
$frontend->stop($station);
return $response->withJson(new Entity\Api\Status(true, __('%s stopped.', __('Frontend'))));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('%s stopped.', __('Frontend'))));
break;
case "start":
case 'start':
$frontend->start($station);
return $response->withJson(new Entity\Api\Status(true, __('%s started.', __('Frontend'))));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('%s started.', __('Frontend'))));
break;
case "restart":
case 'restart':
default:
try
{
@ -113,7 +127,7 @@ class ServicesController
$frontend->write($station);
$frontend->start($station);
return $response->withJson(new Entity\Api\Status(true, __('%s restarted.', __('Frontend'))));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('%s restarted.', __('Frontend'))));
break;
}
}
@ -137,42 +151,48 @@ class ServicesController
* @OA\Response(response=403, description="Access Forbidden", @OA\Schema(ref="#/components/schemas/Api_Error")),
* security={{"api_key": {}}}
* )
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param string|int $station_id
* @param string $do
* @return ResponseInterface
*/
public function backendAction(Request $request, Response $response, $station_id, $do = 'restart'): ResponseInterface
public function backendAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $do = 'restart'): ResponseInterface
{
$station = $request->getStation();
$backend = $request->getStationBackend();
$station = RequestHelper::getStation($request);
$backend = RequestHelper::getStationBackend($request);
switch ($do) {
case "skip":
case 'skip':
if (method_exists($backend, 'skip')) {
$backend->skip($station);
}
return $response->withJson(new Entity\Api\Status(true, __('Song skipped.')));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('Song skipped.')));
break;
case "disconnect":
case 'disconnect':
if (method_exists($backend, 'disconnectStreamer')) {
$backend->disconnectStreamer($station);
}
return $response->withJson(new Entity\Api\Status(true, __('Streamer disconnected.')));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('Streamer disconnected.')));
break;
case "stop":
case 'stop':
$backend->stop($station);
return $response->withJson(new Entity\Api\Status(true, __('%s stopped.', __('Backend'))));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('%s stopped.', __('Backend'))));
break;
case "start":
case 'start':
$backend->start($station);
return $response->withJson(new Entity\Api\Status(true, __('%s started.', __('Backend'))));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('%s started.', __('Backend'))));
break;
case "restart":
case 'restart':
default:
try
{
@ -182,7 +202,7 @@ class ServicesController
$backend->write($station);
$backend->start($station);
return $response->withJson(new Entity\Api\Status(true, __('%s restarted.', __('Backend'))));
return ResponseHelper::withJson($response, new Entity\Api\Status(true, __('%s restarted.', __('Backend'))));
break;
}
}

View File

@ -2,12 +2,10 @@
namespace App\Controller\Api\Stations;
use App\Entity;
use App\Http\Request;
use App\Http\RequestHelper;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ServerRequestInterface;
/**
* @see \App\Provider\ApiProvider
*/
class StreamersController extends AbstractStationApiCrudController
{
protected $entityClass = Entity\StationStreamer::class;
@ -100,11 +98,11 @@ class StreamersController extends AbstractStationApiCrudController
/**
* @inheritDoc
*/
protected function _getStation(Request $request): Entity\Station
protected function _getStation(ServerRequestInterface $request): Entity\Station
{
$station = parent::_getStation($request);
$backend = $request->getStationBackend();
$backend = RequestHelper::getStationBackend($request);
if (!$backend::supportsStreamers()) {
throw new \App\Exception\StationUnsupported;
}

View File

@ -2,12 +2,8 @@
namespace App\Controller\Api\Stations;
use App\Entity;
use App\Http\Request;
use OpenApi\Annotations as OA;
/**
* @see \App\Provider\ApiProvider
*/
class WebhooksController extends AbstractStationApiCrudController
{
protected $entityClass = Entity\StationWebhook::class;

View File

@ -4,13 +4,14 @@ namespace App\Controller\Frontend;
use App\Acl;
use App\Auth;
use App\Entity\Repository\SettingsRepository;
use App\Entity\Settings;
use App\Entity\User;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\RateLimit;
use Doctrine\ORM\EntityManager;
use App\Entity\Settings;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class AccountController
{
@ -31,7 +32,6 @@ class AccountController
* @param Auth $auth
* @param RateLimit $rate_limit
* @param Acl $acl
* @see \App\Provider\FrontendProvider
*/
public function __construct(
EntityManager $em,
@ -46,7 +46,7 @@ class AccountController
$this->acl = $acl;
}
public function loginAction(Request $request, Response $response): ResponseInterface
public function loginAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
// Check installation completion progress.
@ -56,15 +56,15 @@ class AccountController
$num_users = $this->em->createQuery(/** @lang DQL */'SELECT COUNT(u.id) FROM App\Entity\User u')->getSingleScalarResult();
if ($num_users == 0) {
return $response->withRedirect($request->getRouter()->named('setup:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('setup:index'));
}
}
if ($this->auth->isLoggedIn()) {
return $response->withRedirect($request->getRouter()->named('dashboard'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('dashboard'));
}
$session = $request->getSession();
$session = RequestHelper::getSession($request);
if (!empty($_POST['username']) && !empty($_POST['password'])) {
try {
@ -73,7 +73,7 @@ class AccountController
$session->flash('<b>' . __('Too many login attempts') . '</b><br>' . __('You have attempted to log in too many times. Please wait 30 seconds and try again.'),
'red');
return $response->withRedirect($request->getUri()->getPath());
return ResponseHelper::withRedirect($response, $request->getUri()->getPath());
}
$user = $this->auth->authenticate($_POST['username'], $_POST['password']);
@ -91,33 +91,35 @@ class AccountController
// Redirect for 2FA.
if (!$this->auth->isLoginComplete()) {
return $response->withRedirect($request->getRouter()->named('account:login:2fa'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('account:login:2fa'));
}
$session->flash('<b>' . __('Logged in successfully.') . '</b><br>' . $user->getEmail(), 'green');
$referrer = $session->get('login_referrer');
if (!empty($referrer->url)) {
return $response->withRedirect($referrer->url);
return ResponseHelper::withRedirect($response, $referrer->url);
}
return $response->withRedirect($request->getRouter()->named('dashboard'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('dashboard'));
}
$session->flash('<b>' . __('Login unsuccessful') . '</b><br>' . __('Your credentials could not be verified.'),
'red');
return $response->withRedirect($request->getUri());
return ResponseHelper::withRedirect($response, $request->getUri());
}
return $request->getView()->renderToResponse($response, 'frontend/account/login');
return RequestHelper::getView($request)->renderToResponse($response, 'frontend/account/login');
}
public function twoFactorAction(Request $request, Response $response): ResponseInterface
public function twoFactorAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
if ($request->isPost()) {
$session = $request->getSession();
$otp = $request->getParsedBodyParam('otp');
if ('POST' === $request->getMethod()) {
$session = RequestHelper::getSession($request);
$parsedBody = $request->getParsedBody();
$otp = $parsedBody['otp'];
if ($this->auth->verifyTwoFactor($otp)) {
@ -127,33 +129,33 @@ class AccountController
$referrer = $session->get('login_referrer');
if (!empty($referrer->url)) {
return $response->withRedirect($referrer->url);
return ResponseHelper::withRedirect($response, $referrer->url);
}
return $response->withRedirect($request->getRouter()->named('dashboard'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('dashboard'));
}
$session->flash('<b>' . __('Login unsuccessful') . '</b><br>' . __('Your credentials could not be verified.'),
'red');
return $response->withRedirect($request->getUri());
return ResponseHelper::withRedirect($response, $request->getUri());
}
return $request->getView()->renderToResponse($response, 'frontend/account/two_factor');
return RequestHelper::getView($request)->renderToResponse($response, 'frontend/account/two_factor');
}
public function logoutAction(Request $request, Response $response): ResponseInterface
public function logoutAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$this->auth->logout();
$request->getSession()->destroy();
RequestHelper::getSession($request)->destroy();
return $response->withRedirect($request->getRouter()->named('account:login'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('account:login'));
}
public function endmasqueradeAction(Request $request, Response $response): ResponseInterface
public function endmasqueradeAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$this->auth->endMasquerade();
return $response->withRedirect($request->getRouter()->named('admin:users:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('admin:users:index'));
}
}

View File

@ -1,13 +1,15 @@
<?php
namespace App\Controller\Frontend;
use App\Entity;
use App\Exception\NotFound;
use App\Form\Form;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ApiKeysController
{
@ -25,31 +27,30 @@ class ApiKeysController
/**
* @param EntityManager $em
* @param array $form_config
* @see \App\Provider\FrontendProvider
* @param Config $config
*/
public function __construct(EntityManager $em, array $form_config)
public function __construct(EntityManager $em, Config $config)
{
$this->em = $em;
$this->form_config = $form_config;
$this->form_config = $config->get('forms/api_key');
$this->record_repo = $this->em->getRepository(Entity\ApiKey::class);
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$user = $request->getUser();
$user = RequestHelper::getUser($request);
return $request->getView()->renderToResponse($response, 'frontend/api_keys/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'frontend/api_keys/index', [
'records' => $user->getApiKeys(),
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function editAction(Request $request, Response $response, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $id = null): ResponseInterface
{
$user = $request->getUser();
$view = $request->getView();
$user = RequestHelper::getUser($request);
$view = RequestHelper::getView($request);
$form = new Form($this->form_config);
@ -93,8 +94,8 @@ class ApiKeysController
]);
}
$request->getSession()->flash(__('%s updated.', __('API Key')), 'green');
return $response->withRedirect($request->getRouter()->named('api_keys:index'));
RequestHelper::getSession($request)->flash(__('%s updated.', __('API Key')), 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('api_keys:index'));
}
return $view->renderToResponse($response, 'system/form_page', [
@ -104,9 +105,9 @@ class ApiKeysController
]);
}
public function deleteAction(Request $request, Response $response, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $id, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
/** @var Entity\User $user */
$user = $request->getAttribute('user');
@ -120,8 +121,8 @@ class ApiKeysController
$this->em->flush();
$this->em->refresh($user);
$request->getSession()->flash(__('%s deleted.', __('API Key')), 'green');
RequestHelper::getSession($request)->flash(__('%s deleted.', __('API Key')), 'green');
return $response->withRedirect($request->getRouter()->named('api_keys:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('api_keys:index'));
}
}

View File

@ -2,17 +2,17 @@
namespace App\Controller\Frontend;
use App\Acl;
use App\Entity;
use App\Event;
use Azura\Cache;
use App\Http\RequestHelper;
use App\Http\Router;
use App\Radio\Adapters;
use Azura\Cache;
use Azura\EventDispatcher;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use InfluxDB\Database;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class DashboardController
{
@ -44,8 +44,6 @@ class DashboardController
* @param Database $influx
* @param Adapters $adapter_manager
* @param EventDispatcher $dispatcher
*
* @see \App\Provider\FrontendProvider
*/
public function __construct(
EntityManager $em,
@ -63,11 +61,11 @@ class DashboardController
$this->dispatcher = $dispatcher;
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$view = $request->getView();
$user = $request->getUser();
$router = $request->getRouter();
$view = RequestHelper::getView($request);
$user = RequestHelper::getUser($request);
$router = RequestHelper::getRouter($request);
$show_admin = $this->acl->userAllowed($user, Acl::GLOBAL_VIEW);
@ -90,7 +88,7 @@ class DashboardController
// Get administrator notifications.
$notification_event = new Event\GetNotifications($user);
$this->dispatcher->dispatch(Event\GetNotifications::NAME, $notification_event);
$this->dispatcher->dispatch($notification_event);
$notifications = $notification_event->getNotifications();

View File

@ -1,10 +1,12 @@
<?php
namespace App\Controller\Frontend;
use App\Http\Request;
use App\Http\Response;
use App\Entity;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class IndexController
{
@ -12,36 +14,38 @@ class IndexController
protected $settings_repo;
/**
* @param Entity\Repository\SettingsRepository $settings_repo
* @see \App\Provider\FrontendProvider
* @param EntityManager $em
*/
public function __construct(Entity\Repository\SettingsRepository $settings_repo)
public function __construct(EntityManager $em)
{
/** @var Entity\Repository\SettingsRepository $settings_repo */
$settings_repo = $em->getRepository(Entity\Settings::class);
$this->settings_repo = $settings_repo;
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
// Redirect to complete setup, if it hasn't been completed yet.
if ($this->settings_repo->getSetting(Entity\Settings::SETUP_COMPLETE, 0) === 0) {
return $response->withRedirect($request->getRouter()->named('setup:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('setup:index'));
}
// Redirect to login screen if the user isn't logged in.
$user = $request->getAttribute(Request::ATTRIBUTE_USER);
$user = $request->getAttribute(RequestHelper::ATTR_USER);
if (!($user instanceof Entity\User)) {
// Redirect to a custom homepage URL if specified in settings.
$homepage_redirect = trim($this->settings_repo->getSetting(Entity\Settings::HOMEPAGE_REDIRECT_URL));
if (!empty($homepage_redirect)) {
return $response->withRedirect($homepage_redirect, 302);
return ResponseHelper::withRedirect($response, $homepage_redirect, 302);
}
return $response->withRedirect($request->getRouter()->named('account:login'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('account:login'));
}
// Redirect to dashboard if no other custom redirection rules exist.
return $response->withRedirect($request->getRouter()->named('dashboard'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('dashboard'));
}
}

View File

@ -1,15 +1,18 @@
<?php
namespace App\Controller\Frontend;
use App\Form\Form;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Form\Form;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Azura\Settings;
use BaconQrCode;
use Doctrine\ORM\EntityManager;
use OTPHP\TOTP;
use ParagonIE\ConstantTime\Base32;
use Psr\Http\Message\ResponseInterface;
use BaconQrCode;
use Psr\Http\Message\ServerRequestInterface;
class ProfileController
{
@ -27,38 +30,39 @@ class ProfileController
/**
* @param EntityManager $em
* @param array $profile_form
* @param array $two_factor_form
* @see \App\Provider\FrontendProvider
* @param Config $config
* @param Settings $settings
*/
public function __construct(
EntityManager $em,
array $profile_form,
array $two_factor_form)
{
Config $config,
Settings $settings
) {
$this->em = $em;
$this->profile_form = $profile_form;
$this->two_factor_form = $two_factor_form;
$this->profile_form = $config->get('forms/profile', [
'settings' => $settings,
]);
$this->two_factor_form = $config->get('forms/profile_two_factor');
$this->user_repo = $this->em->getRepository(Entity\User::class);
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$user = $request->getUser();
$user = RequestHelper::getUser($request);
$user_profile = $this->user_repo->toArray($user);
$customization_form = new Form($this->profile_form['groups']['customization'], $user_profile);
return $request->getView()->renderToResponse($response, 'frontend/profile/index', [
'user' => $request->getUser(),
return RequestHelper::getView($request)->renderToResponse($response, 'frontend/profile/index', [
'user' => RequestHelper::getUser($request),
'customization_form' => $customization_form,
]);
}
public function editAction(Request $request, Response $response): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$user = $request->getUser();
$user = RequestHelper::getUser($request);
$form = new Form($this->profile_form);
@ -82,7 +86,7 @@ class ProfileController
$form->populate(array_filter($user_profile));
if ($request->isPost() && $form->isValid($request->getParsedBody())) {
if ('POST' === $request->getMethod() && $form->isValid($request->getParsedBody())) {
$data = $form->getValues();
unset($data['password']);
@ -96,21 +100,21 @@ class ProfileController
$this->em->persist($user);
$this->em->flush();
$request->getSession()->flash(__('Profile saved!'), 'green');
RequestHelper::getSession($request)->flash(__('Profile saved!'), 'green');
return $response->withRedirect($request->getRouter()->named('profile:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('profile:index'));
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $form,
'render_mode' => 'edit',
'title' => __('Edit Profile')
]);
}
public function themeAction(Request $request, Response $response): ResponseInterface
public function themeAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$user = $request->getUser();
$user = RequestHelper::getUser($request);
$theme_field = $this->profile_form['groups']['customization']['elements']['theme'][1];
$theme_options = array_keys($theme_field['choices']);
@ -130,14 +134,15 @@ class ProfileController
$this->em->persist($user);
$this->em->flush($user);
return $response->withRedirect(
$request->getReferrer($request->getRouter()->named('dashboard'))
$referrer = $request->getHeaderLine('HTTP_REFERER');
return ResponseHelper::withRedirect($response,
$referrer ?? (string)RequestHelper::getRouter($request)->named('dashboard')
);
}
public function enableTwoFactorAction(Request $request, Response $response): ResponseInterface
public function enableTwoFactorAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$user = $request->getUser();
$user = RequestHelper::getUser($request);
$form = new Form($this->two_factor_form);
$form->getField('otp')->addValidator(function($otp, \AzuraForms\Field\AbstractField $element) {
@ -149,8 +154,9 @@ class ProfileController
: __('The token you supplied is invalid. Please try again.');
});
if ($request->isPost()) {
$secret = $request->getParsedBodyParam('secret');
if ('POST' === $request->getMethod()) {
$parsedBody = $request->getParsedBody();
$secret = $parsedBody['secret'];
} else {
// Generate new TOTP secret.
$secret = substr(trim(Base32::encodeUpper(random_bytes(128)), '='), 0, 64);
@ -164,14 +170,14 @@ class ProfileController
$totp = TOTP::create($secret);
$totp->setLabel($user->getEmail());
if ($request->isPost() && $form->isValid($request->getParsedBody())) {
if ('POST' === $request->getMethod() && $form->isValid($request->getParsedBody())) {
$user->setTwoFactorSecret($totp->getProvisioningUri());
$this->em->persist($user);
$this->em->flush($user);
$request->getSession()->flash(__('Two-factor authentication enabled.'), 'green');
RequestHelper::getSession($request)->flash(__('Two-factor authentication enabled.'), 'green');
return $response->withRedirect($request->getRouter()->named('profile:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('profile:index'));
}
// Further customize TOTP code (with metadata that won't be stored in the DB)
@ -188,23 +194,23 @@ class ProfileController
$writer = new BaconQrCode\Writer($renderer);
$qr_code = $writer->writeString($totp_uri);
return $request->getView()->renderToResponse($response, 'frontend/profile/enable_two_factor', [
return RequestHelper::getView($request)->renderToResponse($response, 'frontend/profile/enable_two_factor', [
'form' => $form,
'qr_code' => $qr_code,
'totp_uri' => $totp_uri,
]);
}
public function disableTwoFactorAction(Request $request, Response $response): ResponseInterface
public function disableTwoFactorAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$user = $request->getUser();
$user = RequestHelper::getUser($request);
$user->setTwoFactorSecret(null);
$this->em->persist($user);
$this->em->flush($user);
$request->getSession()->flash(__('Two-factor authentication disabled.'), 'green');
RequestHelper::getSession($request)->flash(__('Two-factor authentication disabled.'), 'green');
return $response->withRedirect($request->getRouter()->named('profile:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('profile:index'));
}
}

View File

@ -1,36 +1,36 @@
<?php
namespace App\Controller\Frontend;
use App\Radio\Backend\Liquidsoap;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Radio\Backend\Liquidsoap;
use App\Radio\Remote\AdapterProxy;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class PublicController
{
public function indexAction(Request $request, Response $response, $station_id = null): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response, $station_id = null): ResponseInterface
{
return $this->_getPublicPage($request, $response, 'frontend/public/index');
}
public function embedAction(Request $request, Response $response, $station_id = null): ResponseInterface
public function embedAction(ServerRequestInterface $request, ResponseInterface $response, $station_id = null): ResponseInterface
{
return $this->_getPublicPage($request, $response, 'frontend/public/embed');
}
public function embedrequestsAction(Request $request, Response $response): ResponseInterface
public function embedrequestsAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $this->_getPublicPage($request, $response, 'frontend/public/embedrequests');
}
protected function _getPublicPage(Request $request, Response $response, $template_name, $template_vars = [])
protected function _getPublicPage(ServerRequestInterface $request, ResponseInterface $response, $template_name, $template_vars = [])
{
// Override system-wide iframe refusal
$response = $response->withoutHeader('X-Frame-Options');
$station = $request->getStation();
$station = RequestHelper::getStation($request);
if (!$station->getEnablePublicPage()) {
throw new \App\Exception\StationNotFound;
@ -61,24 +61,24 @@ class PublicController
$station_np = $station->getNowplaying();
if ($station_np instanceof Entity\Api\NowPlaying) {
$station_np->resolveUrls($request->getRouter()->getBaseUrl());
$station_np->resolveUrls(RequestHelper::getRouter($request)->getBaseUrl());
$np = array_intersect_key($station_np->toArray(), $np) + $np;
}
return $request->getView()->renderToResponse($response, $template_name, $template_vars + [
return RequestHelper::getView($request)->renderToResponse($response, $template_name, $template_vars + [
'station' => $station,
'nowplaying' => $np,
]);
}
public function playlistAction(Request $request, Response $response, $station_id, $format = 'pls'): ResponseInterface
public function playlistAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $format = 'pls'): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$streams = [];
$stream_urls = [];
$fa = $request->getStationFrontend();
$fa = RequestHelper::getStationFrontend($request);
foreach ($station->getMounts() as $mount) {
/** @var Entity\StationMount $mount */
if (!$mount->isVisibleOnPublicPages()) {
@ -94,7 +94,7 @@ class PublicController
];
}
$remotes = $request->getStationRemotes();
$remotes = RequestHelper::getStationRemotes($request);
foreach($remotes as $remote_proxy) {
/** @var AdapterProxy $remote_proxy */
$adapter = $remote_proxy->getAdapter();
@ -115,10 +115,10 @@ class PublicController
case 'm3u':
$m3u_file = implode("\n", $stream_urls);
$response->getBody()->write($m3u_file);
return $response
->withHeader('Content-Type', 'audio/x-mpegurl')
->withHeader('Content-Disposition', 'attachment; filename=' . $station->getShortName() . '.m3u')
->write($m3u_file);
->withHeader('Content-Disposition', 'attachment; filename=' . $station->getShortName() . '.m3u');
break;
// PLS Playlist Format
@ -140,17 +140,17 @@ class PublicController
$output[] = 'NumberOfEntries=' . count($streams);
$output[] = 'Version=2';
$response->getBody()->write(implode("\n", $output));
return $response
->withHeader('Content-Type', 'audio/x-scpls')
->withHeader('Content-Disposition', 'attachment; filename=' . $station->getShortName() . '.pls')
->write(implode("\n", $output));
->withHeader('Content-Disposition', 'attachment; filename=' . $station->getShortName() . '.pls');
break;
}
}
public function djAction(Request $request, Response $response, $station_id, $format = 'pls'): ResponseInterface
public function djAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $format = 'pls'): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
if (!$station->getEnablePublicPage()) {
throw new \App\Exception\StationNotFound;
@ -160,16 +160,16 @@ class PublicController
throw new \App\Exception\StationUnsupported;
}
$backend = $request->getStationBackend();
$backend = RequestHelper::getStationBackend($request);
if (!($backend instanceof Liquidsoap)) {
throw new \App\Exception\StationUnsupported;
}
$wss_url = (string)$backend->getWebStreamingUrl($station, $request->getRouter()->getBaseUrl());
$wss_url = (string)$backend->getWebStreamingUrl($station, RequestHelper::getRouter($request)->getBaseUrl());
$wss_url = str_replace('wss://', '', $wss_url);
return $request->getView()->renderToResponse($response, 'frontend/public/dj', [
return RequestHelper::getView($request)->renderToResponse($response, 'frontend/public/dj', [
'station' => $station,
'base_uri' => $wss_url,
]);

View File

@ -3,16 +3,15 @@ namespace App\Controller\Frontend;
use App\Acl;
use App\Auth;
use App\Entity;
use App\Form\Form;
use App\Form\StationForm;
use App\Radio\Adapters;
use App\Radio\Configuration;
use App\Radio\Frontend\SHOUTcast;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class SetupController
{
@ -36,66 +35,63 @@ class SetupController
* @param Auth $auth
* @param Acl $acl
* @param StationForm $station_form
* @param array $settings_form_config
*
* @see \App\Provider\FrontendProvider
* @param Config $config
*/
public function __construct(
EntityManager $em,
Auth $auth,
Acl $acl,
StationForm $station_form,
array $settings_form_config
)
{
Config $config
) {
$this->em = $em;
$this->auth = $auth;
$this->acl = $acl;
$this->station_form = $station_form;
$this->settings_form_config = $settings_form_config;
$this->settings_form_config = $config->get('forms/settings');
}
/**
* Setup Routing Controls
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$current_step = $this->_getSetupStep();
return $response->withRedirect($request->getRouter()->named('setup:'.$current_step));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('setup:'.$current_step));
}
/**
* Placeholder function for "setup complete" redirection.
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function completeAction(Request $request, Response $response): ResponseInterface
public function completeAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$request->getSession()->flash('<b>' . __('Setup has already been completed!') . '</b>', 'red');
RequestHelper::getSession($request)->flash('<b>' . __('Setup has already been completed!') . '</b>', 'red');
return $response->withRedirect($request->getRouter()->named('dashboard'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('dashboard'));
}
/**
* Setup Step 1:
* Create Super Administrator Account
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function registerAction(Request $request, Response $response): ResponseInterface
public function registerAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
// Verify current step.
$current_step = $this->_getSetupStep();
if ($current_step !== 'register' && APP_IN_PRODUCTION) {
return $response->withRedirect($request->getRouter()->named('setup:'.$current_step));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('setup:'.$current_step));
}
// Create first account form.
@ -128,10 +124,10 @@ class SetupController
$this->auth->authenticate($data['username'], $data['password']);
$this->acl->reload();
return $response->withRedirect($request->getRouter()->named('setup:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('setup:index'));
}
return $request->getView()
return RequestHelper::getView($request)
->renderToResponse($response, 'frontend/setup/register');
}
@ -139,23 +135,23 @@ class SetupController
* Setup Step 2:
* Create Station and Parse Metadata
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function stationAction(Request $request, Response $response): ResponseInterface
public function stationAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
// Verify current step.
$current_step = $this->_getSetupStep();
if ($current_step !== 'station' && APP_IN_PRODUCTION) {
return $response->withRedirect($request->getRouter()->named('setup:'.$current_step));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('setup:'.$current_step));
}
if (false !== $this->station_form->process($request)) {
return $response->withRedirect($request->getRouter()->named('setup:settings'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('setup:settings'));
}
return $request->getView()->renderToResponse($response, 'frontend/setup/station', [
return RequestHelper::getView($request)->renderToResponse($response, 'frontend/setup/station', [
'form' => $this->station_form,
]);
}
@ -164,16 +160,16 @@ class SetupController
* Setup Step 3:
* Set site settings.
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function settingsAction(Request $request, Response $response): ResponseInterface
public function settingsAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
// Verify current step.
$current_step = $this->_getSetupStep();
if ($current_step !== 'settings' && APP_IN_PRODUCTION) {
return $response->withRedirect($request->getRouter()->named('setup:'.$current_step));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('setup:'.$current_step));
}
$form = new Form($this->settings_form_config);
@ -193,13 +189,13 @@ class SetupController
$settings_repo->setSettings($data);
// Notify the user and redirect to homepage.
$request->getSession()->flash('<b>' . __('Setup is now complete!') . '</b><br>' . __('Continue setting up your station in the main AzuraCast app.'),
RequestHelper::getSession($request)->flash('<b>' . __('Setup is now complete!') . '</b><br>' . __('Continue setting up your station in the main AzuraCast app.'),
'green');
return $response->withRedirect($request->getRouter()->named('dashboard'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('dashboard'));
}
return $request->getView()->renderToResponse($response, 'frontend/setup/settings', [
return RequestHelper::getView($request)->renderToResponse($response, 'frontend/setup/settings', [
'form' => $form,
]);
}

View File

@ -3,8 +3,9 @@ namespace App\Controller\Stations;
use App\Entity\Station;
use App\Form\EntityForm;
use App\Http\Request;
use App\Http\RequestHelper;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ServerRequestInterface;
abstract class AbstractStationCrudController
{
@ -33,13 +34,13 @@ abstract class AbstractStationCrudController
}
/**
* @param Request $request
* @param ServerRequestInterface $request
* @param string|int|null $id
* @return object|bool|null
*/
protected function _doEdit(Request $request, $id = null)
protected function _doEdit(ServerRequestInterface $request, $id = null)
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$this->form->setStation($station);
$record = $this->_getRecord($station, $id);
@ -53,14 +54,14 @@ abstract class AbstractStationCrudController
}
/**
* @param Request $request
* @param ServerRequestInterface $request
* @param string|int $id
*/
protected function _doDelete(Request $request, $id, $csrf_token): void
protected function _doDelete(ServerRequestInterface $request, $id, $csrf_token): void
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$record = $this->_getRecord($request->getStation(), $id);
$record = $this->_getRecord(RequestHelper::getStation($request), $id);
if ($record instanceof $this->entity_class) {
$this->em->remove($record);

View File

@ -2,12 +2,14 @@
namespace App\Controller\Stations;
use App\Form\Form;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Sync\Task\RadioAutomation;
use Azura\Config;
use Azura\Settings;
use Doctrine\ORM\EntityManager;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class AutomationController
{
@ -25,21 +27,25 @@ class AutomationController
/**
* @param EntityManager $em
* @param array $form_config
* @param RadioAutomation $sync_task
* @see \App\Provider\StationsProvider
* @param Settings $app_settings
* @param Config $config
*/
public function __construct(EntityManager $em, RadioAutomation $sync_task, Settings $app_settings, array $form_config)
{
public function __construct(
EntityManager $em,
RadioAutomation $sync_task,
Settings $app_settings,
Config $config
) {
$this->em = $em;
$this->sync_task = $sync_task;
$this->app_settings = $app_settings;
$this->form_config = $form_config;
$this->form_config = $config->get('forms/automation');
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$automation_settings = (array)$station->getAutomationSettings();
@ -54,29 +60,29 @@ class AutomationController
$this->em->persist($station);
$this->em->flush();
$request->getSession()->flash(__('Changes saved.'), 'green');
RequestHelper::getSession($request)->flash(__('Changes saved.'), 'green');
return $response->withRedirect($request->getUri());
return ResponseHelper::withRedirect($response, $request->getUri());
}
return $request->getView()->renderToResponse($response, 'stations/automation/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/automation/index', [
'app_settings' => $this->app_settings,
'form' => $form,
]);
}
public function runAction(Request $request, Response $response, $station_id): ResponseInterface
public function runAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
try {
if ($this->sync_task->runStation($station, true)) {
$request->getSession()->flash('<b>' . __('Automated assignment complete!') . '</b>', 'green');
RequestHelper::getSession($request)->flash('<b>' . __('Automated assignment complete!') . '</b>', 'green');
}
} catch (\Exception $e) {
$request->getSession()->flash('<b>' . __('Automated assignment error') . ':</b><br>' . $e->getMessage(), 'red');
RequestHelper::getSession($request)->flash('<b>' . __('Automated assignment error') . ':</b><br>' . $e->getMessage(), 'red');
}
return $response->withRedirect($request->getRouter()->fromHere('stations:automation:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:automation:index'));
}
}

View File

@ -3,12 +3,13 @@ namespace App\Controller\Stations\Files;
use App\Entity;
use App\Flysystem\StationFilesystem;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Backend\Liquidsoap;
use App\Radio\Filesystem;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class BatchController extends FilesControllerAbstract
{
@ -22,8 +23,6 @@ class BatchController extends FilesControllerAbstract
* BatchController constructor.
* @param EntityManager $em
* @param Filesystem $filesystem
*
* @see \App\Provider\StationsProvider
*/
public function __construct(EntityManager $em, Filesystem $filesystem)
{
@ -31,16 +30,20 @@ class BatchController extends FilesControllerAbstract
$this->filesystem = $filesystem;
}
public function __invoke(Request $request, Response $response, $station_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$params = RequestHelper::getParams($request);
try {
$request->getSession()->getCsrf()->verify($request->getParam('csrf'), $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($params['csrf'], $this->csrf_namespace);
} catch(\Azura\Exception\CsrfValidation $e) {
return $response->withStatus(403)
->withJson(['error' => ['code' => 403, 'msg' => 'CSRF Failure: '.$e->getMessage()]]);
return ResponseHelper::withJson(
$response->withStatus(403),
['error' => ['code' => 403, 'msg' => 'CSRF Failure: '.$e->getMessage()]]
);
}
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$fs = $this->filesystem->getForStation($station);
/** @var Entity\Repository\StationMediaRepository $media_repo */
@ -125,7 +128,7 @@ class BatchController extends FilesControllerAbstract
$this->em->flush($station);
// Write new PLS playlist configuration.
$backend = $request->getStationBackend();
$backend = RequestHelper::getStationBackend($request);
if ($backend instanceof Liquidsoap) {
foreach($affected_playlists as $playlist) {
@ -205,7 +208,7 @@ class BatchController extends FilesControllerAbstract
$this->em->flush();
// Write new PLS playlist configuration.
$backend = $request->getStationBackend();
$backend = RequestHelper::getStationBackend($request);
if ($backend instanceof Liquidsoap) {
foreach($affected_playlists as $playlist) {
@ -256,7 +259,7 @@ class BatchController extends FilesControllerAbstract
$this->em->clear(Entity\StationPlaylist::class);
$this->em->clear(Entity\StationPlaylistMedia::class);
return $response->withJson([
return ResponseHelper::withJson($response, [
'success' => true,
'files_found' => $files_found,
'files_affected' => $files_affected,

View File

@ -3,16 +3,18 @@ namespace App\Controller\Stations\Files;
use App\Entity;
use App\Form\Form;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Http\Router;
use App\Radio\Filesystem;
use Azura\Config;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UploadedFileInterface;
/**
* Abstract out the Edit File functionality, as it has significant extra code.
* @package Controller\Stations\Files
*/
class EditController extends FilesControllerAbstract
{
@ -26,23 +28,27 @@ class EditController extends FilesControllerAbstract
protected $form_config;
/**
* EditController constructor.
* @param EntityManager $em
* @param Filesystem $filesystem
* @param array $form_config
*
* @see \App\Provider\StationsProvider
* @param Config $config
* @param Router $router
*/
public function __construct(EntityManager $em, Filesystem $filesystem, array $form_config)
{
public function __construct(
EntityManager $em,
Filesystem $filesystem,
Config $config,
Router $router
) {
$this->em = $em;
$this->filesystem = $filesystem;
$this->form_config = $form_config;
$this->form_config = $config->get('forms/media', [
'router' => $router,
]);
}
public function __invoke(Request $request, Response $response, $station_id, $media_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id, $media_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$fs = $this->filesystem->getForStation($station);
@ -134,13 +140,13 @@ class EditController extends FilesControllerAbstract
$this->em->persist($media);
$this->em->flush();
$request->getSession()->flash('<b>' . __('%s updated.', __('Media')) . '</b>', 'green');
RequestHelper::getSession($request)->flash('<b>' . __('%s updated.', __('Media')) . '</b>', 'green');
$file_dir = (dirname($media->getPath()) === '.') ? '' : dirname($media->getPath());
return $response->withRedirect($request->getRouter()->named('stations:files:index', ['station' => $station_id]).'#'.$file_dir, 302);
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('stations:files:index', ['station' => $station_id]).'#'.$file_dir, 302);
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $form,
'render_mode' => 'edit',
'title' =>__('Edit %s', __('Media'))

View File

@ -3,13 +3,13 @@ namespace App\Controller\Stations\Files;
use App\Entity;
use App\Form\Form;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Filesystem;
use Psr\Http\Message\ResponseInterface;
use App\Utilities;
use Azura\Config;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Finder\Finder;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class FilesController extends FilesControllerAbstract
{
@ -23,23 +23,23 @@ class FilesController extends FilesControllerAbstract
protected $form_config;
/**
* FilesController constructor.
* @param EntityManager $em
* @param Filesystem $filesystem
* @param array $form_config
*
* @see \App\Provider\StationsProvider
* @param Config $config
*/
public function __construct(EntityManager $em, Filesystem $filesystem, array $form_config)
{
public function __construct(
EntityManager $em,
Filesystem $filesystem,
Config $config
) {
$this->em = $em;
$this->filesystem = $filesystem;
$this->form_config = $form_config;
$this->form_config = $config->get('forms/rename');
}
public function __invoke(Request $request, Response $response, $station_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$playlists = $this->em->createQuery(/** @lang DQL */'SELECT sp.id, sp.name
FROM App\Entity\StationPlaylist sp
@ -48,7 +48,7 @@ class FilesController extends FilesControllerAbstract
->setParameter('station_id', $station_id)
->setParameter('source', Entity\StationPlaylist::SOURCE_SONGS)
->getArrayResult();
$files_count = $this->em->createQuery(/** @lang DQL */'SELECT COUNT(sm.id) FROM App\Entity\StationMedia sm
WHERE sm.station_id = :station_id')
->setParameter('station_id', $station_id)
@ -63,20 +63,20 @@ class FilesController extends FilesControllerAbstract
$custom_fields['media_custom_'.$row['id']] = $row['name'];
}
return $request->getView()->renderToResponse($response, 'stations/files/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/files/index', [
'playlists' => $playlists,
'custom_fields' => $custom_fields,
'space_used' => $station->getStorageUsed(),
'space_total' => $station->getStorageAvailable(),
'space_percent' => $station->getStorageUsePercentage(),
'files_count' => $files_count,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function renameAction(Request $request, Response $response, $station_id): ResponseInterface
public function renameAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$fs = $this->filesystem->getForStation($station);
$path = $request->getAttribute('file');
@ -123,23 +123,23 @@ class FilesController extends FilesControllerAbstract
$path = $new_path;
}
$request->getSession()->flash('<b>' . __('File renamed!') . '</b>', 'green');
RequestHelper::getSession($request)->flash('<b>' . __('File renamed!') . '</b>', 'green');
$file_dir = (dirname($path) === '.') ? '' : dirname($path);
return $response->withRedirect((string)$request->getRouter()->fromHere('stations:files:index').'#'.$file_dir);
return ResponseHelper::withRedirect($response, (string)RequestHelper::getRouter($request)->fromHere('stations:files:index').'#'.$file_dir);
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $form,
'render_mode' => 'edit',
'title' => __('Rename File/Directory')
]);
}
public function listDirectoriesAction(Request $request, Response $response, $station_id): ResponseInterface
public function listDirectoriesAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$fs = $this->filesystem->getForStation($station);
$file_path = $request->getAttribute('file_path');
@ -163,53 +163,54 @@ class FilesController extends FilesControllerAbstract
];
}, $fs->listContents($file_path)));
return $response->withJson([
return ResponseHelper::withJson($response, [
'rows' => array_values($directories)
]);
}
public function mkdirAction(Request $request, Response $response): ResponseInterface
public function mkdirAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$params = RequestHelper::getParams($request);
try {
$request->getSession()->getCsrf()->verify($request->getParam('csrf'), $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($params['csrf'], $this->csrf_namespace);
} catch(\Azura\Exception\CsrfValidation $e) {
return $this->_err($response, 403, 'CSRF Failure: '.$e->getMessage());
}
$file_path = $request->getAttribute('file_path');
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$fs = $this->filesystem->getForStation($station);
$new_dir = $file_path.'/'.$_POST['name'];
$new_dir = $file_path.'/'.$params['name'];
$dir_created = $fs->createDir($new_dir);
if (!$dir_created) {
return $this->_err($response, 403, sprintf('Directory "%s" was not created', $new_dir));
}
return $response->withJson(['success' => true]);
return ResponseHelper::withJson($response, ['success' => true]);
}
public function uploadAction(Request $request, Response $response): ResponseInterface
public function uploadAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$params = RequestHelper::getParams($request);
try {
$request->getSession()->getCsrf()->verify($request->getParam('csrf'), $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($params['csrf'], $this->csrf_namespace);
} catch(\Azura\Exception\CsrfValidation $e) {
return $response->withStatus(403)
->withJson(['error' => ['code' => 403, 'msg' => 'CSRF Failure: '.$e->getMessage()]]);
return $this->_err($response, 403, 'CSRF Failure: '.$e->getMessage());
}
$station = $request->getStation();
$station = RequestHelper::getStation($request);
if ($station->isStorageFull()) {
return $this->_err($response, 500, __('This station is out of available storage space.'));
}
try {
$flow = new \App\Service\Flow($request, $response, $station->getRadioTempDir());
$flow_response = $flow->process();
if ($flow_response instanceof Response) {
$flow_response = \App\Service\Flow::process($request, $response, $station->getRadioTempDir());
if ($flow_response instanceof ResponseInterface) {
return $flow_response;
}
@ -232,8 +233,8 @@ class FilesController extends FilesControllerAbstract
$station_media = $media_repo->uploadFile($station, $flow_response['path'], $final_path);
// If the user is looking at a playlist's contents, add uploaded media to that playlist.
if ($request->hasParam('searchPhrase')) {
$search_phrase = $request->getParam('searchPhrase');
if (!empty($params['searchPhrase'])) {
$search_phrase = $params['searchPhrase'];
if (0 === strpos($search_phrase, 'playlist:')) {
$playlist_name = substr($search_phrase, 9);
@ -255,20 +256,20 @@ class FilesController extends FilesControllerAbstract
$station->addStorageUsed($flow_response['size']);
$this->em->flush();
return $response->withJson(['success' => true]);
return ResponseHelper::withJson($response, ['success' => true]);
}
} catch (\Exception | \Error $e) {
return $this->_err($response, 500, $e->getMessage());
}
return $response->withJson(['success' => false]);
return ResponseHelper::withJson($response, ['success' => false]);
}
public function downloadAction(Request $request, Response $response): ResponseInterface
public function downloadAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
set_time_limit(600);
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$file_path = $request->getAttribute('file_path');
$fs = $this->filesystem->getForStation($station);
@ -284,13 +285,12 @@ class FilesController extends FilesControllerAbstract
$file_mime = 'application/octet-stream';
}
return $response
->withNoCache()
return ResponseHelper::withNoCache($response)
->withHeader('Content-Type', $file_mime)
->withHeader('Content-Length', $file_meta['size'])
->withHeader('Content-Disposition', sprintf('attachment; filename=%s',
strpos('MSIE', $_SERVER['HTTP_REFERER']) ? rawurlencode($filename) : "\"$filename\""))
->withHeader('X-Accel-Buffering', 'no')
->withBody(new \Slim\Http\Stream($fh));
->withBody(new \Slim\Psr7\Stream($fh));
}
}

View File

@ -1,7 +1,7 @@
<?php
namespace App\Controller\Stations\Files;
use App\Http\Response;
use App\Http\ResponseHelper;
use Psr\Http\Message\ResponseInterface;
/**
@ -16,10 +16,11 @@ abstract class FilesControllerAbstract
/** @var string */
protected $csrf_namespace = 'stations_files';
protected function _err(Response $response, $code, $msg): ResponseInterface
protected function _err(ResponseInterface $response, $code, $msg): ResponseInterface
{
return $response
->withStatus($code)
->withJson(['error' => ['code' => (int)$code, 'msg' => $msg]]);
return ResponseHelper::withJson(
$response->withStatus($code),
['error' => ['code' => (int)$code, 'msg' => $msg]]
);
}
}

View File

@ -2,11 +2,12 @@
namespace App\Controller\Stations\Files;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Filesystem;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ListController extends FilesControllerAbstract
{
@ -20,8 +21,6 @@ class ListController extends FilesControllerAbstract
* ListController constructor.
* @param EntityManager $em
* @param Filesystem $filesystem
*
* @see \App\Provider\StationsProvider
*/
public function __construct(EntityManager $em, Filesystem $filesystem)
{
@ -29,14 +28,15 @@ class ListController extends FilesControllerAbstract
$this->filesystem = $filesystem;
}
public function __invoke(Request $request, Response $response, $station_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$router = $request->getRouter();
$station = RequestHelper::getStation($request);
$router = RequestHelper::getRouter($request);
$fs = $this->filesystem->getForStation($station);
$params = $request->getQueryParams();
if ('true' === $request->getParam('flush_cache', null)) {
if ('true' === $params['flush_cache']) {
$fs->flushAllCaches();
}
@ -45,7 +45,7 @@ class ListController extends FilesControllerAbstract
$file = $request->getAttribute('file');
$file_path = $request->getAttribute('file_path');
$search_phrase = trim($request->getParam('searchPhrase') ?? '');
$search_phrase = trim($params['searchPhrase'] ?? '');
$media_query = $this->em->createQueryBuilder()
->select('partial sm.{id, unique_id, path, length, length_text, artist, title, album}')
@ -191,7 +191,7 @@ class ListController extends FilesControllerAbstract
$return_result = [];
}
return $response->withJson([
return ResponseHelper::withJson($response, [
'current' => $page,
'rowCount' => $row_count,
'total' => $num_results,

View File

@ -2,27 +2,27 @@
namespace App\Controller\Stations;
use App\Controller\Traits\LogViewerTrait;
use App\Http\RequestHelper;
use Azura\Exception;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class LogsController
{
use LogViewerTrait;
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
return $request->getView()->renderToResponse($response, 'stations/logs/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/logs/index', [
'logs' => $this->_getStationLogs($station),
]);
}
public function viewAction(Request $request, Response $response, $station_id, $log_key): ResponseInterface
public function viewAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $log_key): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$log_areas = $this->_getStationLogs($station);
if (!isset($log_areas[$log_key])) {

View File

@ -2,60 +2,59 @@
namespace App\Controller\Stations;
use App\Form\EntityForm;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Form\StationMountForm;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class MountsController extends AbstractStationCrudController
{
/**
* @param EntityForm $form
*
* @see \App\Provider\StationsProvider
* @param StationMountForm $form
*/
public function __construct(EntityForm $form)
public function __construct(StationMountForm $form)
{
parent::__construct($form);
$this->csrf_namespace = 'stations_mounts';
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$frontend = $request->getStationFrontend();
$station = RequestHelper::getStation($request);
$frontend = RequestHelper::getStationFrontend($request);
if (!$frontend::supportsMounts()) {
throw new \App\Exception\StationUnsupported(__('This feature is not currently supported on this station.'));
}
return $request->getView()->renderToResponse($response, 'stations/mounts/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/mounts/index', [
'frontend_type' => $station->getFrontendType(),
'mounts' => $station->getMounts(),
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function editAction(Request $request, Response $response, $station_id, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id = null): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Mount Point')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:mounts:index'));
RequestHelper::getSession($request)->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Mount Point')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:mounts:index'));
}
return $request->getView()->renderToResponse($response, 'stations/mounts/edit', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/mounts/edit', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => sprintf(($id) ? __('Edit %s') : __('Add %s'), __('Mount Point'))
]);
}
public function deleteAction(Request $request, Response $response, $station_id, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id, $csrf_token): ResponseInterface
{
$this->_doDelete($request, $id, $csrf_token);
$request->getSession()->flash('<b>' . __('%s deleted.', __('Mount Point')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:mounts:index'));
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('Mount Point')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:mounts:index'));
}
}

View File

@ -1,13 +1,14 @@
<?php
namespace App\Controller\Stations;
use App\Form\EntityForm;
use App\Utilities;
use Cake\Chronos\Chronos;
use App\Entity;
use App\Form\EntityForm;
use App\Form\StationPlaylistForm;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Cake\Chronos\Chronos;
use Psr\Http\Message\ResponseInterface;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ServerRequestInterface;
class PlaylistsController extends AbstractStationCrudController
{
@ -15,11 +16,9 @@ class PlaylistsController extends AbstractStationCrudController
protected $playlist_media_repo;
/**
* @param EntityForm $form
*
* @see \App\Provider\StationsProvider
* @param StationPlaylistForm $form
*/
public function __construct(EntityForm $form)
public function __construct(StationPlaylistForm $form)
{
parent::__construct($form);
@ -28,16 +27,16 @@ class PlaylistsController extends AbstractStationCrudController
}
/**
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $station_id
* @return ResponseInterface
*/
public function indexAction(Request $request, Response $response, $station_id): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$backend = $request->getStationBackend();
$backend = RequestHelper::getStationBackend($request);
if (!$backend::supportsMedia()) {
throw new \Azura\Exception(__('This feature is not currently supported on this station.'));
}
@ -86,33 +85,36 @@ class PlaylistsController extends AbstractStationCrudController
$playlists[$playlist->getId()] = $playlist_row;
}
return $request->getView()->renderToResponse($response, 'stations/playlists/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/playlists/index', [
'playlists' => $playlists,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
'station_tz' => $station_tz,
'station_now' => $now->toIso8601String(),
'schedule_url' => $request->getRouter()->named('stations:playlists:schedule', ['station' => $station_id]),
'schedule_url' => RequestHelper::getRouter($request)->named('stations:playlists:schedule', ['station' => $station_id]),
]);
}
/**
* Controller used to respond to AJAX requests from the playlist "Schedule View".
*
* @param Request $request
* @param Response $response
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param int|string $station_id
* @return Response
*
* @return ResponseInterface
*/
public function scheduleAction(Request $request, Response $response, $station_id): ResponseInterface
public function scheduleAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$tz = new \DateTimeZone($station->getTimezone());
$start_date_str = substr($request->getParam('start'), 0, 10);
$params = $request->getQueryParams();
$start_date_str = substr($params['start'], 0, 10);
$start_date = Chronos::createFromFormat('Y-m-d', $start_date_str, $tz)
->subDay();
$end_date_str = substr($request->getParam('end'), 0, 10);
$end_date_str = substr($params['end'], 0, 10);
$end_date = Chronos::createFromFormat('Y-m-d', $end_date_str, $tz);
/** @var Entity\StationPlaylist[] $all_playlists */
@ -147,19 +149,19 @@ class PlaylistsController extends AbstractStationCrudController
'title' => $playlist->getName(),
'start' => $playlist_start->toIso8601String(),
'end' => $playlist_end->toIso8601String(),
'url' => (string)$request->getRouter()->named('stations:playlists:edit', ['station' => $station_id, 'id' => $playlist->getId()]),
'url' => (string)RequestHelper::getRouter($request)->named('stations:playlists:edit', ['station' => $station_id, 'id' => $playlist->getId()]),
];
}
$i = $i->addDay();
}
return $response->withJson($events);
return ResponseHelper::withJson($response, $events);
}
public function reorderAction(Request $request, Response $response, $station_id, $id): ResponseInterface
public function reorderAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id): ResponseInterface
{
$record = $this->_getRecord($request->getStation(), $id);
$record = $this->_getRecord(RequestHelper::getStation($request), $id);
if (!$record instanceof Entity\StationPlaylist) {
throw new \App\Exception\NotFound(__('%s not found.', __('Playlist')));
@ -170,15 +172,19 @@ class PlaylistsController extends AbstractStationCrudController
throw new \Azura\Exception(__('This playlist is not a sequential playlist.'));
}
if ($request->isPost()) {
$params = $request->getQueryParams();
if ('POST' === $request->getMethod()) {
try {
$request->getSession()->getCsrf()->verify($request->getParam('csrf'), $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($params['csrf'], $this->csrf_namespace);
} catch(\Azura\Exception\CsrfValidation $e) {
return $response->withStatus(403)
->withJson(['error' => ['code' => 403, 'msg' => 'CSRF Failure: '.$e->getMessage()]]);
return ResponseHelper::withJson(
$response->withStatus(403),
['error' => ['code' => 403, 'msg' => 'CSRF Failure: '.$e->getMessage()]]
);
}
$order_raw = $request->getParam('order');
$order_raw = $params['order'];
$order = json_decode($order_raw, true);
$mapping = [];
@ -188,7 +194,7 @@ class PlaylistsController extends AbstractStationCrudController
$this->playlist_media_repo->setMediaOrder($record, $mapping);
return $response->withJson($mapping);
return ResponseHelper::withJson($response, $mapping);
}
$media_items = $this->em->createQuery(/** @lang DQL */'SELECT spm, sm
@ -199,16 +205,16 @@ class PlaylistsController extends AbstractStationCrudController
->setParameter('playlist_id', $id)
->getArrayResult();
return $request->getView()->renderToResponse($response, 'stations/playlists/reorder', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/playlists/reorder', [
'playlist' => $record,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
'media_items' => $media_items,
]);
}
public function exportAction(Request $request, Response $response, $station_id, $id, $format = 'pls'): ResponseInterface
public function exportAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id, $format = 'pls'): ResponseInterface
{
$record = $this->_getRecord($request->getStation(), $id);
$record = $this->_getRecord(RequestHelper::getStation($request), $id);
$formats = [
'pls' => 'audio/x-scpls',
@ -221,15 +227,15 @@ class PlaylistsController extends AbstractStationCrudController
$file_name = 'playlist_' . $record->getShortName().'.'.$format;
$response->getBody()->write($record->export($format));
return $response
->withHeader('Content-Type', $formats[$format])
->withHeader('Content-Disposition', 'attachment; filename=' . $file_name)
->write($record->export($format));
->withHeader('Content-Disposition', 'attachment; filename=' . $file_name);
}
public function toggleAction(Request $request, Response $response, $station_id, $id): ResponseInterface
public function toggleAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id): ResponseInterface
{
$record = $this->_getRecord($request->getStation(), $id);
$record = $this->_getRecord(RequestHelper::getStation($request), $id);
if (!$record instanceof Entity\StationPlaylist) {
throw new \App\Exception\NotFound(__('%s not found.', __('Playlist')));
@ -245,31 +251,33 @@ class PlaylistsController extends AbstractStationCrudController
? __('Playlist enabled.')
: __('Playlist disabled.');
$request->getSession()->flash('<b>' . $flash_message . '</b><br>' . $record->getName(), 'green');
RequestHelper::getSession($request)->flash('<b>' . $flash_message . '</b><br>' . $record->getName(), 'green');
return $response->withRedirect(
$request->getReferrer($request->getRouter()->fromHere('stations:playlists:index'))
$referrer = $request->getHeaderLine('HTTP_REFERER');
return ResponseHelper::withRedirect($response,
$referrer ?? RequestHelper::getRouter($request)->fromHere('stations:playlists:index')
);
}
public function editAction(Request $request, Response $response, $station_id, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id = null): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Playlist')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:playlists:index'));
RequestHelper::getSession($request)->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Playlist')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:playlists:index'));
}
return $request->getView()->renderToResponse($response, 'stations/playlists/edit', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/playlists/edit', [
'form' => $this->form,
'title' => sprintf(($id) ? __('Edit %s') : __('Add %s'), __('Playlist'))
]);
}
public function deleteAction(Request $request, Response $response, $station_id, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id, $csrf_token): ResponseInterface
{
$this->_doDelete($request, $id, $csrf_token);
$request->getSession()->flash('<b>' . __('%s deleted.', __('Playlist')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:playlists:index'));
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('Playlist')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:playlists:index'));
}
}

View File

@ -1,12 +1,13 @@
<?php
namespace App\Controller\Stations;
use App\Form\StationForm;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Form\StationForm;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ProfileController
{
@ -25,8 +26,6 @@ class ProfileController
/**
* @param EntityManager $em
* @param StationForm $station_form
*
* @see \App\Provider\StationsProvider
*/
public function __construct(
EntityManager $em,
@ -39,17 +38,17 @@ class ProfileController
$this->station_form = $station_form;
}
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$view = $request->getView();
$station = RequestHelper::getStation($request);
$view = RequestHelper::getView($request);
if (!$station->isEnabled()) {
return $view->renderToResponse($response, 'stations/profile/disabled');
}
$frontend = $request->getStationFrontend();
$remotes = $request->getStationRemotes();
$frontend = RequestHelper::getStationFrontend($request);
$remotes = RequestHelper::getStationRemotes($request);
$stream_urls = [
'local' => [],
@ -120,7 +119,7 @@ class ProfileController
$station_np = $station->getNowplaying();
if ($station_np instanceof Entity\Api\NowPlaying) {
$station_np->resolveUrls($request->getRouter()->getBaseUrl());
$station_np->resolveUrls(RequestHelper::getRouter($request)->getBaseUrl());
$np = array_intersect_key($station_np->toArray(), $np) + $np;
}
@ -133,31 +132,31 @@ class ProfileController
'frontend_type' => $station->getFrontendType(),
'frontend_config' => (array)$station->getFrontendConfig(),
'nowplaying' => $np,
'user' => $request->getUser(),
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'user' => RequestHelper::getUser($request),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
return $view->renderToResponse($response, 'stations/profile/index');
}
public function editAction(Request $request, Response $response, $station_id): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
if (false !== $this->station_form->process($request, $station)) {
return $response->withRedirect($request->getRouter()->fromHere('stations:profile:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:profile:index'));
}
return $request->getView()->renderToResponse($response, 'stations/profile/edit', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/profile/edit', [
'form' => $this->station_form,
]);
}
public function toggleAction(Request $request, Response $response, $station_id, $feature, $csrf_token): ResponseInterface
public function toggleAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $feature, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$station = $request->getStation();
$station = RequestHelper::getStation($request);
switch($feature) {
case 'requests':
@ -178,6 +177,6 @@ class ProfileController
$this->em->refresh($station);
return $response->withRedirect($request->getRouter()->fromHere('stations:profile:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:profile:index'));
}
}

View File

@ -1,14 +1,14 @@
<?php
namespace App\Controller\Stations;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class QueueController
{
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $request->getView()->renderToResponse($response, 'stations/queue/index');
return RequestHelper::getView($request)->renderToResponse($response, 'stations/queue/index');
}
}

View File

@ -3,56 +3,58 @@ namespace App\Controller\Stations;
use App\Entity\Station;
use App\Entity\StationRemote;
use App\Form\EntityForm;
use App\Http\Request;
use App\Http\Response;
use App\Form\EntityFormManager;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class RemotesController extends AbstractStationCrudController
{
/**
* @param EntityForm $form
*
* @see \App\Provider\StationsProvider
* @param EntityFormManager $formManager
* @param Config $config
*/
public function __construct(EntityForm $form)
public function __construct(EntityFormManager $formManager, Config $config)
{
$form = $formManager->getForm(StationRemote::class, $config->get('forms/remote'));
parent::__construct($form);
$this->csrf_namespace = 'stations_remotes';
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
return $request->getView()->renderToResponse($response, 'stations/remotes/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/remotes/index', [
'remotes' => $station->getRemotes(),
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function editAction(Request $request, Response $response, $station_id, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id = null): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Remote Relay')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:remotes:index'));
RequestHelper::getSession($request)->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Remote Relay')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:remotes:index'));
}
return $request->getView()->renderToResponse($response, 'stations/remotes/edit', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/remotes/edit', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => sprintf(($id) ? __('Edit %s') : __('Add %s'), __('Remote Relay'))
]);
}
public function deleteAction(Request $request, Response $response, $station_id, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id, $csrf_token): ResponseInterface
{
$this->_doDelete($request, $id, $csrf_token);
$request->getSession()->flash('<b>' . __('%s deleted.', __('Remote Relay')) . '</b>', 'green');
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('Remote Relay')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:remotes:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:remotes:index'));
}
protected function _getRecord(Station $station, $id = null): ?object

View File

@ -1,12 +1,13 @@
<?php
namespace App\Controller\Stations\Reports;
use App\Entity;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Radio\Filesystem;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class DuplicatesController
{
@ -19,8 +20,6 @@ class DuplicatesController
/**
* @param EntityManager $em
* @param Filesystem $filesystem
*
* @see \App\Provider\StationsProvider
*/
public function __construct(EntityManager $em, Filesystem $filesystem)
{
@ -28,7 +27,7 @@ class DuplicatesController
$this->filesystem = $filesystem;
}
public function __invoke(Request $request, Response $response, $station_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$media_raw = $this->em->createQuery(/** @lang DQL */ 'SELECT
sm, s, spm, sp
@ -78,14 +77,14 @@ class DuplicatesController
}
}
return $request->getView()->renderToResponse($response, 'stations/reports/duplicates', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/reports/duplicates', [
'dupes' => $dupes,
]);
}
public function deleteAction(Request $request, Response $response, $station_id, $media_id): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $media_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$fs = $this->filesystem->getForStation($station);
/** @var Entity\Repository\StationMediaRepository $media_repo */
@ -101,9 +100,9 @@ class DuplicatesController
$this->em->remove($media);
$this->em->flush();
$request->getSession()->flash('<b>Duplicate file deleted!</b>', 'green');
RequestHelper::getSession($request)->flash('<b>Duplicate file deleted!</b>', 'green');
}
return $response->withRedirect($request->getRouter()->named('stations:reports:duplicates', ['station' => $station_id]));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->named('stations:reports:duplicates', ['station' => $station_id]));
}
}

View File

@ -1,11 +1,11 @@
<?php
namespace App\Controller\Stations\Reports;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ListenersController
{
@ -14,16 +14,15 @@ class ListenersController
/**
* @param EntityManager $em
* @see \App\Provider\StationsProvider
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$view = $request->getView();
$view = RequestHelper::getView($request);
/** @var Entity\Repository\SettingsRepository $settings_repo */
$settings_repo = $this->em->getRepository(Entity\Settings::class);

View File

@ -1,13 +1,12 @@
<?php
namespace App\Controller\Stations\Reports;
use Azura\Cache;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use Doctrine\ORM\EntityManager;
use InfluxDB\Database;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class OverviewController
{
@ -20,7 +19,6 @@ class OverviewController
/**
* @param EntityManager $em
* @param Database $influx
* @see \App\Provider\StationsProvider
*/
public function __construct(EntityManager $em, Database $influx)
{
@ -28,9 +26,9 @@ class OverviewController
$this->influx = $influx;
}
public function __invoke(Request $request, Response $response, $station_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
// Get current analytics level.
@ -41,7 +39,7 @@ class OverviewController
if ($analytics_level === Entity\Analytics::LEVEL_NONE) {
// The entirety of the dashboard can't be shown, so redirect user to the profile page.
return $request->getView()->renderToResponse($response, 'stations/reports/restricted');
return RequestHelper::getView($request)->renderToResponse($response, 'stations/reports/restricted');
}
/* Statistics */
@ -251,7 +249,7 @@ class OverviewController
return ($a > $b) ? 1 : -1;
});
return $request->getView()->renderToResponse($response, 'stations/reports/overview', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/reports/overview', [
'charts' => [
'daily' => json_encode($daily_data),
'daily_alt' => implode('', $daily_alt),

View File

@ -1,11 +1,12 @@
<?php
namespace App\Controller\Stations\Reports;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Sync\Task\RadioAutomation;
use Doctrine\ORM\EntityManager;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class PerformanceController
{
@ -18,7 +19,6 @@ class PerformanceController
/**
* @param EntityManager $em
* @param RadioAutomation $sync_automation
* @see \App\Provider\StationsProvider
*/
public function __construct(EntityManager $em, RadioAutomation $sync_automation)
{
@ -26,9 +26,9 @@ class PerformanceController
$this->sync_automation = $sync_automation;
}
public function __invoke(Request $request, Response $response, $station_id, $format = 'html'): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id, $format = 'html'): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$automation_config = (array)$station->getAutomationSettings();
$threshold_days = (int)($automation_config['threshold_days'] ?? RadioAutomation::DEFAULT_THRESHOLD_DAYS);
@ -82,14 +82,14 @@ class PerformanceController
$csv_file = \Azura\Utilities\Csv::arrayToCsv($export_csv);
$csv_filename = $station->getShortName() . '_media_' . date('Ymd') . '.csv';
return $response->renderStringAsFile($csv_file, 'text/csv', $csv_filename);
return ResponseHelper::renderStringAsFile($response, $csv_file, 'text/csv', $csv_filename);
}
if ($format === 'json') {
return $response->withJson($report_data);
return ResponseHelper::withJson($response, $report_data);
}
return $request->getView()->renderToResponse($response, 'stations/reports/performance', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/reports/performance', [
'report_data' => $report_data,
]);
}

View File

@ -1,11 +1,12 @@
<?php
namespace App\Controller\Stations\Reports;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class RequestsController
{
@ -17,14 +18,13 @@ class RequestsController
/**
* @param EntityManager $em
* @see \App\Provider\StationsProvider
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function __invoke(Request $request, Response $response, $station_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$requests = $this->em->createQuery(/** @lang DQL */'SELECT
sr, sm, s
@ -36,15 +36,15 @@ class RequestsController
->setParameter('station_id', $station_id)
->getArrayResult();
return $request->getView()->renderToResponse($response, 'stations/reports/requests', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/reports/requests', [
'requests' => $requests,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function deleteAction(Request $request, Response $response, $station_id, $request_id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $request_id, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$media = $this->em->getRepository(Entity\StationRequest::class)->findOneBy([
'id' => $request_id,
@ -56,9 +56,9 @@ class RequestsController
$this->em->remove($media);
$this->em->flush();
$request->getSession()->flash('<b>Request deleted!</b>', 'green');
RequestHelper::getSession($request)->flash('<b>Request deleted!</b>', 'green');
}
return $response->withRedirect($request->getRouter()->fromHere('stations:reports:requests'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:reports:requests'));
}
}

View File

@ -1,13 +1,15 @@
<?php
namespace App\Controller\Stations\Reports;
use App\Form\Form;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Form\Form;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Doctrine\ORM\EntityManager;
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* Produce a report in SoundExchange (the US webcaster licensing agency) format.
@ -26,20 +28,18 @@ class SoundExchangeController
/**
* @param EntityManager $em
* @param Client $http_client
* @param array $form_config
*
* @see \App\Provider\StationsProvider
* @param Config $config
*/
public function __construct(EntityManager $em, Client $http_client, array $form_config)
public function __construct(EntityManager $em, Client $http_client, Config $config)
{
$this->em = $em;
$this->form_config = $form_config;
$this->form_config = $config->get('forms/report/soundexchange');
$this->http_client = $http_client;
}
public function __invoke(Request $request, Response $response, $station_id): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
$form = new Form($this->form_config);
$form->populate([
@ -166,10 +166,10 @@ class SoundExchangeController
. date('dmY', $start_date) . '-'
. date('dmY', $end_date).'_A.txt';
return $response->renderStringAsFile($export_txt, 'text/plain', $export_filename);
return ResponseHelper::renderStringAsFile($response, $export_txt, 'text/plain', $export_filename);
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $form,
'render_mode' => 'edit',
'title' => __('SoundExchange Report')

View File

@ -1,14 +1,14 @@
<?php
namespace App\Controller\Stations\Reports;
use App\Http\Request;
use App\Http\Response;
use App\Http\RequestHelper;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class TimelineController
{
public function __invoke(Request $request, Response $response): ResponseInterface
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $request->getView()->renderToResponse($response, 'stations/reports/timeline');
return RequestHelper::getView($request)->renderToResponse($response, 'stations/reports/timeline');
}
}

View File

@ -1,50 +1,50 @@
<?php
namespace App\Controller\Stations;
use App\Form\EntityForm;
use App\Radio\Backend\AbstractBackend;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Doctrine\ORM\EntityManager;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use App\Form\EntityFormManager;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use Azura\Config;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class StreamersController extends AbstractStationCrudController
{
/**
* @param EntityForm $form
*
* @see \App\Provider\StationsProvider
* @param EntityFormManager $formManager
* @param Config $config
*/
public function __construct(EntityForm $form)
public function __construct(EntityFormManager $formManager, Config $config)
{
$form = $formManager->getForm(Entity\StationStreamer::class, $config->get('forms/streamer'));
parent::__construct($form);
$this->csrf_namespace = 'stations_streamers';
}
public function indexAction(Request $request, Response $response, $station_id): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response, $station_id): ResponseInterface
{
$station = $request->getStation();
$backend = $request->getStationBackend();
$station = RequestHelper::getStation($request);
$backend = RequestHelper::getStationBackend($request);
if (!$backend::supportsStreamers()) {
throw new \App\Exception\StationUnsupported;
}
$view = $request->getView();
$view = RequestHelper::getView($request);
if (!$station->getEnableStreamers()) {
if ($request->hasParam('enable')) {
$params = $request->getQueryParams();
if (isset($params['enable'])) {
$station->setEnableStreamers(true);
$this->em->persist($station);
$this->em->flush();
$request->getSession()->flash('<b>' . __('Streamers enabled!') . '</b><br>' . __('You can now set up streamer (DJ) accounts.'),
RequestHelper::getSession($request)->flash('<b>' . __('Streamers enabled!') . '</b><br>' . __('You can now set up streamer (DJ) accounts.'),
'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:streamers:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:streamers:index'));
}
return $view->renderToResponse($response, 'stations/streamers/disabled');
@ -60,29 +60,29 @@ class StreamersController extends AbstractStationCrudController
'stream_port' => $backend->getStreamPort($station),
'streamers' => $station->getStreamers(),
'dj_mount_point' => $be_settings['dj_mount_point'] ?? '/',
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function editAction(Request $request, Response $response, $station_id, $id = null): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id = null): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Streamer')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:streamers:index'));
RequestHelper::getSession($request)->flash('<b>' . sprintf(($id) ? __('%s updated.') : __('%s added.'), __('Streamer')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:streamers:index'));
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => sprintf(($id) ? __('Edit %s') : __('Add %s'), __('Streamer'))
]);
}
public function deleteAction(Request $request, Response $response, $station_id, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id, $csrf_token): ResponseInterface
{
$this->_doDelete($request, $id, $csrf_token);
$request->getSession()->flash('<b>' . __('%s deleted.', __('Streamer')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:streamers:index'));
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('Streamer')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:streamers:index'));
}
}

View File

@ -1,20 +1,15 @@
<?php
namespace App\Controller\Stations;
use App\Entity;
use App\Form\EntityForm;
use App\Form\StationWebhookForm;
use App\Provider\StationsProvider;
use App\Http\RequestHelper;
use App\Http\ResponseHelper;
use App\Webhook\Dispatcher;
use App\Entity;
use App\Http\Request;
use App\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* Class WebhooksController
* @package App\Controller\Stations
* @see StationsProvider
*/
class WebhooksController extends AbstractStationCrudController
{
/** @var Dispatcher */
@ -24,13 +19,11 @@ class WebhooksController extends AbstractStationCrudController
protected $webhook_config;
/**
* @param EntityForm $form
* @param StationWebhookForm $form
* @param Dispatcher $dispatcher
*
* @see \App\Provider\StationsProvider
*/
public function __construct(
EntityForm $form,
StationWebhookForm $form,
Dispatcher $dispatcher
) {
parent::__construct($form);
@ -43,20 +36,20 @@ class WebhooksController extends AbstractStationCrudController
$this->dispatcher = $dispatcher;
}
public function indexAction(Request $request, Response $response): ResponseInterface
public function indexAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$station = $request->getStation();
$station = RequestHelper::getStation($request);
return $request->getView()->renderToResponse($response, 'stations/webhooks/index', [
return RequestHelper::getView($request)->renderToResponse($response, 'stations/webhooks/index', [
'webhooks' => $station->getWebhooks(),
'webhook_config' => $this->webhook_config,
'csrf' => $request->getSession()->getCsrf()->generate($this->csrf_namespace),
'csrf' => RequestHelper::getSession($request)->getCsrf()->generate($this->csrf_namespace),
]);
}
public function addAction(Request $request, Response $response, $station_id, $type = null): ResponseInterface
public function addAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $type = null): ResponseInterface
{
$view = $request->getView();
$view = RequestHelper::getView($request);
if ($type === null) {
return $view->renderToResponse($response, 'stations/webhooks/add', [
'connectors' => array_filter($this->webhook_config['webhooks'], function($webhook) {
@ -65,11 +58,11 @@ class WebhooksController extends AbstractStationCrudController
]);
}
$record = new Entity\StationWebhook($request->getStation(), $type);
$record = new Entity\StationWebhook(RequestHelper::getStation($request), $type);
if (false !== $this->form->process($request, $record)) {
$request->getSession()->flash('<b>' . __('%s added.', __('Web Hook')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:webhooks:index'));
RequestHelper::getSession($request)->flash('<b>' . __('%s added.', __('Web Hook')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:webhooks:index'));
}
return $view->renderToResponse($response, 'system/form_page', [
@ -79,41 +72,41 @@ class WebhooksController extends AbstractStationCrudController
]);
}
public function editAction(Request $request, Response $response, $station_id, $id): ResponseInterface
public function editAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id): ResponseInterface
{
if (false !== $this->_doEdit($request, $id)) {
$request->getSession()->flash('<b>' . __('%s updated.', __('Web Hook')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:webhooks:index'));
RequestHelper::getSession($request)->flash('<b>' . __('%s updated.', __('Web Hook')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:webhooks:index'));
}
return $request->getView()->renderToResponse($response, 'system/form_page', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/form_page', [
'form' => $this->form,
'render_mode' => 'edit',
'title' => __('Edit %s', __('Web Hook'))
]);
}
public function toggleAction(Request $request, Response $response, $station_id, $id, $csrf_token): ResponseInterface
public function toggleAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
/** @var Entity\StationWebhook $record */
$record = $this->_getRecord($request->getStation(), $id);
$record = $this->_getRecord(RequestHelper::getStation($request), $id);
$new_status = $record->toggleEnabled();
$this->em->persist($record);
$this->em->flush();
$request->getSession()->flash('<b>' . sprintf(($new_status) ? __('%s enabled.') : __('%s disabled.'), __('Web Hook')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:webhooks:index'));
RequestHelper::getSession($request)->flash('<b>' . sprintf(($new_status) ? __('%s enabled.') : __('%s disabled.'), __('Web Hook')) . '</b>', 'green');
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:webhooks:index'));
}
public function testAction(Request $request, Response $response, $station_id, $id, $csrf_token): ResponseInterface
public function testAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id, $csrf_token): ResponseInterface
{
$request->getSession()->getCsrf()->verify($csrf_token, $this->csrf_namespace);
RequestHelper::getSession($request)->getCsrf()->verify($csrf_token, $this->csrf_namespace);
$station = $request->getStation();
$station = RequestHelper::getStation($request);
/** @var Entity\StationWebhook $record */
$record = $this->_getRecord($station, $id);
@ -121,18 +114,18 @@ class WebhooksController extends AbstractStationCrudController
$handler_response = $this->dispatcher->testDispatch($station, $record);
$log_records = $handler_response->getRecords();
return $request->getView()->renderToResponse($response, 'system/log_view', [
return RequestHelper::getView($request)->renderToResponse($response, 'system/log_view', [
'title' => __('Web Hook Test Output'),
'log_records' => $log_records,
]);
}
public function deleteAction(Request $request, Response $response, $station_id, $id, $csrf_token): ResponseInterface
public function deleteAction(ServerRequestInterface $request, ResponseInterface $response, $station_id, $id, $csrf_token): ResponseInterface
{
$this->_doDelete($request, $id, $csrf_token);
$request->getSession()->flash('<b>' . __('%s deleted.', __('Web Hook')) . '</b>', 'green');
RequestHelper::getSession($request)->flash('<b>' . __('%s deleted.', __('Web Hook')) . '</b>', 'green');
return $response->withRedirect($request->getRouter()->fromHere('stations:webhooks:index'));
return ResponseHelper::withRedirect($response, RequestHelper::getRouter($request)->fromHere('stations:webhooks:index'));
}
}

View File

@ -1,73 +0,0 @@
<?php
namespace App\Controller\Traits;
use App\Exception\Validation;
use App\Http\Response;
use Azura\Http\Request;
use AzuraForms\Field\AbstractField;
use AzuraForms\Form;
use FastRoute\Dispatcher;
use Symfony\Component\Validator\ConstraintViolation;
trait ApiProxyTrait
{
public function handleFormSubmission(Form $form, Request $request, $route_name, $route_method = 'GET', $router_args = []): bool
{
if ($request->isPost() && $form->isValid($request->getParsedBody())) {
try {
$resp = $this->proxyRequest($request, $route_name, $route_method, $router_args);
return true;
} catch(Validation $e) {
foreach($e->getDetailedErrors() as $error) {
/** @var ConstraintViolation $error */
$field_name = $error->getPropertyPath();
if ($form->hasField($field_name)) {
/** @var AbstractField $field */
$field = $form->getField($field_name);
$field->addError($error->getMessage());
}
}
}
}
return false;
}
/**
* @param Request $request
* @param $route_name
* @param string $route_method
* @param array $router_args
* @return array|null
* @throws \Azura\Exception
*/
public function proxyRequest(Request $request, $route_name, $route_method = 'GET', $router_args = []): ?array
{
$router = $request->getRouter();
$route_uri = $router->named($route_name, $router_args);
$request = $request
->withUri($route_uri)
->withMethod($route_method)
->withHeader('Accept', 'application/json');
$route_info = $router->dispatch($request);
if ($route_info[0] !== Dispatcher::FOUND) {
throw new \App\Exception('Dispatcher error: route not found.');
}
$route = $router->lookupRoute($route_info[1]);
$response = $route->run($request, new Response);
if (200 === $response->getStatusCode()) {
$body_contents = (string)$response->getBody();
return json_decode($body_contents, true);
}
return null;
}
}

View File

@ -1,18 +1,17 @@
<?php
namespace App\Controller\Traits;
use App\Http\Request;
use App\Http\Response;
use App\Entity;
use App\Http\ResponseHelper;
use App\Radio\Adapters;
use Azura\Exception;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
trait LogViewerTrait
{
static $maximum_log_size = 1048576;
protected function _view(Request $request, Response $response, $log_path, $tail_file = true): ResponseInterface
protected function _view(ServerRequestInterface $request, ResponseInterface $response, $log_path, $tail_file = true): ResponseInterface
{
clearstatcache();
@ -24,13 +23,14 @@ trait LogViewerTrait
$log_contents_parts = explode("\n", file_get_contents($log_path));
$log_contents_parts = str_replace(array(">", "<"), array("&gt;", "&lt;"), $log_contents_parts);
return $response->withJson([
return ResponseHelper::withJson($response, [
'contents' => implode("\n", $log_contents_parts),
'eof' => true,
]);
}
$last_viewed_size = (int)$request->getParam('position', 0);
$params = $request->getQueryParams();
$last_viewed_size = (int)($params['position'] ?? 0);
$log_size = filesize($log_path);
if ($last_viewed_size > $log_size) {
@ -66,7 +66,7 @@ trait LogViewerTrait
fclose($fp);
}
return $response->withJson([
return ResponseHelper::withJson($response, [
'contents' => $log_contents,
'position' => $log_size,
'eof' => false,

View File

@ -1,12 +1,13 @@
<?php
namespace App;
use App\Entity;
use App\Service\NChan;
use Azura\Settings;
use App\Entity;
use App\Http\Request;
use Doctrine\ORM\EntityManager;
use Gettext\Translator;
use GuzzleHttp\Psr7\Uri;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\UriInterface;
class Customization
@ -24,8 +25,11 @@ class Customization
/** @var Entity\Repository\SettingsRepository */
protected $settings_repo;
public function __construct(Settings $app_settings, Entity\Repository\SettingsRepository $settings_repo)
public function __construct(Settings $app_settings, EntityManager $em)
{
/** @var Entity\Repository\SettingsRepository $settings_repo */
$settings_repo = $em->getRepository(Entity\Settings::class);
$this->app_settings = $app_settings;
$this->settings_repo = $settings_repo;
}

View File

@ -2,7 +2,6 @@
namespace App\Entity\Api\Admin;
use App\Entity;
use Azura\Http\Router;
use OpenApi\Annotations as OA;
use Psr\Http\Message\UriInterface;

Some files were not shown because too many files have changed in this diff Show More