mirror of
https://github.com/shlinkio/shlink.git
synced 2026-03-10 17:23:12 +08:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2649395f8 | ||
|
|
b7d9ba8258 | ||
|
|
6526cf8c44 | ||
|
|
a85afb2bee | ||
|
|
8b4067efbe | ||
|
|
c7c2272fab | ||
|
|
bc77750713 | ||
|
|
1ceb38f50b | ||
|
|
d273b56144 | ||
|
|
5cd7305666 | ||
|
|
3040a22c02 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
|||||||
- upload-coverage
|
- upload-coverage
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: geekyeggo/delete-artifact@v2
|
- uses: geekyeggo/delete-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: |
|
name: |
|
||||||
coverage-*
|
coverage-*
|
||||||
|
|||||||
2
.github/workflows/publish-release.yml
vendored
2
.github/workflows/publish-release.yml
vendored
@@ -45,6 +45,6 @@ jobs:
|
|||||||
needs: ['publish']
|
needs: ['publish']
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: geekyeggo/delete-artifact@v2
|
- uses: geekyeggo/delete-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: dist-files-*
|
name: dist-files-*
|
||||||
|
|||||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -4,6 +4,24 @@ 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).
|
The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
|
||||||
|
|
||||||
|
## [4.4.6] - 2025-03-20
|
||||||
|
### 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.
|
||||||
|
* Fix error with new option introduced by `endroid/qr-code` 6.0.4.
|
||||||
|
|
||||||
|
|
||||||
## [4.4.5] - 2025-03-01
|
## [4.4.5] - 2025-03-01
|
||||||
### Added
|
### Added
|
||||||
* *Nothing*
|
* *Nothing*
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"doctrine/migrations": "^3.8",
|
"doctrine/migrations": "^3.8",
|
||||||
"doctrine/orm": "^3.3",
|
"doctrine/orm": "^3.3",
|
||||||
"donatj/phpuseragentparser": "^1.10",
|
"donatj/phpuseragentparser": "^1.10",
|
||||||
"endroid/qr-code": "^6.0",
|
"endroid/qr-code": "^6.0.5",
|
||||||
"friendsofphp/proxy-manager-lts": "^1.0",
|
"friendsofphp/proxy-manager-lts": "^1.0",
|
||||||
"geoip2/geoip2": "^3.1",
|
"geoip2/geoip2": "^3.1",
|
||||||
"guzzlehttp/guzzle": "^7.9",
|
"guzzlehttp/guzzle": "^7.9",
|
||||||
@@ -77,7 +77,8 @@
|
|||||||
"veewee/composer-run-parallel": "^1.4"
|
"veewee/composer-run-parallel": "^1.4"
|
||||||
},
|
},
|
||||||
"conflict": {
|
"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": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ final readonly class QrCodeParams
|
|||||||
public int $size,
|
public int $size,
|
||||||
public int $margin,
|
public int $margin,
|
||||||
public WriterInterface $writer,
|
public WriterInterface $writer,
|
||||||
|
public array $writerOptions,
|
||||||
public ErrorCorrectionLevel $errorCorrectionLevel,
|
public ErrorCorrectionLevel $errorCorrectionLevel,
|
||||||
public RoundBlockSizeMode $roundBlockSizeMode,
|
public RoundBlockSizeMode $roundBlockSizeMode,
|
||||||
public ColorInterface $color,
|
public ColorInterface $color,
|
||||||
@@ -49,11 +50,13 @@ final readonly class QrCodeParams
|
|||||||
public static function fromRequest(ServerRequestInterface $request, QrCodeOptions $defaults): self
|
public static function fromRequest(ServerRequestInterface $request, QrCodeOptions $defaults): self
|
||||||
{
|
{
|
||||||
$query = $request->getQueryParams();
|
$query = $request->getQueryParams();
|
||||||
|
[$writer, $writerOptions] = self::resolveWriterAndWriterOptions($query, $defaults);
|
||||||
|
|
||||||
return new self(
|
return new self(
|
||||||
size: self::resolveSize($query, $defaults),
|
size: self::resolveSize($query, $defaults),
|
||||||
margin: self::resolveMargin($query, $defaults),
|
margin: self::resolveMargin($query, $defaults),
|
||||||
writer: self::resolveWriter($query, $defaults),
|
writer: $writer,
|
||||||
|
writerOptions: $writerOptions,
|
||||||
errorCorrectionLevel: self::resolveErrorCorrection($query, $defaults),
|
errorCorrectionLevel: self::resolveErrorCorrection($query, $defaults),
|
||||||
roundBlockSizeMode: self::resolveRoundBlockSize($query, $defaults),
|
roundBlockSizeMode: self::resolveRoundBlockSize($query, $defaults),
|
||||||
color: self::resolveColor($query, $defaults),
|
color: self::resolveColor($query, $defaults),
|
||||||
@@ -83,14 +86,17 @@ final readonly class QrCodeParams
|
|||||||
return max($intMargin, 0);
|
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'] ?? '');
|
$qFormat = self::normalizeParam($query['format'] ?? '');
|
||||||
$format = contains($qFormat, self::SUPPORTED_FORMATS) ? $qFormat : self::normalizeParam($defaults->format);
|
$format = contains($qFormat, self::SUPPORTED_FORMATS) ? $qFormat : self::normalizeParam($defaults->format);
|
||||||
|
|
||||||
return match ($format) {
|
return match ($format) {
|
||||||
'svg' => new SvgWriter(),
|
'svg' => [new SvgWriter(), []],
|
||||||
default => new PngWriter(),
|
default => [new PngWriter(), [PngWriter::WRITER_OPTION_NUMBER_OF_COLORS => null]],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ readonly class QrCodeAction implements MiddlewareInterface
|
|||||||
$params = QrCodeParams::fromRequest($request, $this->options);
|
$params = QrCodeParams::fromRequest($request, $this->options);
|
||||||
$qrCodeBuilder = new Builder(
|
$qrCodeBuilder = new Builder(
|
||||||
writer: $params->writer,
|
writer: $params->writer,
|
||||||
|
writerOptions: $params->writerOptions,
|
||||||
data: $this->stringifier->stringify($shortUrl),
|
data: $this->stringifier->stringify($shortUrl),
|
||||||
errorCorrectionLevel: $params->errorCorrectionLevel,
|
errorCorrectionLevel: $params->errorCorrectionLevel,
|
||||||
size: $params->size,
|
size: $params->size,
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
|||||||
use Shlinkio\Shlink\Core\Visit\Repository\VisitIterationRepositoryInterface;
|
use Shlinkio\Shlink\Core\Visit\Repository\VisitIterationRepositoryInterface;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
|
use function strtolower;
|
||||||
|
|
||||||
readonly class MatomoVisitSender implements MatomoVisitSenderInterface
|
readonly class MatomoVisitSender implements MatomoVisitSenderInterface
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -60,7 +62,7 @@ readonly class MatomoVisitSender implements MatomoVisitSenderInterface
|
|||||||
if ($location !== null) {
|
if ($location !== null) {
|
||||||
$tracker
|
$tracker
|
||||||
->setCity($location->cityName)
|
->setCity($location->cityName)
|
||||||
->setCountry($location->countryName)
|
->setCountry(strtolower($location->countryCode))
|
||||||
->setLatitude($location->latitude)
|
->setLatitude($location->latitude)
|
||||||
->setLongitude($location->longitude);
|
->setLongitude($location->longitude);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ class MatomoVisitSenderTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Test, DataProvider('provideTrackerMethods')]
|
#[Test, DataProvider('provideTrackerMethods')]
|
||||||
|
/**
|
||||||
|
* @param array<string, string[]> $invokedMethods
|
||||||
|
*/
|
||||||
public function visitIsSentToMatomo(Visit $visit, string|null $originalIpAddress, array $invokedMethods): void
|
public function visitIsSentToMatomo(Visit $visit, string|null $originalIpAddress, array $invokedMethods): void
|
||||||
{
|
{
|
||||||
$tracker = $this->createMock(MatomoTracker::class);
|
$tracker = $this->createMock(MatomoTracker::class);
|
||||||
@@ -66,8 +69,8 @@ class MatomoVisitSenderTest extends TestCase
|
|||||||
)->willReturn($tracker);
|
)->willReturn($tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($invokedMethods as $invokedMethod) {
|
foreach ($invokedMethods as $invokedMethod => $args) {
|
||||||
$tracker->expects($this->once())->method($invokedMethod)->willReturn($tracker);
|
$tracker->expects($this->once())->method($invokedMethod)->with(...$args)->willReturn($tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->trackerBuilder->expects($this->once())->method('buildMatomoTracker')->willReturn($tracker);
|
$this->trackerBuilder->expects($this->once())->method('buildMatomoTracker')->willReturn($tracker);
|
||||||
@@ -81,18 +84,28 @@ class MatomoVisitSenderTest extends TestCase
|
|||||||
yield 'located regular visit' => [
|
yield 'located regular visit' => [
|
||||||
Visit::forValidShortUrl(ShortUrl::withLongUrl('https://shlink.io'), Visitor::empty())
|
Visit::forValidShortUrl(ShortUrl::withLongUrl('https://shlink.io'), Visitor::empty())
|
||||||
->locate(VisitLocation::fromGeolocation(new Location(
|
->locate(VisitLocation::fromGeolocation(new Location(
|
||||||
countryCode: 'countryCode',
|
countryCode: 'US',
|
||||||
countryName: 'countryName',
|
countryName: 'countryName',
|
||||||
regionName: 'regionName',
|
regionName: 'regionName',
|
||||||
city: 'city',
|
city: 'city',
|
||||||
latitude: 123,
|
latitude: 123,
|
||||||
longitude: 123,
|
longitude: 456,
|
||||||
timeZone: 'timeZone',
|
timeZone: 'timeZone',
|
||||||
))),
|
))),
|
||||||
'1.2.3.4',
|
'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')]
|
#[Test, DataProvider('provideUrlsToTrack')]
|
||||||
|
|||||||
Reference in New Issue
Block a user