Refactored tracking actions

This commit is contained in:
Alejandro Celaya 2021-07-15 13:28:31 +02:00
parent fe5460e0c5
commit 265e8cdeaf
8 changed files with 34 additions and 37 deletions

View File

@ -16,9 +16,12 @@ return [
'validate_url' => false, // Deprecated
'visits_webhooks' => [],
'default_short_codes_length' => DEFAULT_SHORT_CODES_LENGTH,
'auto_resolve_titles' => false,
'append_extra_path' => false,
// TODO Move these two options to their own config namespace. Maybe "redirects".
'redirect_status_code' => DEFAULT_REDIRECT_STATUS_CODE,
'redirect_cache_lifetime' => DEFAULT_REDIRECT_CACHE_LIFETIME,
'auto_resolve_titles' => false,
],
];

View File

@ -118,17 +118,14 @@ return [
Action\RedirectAction::class => [
Service\ShortUrl\ShortUrlResolver::class,
Visit\VisitsTracker::class,
ShortUrl\Helper\ShortUrlRedirectionBuilder::class,
Options\TrackingOptions::class,
ShortUrl\Helper\ShortUrlRedirectionBuilder::class,
Util\RedirectResponseHelper::class,
'Logger_Shlink',
],
Action\PixelAction::class => [
Service\ShortUrl\ShortUrlResolver::class,
Visit\VisitsTracker::class,
ShortUrl\Helper\ShortUrlRedirectionBuilder::class,
Options\TrackingOptions::class,
'Logger_Shlink',
],
Action\QrCodeAction::class => [
Service\ShortUrl\ShortUrlResolver::class,

View File

@ -7,33 +7,27 @@ namespace Shlinkio\Shlink\Core\Action;
use Fig\Http\Message\RequestMethodInterface;
use Mezzio\Router\Middleware\ImplicitHeadMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
use Shlinkio\Shlink\Core\Model\Visitor;
use Shlinkio\Shlink\Core\Options\TrackingOptions;
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlRedirectionBuilderInterface;
use Shlinkio\Shlink\Core\Visit\VisitsTrackerInterface;
use function array_key_exists;
abstract class AbstractTrackingAction implements MiddlewareInterface, RequestMethodInterface
{
private LoggerInterface $logger;
public function __construct(
private ShortUrlResolverInterface $urlResolver,
private VisitsTrackerInterface $visitTracker,
private ShortUrlRedirectionBuilderInterface $redirectionBuilder,
private TrackingOptions $trackingOptions,
?LoggerInterface $logger = null
) {
$this->logger = $logger ?? new NullLogger();
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
@ -48,9 +42,8 @@ abstract class AbstractTrackingAction implements MiddlewareInterface, RequestMet
$this->visitTracker->track($shortUrl, Visitor::fromRequest($request));
}
return $this->createSuccessResp($this->redirectionBuilder->buildShortUrlRedirect($shortUrl, $query));
return $this->createSuccessResp($shortUrl, $request);
} catch (ShortUrlNotFoundException $e) {
$this->logger->warning('An error occurred while tracking short code. {e}', ['e' => $e]);
return $this->createErrorResp($request, $handler);
}
}
@ -66,10 +59,13 @@ abstract class AbstractTrackingAction implements MiddlewareInterface, RequestMet
return $disableTrackParam === null || ! array_key_exists($disableTrackParam, $query);
}
abstract protected function createSuccessResp(string $longUrl): ResponseInterface;
abstract protected function createErrorResp(
abstract protected function createSuccessResp(
ShortUrl $shortUrl,
ServerRequestInterface $request,
RequestHandlerInterface $handler,
): ResponseInterface;
protected function createErrorResp(ServerRequestInterface $request, RequestHandlerInterface $handler): Response
{
return $handler->handle($request);
}
}

View File

@ -8,10 +8,11 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Shlinkio\Shlink\Common\Response\PixelResponse;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
class PixelAction extends AbstractTrackingAction
{
protected function createSuccessResp(string $longUrl): ResponseInterface
protected function createSuccessResp(ShortUrl $shortUrl, ServerRequestInterface $request): ResponseInterface
{
return new PixelResponse();
}

View File

@ -7,8 +7,7 @@ namespace Shlinkio\Shlink\Core\Action;
use Fig\Http\Message\StatusCodeInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Options;
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlRedirectionBuilderInterface;
@ -20,21 +19,16 @@ class RedirectAction extends AbstractTrackingAction implements StatusCodeInterfa
public function __construct(
ShortUrlResolverInterface $urlResolver,
VisitsTrackerInterface $visitTracker,
ShortUrlRedirectionBuilderInterface $redirectionBuilder,
Options\TrackingOptions $trackingOptions,
private ShortUrlRedirectionBuilderInterface $redirectionBuilder,
private RedirectResponseHelperInterface $redirectResponseHelper,
?LoggerInterface $logger = null
) {
parent::__construct($urlResolver, $visitTracker, $redirectionBuilder, $trackingOptions, $logger);
parent::__construct($urlResolver, $visitTracker, $trackingOptions);
}
protected function createSuccessResp(string $longUrl): Response
protected function createSuccessResp(ShortUrl $shortUrl, ServerRequestInterface $request): Response
{
$longUrl = $this->redirectionBuilder->buildShortUrlRedirect($shortUrl, $request->getQueryParams());
return $this->redirectResponseHelper->buildRedirectResponse($longUrl);
}
protected function createErrorResp(ServerRequestInterface $request, RequestHandlerInterface $handler): Response
{
return $handler->handle($request);
}
}

View File

@ -19,6 +19,7 @@ class UrlShortenerOptions extends AbstractOptions
private int $redirectStatusCode = DEFAULT_REDIRECT_STATUS_CODE;
private int $redirectCacheLifetime = DEFAULT_REDIRECT_CACHE_LIFETIME;
private bool $autoResolveTitles = false;
private bool $appendExtraPath = false;
public function isUrlValidationEnabled(): bool
{
@ -67,6 +68,16 @@ class UrlShortenerOptions extends AbstractOptions
$this->autoResolveTitles = $autoResolveTitles;
}
public function appendExtraPath(): bool
{
return $this->appendExtraPath;
}
protected function setAppendExtraPath(bool $appendExtraPath): void
{
$this->appendExtraPath = $appendExtraPath;
}
/** @deprecated */
protected function setAnonymizeRemoteAddr(bool $anonymizeRemoteAddr): void
{

View File

@ -16,7 +16,6 @@ use Shlinkio\Shlink\Core\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
use Shlinkio\Shlink\Core\Options\TrackingOptions;
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlRedirectionBuilderInterface;
use Shlinkio\Shlink\Core\Visit\VisitsTracker;
class PixelActionTest extends TestCase
@ -32,13 +31,9 @@ class PixelActionTest extends TestCase
$this->urlResolver = $this->prophesize(ShortUrlResolverInterface::class);
$this->visitTracker = $this->prophesize(VisitsTracker::class);
$redirectBuilder = $this->prophesize(ShortUrlRedirectionBuilderInterface::class);
$redirectBuilder->buildShortUrlRedirect(Argument::cetera())->willReturn('http://domain.com/foo/bar');
$this->action = new PixelAction(
$this->urlResolver->reveal(),
$this->visitTracker->reveal(),
$redirectBuilder->reveal(),
new TrackingOptions(),
);
}

View File

@ -48,8 +48,8 @@ class RedirectActionTest extends TestCase
$this->action = new RedirectAction(
$this->urlResolver->reveal(),
$this->visitTracker->reveal(),
$redirectBuilder->reveal(),
new Options\TrackingOptions(['disableTrackParam' => 'foobar']),
$redirectBuilder->reveal(),
$this->redirectRespHelper->reveal(),
);
}