mirror of
https://github.com/shlinkio/shlink.git
synced 2025-02-25 19:59:04 +03:00
Converted NonUniqueSlugException into a problem details exception
This commit is contained in:
parent
0d7d53ab5b
commit
c1eee2246b
5 changed files with 26 additions and 41 deletions
|
@ -4,10 +4,19 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Shlinkio\Shlink\Core\Exception;
|
namespace Shlinkio\Shlink\Core\Exception;
|
||||||
|
|
||||||
|
use Fig\Http\Message\StatusCodeInterface;
|
||||||
|
use Zend\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
|
||||||
|
use Zend\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
|
||||||
|
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
|
|
||||||
class NonUniqueSlugException extends InvalidArgumentException
|
class NonUniqueSlugException extends InvalidArgumentException implements ProblemDetailsExceptionInterface
|
||||||
{
|
{
|
||||||
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
|
private const TITLE = 'Invalid custom slug';
|
||||||
|
public const TYPE = 'INVALID_SLUG';
|
||||||
|
|
||||||
public static function fromSlug(string $slug, ?string $domain): self
|
public static function fromSlug(string $slug, ?string $domain): self
|
||||||
{
|
{
|
||||||
$suffix = '';
|
$suffix = '';
|
||||||
|
@ -15,6 +24,13 @@ class NonUniqueSlugException extends InvalidArgumentException
|
||||||
$suffix = sprintf(' for domain "%s"', $domain);
|
$suffix = sprintf(' for domain "%s"', $domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new self(sprintf('Provided slug "%s" is not unique%s.', $slug, $suffix));
|
$e = new self(sprintf('Provided slug "%s" is already in use%s.', $slug, $suffix));
|
||||||
|
|
||||||
|
$e->detail = $e->getMessage();
|
||||||
|
$e->title = self::TITLE;
|
||||||
|
$e->type = self::TYPE;
|
||||||
|
$e->status = StatusCodeInterface::STATUS_BAD_REQUEST;
|
||||||
|
|
||||||
|
return $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@ class NonUniqueSlugExceptionTest extends TestCase
|
||||||
public function provideMessages(): iterable
|
public function provideMessages(): iterable
|
||||||
{
|
{
|
||||||
yield 'without domain' => [
|
yield 'without domain' => [
|
||||||
'Provided slug "foo" is not unique.',
|
'Provided slug "foo" is already in use.',
|
||||||
'foo',
|
'foo',
|
||||||
null,
|
null,
|
||||||
];
|
];
|
||||||
yield 'with domain' => [
|
yield 'with domain' => [
|
||||||
'Provided slug "baz" is not unique for domain "bar".',
|
'Provided slug "baz" is already in use for domain "bar".',
|
||||||
'baz',
|
'baz',
|
||||||
'bar',
|
'bar',
|
||||||
];
|
];
|
||||||
|
|
|
@ -7,7 +7,6 @@ namespace Shlinkio\Shlink\Rest\Action\ShortUrl;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
|
||||||
use Shlinkio\Shlink\Core\Exception\ValidationException;
|
use Shlinkio\Shlink\Core\Exception\ValidationException;
|
||||||
use Shlinkio\Shlink\Core\Model\CreateShortUrlData;
|
use Shlinkio\Shlink\Core\Model\CreateShortUrlData;
|
||||||
use Shlinkio\Shlink\Core\Service\UrlShortenerInterface;
|
use Shlinkio\Shlink\Core\Service\UrlShortenerInterface;
|
||||||
|
@ -16,8 +15,6 @@ use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
||||||
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
||||||
use Zend\Diactoros\Response\JsonResponse;
|
use Zend\Diactoros\Response\JsonResponse;
|
||||||
|
|
||||||
use function sprintf;
|
|
||||||
|
|
||||||
abstract class AbstractCreateShortUrlAction extends AbstractRestAction
|
abstract class AbstractCreateShortUrlAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
/** @var UrlShortenerInterface */
|
/** @var UrlShortenerInterface */
|
||||||
|
@ -52,21 +49,13 @@ abstract class AbstractCreateShortUrlAction extends AbstractRestAction
|
||||||
}
|
}
|
||||||
|
|
||||||
$longUrl = $shortUrlData->getLongUrl();
|
$longUrl = $shortUrlData->getLongUrl();
|
||||||
|
$tags = $shortUrlData->getTags();
|
||||||
$shortUrlMeta = $shortUrlData->getMeta();
|
$shortUrlMeta = $shortUrlData->getMeta();
|
||||||
|
|
||||||
try {
|
$shortUrl = $this->urlShortener->urlToShortCode($longUrl, $tags, $shortUrlMeta);
|
||||||
$shortUrl = $this->urlShortener->urlToShortCode($longUrl, $shortUrlData->getTags(), $shortUrlMeta);
|
$transformer = new ShortUrlDataTransformer($this->domainConfig);
|
||||||
$transformer = new ShortUrlDataTransformer($this->domainConfig);
|
|
||||||
|
|
||||||
return new JsonResponse($transformer->transform($shortUrl));
|
return new JsonResponse($transformer->transform($shortUrl));
|
||||||
} catch (NonUniqueSlugException $e) {
|
|
||||||
$customSlug = $shortUrlMeta->getCustomSlug();
|
|
||||||
$this->logger->warning('Provided non-unique slug. {e}', ['e' => $e]);
|
|
||||||
return new JsonResponse([
|
|
||||||
'error' => RestUtils::getRestErrorCodeFromException($e),
|
|
||||||
'message' => sprintf('Provided slug %s is already in use. Try with a different one.', $customSlug),
|
|
||||||
], self::STATUS_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,7 +19,8 @@ class RestUtils
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
public const INVALID_URL_ERROR = Core\InvalidUrlException::TYPE;
|
public const INVALID_URL_ERROR = Core\InvalidUrlException::TYPE;
|
||||||
public const INVALID_ARGUMENT_ERROR = 'INVALID_ARGUMENT';
|
public const INVALID_ARGUMENT_ERROR = 'INVALID_ARGUMENT';
|
||||||
public const INVALID_SLUG_ERROR = 'INVALID_SLUG';
|
/** @deprecated */
|
||||||
|
public const INVALID_SLUG_ERROR = Core\NonUniqueSlugException::TYPE;
|
||||||
public const INVALID_CREDENTIALS_ERROR = 'INVALID_CREDENTIALS';
|
public const INVALID_CREDENTIALS_ERROR = 'INVALID_CREDENTIALS';
|
||||||
public const INVALID_AUTH_TOKEN_ERROR = 'INVALID_AUTH_TOKEN';
|
public const INVALID_AUTH_TOKEN_ERROR = 'INVALID_AUTH_TOKEN';
|
||||||
public const INVALID_AUTHORIZATION_ERROR = 'INVALID_AUTHORIZATION';
|
public const INVALID_AUTHORIZATION_ERROR = 'INVALID_AUTHORIZATION';
|
||||||
|
|
|
@ -8,8 +8,6 @@ use PHPUnit\Framework\TestCase;
|
||||||
use Prophecy\Argument;
|
use Prophecy\Argument;
|
||||||
use Prophecy\Prophecy\ObjectProphecy;
|
use Prophecy\Prophecy\ObjectProphecy;
|
||||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||||
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
|
|
||||||
use Shlinkio\Shlink\Core\Service\UrlShortener;
|
use Shlinkio\Shlink\Core\Service\UrlShortener;
|
||||||
use Shlinkio\Shlink\Rest\Action\ShortUrl\CreateShortUrlAction;
|
use Shlinkio\Shlink\Rest\Action\ShortUrl\CreateShortUrlAction;
|
||||||
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
||||||
|
@ -88,23 +86,4 @@ class CreateShortUrlActionTest extends TestCase
|
||||||
yield ['127.0.0.1'];
|
yield ['127.0.0.1'];
|
||||||
yield ['???/&%$&'];
|
yield ['???/&%$&'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
|
||||||
public function nonUniqueSlugReturnsError(): void
|
|
||||||
{
|
|
||||||
$this->urlShortener->urlToShortCode(
|
|
||||||
Argument::type(Uri::class),
|
|
||||||
Argument::type('array'),
|
|
||||||
ShortUrlMeta::createFromRawData(['customSlug' => 'foo']),
|
|
||||||
Argument::cetera()
|
|
||||||
)->willThrow(NonUniqueSlugException::class)->shouldBeCalledOnce();
|
|
||||||
|
|
||||||
$request = (new ServerRequest())->withParsedBody([
|
|
||||||
'longUrl' => 'http://www.domain.com/foo/bar',
|
|
||||||
'customSlug' => 'foo',
|
|
||||||
]);
|
|
||||||
$response = $this->action->handle($request);
|
|
||||||
$this->assertEquals(400, $response->getStatusCode());
|
|
||||||
$this->assertStringContainsString(RestUtils::INVALID_SLUG_ERROR, (string) $response->getBody());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue