diff --git a/app/src/ViewFunctions/Url.php b/app/src/ViewFunctions/Url.php index 484d9a5..8879207 100644 --- a/app/src/ViewFunctions/Url.php +++ b/app/src/ViewFunctions/Url.php @@ -3,6 +3,7 @@ namespace App\ViewFunctions; use App\Support\Str; +use RuntimeException; class Url extends ViewFunction { @@ -23,21 +24,33 @@ class Url extends ViewFunction } /** - * Return the URL for a given path. + * Return the URL for a given path and action. * - * @param string $path + * @param string $path + * @param string|null $action * * @return string */ - public function __invoke(string $path = '/'): string + public function __invoke(string $path = '/', string $action = null): string { $path = preg_replace('/^.?(\/|\\\)+/', '', $path); - if (is_file($path)) { - return $this->escape($path); - } + switch ($action) { + case null: + return $this->escape($path); - return empty($path) ? '' : sprintf('?dir=%s', $this->escape($path)); + case 'dir': + return empty($path) ? '' : sprintf('?dir=%s', $this->escape($path)); + + case 'info': + return empty($path) ? '?info=.' : sprintf('?info=%s', $this->escape($path)); + + case 'zip': + return empty($path) ? '?zip=.' : sprintf('?zip=%s', $this->escape($path)); + + default: + throw new RuntimeException(sprintf('Invalid action "%s"', $action)); + } } /** diff --git a/app/views/components/file.twig b/app/views/components/file.twig index 136ac43..d8e8578 100644 --- a/app/views/components/file.twig +++ b/app/views/components/file.twig @@ -1,5 +1,5 @@
diff --git a/app/views/components/header.twig b/app/views/components/header.twig index 0259e52..d04409c 100644 --- a/app/views/components/header.twig +++ b/app/views/components/header.twig @@ -14,7 +14,7 @@
{% if path and config('zip_downloads', true) %} - + {% endif %} diff --git a/tests/ViewFunctions/UrlTest.php b/tests/ViewFunctions/UrlTest.php index c7d2393..3b66820 100644 --- a/tests/ViewFunctions/UrlTest.php +++ b/tests/ViewFunctions/UrlTest.php @@ -3,53 +3,91 @@ namespace Tests\ViewFunctions; use App\ViewFunctions\Url; +use RuntimeException; use Tests\TestCase; class UrlTest extends TestCase { - public function test_it_can_return_a_url_for_a_directory(): void + public function test_it_can_return_a_url(): void { $url = new Url; $this->assertEquals('', $url('/')); $this->assertEquals('', $url('./')); - $this->assertEquals('?dir=some/path', $url('some/path')); - $this->assertEquals('?dir=some/path', $url('./some/path')); - $this->assertEquals('?dir=some/path', $url('./some/path')); - $this->assertEquals('?dir=some/file.test', $url('some/file.test')); - $this->assertEquals('?dir=some/file.test', $url('./some/file.test')); + $this->assertEquals('some/path', $url('some/path')); + $this->assertEquals('some/path', $url('./some/path')); + $this->assertEquals('some/path', $url('./some/path')); + $this->assertEquals('some/file.test', $url('some/file.test')); + $this->assertEquals('some/file.test', $url('./some/file.test')); } - public function test_it_can_return_a_url_for_a_directory_using_back_slashes(): void + public function test_it_can_return_a_directory_url(): void + { + $url = new Url; + + $this->assertEquals('', $url('/', 'dir')); + $this->assertEquals('', $url('./', 'dir')); + $this->assertEquals('?dir=some/path', $url('some/path', 'dir')); + $this->assertEquals('?dir=some/path', $url('./some/path', 'dir')); + $this->assertEquals('?dir=some/path', $url('./some/path', 'dir')); + $this->assertEquals('?dir=some/file.test', $url('some/file.test', 'dir')); + $this->assertEquals('?dir=some/file.test', $url('./some/file.test', 'dir')); + } + + public function test_it_can_return_a_file_info_url(): void + { + $url = new Url; + + $this->assertEquals('?info=.', $url('/', 'info')); + $this->assertEquals('?info=.', $url('./', 'info')); + $this->assertEquals('?info=some/path', $url('some/path', 'info')); + $this->assertEquals('?info=some/path', $url('./some/path', 'info')); + $this->assertEquals('?info=some/path', $url('./some/path', 'info')); + $this->assertEquals('?info=some/file.test', $url('some/file.test', 'info')); + $this->assertEquals('?info=some/file.test', $url('./some/file.test', 'info')); + } + + public function test_it_can_return_a_zip_url(): void + { + $url = new Url; + + $this->assertEquals('?zip=.', $url('/', 'zip')); + $this->assertEquals('?zip=.', $url('./', 'zip')); + $this->assertEquals('?zip=some/path', $url('some/path', 'zip')); + $this->assertEquals('?zip=some/path', $url('./some/path', 'zip')); + $this->assertEquals('?zip=some/path', $url('./some/path', 'zip')); + } + + public function test_it_can_return_a_url_with_back_slashes(): void { $url = new Url('\\'); $this->assertEquals('', $url('\\')); $this->assertEquals('', $url('.\\')); - $this->assertEquals('?dir=some\path', $url('some\path')); - $this->assertEquals('?dir=some\path', $url('.\some\path')); - $this->assertEquals('?dir=some\file.test', $url('some\file.test')); - $this->assertEquals('?dir=some\file.test', $url('.\some\file.test')); + $this->assertEquals('some\path', $url('some\path')); + $this->assertEquals('some\path', $url('.\some\path')); + $this->assertEquals('some\file.test', $url('some\file.test')); + $this->assertEquals('some\file.test', $url('.\some\file.test')); + $this->assertEquals('?dir=some\path', $url('some\path', 'dir')); + $this->assertEquals('?info=some\path', $url('some\path', 'info')); + $this->assertEquals('?zip=some\path', $url('some\path', 'zip')); } - public function test_it_can_return_a_url_for_a_file(): void - { - chdir($this->filePath('.')); - - $url = new Url; - - $this->assertEquals('README.md', $url('README.md')); - $this->assertEquals('README.md', $url('./README.md')); - $this->assertEquals('subdir/alpha.scss', $url('subdir/alpha.scss')); - $this->assertEquals('subdir/alpha.scss', $url('./subdir/alpha.scss')); - } - - public function test_it_url_encodes_directory_names(): void + public function test_it_throws_an_exception_for_an_invalid_action(): void { $url = new Url; - $this->assertEquals('?dir=foo/bar%2Bbaz', $url('foo/bar+baz')); - $this->assertEquals('?dir=foo/bar%23baz', $url('foo/bar#baz')); - $this->assertEquals('?dir=foo/bar%26baz', $url('foo/bar&baz')); + $this->expectException(RuntimeException::class); + + $url('some/path', 'INVALID_ACTION'); + } + + public function test_segments_are_url_encoded(): void + { + $url = new Url; + + $this->assertEquals('foo/bar%2Bbaz', $url('foo/bar+baz')); + $this->assertEquals('foo/bar%23baz', $url('foo/bar#baz')); + $this->assertEquals('foo/bar%26baz', $url('foo/bar&baz')); } }