mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-27 16:26:37 +03:00
Created and registered middleware which replaces short-code from short-url on rest paths
This commit is contained in:
parent
622edd2ed1
commit
7ab993b764
11 changed files with 109 additions and 27 deletions
|
@ -1,12 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Shlinkio\Shlink\Common\Middleware\LocaleMiddleware;
|
namespace Shlinkio\Shlink;
|
||||||
use Shlinkio\Shlink\Core\Response\NotFoundHandler;
|
|
||||||
use Shlinkio\Shlink\Rest\Middleware\BodyParserMiddleware;
|
|
||||||
use Shlinkio\Shlink\Rest\Middleware\CheckAuthenticationMiddleware;
|
|
||||||
use Shlinkio\Shlink\Rest\Middleware\CrossDomainMiddleware;
|
|
||||||
use Shlinkio\Shlink\Rest\Middleware\PathVersionMiddleware;
|
|
||||||
use Zend\Expressive;
|
use Zend\Expressive;
|
||||||
use Zend\Stratigility\Middleware\ErrorHandler;
|
use Zend\Stratigility\Middleware\ErrorHandler;
|
||||||
|
|
||||||
|
@ -17,14 +13,15 @@ return [
|
||||||
'middleware' => [
|
'middleware' => [
|
||||||
ErrorHandler::class,
|
ErrorHandler::class,
|
||||||
Expressive\Helper\ContentLengthMiddleware::class,
|
Expressive\Helper\ContentLengthMiddleware::class,
|
||||||
LocaleMiddleware::class,
|
Common\Middleware\LocaleMiddleware::class,
|
||||||
],
|
],
|
||||||
'priority' => 11,
|
'priority' => 12,
|
||||||
],
|
],
|
||||||
'pre-routing-rest' => [
|
'pre-routing-rest' => [
|
||||||
'path' => '/rest',
|
'path' => '/rest',
|
||||||
'middleware' => [
|
'middleware' => [
|
||||||
PathVersionMiddleware::class,
|
Rest\Middleware\PathVersionMiddleware::class,
|
||||||
|
Rest\Middleware\ShortUrl\ShortCodePathMiddleware::class,
|
||||||
],
|
],
|
||||||
'priority' => 11,
|
'priority' => 11,
|
||||||
],
|
],
|
||||||
|
@ -39,10 +36,10 @@ return [
|
||||||
'rest' => [
|
'rest' => [
|
||||||
'path' => '/rest',
|
'path' => '/rest',
|
||||||
'middleware' => [
|
'middleware' => [
|
||||||
CrossDomainMiddleware::class,
|
Rest\Middleware\CrossDomainMiddleware::class,
|
||||||
Expressive\Router\Middleware\ImplicitOptionsMiddleware::class,
|
Expressive\Router\Middleware\ImplicitOptionsMiddleware::class,
|
||||||
BodyParserMiddleware::class,
|
Rest\Middleware\BodyParserMiddleware::class,
|
||||||
CheckAuthenticationMiddleware::class,
|
Rest\Middleware\CheckAuthenticationMiddleware::class,
|
||||||
],
|
],
|
||||||
'priority' => 5,
|
'priority' => 5,
|
||||||
],
|
],
|
||||||
|
@ -50,7 +47,7 @@ return [
|
||||||
'post-routing' => [
|
'post-routing' => [
|
||||||
'middleware' => [
|
'middleware' => [
|
||||||
Expressive\Router\Middleware\DispatchMiddleware::class,
|
Expressive\Router\Middleware\DispatchMiddleware::class,
|
||||||
NotFoundHandler::class,
|
Core\Response\NotFoundHandler::class,
|
||||||
],
|
],
|
||||||
'priority' => 1,
|
'priority' => 1,
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shlinkio\Shlink\Rest;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
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\Action;
|
|
||||||
use Shlinkio\Shlink\Rest\Authentication\JWTService;
|
|
||||||
use Shlinkio\Shlink\Rest\Middleware;
|
|
||||||
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
||||||
use Zend\I18n\Translator\Translator;
|
use Zend\I18n\Translator\Translator;
|
||||||
use Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory;
|
use Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory;
|
||||||
|
@ -16,7 +15,7 @@ return [
|
||||||
|
|
||||||
'dependencies' => [
|
'dependencies' => [
|
||||||
'factories' => [
|
'factories' => [
|
||||||
JWTService::class => ConfigAbstractFactory::class,
|
Authentication\JWTService::class => ConfigAbstractFactory::class,
|
||||||
ApiKeyService::class => ConfigAbstractFactory::class,
|
ApiKeyService::class => ConfigAbstractFactory::class,
|
||||||
|
|
||||||
Action\AuthenticateAction::class => ConfigAbstractFactory::class,
|
Action\AuthenticateAction::class => ConfigAbstractFactory::class,
|
||||||
|
@ -38,14 +37,20 @@ return [
|
||||||
Middleware\PathVersionMiddleware::class => InvokableFactory::class,
|
Middleware\PathVersionMiddleware::class => InvokableFactory::class,
|
||||||
Middleware\CheckAuthenticationMiddleware::class => ConfigAbstractFactory::class,
|
Middleware\CheckAuthenticationMiddleware::class => ConfigAbstractFactory::class,
|
||||||
Middleware\ShortUrl\CreateShortUrlContentNegotiationMiddleware::class => InvokableFactory::class,
|
Middleware\ShortUrl\CreateShortUrlContentNegotiationMiddleware::class => InvokableFactory::class,
|
||||||
|
Middleware\ShortUrl\ShortCodePathMiddleware::class => InvokableFactory::class,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
ConfigAbstractFactory::class => [
|
ConfigAbstractFactory::class => [
|
||||||
JWTService::class => [AppOptions::class],
|
Authentication\JWTService::class => [AppOptions::class],
|
||||||
ApiKeyService::class => ['em'],
|
ApiKeyService::class => ['em'],
|
||||||
|
|
||||||
Action\AuthenticateAction::class => [ApiKeyService::class, JWTService::class, 'translator', 'Logger_Shlink'],
|
Action\AuthenticateAction::class => [
|
||||||
|
ApiKeyService::class,
|
||||||
|
Authentication\JWTService::class,
|
||||||
|
'translator',
|
||||||
|
'Logger_Shlink',
|
||||||
|
],
|
||||||
Action\ShortUrl\CreateShortUrlAction::class => [
|
Action\ShortUrl\CreateShortUrlAction::class => [
|
||||||
Service\UrlShortener::class,
|
Service\UrlShortener::class,
|
||||||
'translator',
|
'translator',
|
||||||
|
@ -88,7 +93,7 @@ return [
|
||||||
Action\Tag\UpdateTagAction::class => [Service\Tag\TagService::class, Translator::class, LoggerInterface::class],
|
Action\Tag\UpdateTagAction::class => [Service\Tag\TagService::class, Translator::class, LoggerInterface::class],
|
||||||
|
|
||||||
Middleware\CheckAuthenticationMiddleware::class => [
|
Middleware\CheckAuthenticationMiddleware::class => [
|
||||||
JWTService::class,
|
Authentication\JWTService::class,
|
||||||
'translator',
|
'translator',
|
||||||
'config.auth.routes_whitelist',
|
'config.auth.routes_whitelist',
|
||||||
'Logger_Shlink',
|
'Logger_Shlink',
|
||||||
|
|
|
@ -12,7 +12,7 @@ use Zend\Diactoros\Uri;
|
||||||
|
|
||||||
class CreateShortUrlAction extends AbstractCreateShortUrlAction
|
class CreateShortUrlAction extends AbstractCreateShortUrlAction
|
||||||
{
|
{
|
||||||
protected const ROUTE_PATH = '/short-codes';
|
protected const ROUTE_PATH = '/short-urls';
|
||||||
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_POST];
|
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_POST];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,7 +16,7 @@ use Zend\I18n\Translator\TranslatorInterface;
|
||||||
|
|
||||||
class DeleteShortUrlAction extends AbstractRestAction
|
class DeleteShortUrlAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
protected const ROUTE_PATH = '/short-codes/{shortCode}';
|
protected const ROUTE_PATH = '/short-urls/{shortCode}';
|
||||||
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
|
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,7 @@ use Zend\I18n\Translator\TranslatorInterface;
|
||||||
|
|
||||||
class EditShortUrlAction extends AbstractRestAction
|
class EditShortUrlAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
protected const ROUTE_PATH = '/short-codes/{shortCode}';
|
protected const ROUTE_PATH = '/short-urls/{shortCode}';
|
||||||
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
|
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,7 +15,7 @@ use Zend\I18n\Translator\TranslatorInterface;
|
||||||
|
|
||||||
class EditShortUrlTagsAction extends AbstractRestAction
|
class EditShortUrlTagsAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
protected const ROUTE_PATH = '/short-codes/{shortCode}/tags';
|
protected const ROUTE_PATH = '/short-urls/{shortCode}/tags';
|
||||||
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
|
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,7 +18,7 @@ class ListShortUrlsAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
use PaginatorUtilsTrait;
|
use PaginatorUtilsTrait;
|
||||||
|
|
||||||
protected const ROUTE_PATH = '/short-codes';
|
protected const ROUTE_PATH = '/short-urls';
|
||||||
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
|
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,7 @@ use Zend\I18n\Translator\TranslatorInterface;
|
||||||
|
|
||||||
class ResolveShortUrlAction extends AbstractRestAction
|
class ResolveShortUrlAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
protected const ROUTE_PATH = '/short-codes/{shortCode}';
|
protected const ROUTE_PATH = '/short-urls/{shortCode}';
|
||||||
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
|
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,7 +15,7 @@ use Zend\I18n\Translator\TranslatorInterface;
|
||||||
|
|
||||||
class SingleStepCreateShortUrlAction extends AbstractCreateShortUrlAction
|
class SingleStepCreateShortUrlAction extends AbstractCreateShortUrlAction
|
||||||
{
|
{
|
||||||
protected const ROUTE_PATH = '/short-codes/shorten';
|
protected const ROUTE_PATH = '/short-urls/shorten';
|
||||||
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
|
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shlinkio\Shlink\Rest\Middleware\ShortUrl;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
|
||||||
|
class ShortCodePathMiddleware implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
private const OLD_PATH_PREFIX = '/short-codes';
|
||||||
|
private const NEW_PATH_PREFIX = '/short-urls';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an incoming server request and return a response, optionally delegating
|
||||||
|
* response creation to a handler.
|
||||||
|
*/
|
||||||
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
|
{
|
||||||
|
$uri = $request->getUri();
|
||||||
|
$path = $uri->getPath();
|
||||||
|
|
||||||
|
// If the path starts with the old prefix, replace it by the new one
|
||||||
|
return $handler->handle(
|
||||||
|
$request->withUri($uri->withPath(\str_replace(self::OLD_PATH_PREFIX, self::NEW_PATH_PREFIX, $path)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace ShlinkioTest\Shlink\Rest\Middleware\ShortUrl;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\Assert;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Prophecy\Argument;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Message\UriInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use Shlinkio\Shlink\Rest\Middleware\ShortUrl\ShortCodePathMiddleware;
|
||||||
|
use Zend\Diactoros\Response;
|
||||||
|
use Zend\Diactoros\Uri;
|
||||||
|
|
||||||
|
class ShortCodePathMiddlewareTest extends TestCase
|
||||||
|
{
|
||||||
|
private $middleware;
|
||||||
|
private $requestHandler;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->middleware = new ShortCodePathMiddleware();
|
||||||
|
$this->requestHandler = $this->prophesize(RequestHandlerInterface::class);
|
||||||
|
$this->requestHandler->handle(Argument::type(ServerRequestInterface::class))->willReturn(new Response());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function properlyReplacesTheOldPathByTheNewOne()
|
||||||
|
{
|
||||||
|
$uri = new Uri('/short-codes/foo');
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getUri()->willReturn($uri);
|
||||||
|
$withUri = $request->withUri(Argument::that(function (UriInterface $uri) {
|
||||||
|
$path = $uri->getPath();
|
||||||
|
|
||||||
|
Assert::assertContains('/short-urls', $path);
|
||||||
|
Assert::assertNotContains('/short-codes', $path);
|
||||||
|
|
||||||
|
return $uri;
|
||||||
|
}))->willReturn($request->reveal());
|
||||||
|
|
||||||
|
$this->middleware->process($request->reveal(), $this->requestHandler->reveal());
|
||||||
|
|
||||||
|
$withUri->shouldHaveBeenCalledTimes(1);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue