mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-28 00:38:46 +03:00
Applied API role specs to global visits
This commit is contained in:
parent
8aa6bdb934
commit
68c601a5a8
9 changed files with 34 additions and 12 deletions
|
@ -56,7 +56,7 @@ class TagRepository extends EntitySpecificationRepository implements TagReposito
|
|||
{
|
||||
$result = (int) $this->matchSingleScalarResult(Spec::andX(
|
||||
new CountTagsWithName($tag),
|
||||
new WithApiKeySpecsEnsuringJoin($apiKey),
|
||||
new WithApiKeySpecsEnsuringJoin($apiKey, 'shortUrls'),
|
||||
));
|
||||
|
||||
return $result > 0;
|
||||
|
|
|
@ -7,11 +7,14 @@ namespace Shlinkio\Shlink\Core\Repository;
|
|||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Happyr\DoctrineSpecification\EntitySpecificationRepository;
|
||||
use Happyr\DoctrineSpecification\Spec;
|
||||
use Happyr\DoctrineSpecification\Specification\Specification;
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||
use Shlinkio\Shlink\Core\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Entity\VisitLocation;
|
||||
use Shlinkio\Shlink\Rest\ApiKey\Spec\WithApiKeySpecsEnsuringJoin;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
|
@ -205,4 +208,11 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
|||
|
||||
return $query->getResult();
|
||||
}
|
||||
|
||||
public function countVisits(?ApiKey $apiKey = null): int
|
||||
{
|
||||
return (int) $this->matchSingleScalarResult(
|
||||
Spec::countOf(new WithApiKeySpecsEnsuringJoin($apiKey, 'shortUrl')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use Happyr\DoctrineSpecification\EntitySpecificationRepositoryInterface;
|
|||
use Happyr\DoctrineSpecification\Specification\Specification;
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\Entity\Visit;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
interface VisitRepositoryInterface extends ObjectRepository, EntitySpecificationRepositoryInterface
|
||||
{
|
||||
|
@ -60,4 +61,6 @@ interface VisitRepositoryInterface extends ObjectRepository, EntitySpecification
|
|||
): array;
|
||||
|
||||
public function countVisitsByTag(string $tag, ?DateRange $dateRange = null, ?Specification $spec = null): int;
|
||||
|
||||
public function countVisits(?ApiKey $apiKey = null): int;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||
use Shlinkio\Shlink\Core\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Repository\VisitRepository;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class VisitsStatsHelper implements VisitsStatsHelperInterface
|
||||
{
|
||||
|
@ -18,15 +19,15 @@ class VisitsStatsHelper implements VisitsStatsHelperInterface
|
|||
$this->em = $em;
|
||||
}
|
||||
|
||||
public function getVisitsStats(): VisitsStats
|
||||
public function getVisitsStats(?ApiKey $apiKey = null): VisitsStats
|
||||
{
|
||||
return new VisitsStats($this->getVisitsCount());
|
||||
return new VisitsStats($this->getVisitsCount($apiKey));
|
||||
}
|
||||
|
||||
private function getVisitsCount(): int
|
||||
private function getVisitsCount(?ApiKey $apiKey): int
|
||||
{
|
||||
/** @var VisitRepository $visitsRepo */
|
||||
$visitsRepo = $this->em->getRepository(Visit::class);
|
||||
return $visitsRepo->count([]);
|
||||
return $visitsRepo->countVisits($apiKey);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@ declare(strict_types=1);
|
|||
namespace Shlinkio\Shlink\Core\Visit;
|
||||
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
interface VisitsStatsHelperInterface
|
||||
{
|
||||
public function getVisitsStats(): VisitsStats;
|
||||
public function getVisitsStats(?ApiKey $apiKey = null): VisitsStats;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ class VisitsStatsHelperTest extends TestCase
|
|||
public function returnsExpectedVisitsStats(int $expectedCount): void
|
||||
{
|
||||
$repo = $this->prophesize(VisitRepository::class);
|
||||
$count = $repo->count([])->willReturn($expectedCount);
|
||||
$count = $repo->countVisits(null)->willReturn($expectedCount);
|
||||
$getRepo = $this->em->getRepository(Visit::class)->willReturn($repo->reveal());
|
||||
|
||||
$stats = $this->helper->getVisitsStats();
|
||||
|
|
|
@ -9,6 +9,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
|
||||
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
||||
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
|
||||
|
||||
class GlobalVisitsAction extends AbstractRestAction
|
||||
{
|
||||
|
@ -24,8 +25,10 @@ class GlobalVisitsAction extends AbstractRestAction
|
|||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
|
||||
|
||||
return new JsonResponse([
|
||||
'visits' => $this->statsHelper->getVisitsStats(),
|
||||
'visits' => $this->statsHelper->getVisitsStats($apiKey),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,17 +12,19 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
|||
class WithApiKeySpecsEnsuringJoin extends BaseSpecification
|
||||
{
|
||||
private ?ApiKey $apiKey;
|
||||
private string $fieldToJoin;
|
||||
|
||||
public function __construct(?ApiKey $apiKey)
|
||||
public function __construct(?ApiKey $apiKey, string $fieldToJoin)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->apiKey = $apiKey;
|
||||
$this->fieldToJoin = $fieldToJoin;
|
||||
}
|
||||
|
||||
protected function getSpec(): Specification
|
||||
{
|
||||
return $this->apiKey === null || $this->apiKey->isAdmin() ? Spec::andX() : Spec::andX(
|
||||
Spec::join('shortUrls', 's'),
|
||||
Spec::join($this->fieldToJoin, 's'),
|
||||
$this->apiKey->spec(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use Prophecy\Prophecy\ObjectProphecy;
|
|||
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
|
||||
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
|
||||
use Shlinkio\Shlink\Rest\Action\Visit\GlobalVisitsAction;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class GlobalVisitsActionTest extends TestCase
|
||||
{
|
||||
|
@ -29,11 +30,12 @@ class GlobalVisitsActionTest extends TestCase
|
|||
/** @test */
|
||||
public function statsAreReturnedFromHelper(): void
|
||||
{
|
||||
$apiKey = new ApiKey();
|
||||
$stats = new VisitsStats(5);
|
||||
$getStats = $this->helper->getVisitsStats()->willReturn($stats);
|
||||
$getStats = $this->helper->getVisitsStats($apiKey)->willReturn($stats);
|
||||
|
||||
/** @var JsonResponse $resp */
|
||||
$resp = $this->action->handle(ServerRequestFactory::fromGlobals());
|
||||
$resp = $this->action->handle(ServerRequestFactory::fromGlobals()->withAttribute(ApiKey::class, $apiKey));
|
||||
$payload = $resp->getPayload();
|
||||
|
||||
self::assertEquals($payload, ['visits' => $stats]);
|
||||
|
|
Loading…
Reference in a new issue