mirror of
https://github.com/shlinkio/shlink.git
synced 2025-12-10 11:05:50 -06:00
Allow filtering by domain in VisitRepository::findOrphanVisits
This commit is contained in:
parent
9dcc51abde
commit
94426c7bf4
@ -20,9 +20,9 @@
|
|||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"akrabat/ip-address-middleware": "^2.6",
|
"akrabat/ip-address-middleware": "^2.6",
|
||||||
"cakephp/chronos": "^3.1",
|
"cakephp/chronos": "^3.1",
|
||||||
"doctrine/dbal": "^4.2",
|
"doctrine/dbal": "^4.3",
|
||||||
"doctrine/migrations": "^3.8",
|
"doctrine/migrations": "^3.9",
|
||||||
"doctrine/orm": "^3.3",
|
"doctrine/orm": "^3.5",
|
||||||
"donatj/phpuseragentparser": "^1.10",
|
"donatj/phpuseragentparser": "^1.10",
|
||||||
"endroid/qr-code": "^6.0.5",
|
"endroid/qr-code": "^6.0.5",
|
||||||
"friendsofphp/proxy-manager-lts": "^1.0",
|
"friendsofphp/proxy-manager-lts": "^1.0",
|
||||||
|
|||||||
@ -21,7 +21,6 @@ use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
|||||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsCountFiltering;
|
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsCountFiltering;
|
||||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||||
use Shlinkio\Shlink\Core\Visit\Spec\CountOfNonOrphanVisits;
|
use Shlinkio\Shlink\Core\Visit\Spec\CountOfNonOrphanVisits;
|
||||||
use Shlinkio\Shlink\Core\Visit\Spec\CountOfOrphanVisits;
|
|
||||||
use Shlinkio\Shlink\Rest\ApiKey\Role;
|
use Shlinkio\Shlink\Rest\ApiKey\Role;
|
||||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
@ -161,15 +160,7 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$qb = $this->createAllVisitsQueryBuilder($filtering);
|
$qb = $this->createOrphanVisitsQueryBuilder($filtering);
|
||||||
$qb->andWhere($qb->expr()->isNull('v.shortUrl'));
|
|
||||||
|
|
||||||
// Parameters in this query need to be inlined, not bound, as we need to use it as sub-query later
|
|
||||||
if ($filtering->type) {
|
|
||||||
$conn = $this->getEntityManager()->getConnection();
|
|
||||||
$qb->andWhere($qb->expr()->eq('v.type', $conn->quote($filtering->type->value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->resolveVisitsWithNativeQuery($qb, $filtering->limit, $filtering->offset);
|
return $this->resolveVisitsWithNativeQuery($qb, $filtering->limit, $filtering->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +170,32 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int) $this->matchSingleScalarResult(new CountOfOrphanVisits($filtering));
|
$qb = $this->createOrphanVisitsQueryBuilder($filtering);
|
||||||
|
$qb->select('COUNT(v.id)');
|
||||||
|
|
||||||
|
return (int) $qb->getQuery()->getSingleScalarResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createOrphanVisitsQueryBuilder(OrphanVisitsCountFiltering $filtering): QueryBuilder
|
||||||
|
{
|
||||||
|
$qb = $this->createAllVisitsQueryBuilder($filtering);
|
||||||
|
$qb->andWhere($qb->expr()->isNull('v.shortUrl'));
|
||||||
|
|
||||||
|
// Parameters in this query need to be inlined, not bound, as we need to use it as sub-query later
|
||||||
|
$conn = $this->getEntityManager()->getConnection();
|
||||||
|
|
||||||
|
if ($filtering->type) {
|
||||||
|
$qb->andWhere($qb->expr()->eq('v.type', $conn->quote($filtering->type->value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$domain = $filtering->domain;
|
||||||
|
if ($domain === Domain::DEFAULT_AUTHORITY) {
|
||||||
|
// TODO
|
||||||
|
} elseif ($domain !== null) {
|
||||||
|
$qb->andWhere($qb->expr()->like('v.visitedUrl', $conn->quote('%' . $domain . '%')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shlinkio\Shlink\Core\Visit\Spec;
|
|
||||||
|
|
||||||
use Happyr\DoctrineSpecification\Spec;
|
|
||||||
use Happyr\DoctrineSpecification\Specification\BaseSpecification;
|
|
||||||
use Happyr\DoctrineSpecification\Specification\Specification;
|
|
||||||
use Shlinkio\Shlink\Core\Spec\InDateRange;
|
|
||||||
use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsCountFiltering;
|
|
||||||
|
|
||||||
class CountOfOrphanVisits extends BaseSpecification
|
|
||||||
{
|
|
||||||
public function __construct(private readonly OrphanVisitsCountFiltering $filtering)
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getSpec(): Specification
|
|
||||||
{
|
|
||||||
$conditions = [
|
|
||||||
Spec::isNull('shortUrl'),
|
|
||||||
new InDateRange($this->filtering->dateRange),
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($this->filtering->excludeBots) {
|
|
||||||
$conditions[] = Spec::eq('potentialBot', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->filtering->type) {
|
|
||||||
$conditions[] = Spec::eq('type', $this->filtering->type->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Spec::countOf(Spec::andX(...$conditions));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -399,7 +399,7 @@ class VisitRepositoryTest extends DatabaseTestCase
|
|||||||
Chronos::parse(sprintf('2020-01-0%s', $i + 1)),
|
Chronos::parse(sprintf('2020-01-0%s', $i + 1)),
|
||||||
));
|
));
|
||||||
$this->getEntityManager()->persist($this->setDateOnVisit(
|
$this->getEntityManager()->persist($this->setDateOnVisit(
|
||||||
fn () => Visit::forRegularNotFound(Visitor::empty()),
|
fn () => Visit::forRegularNotFound(Visitor::fromParams(visitedUrl: 'https://example.com/foo?1=2')),
|
||||||
Chronos::parse(sprintf('2020-01-0%s', $i + 1)),
|
Chronos::parse(sprintf('2020-01-0%s', $i + 1)),
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -438,6 +438,7 @@ class VisitRepositoryTest extends DatabaseTestCase
|
|||||||
type: OrphanVisitType::BASE_URL,
|
type: OrphanVisitType::BASE_URL,
|
||||||
limit: 4,
|
limit: 4,
|
||||||
)));
|
)));
|
||||||
|
self::assertCount(6, $this->repo->findOrphanVisits(new OrphanVisitsListFiltering(domain: 'example.com')));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
@ -457,7 +458,7 @@ class VisitRepositoryTest extends DatabaseTestCase
|
|||||||
Chronos::parse(sprintf('2020-01-0%s', $i + 1)),
|
Chronos::parse(sprintf('2020-01-0%s', $i + 1)),
|
||||||
));
|
));
|
||||||
$this->getEntityManager()->persist($this->setDateOnVisit(
|
$this->getEntityManager()->persist($this->setDateOnVisit(
|
||||||
fn () => Visit::forRegularNotFound(Visitor::empty()),
|
fn () => Visit::forRegularNotFound(Visitor::fromParams(visitedUrl: 'https://example.com/foo/bar')),
|
||||||
Chronos::parse(sprintf('2020-01-0%s', $i + 1)),
|
Chronos::parse(sprintf('2020-01-0%s', $i + 1)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -486,6 +487,9 @@ class VisitRepositoryTest extends DatabaseTestCase
|
|||||||
self::assertEquals(6, $this->repo->countOrphanVisits(new OrphanVisitsCountFiltering(
|
self::assertEquals(6, $this->repo->countOrphanVisits(new OrphanVisitsCountFiltering(
|
||||||
type: OrphanVisitType::REGULAR_404,
|
type: OrphanVisitType::REGULAR_404,
|
||||||
)));
|
)));
|
||||||
|
self::assertEquals(6, $this->repo->countOrphanVisits(new OrphanVisitsCountFiltering(
|
||||||
|
domain: 'example.com',
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user