From e5ef8d7f8c15b8cb90bf0414d6c8715c6417975b Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 3 May 2018 13:21:43 +0200 Subject: [PATCH] Created action which allows short URLs to be created on a single API request --- module/Rest/config/auth.config.php | 1 + module/Rest/config/dependencies.config.php | 8 +++ module/Rest/config/routes.config.php | 7 +-- .../Rest/src/Action/CreateShortCodeAction.php | 4 +- .../AbstractCreateShortCodeAction.php | 8 +-- .../SingleStepCreateShortCodeAction.php | 61 +++++++++++++++++++ module/Rest/src/Service/ApiKeyService.php | 10 +-- .../src/Service/ApiKeyServiceInterface.php | 8 +-- 8 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 module/Rest/src/Action/ShortCode/SingleStepCreateShortCodeAction.php diff --git a/module/Rest/config/auth.config.php b/module/Rest/config/auth.config.php index ab3e1319..b43c333f 100644 --- a/module/Rest/config/auth.config.php +++ b/module/Rest/config/auth.config.php @@ -8,6 +8,7 @@ return [ 'auth' => [ 'routes_whitelist' => [ Action\AuthenticateAction::class, + Action\ShortCode\SingleStepCreateShortCodeAction::class, ], ], diff --git a/module/Rest/config/dependencies.config.php b/module/Rest/config/dependencies.config.php index e4244278..e0d9ede9 100644 --- a/module/Rest/config/dependencies.config.php +++ b/module/Rest/config/dependencies.config.php @@ -21,6 +21,7 @@ return [ Action\AuthenticateAction::class => ConfigAbstractFactory::class, Action\CreateShortCodeAction::class => ConfigAbstractFactory::class, + Action\ShortCode\SingleStepCreateShortCodeAction::class => ConfigAbstractFactory::class, Action\EditShortCodeAction::class => ConfigAbstractFactory::class, Action\ResolveUrlAction::class => ConfigAbstractFactory::class, Action\GetVisitsAction::class => ConfigAbstractFactory::class, @@ -49,6 +50,13 @@ return [ 'config.url_shortener.domain', 'Logger_Shlink', ], + Action\ShortCode\SingleStepCreateShortCodeAction::class => [ + Service\UrlShortener::class, + 'translator', + ApiKeyService::class, + 'config.url_shortener.domain', + 'Logger_Shlink', + ], Action\EditShortCodeAction::class => [Service\ShortUrlService::class, 'translator', 'Logger_Shlink',], Action\ResolveUrlAction::class => [Service\UrlShortener::class, 'translator'], Action\GetVisitsAction::class => [Service\VisitsTracker::class, 'translator', 'Logger_Shlink'], diff --git a/module/Rest/config/routes.config.php b/module/Rest/config/routes.config.php index dac29510..f11078ce 100644 --- a/module/Rest/config/routes.config.php +++ b/module/Rest/config/routes.config.php @@ -10,12 +10,7 @@ return [ // Short codes Action\CreateShortCodeAction::getRouteDef(), -// [ -// 'name' => Action\CreateShortCodeAction::class, -// 'path' => '/short-codes', -// 'middleware' => Action\CreateShortCodeAction::class, -// 'allowed_methods' => [RequestMethod::METHOD_GET], -// ], + Action\ShortCode\SingleStepCreateShortCodeAction::getRouteDef(), Action\EditShortCodeAction::getRouteDef(), Action\ResolveUrlAction::getRouteDef(), Action\ListShortCodesAction::getRouteDef(), diff --git a/module/Rest/src/Action/CreateShortCodeAction.php b/module/Rest/src/Action/CreateShortCodeAction.php index 382e8ac5..3e8ad560 100644 --- a/module/Rest/src/Action/CreateShortCodeAction.php +++ b/module/Rest/src/Action/CreateShortCodeAction.php @@ -5,7 +5,6 @@ namespace Shlinkio\Shlink\Rest\Action; use Psr\Http\Message\ServerRequestInterface as Request; use Shlinkio\Shlink\Core\Exception\InvalidArgumentException; -use Shlinkio\Shlink\Core\Exception\ValidationException; use Shlinkio\Shlink\Core\Model\CreateShortCodeData; use Shlinkio\Shlink\Core\Model\ShortUrlMeta; use Shlinkio\Shlink\Rest\Action\ShortCode\AbstractCreateShortCodeAction; @@ -19,7 +18,6 @@ class CreateShortCodeAction extends AbstractCreateShortCodeAction /** * @param Request $request * @return CreateShortCodeData - * @throws ValidationException * @throws InvalidArgumentException * @throws \InvalidArgumentException */ @@ -27,7 +25,7 @@ class CreateShortCodeAction extends AbstractCreateShortCodeAction { $postData = (array) $request->getParsedBody(); if (! isset($postData['longUrl'])) { - throw new InvalidArgumentException('A URL was not provided'); + throw new InvalidArgumentException($this->translator->translate('A URL was not provided')); } return new CreateShortCodeData( diff --git a/module/Rest/src/Action/ShortCode/AbstractCreateShortCodeAction.php b/module/Rest/src/Action/ShortCode/AbstractCreateShortCodeAction.php index 33978675..6d7ba5f2 100644 --- a/module/Rest/src/Action/ShortCode/AbstractCreateShortCodeAction.php +++ b/module/Rest/src/Action/ShortCode/AbstractCreateShortCodeAction.php @@ -9,7 +9,6 @@ use Psr\Log\LoggerInterface; use Shlinkio\Shlink\Core\Exception\InvalidArgumentException; use Shlinkio\Shlink\Core\Exception\InvalidUrlException; use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException; -use Shlinkio\Shlink\Core\Exception\ValidationException; use Shlinkio\Shlink\Core\Model\CreateShortCodeData; use Shlinkio\Shlink\Core\Service\UrlShortenerInterface; use Shlinkio\Shlink\Rest\Action\AbstractRestAction; @@ -31,7 +30,7 @@ abstract class AbstractCreateShortCodeAction extends AbstractRestAction /** * @var TranslatorInterface */ - private $translator; + protected $translator; public function __construct( UrlShortenerInterface $urlShortener, @@ -57,11 +56,11 @@ abstract class AbstractCreateShortCodeAction extends AbstractRestAction $shortCodeMeta = $shortCodeData->getMeta(); $longUrl = $shortCodeData->getLongUrl(); $customSlug = $shortCodeMeta->getCustomSlug(); - } catch (ValidationException | InvalidArgumentException $e) { + } catch (InvalidArgumentException $e) { $this->logger->warning('Provided data is invalid.' . PHP_EOL . $e); return new JsonResponse([ 'error' => RestUtils::INVALID_ARGUMENT_ERROR, - 'message' => $this->translator->translate('Provided data is invalid'), + 'message' => $e->getMessage(), ], self::STATUS_BAD_REQUEST); } @@ -114,7 +113,6 @@ abstract class AbstractCreateShortCodeAction extends AbstractRestAction /** * @param Request $request * @return CreateShortCodeData - * @throws ValidationException * @throws InvalidArgumentException */ abstract protected function buildUrlToShortCodeData(Request $request): CreateShortCodeData; diff --git a/module/Rest/src/Action/ShortCode/SingleStepCreateShortCodeAction.php b/module/Rest/src/Action/ShortCode/SingleStepCreateShortCodeAction.php new file mode 100644 index 00000000..56d81c9a --- /dev/null +++ b/module/Rest/src/Action/ShortCode/SingleStepCreateShortCodeAction.php @@ -0,0 +1,61 @@ +apiKeyService = $apiKeyService; + } + + /** + * @param Request $request + * @return CreateShortCodeData + * @throws \InvalidArgumentException + * @throws InvalidArgumentException + */ + protected function buildUrlToShortCodeData(Request $request): CreateShortCodeData + { + $query = $request->getQueryParams(); + + // Check provided API key + $apiKey = $this->apiKeyService->getByKey($query['apiKey'] ?? ''); + if ($apiKey === null || ! $apiKey->isValid()) { + throw new InvalidArgumentException( + $this->translator->translate('No API key was provided or it is not valid') + ); + } + + if (! isset($query['longUrl'])) { + throw new InvalidArgumentException($this->translator->translate('A URL was not provided')); + } + + return new CreateShortCodeData(new Uri($query['longUrl'])); + } +} diff --git a/module/Rest/src/Service/ApiKeyService.php b/module/Rest/src/Service/ApiKeyService.php index 6f368e56..e886bcf1 100644 --- a/module/Rest/src/Service/ApiKeyService.php +++ b/module/Rest/src/Service/ApiKeyService.php @@ -28,7 +28,7 @@ class ApiKeyService implements ApiKeyServiceInterface public function create(\DateTime $expirationDate = null) { $key = new ApiKey(); - if (isset($expirationDate)) { + if ($expirationDate !== null) { $key->setExpirationDate($expirationDate); } @@ -44,7 +44,7 @@ class ApiKeyService implements ApiKeyServiceInterface * @param string $key * @return bool */ - public function check($key) + public function check(string $key) { /** @var ApiKey|null $apiKey */ $apiKey = $this->getByKey($key); @@ -58,7 +58,7 @@ class ApiKeyService implements ApiKeyServiceInterface * @return ApiKey * @throws InvalidArgumentException */ - public function disable($key) + public function disable(string $key) { /** @var ApiKey|null $apiKey */ $apiKey = $this->getByKey($key); @@ -77,7 +77,7 @@ class ApiKeyService implements ApiKeyServiceInterface * @param bool $enabledOnly Tells if only enabled keys should be returned * @return ApiKey[] */ - public function listKeys($enabledOnly = false) + public function listKeys(bool $enabledOnly = false) { $conditions = $enabledOnly ? ['enabled' => true] : []; return $this->em->getRepository(ApiKey::class)->findBy($conditions); @@ -89,7 +89,7 @@ class ApiKeyService implements ApiKeyServiceInterface * @param string $key * @return ApiKey|null */ - public function getByKey($key) + public function getByKey(string $key) { /** @var ApiKey|null $apiKey */ $apiKey = $this->em->getRepository(ApiKey::class)->findOneBy([ diff --git a/module/Rest/src/Service/ApiKeyServiceInterface.php b/module/Rest/src/Service/ApiKeyServiceInterface.php index ceaa3b96..eab38503 100644 --- a/module/Rest/src/Service/ApiKeyServiceInterface.php +++ b/module/Rest/src/Service/ApiKeyServiceInterface.php @@ -22,7 +22,7 @@ interface ApiKeyServiceInterface * @param string $key * @return bool */ - public function check($key); + public function check(string $key); /** * Disables provided api key @@ -31,7 +31,7 @@ interface ApiKeyServiceInterface * @return ApiKey * @throws InvalidArgumentException */ - public function disable($key); + public function disable(string $key); /** * Lists all existing api keys @@ -39,7 +39,7 @@ interface ApiKeyServiceInterface * @param bool $enabledOnly Tells if only enabled keys should be returned * @return ApiKey[] */ - public function listKeys($enabledOnly = false); + public function listKeys(bool $enabledOnly = false); /** * Tries to find one API key by its key string @@ -47,5 +47,5 @@ interface ApiKeyServiceInterface * @param string $key * @return ApiKey|null */ - public function getByKey($key); + public function getByKey(string $key); }