Added API endpoint to generate plex access tokens.

This commit is contained in:
abdulmohsen
2024-04-19 22:42:57 +03:00
parent fd99950ac0
commit aee685e88d
6 changed files with 138 additions and 29 deletions

52
composer.lock generated
View File

@@ -299,16 +299,16 @@
},
{
"name": "monolog/monolog",
"version": "3.5.0",
"version": "3.6.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448"
"reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448",
"reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654",
"reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654",
"shasum": ""
},
"require": {
@@ -331,7 +331,7 @@
"phpstan/phpstan": "^1.9",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-strict-rules": "^1.4",
"phpunit/phpunit": "^10.1",
"phpunit/phpunit": "^10.5.17",
"predis/predis": "^1.1 || ^2",
"ruflin/elastica": "^7",
"symfony/mailer": "^5.4 || ^6",
@@ -384,7 +384,7 @@
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/3.5.0"
"source": "https://github.com/Seldaek/monolog/tree/3.6.0"
},
"funding": [
{
@@ -396,7 +396,7 @@
"type": "tidelift"
}
],
"time": "2023-10-27T15:32:31+00:00"
"time": "2024-04-12T21:02:21+00:00"
},
{
"name": "nikic/fast-route",
@@ -2579,16 +2579,16 @@
},
{
"name": "perftools/php-profiler",
"version": "1.1.1",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/perftools/php-profiler.git",
"reference": "40edd32f8ac471dd4d0f6e7057ed0acab4eb1c36"
"reference": "b5051e96679aa0d6cb3afe9a13a4e6a1fd890fea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/perftools/php-profiler/zipball/40edd32f8ac471dd4d0f6e7057ed0acab4eb1c36",
"reference": "40edd32f8ac471dd4d0f6e7057ed0acab4eb1c36",
"url": "https://api.github.com/repos/perftools/php-profiler/zipball/b5051e96679aa0d6cb3afe9a13a4e6a1fd890fea",
"reference": "b5051e96679aa0d6cb3afe9a13a4e6a1fd890fea",
"shasum": ""
},
"require": {
@@ -2635,9 +2635,9 @@
"description": "PHP Profiling based on XHGui",
"support": {
"issues": "https://github.com/perftools/php-profiler/issues",
"source": "https://github.com/perftools/php-profiler/tree/1.1.1"
"source": "https://github.com/perftools/php-profiler/tree/1.1.2"
},
"time": "2022-06-09T14:39:38+00:00"
"time": "2024-04-16T05:42:45+00:00"
},
{
"name": "phar-io/manifest",
@@ -3185,12 +3185,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "00077527dfa5415280a28a044eca385eb3feb7ee"
"reference": "16afe68c1b79917b4e8d8222a39ca4db31b63377"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/00077527dfa5415280a28a044eca385eb3feb7ee",
"reference": "00077527dfa5415280a28a044eca385eb3feb7ee",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/16afe68c1b79917b4e8d8222a39ca4db31b63377",
"reference": "16afe68c1b79917b4e8d8222a39ca4db31b63377",
"shasum": ""
},
"conflict": {
@@ -3277,9 +3277,10 @@
"concrete5/concrete5": "<9.2.8",
"concrete5/core": "<8.5.8|>=9,<9.1",
"contao-components/mediaelement": ">=2.14.2,<2.21.1",
"contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4",
"contao/contao": ">=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4",
"contao/core": ">=2,<3.5.39",
"contao/core-bundle": ">=3,<3.5.35|>=4,<4.9.42|>=4.10,<4.13.28|>=5,<5.1.10",
"contao/core-bundle": "<4.13.40|>=5,<5.3.4",
"contao/listing-bundle": ">=4,<4.4.8",
"contao/managed-edition": "<=1.5",
"corveda/phpsandbox": "<1.3.5",
@@ -3343,7 +3344,7 @@
"ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15",
"ezsystems/ezplatform-user": ">=1,<1.0.1",
"ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31",
"ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.03.5.1",
"ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.06,<=2019.03.5.1",
"ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3",
"ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15",
"ezyang/htmlpurifier": "<4.1.1",
@@ -3374,7 +3375,8 @@
"friendsofsymfony/oauth2-php": "<1.3",
"friendsofsymfony/rest-bundle": ">=1.2,<1.2.2",
"friendsofsymfony/user-bundle": ">=1.2,<1.3.5",
"friendsofsymfony1/symfony1": ">=1.1,<1.5.19",
"friendsofsymfony1/swiftmailer": ">=4,<5.4.13|>=6,<6.2.5",
"friendsofsymfony1/symfony1": ">=1.1,<1.15.19",
"friendsoftypo3/mediace": ">=7.6.2,<7.6.5",
"friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6",
"froala/wysiwyg-editor": "<3.2.7|>=4.0.1,<=4.1.3",
@@ -3495,7 +3497,7 @@
"mantisbt/mantisbt": "<2.26.1",
"marcwillmann/turn": "<0.3.3",
"matyhtf/framework": "<3.0.6",
"mautic/core": "<4.3",
"mautic/core": "<4.4.12|>=5.0.0.0-alpha,<5.0.4",
"mediawiki/core": "<1.36.2",
"mediawiki/matomo": "<2.4.3",
"mediawiki/semantic-media-wiki": "<4.0.2",
@@ -3639,7 +3641,7 @@
"really-simple-plugins/complianz-gdpr": "<6.4.2",
"redaxo/source": "<=5.15.1",
"remdex/livehelperchat": "<4.29",
"reportico-web/reportico": "<=7.1.21",
"reportico-web/reportico": "<=8.1",
"rhukster/dom-sanitizer": "<1.0.7",
"rmccue/requests": ">=1.6,<1.8",
"robrichards/xmlseclibs": ">=1,<3.0.4",
@@ -3710,7 +3712,7 @@
"sumocoders/framework-user-bundle": "<1.4",
"superbig/craft-audit": "<3.0.2",
"swag/paypal": "<5.4.4",
"swiftmailer/swiftmailer": ">=4,<5.4.5",
"swiftmailer/swiftmailer": ">=4,<6.2.5",
"swiftyedit/swiftyedit": "<1.2",
"sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2",
"sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1",
@@ -3760,7 +3762,7 @@
"t3s/content-consent": "<1.0.3|>=2,<2.0.2",
"tastyigniter/tastyigniter": "<3.3",
"tcg/voyager": "<=1.4",
"tecnickcom/tcpdf": "<6.2.22",
"tecnickcom/tcpdf": "<6.7.4",
"terminal42/contao-tablelookupwizard": "<3.3.5",
"thelia/backoffice-default-template": ">=2.1,<2.1.2",
"thelia/thelia": ">=2.1,<2.1.3",
@@ -3768,6 +3770,7 @@
"thinkcmf/thinkcmf": "<=5.1.7",
"thorsten/phpmyfaq": "<3.2.2",
"tikiwiki/tiki-manager": "<=17.1",
"timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1",
"tinymce/tinymce": "<7",
"tinymighty/wiki-seo": "<1.2.2",
"titon/framework": "<9.9.99",
@@ -3821,6 +3824,7 @@
"wikimedia/parsoid": "<0.12.2",
"willdurand/js-translation-bundle": "<2.1.1",
"winter/wn-backend-module": "<1.2.4",
"winter/wn-dusk-plugin": "<2.1",
"winter/wn-system-module": "<1.2.4",
"wintercms/winter": "<=1.2.3",
"woocommerce/woocommerce": "<6.6",
@@ -3922,7 +3926,7 @@
"type": "tidelift"
}
],
"time": "2024-04-08T16:06:11+00:00"
"time": "2024-04-18T17:04:22+00:00"
},
{
"name": "sebastian/cli-parser",

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace App\API\Backends\Plex;
use App\Libs\Attributes\Route\Post;
use App\Libs\DataUtil;
use App\Libs\Exceptions\RuntimeException;
use App\Libs\HTTP_STATUS;
use App\Libs\Traits\APITraits;
use Psr\Http\Message\ResponseInterface as iResponse;
use Psr\Http\Message\ServerRequestInterface as iRequest;
use Symfony\Contracts\HttpClient\HttpClientInterface as iHttp;
final class GenerateAccessToken
{
use APITraits;
public const string URL = '%{api.prefix}/backends/plex/accesstoken';
public function __construct(private iHttp $http)
{
}
#[Post(self::URL . '/{backend:\w+}[/]', name: 'backends.plex.accesstoken')]
public function gAccesstoken(iRequest $request, array $args = []): iResponse
{
$backend = ag($args, 'backend');
$data = DataUtil::fromArray($request->getParsedBody());
if (null === ($uuid = $data->get('uuid'))) {
return api_error('No User (uuid) was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
}
try {
$client = $this->getBackend($backend);
} catch (RuntimeException $e) {
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
}
try {
$token = $client->getUserToken(
userId: $uuid,
username: $data->get('username', $client->getContext()->backendName . '_user'),
);
if (!is_string($token)) {
return api_error('Failed to generate access token.', HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
}
$arr = [
'token' => $token,
];
if ($data->get('username')) {
$arr['username'] = $data->get('username');
}
return api_response(HTTP_STATUS::HTTP_OK, $arr);
} catch (\Throwable $e) {
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
}
}
}

View File

@@ -21,7 +21,7 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
#[Cli(command: self::ROUTE)]
final class AccessTokenCommand extends Command
{
public const ROUTE = 'plex:accesstoken';
public const string ROUTE = 'plex:accesstoken';
public function __construct(protected iLogger $logger)
{

View File

@@ -6,6 +6,7 @@ namespace App;
use App\Backends\Common\ClientInterface as iClient;
use App\Libs\Config;
use App\Libs\ConfigFile;
use App\Libs\Exceptions\RuntimeException;
use Closure;
use DirectoryIterator;
@@ -31,7 +32,7 @@ class Command extends BaseCommand
*
* @var array<string>
*/
public const DISPLAY_OUTPUT = [
public const array DISPLAY_OUTPUT = [
'table',
'json',
'yaml',
@@ -211,11 +212,13 @@ class Command extends BaseCommand
*/
protected function getBackend(string $name, array $config = []): iClient
{
if (null === Config::get("servers.{$name}.type", null)) {
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml');
if (null === $configFile->get("{$name}.type", null)) {
throw new RuntimeException(r('No backend named [{backend}] was found.', ['backend' => $name]));
}
$default = Config::get("servers.{$name}");
$default = $configFile->get($name);
$default['name'] = $name;
return makeBackend(array_replace_recursive($default, $config), $name);

View File

@@ -18,7 +18,7 @@ use Symfony\Component\Yaml\Yaml;
*/
final class ConfigFile implements ArrayAccess, LoggerAwareInterface
{
private const CONTENT_TYPES = ['yaml', 'json'];
private const array CONTENT_TYPES = ['yaml', 'json'];
private array $data = [];
private array $operations = [];
private string $file_hash = '';

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Libs\Traits;
use App\Backends\Common\ClientInterface as iClient;
use App\Libs\Config;
use App\Libs\ConfigFile;
use App\Libs\Exceptions\RuntimeException;
trait APITraits
{
/**
* Retrieves the backend client for the specified name.
*
* @param string $name The name of the backend.
* @param array $config (Optional) Override the default configuration for the backend.
*
* @return iClient The backend client instance.
* @throws RuntimeException If no backend with the specified name is found.
*/
protected function getBackend(string $name, array $config = []): iClient
{
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml');
if (null === $configFile->get("{$name}.type", null)) {
throw new RuntimeException(r("Backend '{backend}' doesn't exists.", ['backend' => $name]));
}
$default = $configFile->get($name);
$default['name'] = $name;
return makeBackend(array_replace_recursive($default, $config), $name);
}
}