diff --git a/src/Cms/File.php b/src/Cms/File.php index 41208db6e2..4fac82c5ed 100644 --- a/src/Cms/File.php +++ b/src/Cms/File.php @@ -624,7 +624,7 @@ public function url(): string * Page URL and the filename as a more stable * alternative for the media URLs. */ - public function previewUrl(): string + public function previewUrl(): string|null { $parent = $this->parent(); $url = Url::to($this->id()); @@ -633,6 +633,12 @@ public function previewUrl(): string case 'page': $preview = $parent->blueprint()->preview(); + // user has no permission to preview page, + // also return null for file preview + if ($preview === false) { + return null; + } + // the page has a custom preview setting, // thus the file is only accessible through // the direct media URL diff --git a/src/Cms/PageBlueprint.php b/src/Cms/PageBlueprint.php index 79be695f2e..6015fbbe24 100644 --- a/src/Cms/PageBlueprint.php +++ b/src/Cms/PageBlueprint.php @@ -180,7 +180,7 @@ public function preview(): string|bool return $this->model->toString($preview); } - return $preview; + return $this->model->permissions()->can('preview', true); } /** diff --git a/src/Cms/SiteBlueprint.php b/src/Cms/SiteBlueprint.php index 5f8b751b2a..65b179c043 100644 --- a/src/Cms/SiteBlueprint.php +++ b/src/Cms/SiteBlueprint.php @@ -51,6 +51,6 @@ public function preview(): string|bool return $this->model->toString($preview); } - return $preview; + return $this->model->permissions()->can('preview', true); } } diff --git a/tests/Cms/Files/FileTest.php b/tests/Cms/Files/FileTest.php index be4b62aa50..d846448bd5 100644 --- a/tests/Cms/Files/FileTest.php +++ b/tests/Cms/Files/FileTest.php @@ -725,6 +725,25 @@ public function testPermalink() public function testPreviewUrl() { + $app = $this->app->clone([ + 'users' => [ + [ + 'id' => 'test', + 'email' => 'test@getkirby.com', + 'role' => 'editor' + ] + ], + 'roles' => [ + [ + 'id' => 'editor', + 'name' => 'editor', + ] + ] + ]); + + // authenticate + $app->impersonate('test@getkirby.com'); + $page = new Page([ 'slug' => 'test', 'files' => [ @@ -738,8 +757,42 @@ public function testPreviewUrl() $this->assertSame('/test/test.pdf', $file->previewUrl()); } + public function testPreviewUrlUnauthenticated() + { + $page = new Page([ + 'slug' => 'test', + 'files' => [ + [ + 'filename' => 'test.pdf' + ] + ] + ]); + + $file = $page->file('test.pdf'); + $this->assertNull($file->previewUrl()); + } + public function testPreviewUrlForDraft() { + $app = $this->app->clone([ + 'users' => [ + [ + 'id' => 'test', + 'email' => 'test@getkirby.com', + 'role' => 'editor' + ] + ], + 'roles' => [ + [ + 'id' => 'editor', + 'name' => 'editor', + ] + ] + ]); + + // authenticate + $app->impersonate('test@getkirby.com'); + $page = new Page([ 'slug' => 'test', 'isDraft' => true, @@ -754,7 +807,7 @@ public function testPreviewUrlForDraft() $this->assertSame($file->url(), $file->previewUrl()); } - public function testPreviewUrlForPageWithCustomPreviewSetting() + public function testPreviewUrlForPageWithDeniedPreviewSetting() { $app = new App([ 'blueprints' => [ @@ -779,15 +832,98 @@ public function testPreviewUrlForPageWithCustomPreviewSetting() ] ] ] + ], + 'users' => [ + [ + 'id' => 'test', + 'email' => 'test@getkirby.com', + 'role' => 'editor' + ] + ], + 'roles' => [ + [ + 'id' => 'editor', + 'name' => 'editor', + ] + ] + ]); + + // authenticate + $app->impersonate('test@getkirby.com'); + + $file = $app->file('test/test.pdf'); + $this->assertNull($file->previewUrl()); + } + + public function testPreviewUrlForPageWithCustomPreviewSetting() + { + $app = new App([ + 'blueprints' => [ + 'pages/test' => [ + 'options' => [ + 'preview' => '/foo/bar' + ] + ] + ], + 'roots' => [ + 'index' => '/dev/null' + ], + 'site' => [ + 'children' => [ + [ + 'slug' => 'test', + 'template' => 'test', + 'files' => [ + [ + 'filename' => 'test.pdf' + ] + ] + ] + ] + ], + 'users' => [ + [ + 'id' => 'test', + 'email' => 'test@getkirby.com', + 'role' => 'editor' + ] + ], + 'roles' => [ + [ + 'id' => 'editor', + 'name' => 'editor', + ] ] ]); + // authenticate + $app->impersonate('test@getkirby.com'); + $file = $app->file('test/test.pdf'); $this->assertSame($file->url(), $file->previewUrl()); } public function testPreviewUrlForUserFile() { + $app = $this->app->clone([ + 'users' => [ + [ + 'id' => 'test', + 'email' => 'test@getkirby.com', + 'role' => 'editor' + ] + ], + 'roles' => [ + [ + 'id' => 'editor', + 'name' => 'editor', + ] + ] + ]); + + // authenticate + $app->impersonate('test@getkirby.com'); + $user = new User([ 'email' => 'test@getkirby.com', 'files' => [ @@ -820,9 +956,25 @@ public function testPreviewUrlForExtendedComponent() ] ] ] + ], + 'users' => [ + [ + 'id' => 'test', + 'email' => 'test@getkirby.com', + 'role' => 'editor' + ] + ], + 'roles' => [ + [ + 'id' => 'editor', + 'name' => 'editor', + ] ] ]); + // authenticate + $app->impersonate('test@getkirby.com'); + $file = $app->file('test/test.pdf'); $this->assertSame('https://getkirby.com/test.pdf', $file->previewUrl()); } diff --git a/tests/Cms/Pages/PageTest.php b/tests/Cms/Pages/PageTest.php index 25a4b17ca7..2a7f939134 100644 --- a/tests/Cms/Pages/PageTest.php +++ b/tests/Cms/Pages/PageTest.php @@ -583,9 +583,30 @@ public function testPreviewUrl() 'slug' => 'test' ]); + // authenticate + $app->impersonate('kirby'); + $this->assertSame('/test', $page->previewUrl()); } + public function testPreviewUrlUnauthenticated() + { + new App([ + 'roots' => [ + 'index' => '/dev/null' + ], + 'urls' => [ + 'index' => '/' + ] + ]); + + $page = new Page([ + 'slug' => 'test' + ]); + + $this->assertNull($page->previewUrl()); + } + public static function previewUrlProvider(): array { return [ @@ -600,23 +621,46 @@ public static function previewUrlProvider(): array ['{{ page.url }}?preview=true', '/test?preview=true&{token}', true], [false, null, false], [false, null, true], + [null, null, false, false], ]; } /** * @dataProvider previewUrlProvider */ - public function testCustomPreviewUrl($input, $expected, $draft) - { + public function testCustomPreviewUrl( + $input, + $expected, + bool $draft, + bool $authenticated = true + ): void { $app = new App([ 'roots' => [ 'index' => '/dev/null' ], 'urls' => [ 'index' => '/' + ], + 'users' => [ + [ + 'id' => 'test', + 'email' => 'test@getkirby.com', + 'role' => 'editor' + ] + ], + 'roles' => [ + [ + 'id' => 'editor', + 'name' => 'editor', + ] ] ]); + // authenticate + if ($authenticated) { + $app->impersonate('test@getkirby.com'); + } + $options = []; if ($input !== null) { diff --git a/tests/Cms/Site/SiteTest.php b/tests/Cms/Site/SiteTest.php index 0440d5b563..75631764e0 100644 --- a/tests/Cms/Site/SiteTest.php +++ b/tests/Cms/Site/SiteTest.php @@ -194,23 +194,45 @@ public static function previewUrlProvider(): array ['https://test.com', 'https://test.com'], ['{{ site.url }}#test', '/#test'], [false, null], + [null, null, false], ]; } /** * @dataProvider previewUrlProvider */ - public function testCustomPreviewUrl($input, $expected) - { + public function testCustomPreviewUrl( + $input, + $expected, + bool $authenticated = true + ): void { $app = new App([ 'roots' => [ 'index' => '/dev/null' ], 'urls' => [ 'index' => '/' + ], + 'users' => [ + [ + 'id' => 'test', + 'email' => 'test@getkirby.com', + 'role' => 'editor' + ] + ], + 'roles' => [ + [ + 'id' => 'editor', + 'name' => 'editor', + ] ] ]); + // authenticate + if ($authenticated) { + $app->impersonate('test@getkirby.com'); + } + $options = []; if ($input !== null) {