mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-26 02:40:41 -06:00
Created action to get mercure integration info
This commit is contained in:
parent
85440c1c5f
commit
2ffbf03cf8
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Laminas\ServiceManager\Proxy\LazyServiceFactory;
|
||||||
|
use Shlinkio\Shlink\Common\Mercure\LcobucciJwtProvider;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
'mercure' => [
|
'mercure' => [
|
||||||
@ -12,4 +15,17 @@ return [
|
|||||||
'jwt_issuer' => 'Shlink',
|
'jwt_issuer' => 'Shlink',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'dependencies' => [
|
||||||
|
'delegators' => [
|
||||||
|
LcobucciJwtProvider::class => [
|
||||||
|
LazyServiceFactory::class,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'lazy_services' => [
|
||||||
|
'class_map' => [
|
||||||
|
LcobucciJwtProvider::class => LcobucciJwtProvider::class,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
18
docs/swagger/definitions/MercureInfo.json
Normal file
18
docs/swagger/definitions/MercureInfo.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": ["mercureHubUrl", "jwt", "jwtExpiration"],
|
||||||
|
"properties": {
|
||||||
|
"mercureHubUrl": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The public URL of the mercure hub that can be used to get real-time updates published by Shlink"
|
||||||
|
},
|
||||||
|
"jwt": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A JWT with subscribe permissions which is valid with the mercure hub"
|
||||||
|
},
|
||||||
|
"jwtExpiration": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The date (in ISO-8601 format) in which the JWT will expire"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
docs/swagger/paths/v2_mercure-info.json
Normal file
67
docs/swagger/paths/v2_mercure-info.json
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"get": {
|
||||||
|
"operationId": "mercureInfo",
|
||||||
|
"tags": [
|
||||||
|
"Integrations"
|
||||||
|
],
|
||||||
|
"summary": "Get mercure integration info",
|
||||||
|
"description": "Returns information to consume updates published by Shlink on a mercure hub. https://mercure.rocks/",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"$ref": "../parameters/version.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKey": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The mercure integration info",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "../definitions/MercureInfo.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"application/json": {
|
||||||
|
"mercureHubUrl": "https://example.com/.well-known/mercure",
|
||||||
|
"jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTaGxpbmsiLCJpYXQiOjE1ODY2ODY3MzIsImV4cCI6MTU4Njk0NTkzMiwibWVyY3VyZSI6eyJzdWJzY3JpYmUiOltdfX0.P-519lgU7dFz0bbNlRG1CXyqugGbaHon4kw6fu4QBdQ",
|
||||||
|
"jwtExpiration": "2020-04-15T12:18:52+02:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"501": {
|
||||||
|
"description": "This Shlink instance is not integrated with a mercure hub",
|
||||||
|
"content": {
|
||||||
|
"application/problem+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "../definitions/Error.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"application/json": {
|
||||||
|
"title": "Mercure integration not configured",
|
||||||
|
"type": "MERCURE_NOT_CONFIGURED",
|
||||||
|
"detail": "This Shlink instance is not integrated with a mercure hub.",
|
||||||
|
"status": 501
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Unexpected error.",
|
||||||
|
"content": {
|
||||||
|
"application/problem+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "../definitions/Error.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -82,6 +82,10 @@
|
|||||||
"$ref": "paths/v1_short-urls_{shortCode}_visits.json"
|
"$ref": "paths/v1_short-urls_{shortCode}_visits.json"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"/rest/v{version}/mercure-info": {
|
||||||
|
"$ref": "paths/v2_mercure-info.json"
|
||||||
|
},
|
||||||
|
|
||||||
"/rest/health": {
|
"/rest/health": {
|
||||||
"$ref": "paths/health.json"
|
"$ref": "paths/health.json"
|
||||||
},
|
},
|
||||||
|
@ -9,6 +9,7 @@ use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
|
|||||||
use Laminas\ServiceManager\Factory\InvokableFactory;
|
use Laminas\ServiceManager\Factory\InvokableFactory;
|
||||||
use Mezzio\Router\Middleware\ImplicitOptionsMiddleware;
|
use Mezzio\Router\Middleware\ImplicitOptionsMiddleware;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Shlinkio\Shlink\Common\Mercure\LcobucciJwtProvider;
|
||||||
use Shlinkio\Shlink\Core\Options\AppOptions;
|
use Shlinkio\Shlink\Core\Options\AppOptions;
|
||||||
use Shlinkio\Shlink\Core\Service;
|
use Shlinkio\Shlink\Core\Service;
|
||||||
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
||||||
@ -20,6 +21,7 @@ return [
|
|||||||
ApiKeyService::class => ConfigAbstractFactory::class,
|
ApiKeyService::class => ConfigAbstractFactory::class,
|
||||||
|
|
||||||
Action\HealthAction::class => ConfigAbstractFactory::class,
|
Action\HealthAction::class => ConfigAbstractFactory::class,
|
||||||
|
Action\MercureAction::class => ConfigAbstractFactory::class,
|
||||||
Action\ShortUrl\CreateShortUrlAction::class => ConfigAbstractFactory::class,
|
Action\ShortUrl\CreateShortUrlAction::class => ConfigAbstractFactory::class,
|
||||||
Action\ShortUrl\SingleStepCreateShortUrlAction::class => ConfigAbstractFactory::class,
|
Action\ShortUrl\SingleStepCreateShortUrlAction::class => ConfigAbstractFactory::class,
|
||||||
Action\ShortUrl\EditShortUrlAction::class => ConfigAbstractFactory::class,
|
Action\ShortUrl\EditShortUrlAction::class => ConfigAbstractFactory::class,
|
||||||
@ -46,6 +48,7 @@ return [
|
|||||||
ApiKeyService::class => ['em'],
|
ApiKeyService::class => ['em'],
|
||||||
|
|
||||||
Action\HealthAction::class => [Connection::class, AppOptions::class, 'Logger_Shlink'],
|
Action\HealthAction::class => [Connection::class, AppOptions::class, 'Logger_Shlink'],
|
||||||
|
Action\MercureAction::class => [LcobucciJwtProvider::class, 'config.mercure', 'Logger_Shlink'],
|
||||||
Action\ShortUrl\CreateShortUrlAction::class => [
|
Action\ShortUrl\CreateShortUrlAction::class => [
|
||||||
Service\UrlShortener::class,
|
Service\UrlShortener::class,
|
||||||
'config.url_shortener.domain',
|
'config.url_shortener.domain',
|
||||||
|
@ -33,6 +33,8 @@ return [
|
|||||||
Action\Tag\DeleteTagsAction::getRouteDef(),
|
Action\Tag\DeleteTagsAction::getRouteDef(),
|
||||||
Action\Tag\CreateTagsAction::getRouteDef(),
|
Action\Tag\CreateTagsAction::getRouteDef(),
|
||||||
Action\Tag\UpdateTagAction::getRouteDef(),
|
Action\Tag\UpdateTagAction::getRouteDef(),
|
||||||
|
|
||||||
|
Action\MercureAction::getRouteDef(),
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
56
module/Rest/src/Action/MercureAction.php
Normal file
56
module/Rest/src/Action/MercureAction.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shlinkio\Shlink\Rest\Action;
|
||||||
|
|
||||||
|
use Cake\Chronos\Chronos;
|
||||||
|
use Laminas\Diactoros\Response\JsonResponse;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Shlinkio\Shlink\Common\Mercure\JwtProviderInterface;
|
||||||
|
use Shlinkio\Shlink\Rest\Exception\MercureException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class MercureAction extends AbstractRestAction
|
||||||
|
{
|
||||||
|
protected const ROUTE_PATH = '/mercure-info';
|
||||||
|
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
|
||||||
|
|
||||||
|
private JwtProviderInterface $jwtProvider;
|
||||||
|
private array $mercureConfig;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
JwtProviderInterface $jwtProvider,
|
||||||
|
array $mercureConfig,
|
||||||
|
?LoggerInterface $logger = null
|
||||||
|
) {
|
||||||
|
parent::__construct($logger);
|
||||||
|
$this->jwtProvider = $jwtProvider;
|
||||||
|
$this->mercureConfig = $mercureConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
|
$hubUrl = $this->mercureConfig['public_hub_url'] ?? null;
|
||||||
|
if ($hubUrl === null) {
|
||||||
|
throw MercureException::mercureNotConfigured();
|
||||||
|
}
|
||||||
|
|
||||||
|
$days = $this->mercureConfig['jwt_days_duration'] ?? 3;
|
||||||
|
$expiresAt = Chronos::now()->addDays($days);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$jwt = $this->jwtProvider->buildSubscriptionToken($expiresAt);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
throw MercureException::mercureNotConfigured($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'mercureHubUrl' => $hubUrl,
|
||||||
|
'token' => $jwt,
|
||||||
|
'jwtExpiration' => $expiresAt->toAtomString(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
30
module/Rest/src/Exception/MercureException.php
Normal file
30
module/Rest/src/Exception/MercureException.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shlinkio\Shlink\Rest\Exception;
|
||||||
|
|
||||||
|
use Fig\Http\Message\StatusCodeInterface;
|
||||||
|
use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
|
||||||
|
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class MercureException extends RuntimeException implements ProblemDetailsExceptionInterface
|
||||||
|
{
|
||||||
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
|
private const TITLE = 'Mercure integration not configured';
|
||||||
|
private const TYPE = 'MERCURE_NOT_CONFIGURED';
|
||||||
|
|
||||||
|
public static function mercureNotConfigured(?Throwable $prev = null): self
|
||||||
|
{
|
||||||
|
$e = new self('This Shlink instance is not integrated with a mercure hub.', 1, $prev);
|
||||||
|
|
||||||
|
$e->detail = $e->getMessage();
|
||||||
|
$e->title = self::TITLE;
|
||||||
|
$e->type = self::TYPE;
|
||||||
|
$e->status = StatusCodeInterface::STATUS_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
return $e;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user