From 3040a22c021795fdc45857c4f9d815e2c3fd480b Mon Sep 17 00:00:00 2001 From: wuuei <9289130+wuuei@users.noreply.github.com> Date: Thu, 13 Mar 2025 15:33:00 +0100 Subject: [PATCH 1/7] Fix Matomo country logging by sending country code instead of country name Matomo expects the country code in lowercase for accurate logging and proper flag display --- module/Core/src/Matomo/MatomoVisitSender.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/Core/src/Matomo/MatomoVisitSender.php b/module/Core/src/Matomo/MatomoVisitSender.php index 9fc0176a..94f25e2f 100644 --- a/module/Core/src/Matomo/MatomoVisitSender.php +++ b/module/Core/src/Matomo/MatomoVisitSender.php @@ -60,7 +60,7 @@ readonly class MatomoVisitSender implements MatomoVisitSenderInterface if ($location !== null) { $tracker ->setCity($location->cityName) - ->setCountry($location->countryName) + ->setCountry(strtolower($location->countryCode)) ->setLatitude($location->latitude) ->setLongitude($location->longitude); } From 5cd7305666ebf199d257ef64d1e863f37acb060d Mon Sep 17 00:00:00 2001 From: wuuei <9289130+wuuei@users.noreply.github.com> Date: Fri, 14 Mar 2025 15:20:49 +0000 Subject: [PATCH 2/7] Fix code style to resolve failing check --- module/Core/src/Matomo/MatomoVisitSender.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/Core/src/Matomo/MatomoVisitSender.php b/module/Core/src/Matomo/MatomoVisitSender.php index 94f25e2f..6a32c2a5 100644 --- a/module/Core/src/Matomo/MatomoVisitSender.php +++ b/module/Core/src/Matomo/MatomoVisitSender.php @@ -11,6 +11,8 @@ use Shlinkio\Shlink\Core\Visit\Entity\Visit; use Shlinkio\Shlink\Core\Visit\Repository\VisitIterationRepositoryInterface; use Throwable; +use function strtolower; + readonly class MatomoVisitSender implements MatomoVisitSenderInterface { public function __construct( From d273b561444067a88e198f25246b7c61c4e8013a Mon Sep 17 00:00:00 2001 From: wuuei <9289130+wuuei@users.noreply.github.com> Date: Fri, 14 Mar 2025 15:21:55 +0000 Subject: [PATCH 3/7] Lock "endroid/qr-code" to 6.0.3 so that unit tests complete --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d23ec7cf..4a8c4e87 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "doctrine/migrations": "^3.8", "doctrine/orm": "^3.3", "donatj/phpuseragentparser": "^1.10", - "endroid/qr-code": "^6.0", + "endroid/qr-code": "<6.0.4", "friendsofphp/proxy-manager-lts": "^1.0", "geoip2/geoip2": "^3.1", "guzzlehttp/guzzle": "^7.9", From 1ceb38f50bd5f1e6dbb4bb79c3e807d2a7543813 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 14 Mar 2025 17:38:53 +0100 Subject: [PATCH 4/7] Test actual arguments set to matomo tracker when sending visits --- .../test/Matomo/MatomoVisitSenderTest.php | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/module/Core/test/Matomo/MatomoVisitSenderTest.php b/module/Core/test/Matomo/MatomoVisitSenderTest.php index 0acccd1d..7d66d868 100644 --- a/module/Core/test/Matomo/MatomoVisitSenderTest.php +++ b/module/Core/test/Matomo/MatomoVisitSenderTest.php @@ -43,6 +43,9 @@ class MatomoVisitSenderTest extends TestCase } #[Test, DataProvider('provideTrackerMethods')] + /** + * @param array $invokedMethods + */ public function visitIsSentToMatomo(Visit $visit, string|null $originalIpAddress, array $invokedMethods): void { $tracker = $this->createMock(MatomoTracker::class); @@ -66,8 +69,8 @@ class MatomoVisitSenderTest extends TestCase )->willReturn($tracker); } - foreach ($invokedMethods as $invokedMethod) { - $tracker->expects($this->once())->method($invokedMethod)->willReturn($tracker); + foreach ($invokedMethods as $invokedMethod => $args) { + $tracker->expects($this->once())->method($invokedMethod)->with(...$args)->willReturn($tracker); } $this->trackerBuilder->expects($this->once())->method('buildMatomoTracker')->willReturn($tracker); @@ -81,18 +84,28 @@ class MatomoVisitSenderTest extends TestCase yield 'located regular visit' => [ Visit::forValidShortUrl(ShortUrl::withLongUrl('https://shlink.io'), Visitor::empty()) ->locate(VisitLocation::fromGeolocation(new Location( - countryCode: 'countryCode', + countryCode: 'US', countryName: 'countryName', regionName: 'regionName', city: 'city', latitude: 123, - longitude: 123, + longitude: 456, timeZone: 'timeZone', ))), '1.2.3.4', - ['setCity', 'setCountry', 'setLatitude', 'setLongitude', 'setIp'], + [ + 'setCity' => ['city'], + 'setCountry' => ['us'], + 'setLatitude' => [123], + 'setLongitude' => [456], + 'setIp' => ['1.2.3.4'], + ], + ]; + yield 'fallback IP' => [ + Visit::forBasePath(Visitor::fromParams(remoteAddress: '5.6.7.8')), + null, + ['setIp' => ['5.6.7.0']], ]; - yield 'fallback IP' => [Visit::forBasePath(Visitor::fromParams(remoteAddress: '1.2.3.4')), null, ['setIp']]; } #[Test, DataProvider('provideUrlsToTrack')] From c7c2272faba41171cf4aae2eb9269d79b8b5ffb0 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 14 Mar 2025 17:53:23 +0100 Subject: [PATCH 5/7] Update changelog --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad221705..8e1d5b29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ 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). +## [Unreleased] +### Added +* *Nothing* + +### Changed +* *Nothing* + +### Deprecated +* *Nothing* + +### Removed +* *Nothing* + +### Fixed +* [#2391](https://github.com/shlinkio/shlink/issues/2391) When sending visits to Matomo, send the country code, not the country name. + + ## [4.4.5] - 2025-03-01 ### Added * *Nothing* From 8b4067efbe7cf5ea2dfa3c9ec3acd506bb7fd90a Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 14 Mar 2025 17:57:55 +0100 Subject: [PATCH 6/7] Update geekyeggo/delete-artifact action to v5 --- .github/workflows/ci.yml | 2 +- .github/workflows/publish-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2bc57d2..51803a4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,7 +96,7 @@ jobs: - upload-coverage runs-on: ubuntu-24.04 steps: - - uses: geekyeggo/delete-artifact@v2 + - uses: geekyeggo/delete-artifact@v5 with: name: | coverage-* diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index a2783f97..a6b923b4 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -45,6 +45,6 @@ jobs: needs: ['publish'] runs-on: ubuntu-24.04 steps: - - uses: geekyeggo/delete-artifact@v2 + - uses: geekyeggo/delete-artifact@v5 with: name: dist-files-* From 6526cf8c44bb9e8f59b09f32ebaf8ce57e7a95e3 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 20 Mar 2025 09:16:53 +0100 Subject: [PATCH 7/7] Fix error intrduced by endroid/qr-code 6.0.4 --- CHANGELOG.md | 3 ++- composer.json | 5 +++-- module/Core/src/Action/Model/QrCodeParams.php | 14 ++++++++++---- module/Core/src/Action/QrCodeAction.php | 1 + 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e1d5b29..818a25f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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). -## [Unreleased] +## [4.4.6] - 2025-03-20 ### Added * *Nothing* @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this ### Fixed * [#2391](https://github.com/shlinkio/shlink/issues/2391) When sending visits to Matomo, send the country code, not the country name. +* Fix error with new option introduced by `endroid/qr-code` 6.0.4. ## [4.4.5] - 2025-03-01 diff --git a/composer.json b/composer.json index 4a8c4e87..fa8cc972 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "doctrine/migrations": "^3.8", "doctrine/orm": "^3.3", "donatj/phpuseragentparser": "^1.10", - "endroid/qr-code": "<6.0.4", + "endroid/qr-code": "^6.0.5", "friendsofphp/proxy-manager-lts": "^1.0", "geoip2/geoip2": "^3.1", "guzzlehttp/guzzle": "^7.9", @@ -77,7 +77,8 @@ "veewee/composer-run-parallel": "^1.4" }, "conflict": { - "symfony/var-exporter": ">=6.3.9,<=6.4.0" + "symfony/var-exporter": ">=6.3.9,<=6.4.0", + "phpunit/phpunit": "12.0.9" }, "autoload": { "psr-4": { diff --git a/module/Core/src/Action/Model/QrCodeParams.php b/module/Core/src/Action/Model/QrCodeParams.php index 459c99b7..3b25b611 100644 --- a/module/Core/src/Action/Model/QrCodeParams.php +++ b/module/Core/src/Action/Model/QrCodeParams.php @@ -38,6 +38,7 @@ final readonly class QrCodeParams public int $size, public int $margin, public WriterInterface $writer, + public array $writerOptions, public ErrorCorrectionLevel $errorCorrectionLevel, public RoundBlockSizeMode $roundBlockSizeMode, public ColorInterface $color, @@ -49,11 +50,13 @@ final readonly class QrCodeParams public static function fromRequest(ServerRequestInterface $request, QrCodeOptions $defaults): self { $query = $request->getQueryParams(); + [$writer, $writerOptions] = self::resolveWriterAndWriterOptions($query, $defaults); return new self( size: self::resolveSize($query, $defaults), margin: self::resolveMargin($query, $defaults), - writer: self::resolveWriter($query, $defaults), + writer: $writer, + writerOptions: $writerOptions, errorCorrectionLevel: self::resolveErrorCorrection($query, $defaults), roundBlockSizeMode: self::resolveRoundBlockSize($query, $defaults), color: self::resolveColor($query, $defaults), @@ -83,14 +86,17 @@ final readonly class QrCodeParams return max($intMargin, 0); } - private static function resolveWriter(array $query, QrCodeOptions $defaults): WriterInterface + /** + * @return array{WriterInterface, array} + */ + private static function resolveWriterAndWriterOptions(array $query, QrCodeOptions $defaults): array { $qFormat = self::normalizeParam($query['format'] ?? ''); $format = contains($qFormat, self::SUPPORTED_FORMATS) ? $qFormat : self::normalizeParam($defaults->format); return match ($format) { - 'svg' => new SvgWriter(), - default => new PngWriter(), + 'svg' => [new SvgWriter(), []], + default => [new PngWriter(), [PngWriter::WRITER_OPTION_NUMBER_OF_COLORS => null]], }; } diff --git a/module/Core/src/Action/QrCodeAction.php b/module/Core/src/Action/QrCodeAction.php index fbc83c21..889d1d04 100644 --- a/module/Core/src/Action/QrCodeAction.php +++ b/module/Core/src/Action/QrCodeAction.php @@ -45,6 +45,7 @@ readonly class QrCodeAction implements MiddlewareInterface $params = QrCodeParams::fromRequest($request, $this->options); $qrCodeBuilder = new Builder( writer: $params->writer, + writerOptions: $params->writerOptions, data: $this->stringifier->stringify($shortUrl), errorCorrectionLevel: $params->errorCorrectionLevel, size: $params->size,