mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-25 06:11:11 +03:00
Implemented EditShortCodeAction
This commit is contained in:
parent
7ba9eb8e2c
commit
84094a51a2
7 changed files with 189 additions and 13 deletions
|
@ -9,7 +9,7 @@ return [
|
|||
'routes' => [
|
||||
[
|
||||
'name' => Action\AuthenticateAction::class,
|
||||
'path' => '/rest/v{version:1}/authenticate',
|
||||
'path' => '/authenticate',
|
||||
'middleware' => Action\AuthenticateAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_POST],
|
||||
],
|
||||
|
@ -17,25 +17,31 @@ return [
|
|||
// Short codes
|
||||
[
|
||||
'name' => Action\CreateShortcodeAction::class,
|
||||
'path' => '/rest/v{version:1}/short-codes',
|
||||
'path' => '/short-codes',
|
||||
'middleware' => Action\CreateShortcodeAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_POST],
|
||||
],
|
||||
[
|
||||
'name' => Action\EditShortCodeAction::class,
|
||||
'path' => '/short-codes/{shortCode}',
|
||||
'middleware' => Action\EditShortCodeAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_PUT],
|
||||
],
|
||||
[
|
||||
'name' => Action\ResolveUrlAction::class,
|
||||
'path' => '/rest/v{version:1}/short-codes/{shortCode}',
|
||||
'path' => '/short-codes/{shortCode}',
|
||||
'middleware' => Action\ResolveUrlAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_GET],
|
||||
],
|
||||
[
|
||||
'name' => Action\ListShortcodesAction::class,
|
||||
'path' => '/rest/v{version:1}/short-codes',
|
||||
'path' => '/short-codes',
|
||||
'middleware' => Action\ListShortcodesAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_GET],
|
||||
],
|
||||
[
|
||||
'name' => Action\EditShortcodeTagsAction::class,
|
||||
'path' => '/rest/v{version:1}/short-codes/{shortCode}/tags',
|
||||
'path' => '/short-codes/{shortCode}/tags',
|
||||
'middleware' => Action\EditShortcodeTagsAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_PUT],
|
||||
],
|
||||
|
@ -43,7 +49,7 @@ return [
|
|||
// Visits
|
||||
[
|
||||
'name' => Action\GetVisitsAction::class,
|
||||
'path' => '/rest/v{version:1}/short-codes/{shortCode}/visits',
|
||||
'path' => '/short-codes/{shortCode}/visits',
|
||||
'middleware' => Action\GetVisitsAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_GET],
|
||||
],
|
||||
|
@ -51,25 +57,25 @@ return [
|
|||
// Tags
|
||||
[
|
||||
'name' => Action\Tag\ListTagsAction::class,
|
||||
'path' => '/rest/v{version:1}/tags',
|
||||
'path' => '/tags',
|
||||
'middleware' => Action\Tag\ListTagsAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_GET],
|
||||
],
|
||||
[
|
||||
'name' => Action\Tag\DeleteTagsAction::class,
|
||||
'path' => '/rest/v{version:1}/tags',
|
||||
'path' => '/tags',
|
||||
'middleware' => Action\Tag\DeleteTagsAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_DELETE],
|
||||
],
|
||||
[
|
||||
'name' => Action\Tag\CreateTagsAction::class,
|
||||
'path' => '/rest/v{version:1}/tags',
|
||||
'path' => '/tags',
|
||||
'middleware' => Action\Tag\CreateTagsAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_POST],
|
||||
],
|
||||
[
|
||||
'name' => Action\Tag\UpdateTagAction::class,
|
||||
'path' => '/rest/v{version:1}/tags',
|
||||
'path' => '/tags',
|
||||
'middleware' => Action\Tag\UpdateTagAction::class,
|
||||
'allowed_methods' => [RequestMethod::METHOD_PUT],
|
||||
],
|
||||
|
|
|
@ -6,9 +6,36 @@ namespace Shlinkio\Shlink\Rest\Action;
|
|||
use Interop\Http\ServerMiddleware\DelegateInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Shlinkio\Shlink\Core\Exception;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
|
||||
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
|
||||
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
use Zend\Diactoros\Response\JsonResponse;
|
||||
use Zend\I18n\Translator\TranslatorInterface;
|
||||
|
||||
class EditShortCodeAction extends AbstractRestAction
|
||||
{
|
||||
/**
|
||||
* @var ShortUrlServiceInterface
|
||||
*/
|
||||
private $shortUrlService;
|
||||
/**
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
private $translator;
|
||||
|
||||
public function __construct(
|
||||
ShortUrlServiceInterface $shortUrlService,
|
||||
TranslatorInterface $translator,
|
||||
LoggerInterface $logger = null
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
$this->shortUrlService = $shortUrlService;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an incoming server request and return a response, optionally delegating
|
||||
* to the next middleware component to create the response.
|
||||
|
@ -17,8 +44,31 @@ class EditShortCodeAction extends AbstractRestAction
|
|||
* @param DelegateInterface $delegate
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, DelegateInterface $delegate): ResponseInterface
|
||||
{
|
||||
$postData = (array) $request->getParsedBody();
|
||||
$shortCode = $request->getAttribute('shortCode', '');
|
||||
|
||||
try {
|
||||
$this->shortUrlService->updateMetadataByShortCode(
|
||||
$shortCode,
|
||||
ShortUrlMeta::createFromRawData($postData)
|
||||
);
|
||||
return new EmptyResponse();
|
||||
} catch (Exception\InvalidShortCodeException $e) {
|
||||
$this->logger->warning('Provided data is invalid.' . PHP_EOL . $e);
|
||||
return new JsonResponse([
|
||||
'error' => RestUtils::getRestErrorCodeFromException($e),
|
||||
'message' => \sprintf($this->translator->translate('No URL found for short code "%s"'), $shortCode),
|
||||
], self::STATUS_NOT_FOUND);
|
||||
} catch (Exception\ValidationException $e) {
|
||||
$this->logger->warning('Provided data is invalid.' . PHP_EOL . $e);
|
||||
return new JsonResponse([
|
||||
'error' => RestUtils::getRestErrorCodeFromException($e),
|
||||
'message' => $this->translator->translate('Provided data is invalid.'),
|
||||
], self::STATUS_BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,24 @@ use Zend\Stdlib\Glob;
|
|||
|
||||
class ConfigProvider
|
||||
{
|
||||
const ROUTES_PREFIX = '/rest/v{version:1}';
|
||||
|
||||
public function __invoke()
|
||||
{
|
||||
return Factory::fromFiles(Glob::glob(__DIR__ . '/../config/{,*.}config.php', Glob::GLOB_BRACE));
|
||||
return $this->applyRoutesPrefix(
|
||||
Factory::fromFiles(Glob::glob(__DIR__ . '/../config/{,*.}config.php', Glob::GLOB_BRACE))
|
||||
);
|
||||
}
|
||||
|
||||
private function applyRoutesPrefix(array $config): array
|
||||
{
|
||||
$routes =& $config['routes'] ?? [];
|
||||
|
||||
// Prepend the routes prefix to every path
|
||||
foreach ($routes as $key => $route) {
|
||||
$routes[$key]['path'] = self::ROUTES_PREFIX . $route['path'];
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class RestUtils
|
|||
case $e instanceof Core\NonUniqueSlugException:
|
||||
return self::INVALID_SLUG_ERROR;
|
||||
case $e instanceof Common\InvalidArgumentException:
|
||||
case $e instanceof Core\ValidationException:
|
||||
return self::INVALID_ARGUMENT_ERROR;
|
||||
case $e instanceof Rest\AuthenticationException:
|
||||
return self::INVALID_CREDENTIALS_ERROR;
|
||||
|
|
93
module/Rest/test/Action/EditShortCodeActionTest.php
Normal file
93
module/Rest/test/Action/EditShortCodeActionTest.php
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\Rest\Action;
|
||||
|
||||
use Interop\Http\ServerMiddleware\DelegateInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||
use Shlinkio\Shlink\Core\Exception\InvalidShortCodeException;
|
||||
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
|
||||
use Shlinkio\Shlink\Rest\Action\EditShortCodeAction;
|
||||
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
||||
use Zend\Diactoros\Response\JsonResponse;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
use Zend\I18n\Translator\Translator;
|
||||
|
||||
class EditShortCodeActionTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var EditShortCodeAction
|
||||
*/
|
||||
private $action;
|
||||
/**
|
||||
* @var ObjectProphecy
|
||||
*/
|
||||
private $shortUrlService;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->shortUrlService = $this->prophesize(ShortUrlServiceInterface::class);
|
||||
$this->action = new EditShortCodeAction($this->shortUrlService->reveal(), Translator::factory([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function invalidDataReturnsError()
|
||||
{
|
||||
$request = ServerRequestFactory::fromGlobals()->withParsedBody([
|
||||
'maxVisits' => 'invalid',
|
||||
]);
|
||||
|
||||
/** @var JsonResponse $resp */
|
||||
$resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal());
|
||||
$payload = $resp->getPayload();
|
||||
|
||||
$this->assertEquals(400, $resp->getStatusCode());
|
||||
$this->assertEquals(RestUtils::INVALID_ARGUMENT_ERROR, $payload['error']);
|
||||
$this->assertEquals('Provided data is invalid.', $payload['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function incorrectShortCodeReturnsError()
|
||||
{
|
||||
$request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', 'abc123')
|
||||
->withParsedBody([
|
||||
'maxVisits' => 5,
|
||||
]);
|
||||
$updateMeta = $this->shortUrlService->updateMetadataByShortCode(Argument::cetera())->willThrow(
|
||||
InvalidShortCodeException::class
|
||||
);
|
||||
|
||||
/** @var JsonResponse $resp */
|
||||
$resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal());
|
||||
$payload = $resp->getPayload();
|
||||
|
||||
$this->assertEquals(404, $resp->getStatusCode());
|
||||
$this->assertEquals(RestUtils::INVALID_SHORTCODE_ERROR, $payload['error']);
|
||||
$this->assertEquals('No URL found for short code "abc123"', $payload['message']);
|
||||
$updateMeta->shouldHaveBeenCalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function correctShortCodeReturnsSuccess()
|
||||
{
|
||||
$request = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', 'abc123')
|
||||
->withParsedBody([
|
||||
'maxVisits' => 5,
|
||||
]);
|
||||
$updateMeta = $this->shortUrlService->updateMetadataByShortCode(Argument::cetera())->willReturn(new ShortUrl());
|
||||
|
||||
$resp = $this->action->process($request, $this->prophesize(DelegateInterface::class)->reveal());
|
||||
|
||||
$this->assertEquals(204, $resp->getStatusCode());
|
||||
$updateMeta->shouldHaveBeenCalled();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
<phpunit bootstrap="./func_tests_bootstrap.php" colors="true">
|
||||
<?xml version="1.0"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.5/phpunit.xsd"
|
||||
bootstrap="./func_tests_bootstrap.php"
|
||||
colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Shlink functional database tests">
|
||||
<directory>./module/*/test-func</directory>
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<phpunit bootstrap="./vendor/autoload.php" colors="true">
|
||||
<?xml version="1.0"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.5/phpunit.xsd"
|
||||
bootstrap="./vendor/autoload.php"
|
||||
colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Common">
|
||||
<directory>./module/Common/test</directory>
|
||||
|
|
Loading…
Reference in a new issue