Ensure filtering of custom-slug is different depending on the multi-sement lugsfeature flag

This commit is contained in:
Alejandro Celaya
2022-08-05 08:38:05 +02:00
parent 6834e72c4a
commit fc0d99be41
13 changed files with 82 additions and 24 deletions

View File

@@ -14,6 +14,7 @@ use function Shlinkio\Shlink\Core\getOptionalBoolFromInputFilter;
use function Shlinkio\Shlink\Core\getOptionalIntFromInputFilter;
use function Shlinkio\Shlink\Core\normalizeDate;
// TODO Rename to ShortUrlEdition
final class ShortUrlEdit implements TitleResolutionModelInterface
{
private bool $longUrlPropWasProvided = false;

View File

@@ -16,6 +16,7 @@ use function Shlinkio\Shlink\Core\normalizeDate;
use const Shlinkio\Shlink\DEFAULT_SHORT_CODES_LENGTH;
// TODO Rename to ShortUrlCreation
final class ShortUrlMeta implements TitleResolutionModelInterface
{
private string $longUrl;

View File

@@ -6,14 +6,40 @@ namespace Shlinkio\Shlink\Core\Options;
use Laminas\Stdlib\AbstractOptions;
use const Shlinkio\Shlink\DEFAULT_SHORT_CODES_LENGTH;
class UrlShortenerOptions extends AbstractOptions
{
protected $__strictMode__ = false; // phpcs:ignore
private array $domain = [];
private int $defaultShortCodesLength = DEFAULT_SHORT_CODES_LENGTH;
private bool $autoResolveTitles = false;
private bool $appendExtraPath = false;
private bool $multiSegmentSlugsEnabled = false;
public function domain(): array
{
return $this->domain;
}
protected function setDomain(array $domain): self
{
$this->domain = $domain;
return $this;
}
public function defaultShortCodesLength(): int
{
return $this->defaultShortCodesLength;
}
protected function setDefaultShortCodesLength(int $defaultShortCodesLength): self
{
$this->defaultShortCodesLength = $defaultShortCodesLength;
return $this;
}
public function autoResolveTitles(): bool
{
return $this->autoResolveTitles;

View File

@@ -10,12 +10,13 @@ use Laminas\InputFilter\Input;
use Laminas\InputFilter\InputFilter;
use Laminas\Validator;
use Shlinkio\Shlink\Common\Validation;
use Shlinkio\Shlink\Core\Config\EnvVars;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
use function is_string;
use function ltrim;
use function str_replace;
use function substr;
use function trim;
use const Shlinkio\Shlink\MIN_SHORT_CODES_LENGTH;
@@ -40,7 +41,7 @@ class ShortUrlInputFilter extends InputFilter
private function __construct(array $data, bool $requireLongUrl)
{
$this->initialize($requireLongUrl);
$this->initialize($requireLongUrl, $data[EnvVars::MULTI_SEGMENT_SLUGS_ENABLED->value] ?? false);
$this->setData($data);
}
@@ -54,7 +55,7 @@ class ShortUrlInputFilter extends InputFilter
return new self($data, false);
}
private function initialize(bool $requireLongUrl): void
private function initialize(bool $requireLongUrl, bool $multiSegmentEnabled): void
{
$longUrlInput = $this->createInput(self::LONG_URL, $requireLongUrl);
$longUrlInput->getValidatorChain()->attach(new Validator\NotEmpty([
@@ -77,9 +78,10 @@ class ShortUrlInputFilter extends InputFilter
// FIXME The only way to enforce the NotEmpty validator to be evaluated when the value is provided but it's
// empty, is by using the deprecated setContinueIfEmpty
$customSlug = $this->createInput(self::CUSTOM_SLUG, false)->setContinueIfEmpty(true);
$customSlug->getFilterChain()->attach(new Filter\Callback(
static fn (mixed $value) => is_string($value) ? ltrim(str_replace(' ', '-', $value), '/') : $value,
));
$customSlug->getFilterChain()->attach(new Filter\Callback(match ($multiSegmentEnabled) {
true => static fn (mixed $v) => is_string($v) ? trim(str_replace(' ', '-', $v), '/') : $v,
false => static fn (mixed $v) => is_string($v) ? str_replace([' ', '/'], '-', $v) : $v,
}));
$customSlug->getValidatorChain()->attach(new Validator\NotEmpty([
Validator\NotEmpty::STRING,
Validator\NotEmpty::SPACE,

View File

@@ -6,6 +6,7 @@ namespace ShlinkioTest\Shlink\Core\Model;
use Cake\Chronos\Chronos;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Config\EnvVars;
use Shlinkio\Shlink\Core\Exception\ValidationException;
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
use Shlinkio\Shlink\Core\Validation\ShortUrlInputFilter;
@@ -74,12 +75,16 @@ class ShortUrlMetaTest extends TestCase
* @test
* @dataProvider provideCustomSlugs
*/
public function properlyCreatedInstanceReturnsValues(string $customSlug, string $expectedSlug): void
{
public function properlyCreatedInstanceReturnsValues(
string $customSlug,
string $expectedSlug,
bool $multiSegmentEnabled = false,
): void {
$meta = ShortUrlMeta::fromRawData([
'validSince' => Chronos::parse('2015-01-01')->toAtomString(),
'customSlug' => $customSlug,
'longUrl' => '',
EnvVars::MULTI_SEGMENT_SLUGS_ENABLED->value => $multiSegmentEnabled,
]);
self::assertTrue($meta->hasValidSince());
@@ -103,8 +108,10 @@ class ShortUrlMetaTest extends TestCase
yield ['foo bar', 'foo-bar'];
yield ['foo bar baz', 'foo-bar-baz'];
yield ['foo bar-baz', 'foo-bar-baz'];
yield ['foo/bar/baz', 'foo/bar/baz'];
yield ['/foo/bar/baz', 'foo/bar/baz'];
yield ['foo/bar/baz', 'foo/bar/baz', true];
yield ['/foo/bar/baz', 'foo/bar/baz', true];
yield ['foo/bar/baz', 'foo-bar-baz'];
yield ['/foo/bar/baz', '-foo-bar-baz'];
yield ['wp-admin.php', 'wp-admin.php'];
yield ['UPPER_lower', 'UPPER_lower'];
yield ['more~url_special.chars', 'more~url_special.chars'];