diff --git a/module/Core/src/Service/UrlShortener.php b/module/Core/src/Service/UrlShortener.php index e85062b5..e6cdf947 100644 --- a/module/Core/src/Service/UrlShortener.php +++ b/module/Core/src/Service/UrlShortener.php @@ -93,7 +93,6 @@ class UrlShortener implements UrlShortenerInterface $this->checkUrlExists($url); $customSlug = $this->processCustomSlug($customSlug); - // Transactionally insert the short url, then generate the short code and finally update the short code try { $this->em->beginTransaction(); diff --git a/module/Rest/src/Action/CreateShortcodeAction.php b/module/Rest/src/Action/CreateShortcodeAction.php index 8969ee75..a4f7919b 100644 --- a/module/Rest/src/Action/CreateShortcodeAction.php +++ b/module/Rest/src/Action/CreateShortcodeAction.php @@ -8,6 +8,7 @@ use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Log\LoggerInterface; use Shlinkio\Shlink\Core\Exception\InvalidUrlException; +use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException; use Shlinkio\Shlink\Core\Service\UrlShortenerInterface; use Shlinkio\Shlink\Rest\Util\RestUtils; use Zend\Diactoros\Response\JsonResponse; @@ -57,12 +58,16 @@ class CreateShortcodeAction extends AbstractRestAction ], self::STATUS_BAD_REQUEST); } $longUrl = $postData['longUrl']; - $tags = (array) ($postData['tags'] ?? []); - $validSince = $this->getOptionalDate($postData, 'validSince'); - $validUntil = $this->getOptionalDate($postData, 'validUntil'); + $customSlug = $postData['customSlug'] ?? null; try { - $shortCode = $this->urlShortener->urlToShortCode(new Uri($longUrl), $tags, $validSince, $validUntil); + $shortCode = $this->urlShortener->urlToShortCode( + new Uri($longUrl), + (array) ($postData['tags'] ?? []), + $this->getOptionalDate($postData, 'validSince'), + $this->getOptionalDate($postData, 'validUntil'), + $customSlug + ); $shortUrl = (new Uri())->withPath($shortCode) ->withScheme($this->domainConfig['schema']) ->withHost($this->domainConfig['hostname']); @@ -81,7 +86,16 @@ class CreateShortcodeAction extends AbstractRestAction $longUrl ), ], self::STATUS_BAD_REQUEST); - } catch (\Exception $e) { + } catch (NonUniqueSlugException $e) { + $this->logger->warning('Provided non-unique slug.' . PHP_EOL . $e); + return new JsonResponse([ + 'error' => RestUtils::getRestErrorCodeFromException($e), + 'message' => sprintf( + $this->translator->translate('Provided slug %s is already in use. Try with a different one.'), + $customSlug + ), + ], self::STATUS_BAD_REQUEST); + } catch (\Throwable $e) { $this->logger->error('Unexpected error creating shortcode.' . PHP_EOL . $e); return new JsonResponse([ 'error' => RestUtils::UNKNOWN_ERROR, diff --git a/module/Rest/src/Util/RestUtils.php b/module/Rest/src/Util/RestUtils.php index f18ae72e..dcd6632e 100644 --- a/module/Rest/src/Util/RestUtils.php +++ b/module/Rest/src/Util/RestUtils.php @@ -12,6 +12,7 @@ class RestUtils const INVALID_SHORTCODE_ERROR = 'INVALID_SHORTCODE'; const INVALID_URL_ERROR = 'INVALID_URL'; const INVALID_ARGUMENT_ERROR = 'INVALID_ARGUMENT'; + const INVALID_SLUG_ERROR = 'INVALID_SLUG'; const INVALID_CREDENTIALS_ERROR = 'INVALID_CREDENTIALS'; const INVALID_AUTH_TOKEN_ERROR = 'INVALID_AUTH_TOKEN'; const INVALID_AUTHORIZATION_ERROR = 'INVALID_AUTHORIZATION'; @@ -26,6 +27,8 @@ class RestUtils return self::INVALID_SHORTCODE_ERROR; case $e instanceof Core\InvalidUrlException: return self::INVALID_URL_ERROR; + case $e instanceof Core\NonUniqueSlugException: + return self::INVALID_SLUG_ERROR; case $e instanceof Common\InvalidArgumentException: return self::INVALID_ARGUMENT_ERROR; case $e instanceof Rest\AuthenticationException: