Skip to content

Commit

Permalink
Allow QR code logo to be individually disabled
Browse files Browse the repository at this point in the history
  • Loading branch information
acelaya committed Dec 18, 2024
1 parent 736e09a commit a0971e9
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 14 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this

All [URI-reserved characters](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2) were disallowed up until now, but from now on, only the gen-delimiters are.

* [#2229](https://github.com/shlinkio/shlink/issues/2229) Add option to dynamically disable the logo on QR codes.

### Changed
* [#2281](https://github.com/shlinkio/shlink/issues/2281) Update docker image to PHP 8.4
* [#2124](https://github.com/shlinkio/shlink/issues/2124) Improve how Shlink decides if a GeoLite db file needs to be downloaded, and reduces the chances for API limits to be reached.
Expand Down
10 changes: 10 additions & 0 deletions docs/swagger/paths/{shortCode}_qr-code.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@
"type": "string",
"default": "#ffffff"
}
},
{
"name": "logo",
"in": "query",
"description": "Currently used to disable the logo that was set via configuration options. It may be used in future to dynamically choose from multiple logos.",
"required": false,
"schema": {
"type": "string",
"enum": ["disable"]
}
}
],
"responses": {
Expand Down
18 changes: 10 additions & 8 deletions module/Core/src/Action/Model/QrCodeParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,21 @@
use const Shlinkio\Shlink\DEFAULT_QR_CODE_BG_COLOR;
use const Shlinkio\Shlink\DEFAULT_QR_CODE_COLOR;

final class QrCodeParams
final readonly class QrCodeParams
{
private const int MIN_SIZE = 50;
private const int MAX_SIZE = 1000;
private const array SUPPORTED_FORMATS = ['png', 'svg'];

private function __construct(
public readonly int $size,
public readonly int $margin,
public readonly WriterInterface $writer,
public readonly ErrorCorrectionLevel $errorCorrectionLevel,
public readonly RoundBlockSizeMode $roundBlockSizeMode,
public readonly ColorInterface $color,
public readonly ColorInterface $bgColor,
public int $size,
public int $margin,
public WriterInterface $writer,
public ErrorCorrectionLevel $errorCorrectionLevel,
public RoundBlockSizeMode $roundBlockSizeMode,
public ColorInterface $color,
public ColorInterface $bgColor,
public bool $disableLogo,
) {
}

Expand All @@ -57,6 +58,7 @@ public static function fromRequest(ServerRequestInterface $request, QrCodeOption
roundBlockSizeMode: self::resolveRoundBlockSize($query, $defaults),
color: self::resolveColor($query, $defaults),
bgColor: self::resolveBackgroundColor($query, $defaults),
disableLogo: isset($query['logo']) && $query['logo'] === 'disable',
);
}

Expand Down
2 changes: 1 addition & 1 deletion module/Core/src/Action/QrCodeAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function process(Request $request, RequestHandlerInterface $handler): Res
private function buildQrCode(Builder $qrCodeBuilder, QrCodeParams $params): ResultInterface
{
$logoUrl = $this->options->logoUrl;
if ($logoUrl === null) {
if ($logoUrl === null || $params->disableLogo) {
return $qrCodeBuilder->build();
}

Expand Down
15 changes: 10 additions & 5 deletions module/Core/test/Action/QrCodeActionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface;
Expand Down Expand Up @@ -294,11 +295,15 @@ public function qrCodeIsResolvedBasedOnOptions(bool $enabledForDisabledShortUrls
}

#[Test]
public function logoIsAddedToQrCodeIfOptionIsDefined(): void
#[TestWith([[], '4696E5'])] // The logo has Shlink's brand color
#[TestWith([['logo' => 'disable'], '000000'])] // No logo will be added if explicitly disabled
public function logoIsAddedToQrCodeIfOptionIsDefined(array $query, string $expectedColor): void
{
$logoUrl = 'https://avatars.githubusercontent.com/u/20341790?v=4'; // Shlink logo
$logoUrl = 'https://avatars.githubusercontent.com/u/20341790?v=4'; // Shlink's logo
$code = 'abc123';
$req = ServerRequestFactory::fromGlobals()->withAttribute('shortCode', $code);
$req = ServerRequestFactory::fromGlobals()
->withAttribute('shortCode', $code)
->withQueryParams($query);

$this->urlResolver->method('resolveEnabledShortUrl')->with(
ShortUrlIdentifier::fromShortCodeAndDomain($code),
Expand All @@ -309,9 +314,9 @@ public function logoIsAddedToQrCodeIfOptionIsDefined(): void
$image = imagecreatefromstring($resp->getBody()->__toString());
self::assertNotFalse($image);

// At around 100x100 px we can already find the logo, which has Shlink's brand color
// At around 100x100 px we can already find the logo, if present
$resultingColor = imagecolorat($image, 100, 100);
self::assertEquals(hexdec('4696E5'), $resultingColor);
self::assertEquals(hexdec($expectedColor), $resultingColor);
}

public static function provideEnabled(): iterable
Expand Down

0 comments on commit a0971e9

Please sign in to comment.