Compare commits

...

9 Commits

Author SHA1 Message Date
Alejandro Celaya
6991138812 Merge pull request #2379 from shlinkio/develop
Release 4.4.5
2025-03-01 09:41:16 +01:00
Alejandro Celaya
5eb1808217 Update CHANGELOG.md with V4.4.5 2025-03-01 09:14:37 +01:00
Alejandro Celaya
5eb14c5315 Merge pull request #2375 from acelaya-forks/feature/deprecation-error-reporting
Disable deprecation warnings when running in production envs
2025-02-21 21:18:44 +01:00
Alejandro Celaya
a18360a4d6 Disable deprecation warnings when running in production envs 2025-02-21 21:13:29 +01:00
Alejandro Celaya
104b1e7d04 Merge pull request #2371 from shlinkio/develop
Release 4.4.4
2025-02-19 19:40:28 +01:00
Alejandro Celaya
af2d67695b Merge pull request #2370 from acelaya-forks/feature/missing-join-fix
Fix 500 error when listing non-orphan visits with short-url-depending API key
2025-02-19 19:37:36 +01:00
Alejandro Celaya
449a588796 Fix 500 error when listing non-orphan visits with short-url-depending API key 2025-02-19 19:33:44 +01:00
Alejandro Celaya
7bbc938743 Merge pull request #2369 from acelaya-forks/feature/redis-cluster-fix
Downgrade to symfony/lock 7.1.6
2025-02-19 17:55:53 +01:00
Alejandro Celaya
766758ff9b Downgrade to symfony/lock 7.1.6 2025-02-19 17:45:52 +01:00
6 changed files with 64 additions and 20 deletions

View File

@@ -4,6 +4,43 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
## [4.4.5] - 2025-03-01
### Added
* *Nothing*
### Changed
* *Nothing*
### Deprecated
* *Nothing*
### Removed
* *Nothing*
### Fixed
* [#2373](https://github.com/shlinkio/shlink/issues/2373) Ensure deprecation warnings do not end up escalated to `ErrorException`s by `ProblemDetailsMiddleware`.
In order to do this, Shlink will entirely ignore deprecation warnings when running in production, as those do not mean something is not working, but only that something will break in future versions.
## [4.4.4] - 2025-02-19
### Added
* *Nothing*
### Changed
* *Nothing*
### Deprecated
* *Nothing*
### Removed
* *Nothing*
### Fixed
* [#2366](https://github.com/shlinkio/shlink/issues/2366) Fix error "Cannot use 'SCRIPT' with redis-cluster" thrown when creating a lock while using a redis cluster.
* [#2368](https://github.com/shlinkio/shlink/issues/2368) Fix error when listing non-orphan visits using API key with `AUTHORED_SHORT_URLS` role.
## [4.4.3] - 2025-02-15
### Added
* *Nothing*

View File

@@ -56,7 +56,7 @@
"spiral/roadrunner-jobs": "^4.6",
"symfony/console": "^7.2",
"symfony/filesystem": "^7.2",
"symfony/lock": "7.2.0",
"symfony/lock": "7.1.6",
"symfony/process": "^7.2",
"symfony/string": "^7.2"
},

View File

@@ -11,6 +11,7 @@ use function Shlinkio\Shlink\Core\enumValues;
use const Shlinkio\Shlink\LOCAL_LOCK_FACTORY;
// Set current directory to the project's root directory
chdir(dirname(__DIR__));
require 'vendor/autoload.php';
@@ -21,7 +22,11 @@ loadEnvVarsFromConfig(
enumValues(EnvVars::class),
);
// This is one of the first files loaded. Configure the timezone and memory limit here
// This is one of the first files loaded. Set global configuration here
error_reporting(
// Set a less strict error reporting for prod, where deprecation warnings should be ignored
EnvVars::isProdEnv() ? E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED : E_ALL,
);
ini_set('memory_limit', EnvVars::MEMORY_LIMIT->loadFromEnv());
date_default_timezone_set(EnvVars::TIMEZONE->loadFromEnv());

View File

@@ -1,5 +1,4 @@
display_errors=On
error_reporting=-1
log_errors_max_len=0
zend.assertions=1
assert.exception=1

View File

@@ -21,6 +21,7 @@ use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
use Shlinkio\Shlink\Core\Visit\Spec\CountOfNonOrphanVisits;
use Shlinkio\Shlink\Core\Visit\Spec\CountOfOrphanVisits;
use Shlinkio\Shlink\Rest\ApiKey\Role;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
use const PHP_INT_MAX;
@@ -177,7 +178,12 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
$qb = $this->createAllVisitsQueryBuilder($filtering);
$qb->andWhere($qb->expr()->isNotNull('v.shortUrl'));
$this->applySpecification($qb, $filtering->apiKey?->inlinedSpec());
$apiKey = $filtering->apiKey;
if (ApiKey::isShortUrlRestricted($apiKey)) {
$qb->join('v.shortUrl', 's');
}
$this->applySpecification($qb, $apiKey?->inlinedSpec(), 'v');
return $this->resolveVisitsWithNativeQuery($qb, $filtering->limit, $filtering->offset);
}

View File

@@ -470,22 +470,18 @@ class VisitRepositoryTest extends DatabaseTestCase
#[Test]
public function findNonOrphanVisitsReturnsExpectedResult(): void
{
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => 'https://1']));
$this->getEntityManager()->persist($shortUrl);
$this->createVisitsForShortUrl($shortUrl, 7);
$authoredApiKey = ApiKey::fromMeta(ApiKeyMeta::withRoles(RoleDefinition::forAuthoredShortUrls()));
$this->getEntityManager()->persist($authoredApiKey);
$shortUrl2 = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => 'https://2']));
$this->getEntityManager()->persist($shortUrl2);
$this->createVisitsForShortUrl($shortUrl2, 4);
$shortUrl3 = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => 'https://3']));
$this->getEntityManager()->persist($shortUrl3);
$this->createVisitsForShortUrl($shortUrl3, 10);
$this->createShortUrlsAndVisits(withDomain: false, visitsAmount: 7);
$this->createShortUrlsAndVisits(withDomain: false, apiKey: $authoredApiKey, visitsAmount: 4);
$this->createShortUrlsAndVisits(withDomain: false, visitsAmount: 10);
$this->getEntityManager()->flush();
self::assertCount(21, $this->repo->findNonOrphanVisits(new VisitsListFiltering()));
self::assertCount(21, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::allTime())));
self::assertCount(4, $this->repo->findNonOrphanVisits(new VisitsListFiltering(apiKey: $authoredApiKey)));
self::assertCount(7, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::since(
Chronos::parse('2016-01-05')->endOfDay(),
))));
@@ -503,11 +499,11 @@ class VisitRepositoryTest extends DatabaseTestCase
self::assertCount(3, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::between(
Chronos::parse('2016-01-03')->startOfDay(),
Chronos::parse('2016-01-08')->endOfDay(),
), false, null, 10, 10)));
self::assertCount(15, $this->repo->findNonOrphanVisits(new VisitsListFiltering(null, true)));
self::assertCount(10, $this->repo->findNonOrphanVisits(new VisitsListFiltering(null, false, null, 10)));
self::assertCount(1, $this->repo->findNonOrphanVisits(new VisitsListFiltering(null, false, null, 10, 20)));
self::assertCount(5, $this->repo->findNonOrphanVisits(new VisitsListFiltering(null, false, null, 5, 5)));
), limit: 10, offset: 10)));
self::assertCount(15, $this->repo->findNonOrphanVisits(new VisitsListFiltering(excludeBots: true)));
self::assertCount(10, $this->repo->findNonOrphanVisits(new VisitsListFiltering(limit: 10)));
self::assertCount(1, $this->repo->findNonOrphanVisits(new VisitsListFiltering(limit: 10, offset: 20)));
self::assertCount(5, $this->repo->findNonOrphanVisits(new VisitsListFiltering(limit: 5, offset: 5)));
}
#[Test]
@@ -535,6 +531,7 @@ class VisitRepositoryTest extends DatabaseTestCase
bool|string $withDomain = true,
array $tags = [],
ApiKey|null $apiKey = null,
int $visitsAmount = 6,
): array {
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
ShortUrlInputFilter::LONG_URL => 'https://longUrl',
@@ -545,7 +542,7 @@ class VisitRepositoryTest extends DatabaseTestCase
$shortCode = $shortUrl->getShortCode();
$this->getEntityManager()->persist($shortUrl);
$this->createVisitsForShortUrl($shortUrl);
$this->createVisitsForShortUrl($shortUrl, $visitsAmount);
if ($withDomain !== false) {
$shortUrlWithDomain = ShortUrl::create(ShortUrlCreation::fromRawData([