diff --git a/app/App/MetaController.php b/app/App/MetaController.php index 1515b4f7e..a94334c58 100644 --- a/app/App/MetaController.php +++ b/app/App/MetaController.php @@ -64,4 +64,14 @@ class MetaController extends Controller 'jsLibData' => file_get_contents(base_path('dev/licensing/js-library-licenses.txt')), ]); } + + /** + * Show the view for /opensearch.xml. + */ + public function opensearch() + { + return response() + ->view('misc.opensearch') + ->header('Content-Type', 'application/opensearchdescription+xml'); + } } diff --git a/lang/en/common.php b/lang/en/common.php index 266174eed..b05169bb2 100644 --- a/lang/en/common.php +++ b/lang/en/common.php @@ -107,4 +107,7 @@ return [ // Not directly used but available for convenience to users. 'privacy_policy' => 'Privacy Policy', 'terms_of_service' => 'Terms of Service', + + // OpenSearch + 'opensearch_description' => 'Search :appName', ]; diff --git a/resources/views/layouts/base.blade.php b/resources/views/layouts/base.blade.php index 4d4d07dc2..ddecb8e76 100644 --- a/resources/views/layouts/base.blade.php +++ b/resources/views/layouts/base.blade.php @@ -32,6 +32,9 @@ + + + @yield('head') diff --git a/resources/views/misc/opensearch.blade.php b/resources/views/misc/opensearch.blade.php new file mode 100644 index 000000000..5c1503fc4 --- /dev/null +++ b/resources/views/misc/opensearch.blade.php @@ -0,0 +1,12 @@ + + + {{ mb_strimwidth(setting('app-name'), 0, 16) }} + {{ trans('common.opensearch_description', ['appName' => setting('app-name')]) }} + {{ setting('app-icon') ?: url('/icon.png') }} + {{ setting('app-icon-180') ?: url('/icon-180.png') }} + {{ setting('app-icon-128') ?: url('/icon-128.png') }} + {{ setting('app-icon-64') ?: url('/icon-64.png') }} + {{ setting('app-icon-32') ?: url('/icon-32.png') }} + + + diff --git a/routes/web.php b/routes/web.php index 58b8f4e54..81b938f32 100644 --- a/routes/web.php +++ b/routes/web.php @@ -23,6 +23,7 @@ Route::get('/robots.txt', [MetaController::class, 'robots']); Route::get('/favicon.ico', [MetaController::class, 'favicon']); Route::get('/manifest.json', [MetaController::class, 'pwaManifest']); Route::get('/licenses', [MetaController::class, 'licenses']); +Route::get('/opensearch.xml', [MetaController::class, 'opensearch']); // Authenticated routes... Route::middleware('auth')->group(function () { diff --git a/tests/HelpTest.php b/tests/Meta/HelpTest.php similarity index 94% rename from tests/HelpTest.php rename to tests/Meta/HelpTest.php index 9cf80717f..e1de96bc8 100644 --- a/tests/HelpTest.php +++ b/tests/Meta/HelpTest.php @@ -1,6 +1,8 @@ put('app-name', $appName); + $resultUrl = url('/search') . '?term={searchTerms}'; + $selfUrl = url('/opensearch.xml'); + + $resp = $this->get('/opensearch.xml'); + $resp->assertOk(); + + $html = $this->withHtml($resp); + + $html->assertElementExists('OpenSearchDescription > ShortName'); + $html->assertElementContains('OpenSearchDescription > ShortName', mb_strimwidth($appName, 0, 16)); + $html->assertElementNotContains('OpenSearchDescription > ShortName', $appName); + + $html->assertElementExists('OpenSearchDescription > Description'); + $html->assertElementContains('OpenSearchDescription > Description', "Search {$appName}"); + $html->assertElementExists('OpenSearchDescription > Image'); + $html->assertElementExists('OpenSearchDescription > Url[rel="results"][template="' . htmlspecialchars($resultUrl) . '"]'); + $html->assertElementExists('OpenSearchDescription > Url[rel="self"][template="' . htmlspecialchars($selfUrl) . '"]'); + } + + public function test_opensearch_linked_to_from_home() + { + $appName = setting('app-name'); + $endpointUrl = url('/opensearch.xml'); + + $resp = $this->asViewer()->get('/'); + $html = $this->withHtml($resp); + + $html->assertElementExists('head > link[rel="search"][type="application/opensearchdescription+xml"][title="' . htmlspecialchars($appName) . '"][href="' . htmlspecialchars($endpointUrl) . '"]'); + } +} diff --git a/tests/PwaManifestTest.php b/tests/Meta/PwaManifestTest.php similarity index 98% rename from tests/PwaManifestTest.php rename to tests/Meta/PwaManifestTest.php index c66f8b360..fc6d19b54 100644 --- a/tests/PwaManifestTest.php +++ b/tests/Meta/PwaManifestTest.php @@ -1,6 +1,8 @@ get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); + + $this->setSettings(['app-public' => 'true']); + + $resp = $this->get('/robots.txt'); + $resp->assertSee("User-agent: *\nDisallow:"); + $resp->assertDontSee('Disallow: /'); + } + + public function test_robots_effected_by_setting() + { + $this->get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); + + config()->set('app.allow_robots', true); + + $resp = $this->get('/robots.txt'); + $resp->assertSee("User-agent: *\nDisallow:"); + $resp->assertDontSee('Disallow: /'); + + // Check config overrides app-public setting + config()->set('app.allow_robots', false); + $this->setSettings(['app-public' => 'true']); + $this->get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); + } +} diff --git a/tests/PublicActionTest.php b/tests/PublicActionTest.php index 875b279a8..76745aaac 100644 --- a/tests/PublicActionTest.php +++ b/tests/PublicActionTest.php @@ -128,33 +128,6 @@ class PublicActionTest extends TestCase $resp->assertDontSee($page->name); } - public function test_robots_effected_by_public_status() - { - $this->get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); - - $this->setSettings(['app-public' => 'true']); - - $resp = $this->get('/robots.txt'); - $resp->assertSee("User-agent: *\nDisallow:"); - $resp->assertDontSee('Disallow: /'); - } - - public function test_robots_effected_by_setting() - { - $this->get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); - - config()->set('app.allow_robots', true); - - $resp = $this->get('/robots.txt'); - $resp->assertSee("User-agent: *\nDisallow:"); - $resp->assertDontSee('Disallow: /'); - - // Check config overrides app-public setting - config()->set('app.allow_robots', false); - $this->setSettings(['app-public' => 'true']); - $this->get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); - } - public function test_default_favicon_file_created_upon_access() { $faviconPath = public_path('favicon.ico');