WIP: rewrite to feat NC 30 #2
3
.gitignore
vendored
3
.gitignore
vendored
@ -18,3 +18,6 @@ js/
|
||||
build/
|
||||
coverage/
|
||||
utils/docker-ci
|
||||
|
||||
vendor/
|
||||
.php-cs-fixer.cache
|
||||
|
31
.php-cs-fixer.dist.php
Normal file
31
.php-cs-fixer.dist.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once './vendor/autoload.php';
|
||||
|
||||
use Nextcloud\CodingStandard\Config;
|
||||
|
||||
class MyConfig extends Config
|
||||
{
|
||||
public function getRules(): array
|
||||
{
|
||||
$rules = parent::getRules();
|
||||
$rules['@PhpCsFixer'] = true;
|
||||
$rules['curly_braces_position']['classes_opening_brace'] = 'next_line_unless_newline_at_signature_end';
|
||||
$rules['phpdoc_to_comment'] = false;
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
||||
$config = new MyConfig();
|
||||
$config
|
||||
->getFinder()
|
||||
->notPath('build')
|
||||
->notPath('l10n')
|
||||
->notPath('node_modules')
|
||||
->notPath('src')
|
||||
->notPath('vendor')
|
||||
->in(__DIR__);
|
||||
|
||||
return $config;
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,74 +20,71 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
return [
|
||||
'resources' => [
|
||||
'favorite' => ['url' => '/api/favorites'],
|
||||
'recent' => ['url' => '/api/recent'],
|
||||
'export' => ['url' => '/export'],
|
||||
'station' => ['url' => '/station'],
|
||||
],
|
||||
'routes' => [
|
||||
'resources' => [
|
||||
'favorite' => ['url' => '/api/favorites'],
|
||||
'recent' => ['url' => '/api/recent'],
|
||||
'export' => ['url' => '/export'],
|
||||
'station' => ['url' => '/station'],
|
||||
],
|
||||
'routes' => [
|
||||
// Web page templates
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/',
|
||||
'verb' => 'GET',
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/top',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'top',
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/recent',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'recent',
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/new',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'new',
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/favorites',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'favorites',
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/categories',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'categories',
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/search',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'search',
|
||||
],
|
||||
|
||||
// Web page templates
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/',
|
||||
'verb' => 'GET'
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/top',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'top'
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/recent',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'recent'
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/new',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'new'
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/favorites',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'favorites'
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/categories',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'categories'
|
||||
],
|
||||
[
|
||||
'name' => 'page#index',
|
||||
'url' => '/search',
|
||||
'verb' => 'GET',
|
||||
'postfix' => 'search',
|
||||
],
|
||||
|
||||
// Api
|
||||
[
|
||||
'name' => 'favorite_api#preflighted_cors',
|
||||
'url' => '/api/0.1/{path}',
|
||||
'verb' => 'OPTIONS',
|
||||
'requirements' => ['path' => '.+']
|
||||
],
|
||||
[
|
||||
'name' => 'recent_api#preflighted_cors',
|
||||
'url' => '/api/0.1/{path}',
|
||||
'verb' => 'OPTIONS',
|
||||
'requirements' => ['path' => '.+']
|
||||
]
|
||||
|
||||
]
|
||||
// Api
|
||||
[
|
||||
'name' => 'favorite_api#preflighted_cors',
|
||||
'url' => '/api/0.1/{path}',
|
||||
'verb' => 'OPTIONS',
|
||||
'requirements' => ['path' => '.+'],
|
||||
],
|
||||
[
|
||||
'name' => 'recent_api#preflighted_cors',
|
||||
'url' => '/api/0.1/{path}',
|
||||
'verb' => 'OPTIONS',
|
||||
'requirements' => ['path' => '.+'],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@ -2,11 +2,35 @@
|
||||
"name": "onny/radio",
|
||||
"description": "Lint config for onny/radio",
|
||||
"license": "AGPL",
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"classmap-authoritative": true
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OCA\\Radio\\": "lib/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "find . -name \\*.php -not -path './vendor/*' -exec php -l \"{}\" \\;"
|
||||
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './vendor-bin/*' -not -path './build/*' -print0 | xargs -0 -n1 php -l",
|
||||
"cs:check": "php-cs-fixer fix --dry-run --diff",
|
||||
"cs:fix": "php-cs-fixer fix",
|
||||
"psalm": "psalm --threads=1 --no-cache --show-info=true",
|
||||
"rector": "rector && composer cs:fix"
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"nextcloud/ocp": "^30.0.2",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"nextcloud/coding-standard": "^1.3.2",
|
||||
"nextcloud/rector": "^0.2.1",
|
||||
"rector/rector": "^1.2.10",
|
||||
"vimeo/psalm": "^5.26.1",
|
||||
"doctrine/dbal": "^4.2.1"
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"classmap-authoritative": true,
|
||||
"platform": {
|
||||
"php": "8.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3567
composer.lock
generated
Normal file
3567
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,25 +18,23 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\Radio\AppInfo;
|
||||
|
||||
use OC\Security\CSP\ContentSecurityPolicy;
|
||||
use OCA\Radio\Dashboard\RadioWidget;
|
||||
use OCA\Radio\Search\SearchProvider;
|
||||
use OCP\AppFramework\App;
|
||||
use OCP\AppFramework\Bootstrap\IBootContext;
|
||||
use OCP\AppFramework\Bootstrap\IBootstrap;
|
||||
use OCP\AppFramework\Bootstrap\IRegistrationContext;
|
||||
use OCP\IRequest;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
use OCA\Radio\Dashboard\RadioWidget;
|
||||
|
||||
class Application extends App implements IBootstrap {
|
||||
|
||||
class Application extends App implements IBootstrap
|
||||
{
|
||||
public const APP_ID = 'radio';
|
||||
|
||||
public function __construct() {
|
||||
@ -44,32 +42,11 @@ class Application extends App implements IBootstrap {
|
||||
}
|
||||
|
||||
public function register(IRegistrationContext $context): void {
|
||||
|
||||
$context->registerSearchProvider(SearchProvider::class);
|
||||
$context->registerDashboardWidget(RadioWidget::class);
|
||||
|
||||
$context->registerService('request', static function ($c) {
|
||||
return $c->get(IRequest::class);
|
||||
});
|
||||
|
||||
$this->registerCsp();
|
||||
|
||||
$context->registerService('request', static fn (ContainerInterface $c): mixed => $c->get(IRequest::class));
|
||||
}
|
||||
|
||||
public function boot(IBootContext $context): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow radio-browser hosts in the csp
|
||||
*
|
||||
* @throws \OCP\AppFramework\QueryException
|
||||
*/
|
||||
public function registerCsp() {
|
||||
$manager = $this->getContainer()->getServer()->getContentSecurityPolicyManager();
|
||||
$policy = new ContentSecurityPolicy();
|
||||
$policy->addAllowedConnectDomain('https://de1.api.radio-browser.info');
|
||||
$policy->addAllowedImageDomain('*');
|
||||
$policy->addAllowedMediaDomain('*');
|
||||
$manager->addDefaultPolicy($policy);
|
||||
}
|
||||
public function boot(IBootContext $context): void {}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,24 +20,23 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Controller;
|
||||
|
||||
use Closure;
|
||||
|
||||
use OCA\Radio\Service\StationNotFound;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
|
||||
use OCA\Radio\Service\StationNotFound;
|
||||
|
||||
trait Errors {
|
||||
protected function handleNotFound(Closure $callback): DataResponse {
|
||||
trait Errors
|
||||
{
|
||||
protected function handleNotFound(\Closure $callback): DataResponse {
|
||||
try {
|
||||
/** @psalm-suppress MixedArgument */
|
||||
return new DataResponse($callback());
|
||||
} catch (StationNotFound $e) {
|
||||
$message = ['message' => $e->getMessage()];
|
||||
} catch (StationNotFound $stationNotFound) {
|
||||
$message = ['message' => $stationNotFound->getMessage()];
|
||||
|
||||
return new DataResponse($message, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,60 +20,70 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Controller;
|
||||
|
||||
use OC;
|
||||
use OCA\Radio\ExportResponse;
|
||||
use OCA\Radio\AppInfo\Application;
|
||||
use OCA\Radio\Service\FavoriteService;
|
||||
use OCA\Radio\Service\UserService;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\DataDownloadResponse;
|
||||
use OCP\Defaults;
|
||||
use OCP\HintException;
|
||||
use OCP\IDateTimeFormatter;
|
||||
use OCP\IRequest;
|
||||
use SimpleXMLElement;
|
||||
use DOMDocument;
|
||||
|
||||
class ExportController extends Controller {
|
||||
/** @var FavoriteService */
|
||||
private $service;
|
||||
|
||||
/** @var string */
|
||||
private $userId;
|
||||
|
||||
class ExportController extends Controller
|
||||
{
|
||||
use Errors;
|
||||
|
||||
public function __construct(IRequest $request,
|
||||
FavoriteService $service,
|
||||
$userId) {
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
private readonly FavoriteService $service,
|
||||
private readonly UserService $user,
|
||||
private readonly Defaults $defaults,
|
||||
private readonly IDateTimeFormatter $dateTime,
|
||||
) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
$this->service = $service;
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function index() {
|
||||
|
||||
$xml = new SimpleXMLElement('<?xml version="1.0"?><playlist></playlist>');
|
||||
$xml->addAttribute('encoding', 'UTF-8');
|
||||
$trackList = $xml->addChild('trackList');
|
||||
foreach($this->service->findAll($this->userId) as $station) {
|
||||
$track = $trackList->addChild('track');
|
||||
$track->addChild('location', $station->getUrlresolved());
|
||||
$track->addChild('title', $station->getName());
|
||||
$track->addChild('image', $station->getFavicon());
|
||||
#[NoAdminRequired]
|
||||
public function index(): DataDownloadResponse {
|
||||
$user = $this->user->getUser();
|
||||
if (is_null($user)) {
|
||||
throw new HintException('User not logged in');
|
||||
}
|
||||
|
||||
$dom = new DOMDocument("1.0");
|
||||
$xml = new \SimpleXMLElement('<?xml version="1.0"?><playlist></playlist>');
|
||||
$xml->addAttribute('encoding', 'UTF-8');
|
||||
|
||||
$trackList = $xml->addChild('trackList');
|
||||
if ($trackList instanceof \SimpleXMLElement) {
|
||||
foreach ($this->service->findAll($user->getUID()) as $station) {
|
||||
$track = $trackList->addChild('track');
|
||||
if ($track instanceof \SimpleXMLElement) {
|
||||
$track->addChild('location', $station->getUrlresolved());
|
||||
$track->addChild('title', $station->getName());
|
||||
$track->addChild('image', $station->getFavicon());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dom = new \DOMDocument('1.0');
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
|
||||
/** @psalm-suppress ArgumentTypeCoercion */
|
||||
$dom->loadXML($xml->asXML());
|
||||
$returnstring = $dom->saveXML();
|
||||
|
||||
return new ExportResponse($dom->saveXML());
|
||||
$userName = $user->getDisplayName();
|
||||
$productName = $this->defaults->getName();
|
||||
$date = $this->dateTime->formatDate(time());
|
||||
$export_name = sprintf('%s Radio Favorites (%s) (%s).xspf', $productName, $userName, $date);
|
||||
|
||||
return new DataDownloadResponse($returnstring, $export_name, 'application/xspf+xml');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,83 +20,101 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Controller;
|
||||
|
||||
use OCA\Radio\AppInfo\Application;
|
||||
use OCA\Radio\Db\Station;
|
||||
use OCA\Radio\Service\FavoriteService;
|
||||
use OCA\Radio\Service\UserService;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IRequest;
|
||||
|
||||
class FavoriteController extends Controller {
|
||||
/** @var FavoriteService */
|
||||
private $service;
|
||||
|
||||
/** @var string */
|
||||
private $userId;
|
||||
|
||||
class FavoriteController extends Controller
|
||||
{
|
||||
use Errors;
|
||||
|
||||
public function __construct(IRequest $request,
|
||||
FavoriteService $service,
|
||||
$userId) {
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
private readonly FavoriteService $service,
|
||||
private readonly UserService $user,
|
||||
) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
$this->service = $service;
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function index(): DataResponse {
|
||||
return new DataResponse($this->service->findAll($this->userId));
|
||||
return new DataResponse($this->service->findAll($this->user->getUserUID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function show(int $id): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id) {
|
||||
return $this->service->find($id, $this->userId);
|
||||
});
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->find($id, $this->user->getUserUID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function create(string $stationuuid, string $name, string $favicon, string $urlresolved,
|
||||
string $bitrate, string $country, string $language, string $homepage,
|
||||
string $codec, string $tags): DataResponse {
|
||||
return new DataResponse($this->service->create($stationuuid, $name,
|
||||
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags, $this->userId));
|
||||
}
|
||||
#[NoAdminRequired]
|
||||
public function create(
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
string $favicon,
|
||||
string $urlresolved,
|
||||
string $bitrate,
|
||||
string $country,
|
||||
string $language,
|
||||
string $homepage,
|
||||
string $codec,
|
||||
string $tags
|
||||
): DataResponse {
|
||||
return new DataResponse($this->service->create(
|
||||
$stationuuid,
|
||||
$name,
|
||||
$favicon,
|
||||
$urlresolved,
|
||||
$bitrate,
|
||||
$country,
|
||||
$language,
|
||||
$homepage,
|
||||
$codec,
|
||||
$tags,
|
||||
$this->user->getUserUID()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function update(int $id, string $stationuuid,
|
||||
string $name, string $favicon, string $urlresolved,
|
||||
string $bitrate, string $country, string $language, string $homepage,
|
||||
string $codec, string $tags): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id, $stationuuid, $name,
|
||||
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags) {
|
||||
return $this->service->update($id, $stationuuid, $name, $favicon,
|
||||
$urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags, $this->userId);
|
||||
});
|
||||
}
|
||||
#[NoAdminRequired]
|
||||
public function update(
|
||||
int $id,
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
string $favicon,
|
||||
string $urlresolved,
|
||||
string $bitrate,
|
||||
string $country,
|
||||
string $language,
|
||||
string $homepage,
|
||||
string $codec,
|
||||
string $tags
|
||||
): DataResponse {
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->update(
|
||||
$id,
|
||||
$stationuuid,
|
||||
$name,
|
||||
$favicon,
|
||||
$urlresolved,
|
||||
$bitrate,
|
||||
$country,
|
||||
$language,
|
||||
$homepage,
|
||||
$codec,
|
||||
$tags,
|
||||
$this->user->getUserUID()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function destroy(int $id): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id) {
|
||||
return $this->service->delete($id, $this->userId);
|
||||
});
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->delete($id, $this->user->getUserUID()));
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,36 +18,42 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\Radio\Controller;
|
||||
|
||||
use OCP\IRequest;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCA\Radio\AppInfo\Application;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
|
||||
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\IRequest;
|
||||
use OCP\Util;
|
||||
|
||||
class PageController extends Controller {
|
||||
|
||||
protected $appName;
|
||||
|
||||
public function __construct($appName, IRequest $request) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->appName = $appName;
|
||||
class PageController extends Controller
|
||||
{
|
||||
public function __construct(IRequest $request) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
*/
|
||||
public function index() {
|
||||
Util::addScript($this->appName, 'radio-main');
|
||||
Util::addStyle($this->appName, 'icons');
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
public function index(): TemplateResponse {
|
||||
Util::addScript(Application::APP_ID, 'radio-main');
|
||||
Util::addStyle(Application::APP_ID, 'icons');
|
||||
|
||||
// Allow radio-browser hosts in the csp
|
||||
$policy = new ContentSecurityPolicy();
|
||||
$policy->addAllowedConnectDomain('https://de1.api.radio-browser.info');
|
||||
$policy->addAllowedImageDomain('*');
|
||||
$policy->addAllowedMediaDomain('*');
|
||||
|
||||
$response = new TemplateResponse(Application::APP_ID, 'main');
|
||||
$response->setContentSecurityPolicy($policy);
|
||||
|
||||
$response = new TemplateResponse($this->appName, 'main');
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,82 +20,101 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Controller;
|
||||
|
||||
use OCA\Radio\AppInfo\Application;
|
||||
use OCA\Radio\Db\Station;
|
||||
use OCA\Radio\Service\RecentService;
|
||||
use OCA\Radio\Service\UserService;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IRequest;
|
||||
|
||||
class RecentController extends Controller {
|
||||
/** @var RecentService */
|
||||
private $service;
|
||||
|
||||
/** @var string */
|
||||
private $userId;
|
||||
|
||||
class RecentController extends Controller
|
||||
{
|
||||
use Errors;
|
||||
|
||||
public function __construct(IRequest $request,
|
||||
RecentService $service,
|
||||
$userId) {
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
private readonly RecentService $service,
|
||||
private readonly UserService $user,
|
||||
) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
$this->service = $service;
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function index(): DataResponse {
|
||||
return new DataResponse($this->service->findAll($this->userId));
|
||||
return new DataResponse($this->service->findAll($this->user->getUserUID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function show(int $id): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id) {
|
||||
return $this->service->find($id, $this->userId);
|
||||
});
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->find($id, $this->user->getUserUID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function create(string $stationuuid, string $name, string $favicon, string $urlresolved,
|
||||
string $bitrate, string $country, string $language, string $homepage,
|
||||
string $codec, string $tags): DataResponse {
|
||||
return new DataResponse($this->service->create($stationuuid, $name,
|
||||
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags, $this->userId));
|
||||
#[NoAdminRequired]
|
||||
public function create(
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
string $favicon,
|
||||
string $urlresolved,
|
||||
string $bitrate,
|
||||
string $country,
|
||||
string $language,
|
||||
string $homepage,
|
||||
string $codec,
|
||||
string $tags
|
||||
): DataResponse {
|
||||
return new DataResponse($this->service->create(
|
||||
$stationuuid,
|
||||
$name,
|
||||
$favicon,
|
||||
$urlresolved,
|
||||
$bitrate,
|
||||
$country,
|
||||
$language,
|
||||
$homepage,
|
||||
$codec,
|
||||
$tags,
|
||||
$this->user->getUserUID()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function update(int $id, string $stationuuid, string $name,
|
||||
string $favicon, string $urlresolved, string $bitrate, string $country,
|
||||
string $language, string $homepage, string $codec, string $tags): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id, $stationuuid, $name,
|
||||
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags) {
|
||||
return $this->service->update($id, $stationuuid, $name, $favicon,
|
||||
$urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags, $this->userId);
|
||||
});
|
||||
#[NoAdminRequired]
|
||||
public function update(
|
||||
int $id,
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
string $favicon,
|
||||
string $urlresolved,
|
||||
string $bitrate,
|
||||
string $country,
|
||||
string $language,
|
||||
string $homepage,
|
||||
string $codec,
|
||||
string $tags
|
||||
): DataResponse {
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->update(
|
||||
$id,
|
||||
$stationuuid,
|
||||
$name,
|
||||
$favicon,
|
||||
$urlresolved,
|
||||
$bitrate,
|
||||
$country,
|
||||
$language,
|
||||
$homepage,
|
||||
$codec,
|
||||
$tags,
|
||||
$this->user->getUserUID()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function destroy(int $id): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id) {
|
||||
return $this->service->delete($id, $this->userId);
|
||||
});
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->delete($id, $this->user->getUserUID()));
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,87 +20,103 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Controller;
|
||||
|
||||
use OCA\Radio\AppInfo\Application;
|
||||
use OCA\Radio\Db\Station;
|
||||
use OCA\Radio\Service\RadioBrowserApiService;
|
||||
use OCA\Radio\Service\RecentService;
|
||||
use OCA\Radio\Service\UserService;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IRequest;
|
||||
|
||||
class StationController extends Controller {
|
||||
/** @var StationController */
|
||||
private $service;
|
||||
|
||||
/** @var RadioBrowserApiService */
|
||||
private $radiobrowserapi;
|
||||
|
||||
/** @var string */
|
||||
private $userId;
|
||||
|
||||
class StationController extends Controller
|
||||
{
|
||||
use Errors;
|
||||
|
||||
public function __construct(IRequest $request,
|
||||
RecentService $service,
|
||||
RadioBrowserApiService $radiobrowserapi,
|
||||
$userId) {
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
private readonly RecentService $service,
|
||||
private readonly RadioBrowserApiService $radiobrowserapi,
|
||||
private readonly UserService $user,
|
||||
) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
$this->service = $service;
|
||||
$this->radiobrowserapi = $radiobrowserapi;
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function index(): DataResponse {
|
||||
return new DataResponse($this->service->findAll($this->userId));
|
||||
return new DataResponse($this->service->findAll($this->user->getUserUID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function show(int $id): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id) {
|
||||
return $this->service->find($id, $this->userId);
|
||||
});
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->find($id, $this->user->getUserUID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function create(string $stationuuid, string $name, string $favicon, string $urlresolved,
|
||||
string $bitrate, string $country, string $language, string $homepage,
|
||||
string $codec, string $tags): DataResponse {
|
||||
return new DataResponse($this->service->create($stationuuid, $name,
|
||||
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags, $this->userId));
|
||||
#[NoAdminRequired]
|
||||
public function create(
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
string $favicon,
|
||||
string $urlresolved,
|
||||
string $bitrate,
|
||||
string $country,
|
||||
string $language,
|
||||
string $homepage,
|
||||
string $codec,
|
||||
string $tags
|
||||
): DataResponse {
|
||||
return new DataResponse($this->service->create(
|
||||
$stationuuid,
|
||||
$name,
|
||||
$favicon,
|
||||
$urlresolved,
|
||||
$bitrate,
|
||||
$country,
|
||||
$language,
|
||||
$homepage,
|
||||
$codec,
|
||||
$tags,
|
||||
$this->user->getUserUID()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function update(int $id, string $stationuuid, string $name,
|
||||
string $favicon, string $urlresolved, string $bitrate, string $country,
|
||||
string $language, string $homepage, string $codec, string $tags): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id, $stationuuid, $name,
|
||||
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags) {
|
||||
return $this->service->update($id, $stationuuid, $name, $favicon,
|
||||
$urlresolved, $bitrate, $country, $language, $homepage, $codec,
|
||||
$tags, $this->userId);
|
||||
});
|
||||
#[NoAdminRequired]
|
||||
public function update(
|
||||
int $id,
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
string $favicon,
|
||||
string $urlresolved,
|
||||
string $bitrate,
|
||||
string $country,
|
||||
string $language,
|
||||
string $homepage,
|
||||
string $codec,
|
||||
string $tags
|
||||
): DataResponse {
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->update(
|
||||
$id,
|
||||
$stationuuid,
|
||||
$name,
|
||||
$favicon,
|
||||
$urlresolved,
|
||||
$bitrate,
|
||||
$country,
|
||||
$language,
|
||||
$homepage,
|
||||
$codec,
|
||||
$tags,
|
||||
$this->user->getUserUID()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function destroy(int $id): DataResponse {
|
||||
return $this->handleNotFound(function () use ($id) {
|
||||
return $this->service->delete($id, $this->userId);
|
||||
});
|
||||
return $this->handleNotFound(fn (): ?Station => $this->service->delete($id, $this->user->getUserUID()));
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,74 +20,45 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Dashboard;
|
||||
|
||||
use OCA\Radio\AppInfo\Application;
|
||||
use OCP\Dashboard\IWidget;
|
||||
use OCP\IL10N;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\Util;
|
||||
|
||||
use OCA\Radio\AppInfo\Application;
|
||||
|
||||
class RadioWidget implements IWidget {
|
||||
|
||||
/** @var IL10N */
|
||||
private $l10n;
|
||||
|
||||
/** @var IURLGenerator */
|
||||
private $urlGenerator;
|
||||
|
||||
class RadioWidget implements IWidget
|
||||
{
|
||||
public function __construct(
|
||||
IL10N $l10n,
|
||||
IURLGenerator $urlGenerator
|
||||
) {
|
||||
$this->l10n = $l10n;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
private readonly IL10N $l10n,
|
||||
private readonly IURLGenerator $urlGenerator
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getId(): string {
|
||||
return Application::APP_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getTitle(): string {
|
||||
return $this->l10n->t('Radio stations');
|
||||
}
|
||||
return $this->l10n->t('Radio stations');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getIconClass(): string {
|
||||
return 'icon-radio';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getUrl(): ?string {
|
||||
return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('radio.page.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function load(): void {
|
||||
Util::addScript(Application::APP_ID, 'radio-dashboard');
|
||||
Util::addStyle(Application::APP_ID, 'dashboard');
|
||||
Util::addScript(Application::APP_ID, 'radio-dashboard');
|
||||
Util::addStyle(Application::APP_ID, 'dashboard');
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,49 +20,50 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Db;
|
||||
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
class FavoriteMapper extends QBMapper {
|
||||
/**
|
||||
* @extends QBMapper<Station>
|
||||
*/
|
||||
class FavoriteMapper extends QBMapper
|
||||
{
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'favorites', Station::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $userId
|
||||
* @return Entity|Station
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
||||
* @throws MultipleObjectsReturnedException
|
||||
* @throws DoesNotExistException
|
||||
*/
|
||||
public function find(int $id, string $userId): Station {
|
||||
/* @var $qb IQueryBuilder */
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('*')
|
||||
->from('favorites')
|
||||
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
|
||||
->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)))
|
||||
;
|
||||
|
||||
return $this->findEntity($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
* @return array
|
||||
* @return Station[]
|
||||
*/
|
||||
public function findAll(string $userId): array {
|
||||
/* @var $qb IQueryBuilder */
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('*')
|
||||
->from('favorites')
|
||||
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
|
||||
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)))
|
||||
;
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,31 +20,30 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Db;
|
||||
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
class RecentMapper extends QBMapper {
|
||||
/**
|
||||
* @extends QBMapper<Station>
|
||||
*/
|
||||
class RecentMapper extends QBMapper
|
||||
{
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'recent', Station::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $userId
|
||||
* @return Entity|Station
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
||||
* @throws MultipleObjectsReturnedException
|
||||
* @throws DoesNotExistException
|
||||
*/
|
||||
public function find(int $id, string $userId): Station {
|
||||
/* @var $qb IQueryBuilder */
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->selectDistinct('stationuuid')
|
||||
->addSelect('name')
|
||||
@ -57,16 +58,16 @@ class RecentMapper extends QBMapper {
|
||||
->from('recent')
|
||||
->orderBy('id', 'DESC')
|
||||
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
|
||||
->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)))
|
||||
;
|
||||
|
||||
return $this->findEntity($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
* @return array
|
||||
* @return Station[]
|
||||
*/
|
||||
public function findAll(string $userId): array {
|
||||
/* @var $qb IQueryBuilder */
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->selectDistinct('stationuuid')
|
||||
->addSelect('name')
|
||||
@ -80,7 +81,9 @@ class RecentMapper extends QBMapper {
|
||||
->addSelect('tags')
|
||||
->from('recent')
|
||||
->orderBy('id', 'DESC')
|
||||
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
|
||||
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)))
|
||||
;
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,27 +20,61 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Db;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
|
||||
class Station extends Entity implements JsonSerializable {
|
||||
protected $stationuuid;
|
||||
protected $name;
|
||||
protected $favicon;
|
||||
protected $urlresolved;
|
||||
protected $bitrate;
|
||||
protected $country;
|
||||
protected $language;
|
||||
protected $homepage;
|
||||
protected $codec;
|
||||
protected $tags;
|
||||
protected $userId;
|
||||
/**
|
||||
* @method string getStationuuid()
|
||||
* @method string getName()
|
||||
* @method ?string getFavicon()
|
||||
* @method ?string getUrlresolved()
|
||||
* @method ?string getBitrate()
|
||||
* @method ?string getCountry()
|
||||
* @method ?string getLanguage()
|
||||
* @method ?string getHomepage()
|
||||
* @method ?string getCodec()
|
||||
* @method ?string getTags()
|
||||
* @method string getUserId()
|
||||
* @method void setStationuuid(string $stationuuid)
|
||||
* @method void setName(string $name)
|
||||
* @method void setFavicon(?string $favicon)
|
||||
* @method void setUrlresolved(?string $urlresolved)
|
||||
* @method void setBitrate(?string $bitrate)
|
||||
* @method void setCountry(?string $country)
|
||||
* @method void setLanguage(?string $language)
|
||||
* @method void setHomepage(?string $homepage)
|
||||
* @method void setCodec(?string $codec)
|
||||
* @method void setTags(?string $tags)
|
||||
* @method void setUserId(string $userId)
|
||||
*
|
||||
* @psalm-suppress PropertyNotSetInConstructor
|
||||
*/
|
||||
class Station extends Entity implements \JsonSerializable
|
||||
{
|
||||
protected string $stationuuid;
|
||||
|
||||
protected string $name;
|
||||
|
||||
protected ?string $favicon = null;
|
||||
|
||||
protected ?string $urlresolved = null;
|
||||
|
||||
protected ?string $bitrate = null;
|
||||
|
||||
protected ?string $country = null;
|
||||
|
||||
protected ?string $language = null;
|
||||
|
||||
protected ?string $homepage = null;
|
||||
|
||||
protected ?string $codec = null;
|
||||
|
||||
protected ?string $tags = null;
|
||||
|
||||
protected string $userId;
|
||||
|
||||
public function jsonSerialize(): array {
|
||||
return [
|
||||
@ -52,7 +88,8 @@ class Station extends Entity implements JsonSerializable {
|
||||
'language' => $this->language,
|
||||
'homepage' => $this->homepage,
|
||||
'codec' => $this->codec,
|
||||
'tags' => $this->tags
|
||||
'tags' => $this->tags,
|
||||
'userId' => $this->userId,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio;
|
||||
|
||||
use OC;
|
||||
use OC\HintException;
|
||||
use OCP\AppFramework\Http\Response;
|
||||
|
||||
class ExportResponse extends Response {
|
||||
private $returnstring;
|
||||
|
||||
public function __construct($returnstring) {
|
||||
parent::__construct();
|
||||
|
||||
$user = OC::$server->getUserSession()->getUser();
|
||||
if (is_null($user)) {
|
||||
throw new HintException('User not logged in');
|
||||
}
|
||||
|
||||
$userName = $user->getDisplayName();
|
||||
$productName = OC::$server->getThemingDefaults()->getName();
|
||||
$dateTime = OC::$server->getDateTimeFormatter();
|
||||
|
||||
$export_name = '"' . $productName . ' Radio Favorites (' . $userName . ') (' . $dateTime->formatDate(time()) . ').xspf"';
|
||||
$this->addHeader("Cache-Control", "private");
|
||||
$this->addHeader("Content-Type", " application/xspf+xml");
|
||||
$this->addHeader("Content-Length", strlen($returnstring));
|
||||
$this->addHeader("Content-Disposition", "attachment; filename=" . $export_name);
|
||||
$this->returnstring = $returnstring;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
return $this->returnstring;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,27 +18,24 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\Radio\Migration;
|
||||
|
||||
use Closure;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
|
||||
class Version000000Date20181013124731 extends SimpleMigrationStep {
|
||||
|
||||
class Version000000Date20181013124731 extends SimpleMigrationStep
|
||||
{
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
||||
* @param array $options
|
||||
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
||||
*
|
||||
* @return null|ISchemaWrapper
|
||||
*/
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
|
||||
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,7 +18,6 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
@ -26,32 +25,22 @@ declare(strict_types=1);
|
||||
namespace OCA\Radio\Search;
|
||||
|
||||
use OCA\Radio\AppInfo\Application;
|
||||
use OCP\IUser;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\Search\IProvider;
|
||||
use OCP\Search\ISearchQuery;
|
||||
use OCP\Search\SearchResult;
|
||||
use OCP\Search\SearchResultEntry;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
use OCP\Http\Client\IClientService;
|
||||
|
||||
use function urlencode;
|
||||
|
||||
class SearchProvider implements IProvider {
|
||||
|
||||
/** @var IClientService */
|
||||
private $clientService;
|
||||
|
||||
/** @var IURLGenerator */
|
||||
private $url;
|
||||
|
||||
class SearchProvider implements IProvider
|
||||
{
|
||||
public function __construct(
|
||||
IClientService $clientService,
|
||||
IURLGenerator $url
|
||||
) {
|
||||
$this->clientService = $clientService;
|
||||
$this->url = $url;
|
||||
}
|
||||
private readonly IClientService $clientService,
|
||||
private readonly IURLGenerator $url,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {}
|
||||
|
||||
public function getId(): string {
|
||||
return Application::APP_ID;
|
||||
@ -62,38 +51,43 @@ class SearchProvider implements IProvider {
|
||||
}
|
||||
|
||||
public function getOrder(string $route, array $routeParameters): int {
|
||||
if (strpos($route, 'files' . '.') === 0) {
|
||||
if (str_starts_with($route, 'files.')) {
|
||||
return 25;
|
||||
} elseif (strpos($route, Application::APP_ID . '.') === 0) {
|
||||
}
|
||||
|
||||
if (str_starts_with($route, Application::APP_ID.'.')) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
public function search(IUser $user, ISearchQuery $query): SearchResult {
|
||||
|
||||
public function search(IUser $user, ISearchQuery $query): SearchResult {
|
||||
$term = $query->getTerm();
|
||||
$url = "https://de1.api.radio-browser.info/json/stations/byname/" . $term . "?limit=20";
|
||||
$url = 'https://de1.api.radio-browser.info/json/stations/byname/'.$term.'?limit=20';
|
||||
|
||||
$client = $this->clientService->newClient();
|
||||
|
||||
try {
|
||||
$response = $client->get($url);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error("Could not search for radio stations: " . $e->getMessage());
|
||||
throw $e;
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->error('Could not search for radio stations: '.$exception->getMessage());
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
$body = $response->getBody();
|
||||
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
/** @var array<array<string, string>> $parsed */
|
||||
$parsed = json_decode($body, true);
|
||||
|
||||
$result = array_map(function (array $result) use ($term) {
|
||||
return new SearchResultEntry(
|
||||
$result['favicon'],
|
||||
$result['name'],
|
||||
str_replace(",",", ",$result['tags']),
|
||||
$this->url->linkToRouteAbsolute('radio.page.index') . '#/search/' . $term,
|
||||
'icon-radio-trans'
|
||||
);
|
||||
}, $parsed);
|
||||
$result = array_map(fn (array $result): SearchResultEntry => new SearchResultEntry(
|
||||
$result['favicon'],
|
||||
$result['name'],
|
||||
str_replace(',', ', ', $result['tags']),
|
||||
$this->url->linkToRouteAbsolute('radio.page.index').'#/search/'.$term,
|
||||
'icon-radio-trans'
|
||||
), $parsed);
|
||||
|
||||
return SearchResult::complete(
|
||||
$this->getName(),
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,56 +20,55 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Service;
|
||||
|
||||
use Exception;
|
||||
|
||||
use OCA\Radio\Db\FavoriteMapper;
|
||||
use OCA\Radio\Db\Station;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
|
||||
use OCA\Radio\Db\Station;
|
||||
use OCA\Radio\Db\FavoriteMapper;
|
||||
|
||||
class FavoriteService {
|
||||
|
||||
/** @var FavoriteMapper */
|
||||
private $mapper;
|
||||
|
||||
public function __construct(FavoriteMapper $mapper) {
|
||||
class FavoriteService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly FavoriteMapper $mapper
|
||||
) {
|
||||
$this->mapper = $mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Station[]
|
||||
*/
|
||||
public function findAll(string $userId): array {
|
||||
return $this->mapper->findAll($userId);
|
||||
}
|
||||
|
||||
private function handleException(Exception $e): void {
|
||||
if ($e instanceof DoesNotExistException ||
|
||||
$e instanceof MultipleObjectsReturnedException) {
|
||||
throw new StationNotFound($e->getMessage());
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function find($id, $userId) {
|
||||
public function find(int $id, string $userId): ?Station {
|
||||
try {
|
||||
return $this->mapper->find($id, $userId);
|
||||
|
||||
// in order to be able to plug in different storage backends like files
|
||||
// for instance it is a good idea to turn storage related exceptions
|
||||
// into service related exceptions so controllers and service users
|
||||
// have to deal with only one type of exception
|
||||
} catch (Exception $e) {
|
||||
$this->handleException($e);
|
||||
// for instance it is a good idea to turn storage related exceptions
|
||||
// into service related exceptions so controllers and service users
|
||||
// have to deal with only one type of exception
|
||||
} catch (\Exception $exception) {
|
||||
return $this->handleException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function create($stationuuid, $name, $favicon, $urlresolved,
|
||||
$bitrate, $country, $language, $homepage, $codec, $tags, $userId) {
|
||||
public function create(
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
?string $favicon,
|
||||
?string $urlresolved,
|
||||
?string $bitrate,
|
||||
?string $country,
|
||||
?string $language,
|
||||
?string $homepage,
|
||||
?string $codec,
|
||||
?string $tags,
|
||||
string $userId
|
||||
): Station {
|
||||
$station = new Station();
|
||||
$station->setStationuuid($stationuuid);
|
||||
$station->setName($name);
|
||||
@ -80,11 +81,24 @@ class FavoriteService {
|
||||
$station->setCodec($codec);
|
||||
$station->setTags($tags);
|
||||
$station->setUserId($userId);
|
||||
|
||||
return $this->mapper->insert($station);
|
||||
}
|
||||
|
||||
public function update($id, $stationuuid, $name, $favicon, $urlresolved,
|
||||
$bitrate, $country, $language, $homepage, $codec, $tags, $userId) {
|
||||
public function update(
|
||||
int $id,
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
?string $favicon,
|
||||
?string $urlresolved,
|
||||
?string $bitrate,
|
||||
?string $country,
|
||||
?string $language,
|
||||
?string $homepage,
|
||||
?string $codec,
|
||||
?string $tags,
|
||||
string $userId
|
||||
): ?Station {
|
||||
try {
|
||||
$station = $this->mapper->find($id, $userId);
|
||||
$station->setStationuuid($stationuuid);
|
||||
@ -97,19 +111,30 @@ class FavoriteService {
|
||||
$station->setHomepage($homepage);
|
||||
$station->setCodec($codec);
|
||||
$station->setTags($tags);
|
||||
|
||||
return $this->mapper->update($station);
|
||||
} catch (Exception $e) {
|
||||
$this->handleException($e);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->handleException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete($id, $userId) {
|
||||
public function delete(int $id, string $userId): ?Station {
|
||||
try {
|
||||
$station = $this->mapper->find($id, $userId);
|
||||
$this->mapper->delete($station);
|
||||
|
||||
return $station;
|
||||
} catch (Exception $e) {
|
||||
$this->handleException($e);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->handleException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleException(\Throwable $e): void {
|
||||
if ($e instanceof DoesNotExistException
|
||||
|| $e instanceof MultipleObjectsReturnedException) {
|
||||
throw new StationNotFound($e->getMessage());
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,119 +18,116 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\Radio\Service;
|
||||
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
use function urlencode;
|
||||
|
||||
class RadioBrowserApiService {
|
||||
|
||||
/** @var IClientService */
|
||||
private $clientService;
|
||||
|
||||
/** @var IURLGenerator */
|
||||
private $url;
|
||||
|
||||
public $baseUrl = "https://api.fyyd.de/0.2";
|
||||
class RadioBrowserApiService
|
||||
{
|
||||
public string $baseUrl = 'https://api.fyyd.de/0.2';
|
||||
|
||||
public function __construct(
|
||||
IClientService $clientService,
|
||||
IURLGenerator $url
|
||||
) {
|
||||
$this->clientService = $clientService;
|
||||
$this->url = $url;
|
||||
}
|
||||
private readonly IClientService $clientService,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {}
|
||||
|
||||
public function queryEpisodes(int $podcast_id, int $count = 20, int $page = 0) {
|
||||
|
||||
$url = $this->baseUrl . "/podcast/episodes";
|
||||
public function queryEpisodes(int $podcast_id, int $count = 20, int $page = 0): mixed {
|
||||
$url = $this->baseUrl.'/podcast/episodes';
|
||||
$options = [];
|
||||
|
||||
$options['query'] = [
|
||||
'podcast_id' => $podcast_id,
|
||||
'count' => $count,
|
||||
'page' => $page
|
||||
'page' => $page,
|
||||
];
|
||||
|
||||
$client = $this->clientService->newClient();
|
||||
|
||||
try {
|
||||
$response = $client->get($url, $options);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error("Could not search for podcasts: " . $e->getMessage());
|
||||
throw $e;
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->error('Could not search for podcasts: '.$exception->getMessage());
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
$body = $response->getBody();
|
||||
|
||||
$parsed = json_decode($body, true);
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
return $parsed;
|
||||
return json_decode($body, true);
|
||||
}
|
||||
|
||||
public function queryEpisode(int $episode_id) {
|
||||
|
||||
$url = $this->baseUrl . "/episode";
|
||||
public function queryEpisode(int $episode_id): mixed {
|
||||
$url = $this->baseUrl.'/episode';
|
||||
$options = [];
|
||||
|
||||
$options['query'] = [
|
||||
'episode_id' => $episode_id,
|
||||
];
|
||||
|
||||
$client = $this->clientService->newClient();
|
||||
|
||||
try {
|
||||
$response = $client->get($url, $options);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error("Could not search for podcasts: " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
$body = $response->getBody();
|
||||
$parsed = json_decode($body, true);
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->error('Could not search for podcasts: '.$exception->getMessage());
|
||||
|
||||
return $parsed;
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
return json_decode($body, true);
|
||||
}
|
||||
|
||||
public function queryPodcast(int $podcast_id) {
|
||||
|
||||
$url = $this->baseUrl . "/podcast";
|
||||
public function queryPodcast(int $podcast_id): mixed {
|
||||
$url = $this->baseUrl.'/podcast';
|
||||
$options = [];
|
||||
|
||||
$options['query'] = [
|
||||
'podcast_id' => $podcast_id,
|
||||
];
|
||||
|
||||
$client = $this->clientService->newClient();
|
||||
|
||||
try {
|
||||
$response = $client->get($url, $options);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error("Could not search for podcasts: " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
$body = $response->getBody();
|
||||
$parsed = json_decode($body, true);
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->error('Could not search for podcasts: '.$exception->getMessage());
|
||||
|
||||
return $parsed;
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
return json_decode($body, true);
|
||||
}
|
||||
|
||||
public function queryCategory(string $category, int $count = 20,
|
||||
int $page = 0) {
|
||||
public function queryCategory(
|
||||
string $category,
|
||||
int $count = 20,
|
||||
int $page = 0
|
||||
): mixed {
|
||||
$options = [];
|
||||
|
||||
if ($category === 'hot') {
|
||||
$url = $this->baseUrl . "/feature/podcast/hot";
|
||||
if ('hot' === $category) {
|
||||
$url = $this->baseUrl.'/feature/podcast/hot';
|
||||
$options['query'] = [
|
||||
'count' => $count,
|
||||
'page' => $page,
|
||||
];
|
||||
} else if ($category === 'latest') {
|
||||
$url = $this->baseUrl . "/podcast/latest";
|
||||
} elseif ('latest' === $category) {
|
||||
$url = $this->baseUrl.'/podcast/latest';
|
||||
$options['query'] = [
|
||||
'count' => $count,
|
||||
'page' => $page,
|
||||
];
|
||||
} else {
|
||||
$url = $this->baseUrl . "/category";
|
||||
$url = $this->baseUrl.'/category';
|
||||
$options['query'] = [
|
||||
'count' => $count,
|
||||
'page' => $page,
|
||||
@ -139,15 +136,17 @@ class RadioBrowserApiService {
|
||||
}
|
||||
|
||||
$client = $this->clientService->newClient();
|
||||
|
||||
try {
|
||||
$response = $client->get($url, $options);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error("Could not search for podcasts: " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
$body = $response->getBody();
|
||||
$parsed = json_decode($body, true);
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->error('Could not search for podcasts: '.$exception->getMessage());
|
||||
|
||||
return $parsed;
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
return json_decode($body, true);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,56 +20,55 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Service;
|
||||
|
||||
use Exception;
|
||||
|
||||
use OCA\Radio\Db\RecentMapper;
|
||||
use OCA\Radio\Db\Station;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
|
||||
use OCA\Radio\Db\Station;
|
||||
use OCA\Radio\Db\RecentMapper;
|
||||
|
||||
class RecentService {
|
||||
|
||||
/** @var RecentMapper */
|
||||
private $mapper;
|
||||
|
||||
public function __construct(RecentMapper $mapper) {
|
||||
class RecentService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RecentMapper $mapper
|
||||
) {
|
||||
$this->mapper = $mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Station[]
|
||||
*/
|
||||
public function findAll(string $userId): array {
|
||||
return $this->mapper->findAll($userId);
|
||||
}
|
||||
|
||||
private function handleException(Exception $e): void {
|
||||
if ($e instanceof DoesNotExistException ||
|
||||
$e instanceof MultipleObjectsReturnedException) {
|
||||
throw new StationNotFound($e->getMessage());
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function find($id, $userId) {
|
||||
public function find(int $id, string $userId): ?Station {
|
||||
try {
|
||||
return $this->mapper->find($id, $userId);
|
||||
|
||||
// in order to be able to plug in different storage backends like files
|
||||
// for instance it is a good idea to turn storage related exceptions
|
||||
// into service related exceptions so controllers and service users
|
||||
// have to deal with only one type of exception
|
||||
} catch (Exception $e) {
|
||||
$this->handleException($e);
|
||||
// for instance it is a good idea to turn storage related exceptions
|
||||
// into service related exceptions so controllers and service users
|
||||
// have to deal with only one type of exception
|
||||
} catch (\Exception $exception) {
|
||||
return $this->handleException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function create($stationuuid, $name, $favicon, $urlresolved,
|
||||
$bitrate, $country, $language, $homepage, $codec, $tags, $userId) {
|
||||
public function create(
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
?string $favicon,
|
||||
?string $urlresolved,
|
||||
?string $bitrate,
|
||||
?string $country,
|
||||
?string $language,
|
||||
?string $homepage,
|
||||
?string $codec,
|
||||
?string $tags,
|
||||
string $userId
|
||||
): Station {
|
||||
$station = new Station();
|
||||
$station->setStationuuid($stationuuid);
|
||||
$station->setName($name);
|
||||
@ -80,11 +81,24 @@ class RecentService {
|
||||
$station->setCodec($codec);
|
||||
$station->setTags($tags);
|
||||
$station->setUserId($userId);
|
||||
|
||||
return $this->mapper->insert($station);
|
||||
}
|
||||
|
||||
public function update($id, $stationuuid, $name, $favicon, $urlresolved,
|
||||
$bitrate, $country, $language, $homepage, $codec, $tags, $userId) {
|
||||
public function update(
|
||||
int $id,
|
||||
string $stationuuid,
|
||||
string $name,
|
||||
?string $favicon,
|
||||
?string $urlresolved,
|
||||
?string $bitrate,
|
||||
?string $country,
|
||||
?string $language,
|
||||
?string $homepage,
|
||||
?string $codec,
|
||||
?string $tags,
|
||||
string $userId
|
||||
): ?Station {
|
||||
try {
|
||||
$station = $this->mapper->find($id, $userId);
|
||||
$station->setStationuuid($stationuuid);
|
||||
@ -97,19 +111,33 @@ class RecentService {
|
||||
$station->setHomepage($homepage);
|
||||
$station->setCodec($codec);
|
||||
$station->setTags($tags);
|
||||
|
||||
return $this->mapper->update($station);
|
||||
} catch (Exception $e) {
|
||||
$this->handleException($e);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->handleException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete($id, $userId) {
|
||||
public function delete(int $id, string $userId): ?Station {
|
||||
try {
|
||||
$station = $this->mapper->find($id, $userId);
|
||||
$this->mapper->delete($station);
|
||||
|
||||
return $station;
|
||||
} catch (Exception $e) {
|
||||
$this->handleException($e);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->handleException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function handleException(\Throwable $e): void {
|
||||
if ($e instanceof DoesNotExistException
|
||||
|| $e instanceof MultipleObjectsReturnedException) {
|
||||
throw new StationNotFound($e->getMessage());
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,10 +20,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Radio\Service;
|
||||
|
||||
class StationNotFound extends \Exception {
|
||||
}
|
||||
class StationNotFound extends \Exception {}
|
||||
|
25
lib/Service/UserService.php
Normal file
25
lib/Service/UserService.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\Radio\Service;
|
||||
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
|
||||
class UserService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly IUserSession $userSession
|
||||
) {}
|
||||
|
||||
public function getUserUID(): string {
|
||||
$user = $this->getUser();
|
||||
|
||||
return $user instanceof IUser ? $user->getUID() : '';
|
||||
}
|
||||
|
||||
public function getUser(): ?IUser {
|
||||
return $this->userSession->getUser();
|
||||
}
|
||||
}
|
21
psalm.xml
Normal file
21
psalm.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0"?>
|
||||
<psalm
|
||||
errorLevel="1"
|
||||
resolveFromConfigFile="true"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="https://getpsalm.org/schema/config"
|
||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
||||
findUnusedBaselineEntry="true"
|
||||
findUnusedCode="false"
|
||||
phpVersion="8.1"
|
||||
>
|
||||
<projectFiles>
|
||||
<directory name="lib" />
|
||||
<ignoreFiles>
|
||||
<directory name="vendor" />
|
||||
</ignoreFiles>
|
||||
</projectFiles>
|
||||
<extraFiles>
|
||||
<directory name="vendor"/>
|
||||
</extraFiles>
|
||||
</psalm>
|
34
rector.php
Normal file
34
rector.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Nextcloud\Rector\Set\NextcloudSets;
|
||||
use Rector\Config\RectorConfig;
|
||||
|
||||
return RectorConfig::configure()
|
||||
->withPaths([
|
||||
__DIR__.'/appinfo',
|
||||
__DIR__.'/lib',
|
||||
])
|
||||
->withPhpSets(php81: true)
|
||||
->withSets([
|
||||
NextcloudSets::NEXTCLOUD_27,
|
||||
])
|
||||
->withPreparedSets(
|
||||
deadCode: true,
|
||||
codeQuality: true,
|
||||
codingStyle: true,
|
||||
typeDeclarations: true,
|
||||
privatization: true,
|
||||
instanceOf: true,
|
||||
earlyReturn: true,
|
||||
strictBooleans: true,
|
||||
rectorPreset: true,
|
||||
phpunitCodeQuality: true,
|
||||
doctrineCodeQuality: true,
|
||||
symfonyCodeQuality: true,
|
||||
symfonyConfigs: true,
|
||||
twig: true,
|
||||
phpunit: true,
|
||||
)
|
||||
;
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Radio App
|
||||
* Radio App.
|
||||
*
|
||||
* @author Jonas Heinrich
|
||||
* @copyright 2021 Jonas Heinrich <onny@project-insanity.org>
|
||||
@ -18,7 +18,5 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
echo "<div id='vue-content'></div>";
|
||||
|
Loading…
Reference in New Issue
Block a user