mirror of
https://github.com/shlinkio/shlink.git
synced 2025-03-29 13:03:52 +03:00
Updated UrlShortener so that it does not match a short code which is out of the validity dat erange
This commit is contained in:
parent
68b4cfbae0
commit
a3bbd06fe3
6 changed files with 116 additions and 42 deletions
|
@ -15,14 +15,20 @@ interface PaginableRepositoryInterface
|
||||||
* @param string|array|null $orderBy
|
* @param string|array|null $orderBy
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function findList($limit = null, $offset = null, $searchTerm = null, array $tags = [], $orderBy = null);
|
public function findList(
|
||||||
|
int $limit = null,
|
||||||
|
int $offset = null,
|
||||||
|
string $searchTerm = null,
|
||||||
|
array $tags = [],
|
||||||
|
$orderBy = null
|
||||||
|
): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts the number of elements in a list using provided filtering data
|
* Counts the number of elements in a list using provided filtering data
|
||||||
*
|
*
|
||||||
* @param null $searchTerm
|
* @param string|null $searchTerm
|
||||||
* @param array $tags
|
* @param array $tags
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function countList($searchTerm = null, array $tags = []);
|
public function countList(string $searchTerm = null, array $tags = []): int;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,22 +54,32 @@ class ShortUrl extends AbstractEntity implements \JsonSerializable
|
||||||
* })
|
* })
|
||||||
*/
|
*/
|
||||||
protected $tags;
|
protected $tags;
|
||||||
|
/**
|
||||||
|
* @var \DateTime
|
||||||
|
* @ORM\Column(name="valid_since", type="datetime", nullable=true)
|
||||||
|
*/
|
||||||
|
protected $validSince;
|
||||||
|
/**
|
||||||
|
* @var \DateTime
|
||||||
|
* @ORM\Column(name="valid_until", type="datetime", nullable=true)
|
||||||
|
*/
|
||||||
|
protected $validUntil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ShortUrl constructor.
|
* ShortUrl constructor.
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->setDateCreated(new \DateTime());
|
$this->dateCreated = new \DateTime();
|
||||||
$this->setVisits(new ArrayCollection());
|
$this->visits = new ArrayCollection();
|
||||||
$this->setShortCode('');
|
$this->shortCode = '';
|
||||||
$this->tags = new ArrayCollection();
|
$this->tags = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getOriginalUrl()
|
public function getOriginalUrl(): string
|
||||||
{
|
{
|
||||||
return $this->originalUrl;
|
return $this->originalUrl;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +88,7 @@ class ShortUrl extends AbstractEntity implements \JsonSerializable
|
||||||
* @param string $originalUrl
|
* @param string $originalUrl
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setOriginalUrl($originalUrl)
|
public function setOriginalUrl(string $originalUrl)
|
||||||
{
|
{
|
||||||
$this->originalUrl = (string) $originalUrl;
|
$this->originalUrl = (string) $originalUrl;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -87,7 +97,7 @@ class ShortUrl extends AbstractEntity implements \JsonSerializable
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getShortCode()
|
public function getShortCode(): string
|
||||||
{
|
{
|
||||||
return $this->shortCode;
|
return $this->shortCode;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +106,7 @@ class ShortUrl extends AbstractEntity implements \JsonSerializable
|
||||||
* @param string $shortCode
|
* @param string $shortCode
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShortCode($shortCode)
|
public function setShortCode(string $shortCode)
|
||||||
{
|
{
|
||||||
$this->shortCode = $shortCode;
|
$this->shortCode = $shortCode;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -105,7 +115,7 @@ class ShortUrl extends AbstractEntity implements \JsonSerializable
|
||||||
/**
|
/**
|
||||||
* @return \DateTime
|
* @return \DateTime
|
||||||
*/
|
*/
|
||||||
public function getDateCreated()
|
public function getDateCreated(): \DateTime
|
||||||
{
|
{
|
||||||
return $this->dateCreated;
|
return $this->dateCreated;
|
||||||
}
|
}
|
||||||
|
@ -114,34 +124,16 @@ class ShortUrl extends AbstractEntity implements \JsonSerializable
|
||||||
* @param \DateTime $dateCreated
|
* @param \DateTime $dateCreated
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDateCreated($dateCreated)
|
public function setDateCreated(\DateTime $dateCreated)
|
||||||
{
|
{
|
||||||
$this->dateCreated = $dateCreated;
|
$this->dateCreated = $dateCreated;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Visit[]|Collection
|
|
||||||
*/
|
|
||||||
public function getVisits()
|
|
||||||
{
|
|
||||||
return $this->visits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Visit[]|Collection $visits
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setVisits($visits)
|
|
||||||
{
|
|
||||||
$this->visits = $visits;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection|Tag[]
|
* @return Collection|Tag[]
|
||||||
*/
|
*/
|
||||||
public function getTags()
|
public function getTags(): Collection
|
||||||
{
|
{
|
||||||
return $this->tags;
|
return $this->tags;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +142,7 @@ class ShortUrl extends AbstractEntity implements \JsonSerializable
|
||||||
* @param Collection|Tag[] $tags
|
* @param Collection|Tag[] $tags
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTags($tags)
|
public function setTags(Collection $tags)
|
||||||
{
|
{
|
||||||
$this->tags = $tags;
|
$this->tags = $tags;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -166,6 +158,42 @@ class ShortUrl extends AbstractEntity implements \JsonSerializable
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DateTime|null
|
||||||
|
*/
|
||||||
|
public function getValidSince()
|
||||||
|
{
|
||||||
|
return $this->validSince;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DateTime|null $validSince
|
||||||
|
* @return $this|self
|
||||||
|
*/
|
||||||
|
public function setValidSince($validSince): self
|
||||||
|
{
|
||||||
|
$this->validSince = $validSince;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DateTime|null
|
||||||
|
*/
|
||||||
|
public function getValidUntil()
|
||||||
|
{
|
||||||
|
return $this->validUntil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DateTime|null $validUntil
|
||||||
|
* @return $this|self
|
||||||
|
*/
|
||||||
|
public function setValidUntil($validUntil): self
|
||||||
|
{
|
||||||
|
$this->validUntil = $validUntil;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify data which should be serialized to JSON
|
* Specify data which should be serialized to JSON
|
||||||
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
|
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
|
||||||
|
|
|
@ -17,8 +17,13 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
||||||
* @param string|array|null $orderBy
|
* @param string|array|null $orderBy
|
||||||
* @return \Shlinkio\Shlink\Core\Entity\ShortUrl[]
|
* @return \Shlinkio\Shlink\Core\Entity\ShortUrl[]
|
||||||
*/
|
*/
|
||||||
public function findList($limit = null, $offset = null, $searchTerm = null, array $tags = [], $orderBy = null)
|
public function findList(
|
||||||
{
|
int $limit = null,
|
||||||
|
int $offset = null,
|
||||||
|
string $searchTerm = null,
|
||||||
|
array $tags = [],
|
||||||
|
$orderBy = null
|
||||||
|
): array {
|
||||||
$qb = $this->createListQueryBuilder($searchTerm, $tags);
|
$qb = $this->createListQueryBuilder($searchTerm, $tags);
|
||||||
$qb->select('s');
|
$qb->select('s');
|
||||||
|
|
||||||
|
@ -74,7 +79,7 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
||||||
* @param array $tags
|
* @param array $tags
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function countList($searchTerm = null, array $tags = [])
|
public function countList(string $searchTerm = null, array $tags = []): int
|
||||||
{
|
{
|
||||||
$qb = $this->createListQueryBuilder($searchTerm, $tags);
|
$qb = $this->createListQueryBuilder($searchTerm, $tags);
|
||||||
$qb->select('COUNT(s)');
|
$qb->select('COUNT(s)');
|
||||||
|
@ -87,7 +92,7 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
||||||
* @param array $tags
|
* @param array $tags
|
||||||
* @return QueryBuilder
|
* @return QueryBuilder
|
||||||
*/
|
*/
|
||||||
protected function createListQueryBuilder($searchTerm = null, array $tags = [])
|
protected function createListQueryBuilder(string $searchTerm = null, array $tags = []): QueryBuilder
|
||||||
{
|
{
|
||||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||||
$qb->from(ShortUrl::class, 's');
|
$qb->from(ShortUrl::class, 's');
|
||||||
|
@ -117,4 +122,29 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
||||||
|
|
||||||
return $qb;
|
return $qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $shortCode
|
||||||
|
* @return ShortUrl|null
|
||||||
|
*/
|
||||||
|
public function findOneByShortCode(string $shortCode)
|
||||||
|
{
|
||||||
|
$now = new \DateTimeImmutable();
|
||||||
|
|
||||||
|
$qb = $this->createQueryBuilder('s');
|
||||||
|
$qb->where($qb->expr()->eq('s.shortCode', ':shortCode'))
|
||||||
|
->setParameter('shortCode', $shortCode)
|
||||||
|
->andWhere($qb->expr()->orX(
|
||||||
|
$qb->expr()->lte('s.validSince', ':now'),
|
||||||
|
$qb->expr()->isNull('s.validSince')
|
||||||
|
))
|
||||||
|
->andWhere($qb->expr()->orX(
|
||||||
|
$qb->expr()->gte('s.validUntil', ':now'),
|
||||||
|
$qb->expr()->isNull('s.validUntil')
|
||||||
|
))
|
||||||
|
->setParameter('now', $now)
|
||||||
|
->setMaxResults(1);
|
||||||
|
|
||||||
|
return $qb->getQuery()->getOneOrNullResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,13 @@ namespace Shlinkio\Shlink\Core\Repository;
|
||||||
|
|
||||||
use Doctrine\Common\Persistence\ObjectRepository;
|
use Doctrine\Common\Persistence\ObjectRepository;
|
||||||
use Shlinkio\Shlink\Common\Repository\PaginableRepositoryInterface;
|
use Shlinkio\Shlink\Common\Repository\PaginableRepositoryInterface;
|
||||||
|
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||||
|
|
||||||
interface ShortUrlRepositoryInterface extends ObjectRepository, PaginableRepositoryInterface
|
interface ShortUrlRepositoryInterface extends ObjectRepository, PaginableRepositoryInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @param string $shortCode
|
||||||
|
* @return ShortUrl|null
|
||||||
|
*/
|
||||||
|
public function findOneByShortCode(string $shortCode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||||
use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException;
|
use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException;
|
||||||
use Shlinkio\Shlink\Core\Exception\InvalidShortCodeException;
|
use Shlinkio\Shlink\Core\Exception\InvalidShortCodeException;
|
||||||
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
|
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
|
||||||
|
use Shlinkio\Shlink\Core\Repository\ShortUrlRepository;
|
||||||
use Shlinkio\Shlink\Core\Util\TagManagerTrait;
|
use Shlinkio\Shlink\Core\Util\TagManagerTrait;
|
||||||
|
|
||||||
class UrlShortener implements UrlShortenerInterface
|
class UrlShortener implements UrlShortenerInterface
|
||||||
|
@ -160,11 +161,13 @@ class UrlShortener implements UrlShortenerInterface
|
||||||
throw InvalidShortCodeException::fromCharset($shortCode, $this->chars);
|
throw InvalidShortCodeException::fromCharset($shortCode, $this->chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
$criteria = ['shortCode' => $shortCode];
|
/** @var ShortUrlRepository $shortUrlRepo */
|
||||||
/** @var ShortUrl|null $shortUrl */
|
$shortUrlRepo = $this->em->getRepository(ShortUrl::class);
|
||||||
$shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy($criteria);
|
$shortUrl = $shortUrlRepo->findOneByShortCode($shortCode);
|
||||||
if ($shortUrl === null) {
|
if ($shortUrl === null) {
|
||||||
throw EntityDoesNotExistException::createFromEntityAndConditions(ShortUrl::class, $criteria);
|
throw EntityDoesNotExistException::createFromEntityAndConditions(ShortUrl::class, [
|
||||||
|
'shortCode' => $shortCode,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the shortcode
|
// Cache the shortcode
|
||||||
|
|
|
@ -16,6 +16,7 @@ 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\Repository\ShortUrlRepositoryInterface;
|
||||||
use Shlinkio\Shlink\Core\Service\UrlShortener;
|
use Shlinkio\Shlink\Core\Service\UrlShortener;
|
||||||
use Zend\Diactoros\Uri;
|
use Zend\Diactoros\Uri;
|
||||||
|
|
||||||
|
@ -127,8 +128,8 @@ class UrlShortenerTest extends TestCase
|
||||||
$shortUrl->setShortCode($shortCode)
|
$shortUrl->setShortCode($shortCode)
|
||||||
->setOriginalUrl('expected_url');
|
->setOriginalUrl('expected_url');
|
||||||
|
|
||||||
$repo = $this->prophesize(ObjectRepository::class);
|
$repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
||||||
$repo->findOneBy(['shortCode' => $shortCode])->willReturn($shortUrl);
|
$repo->findOneByShortCode($shortCode)->willReturn($shortUrl);
|
||||||
$this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
|
$this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
|
||||||
|
|
||||||
$this->assertFalse($this->cache->contains($shortCode . '_longUrl'));
|
$this->assertFalse($this->cache->contains($shortCode . '_longUrl'));
|
||||||
|
|
Loading…
Add table
Reference in a new issue