Compare commits

...

9 Commits

Author SHA1 Message Date
Dan Brown
e65655594f
Merge branch 'feature/opensearch' into development 2024-09-30 17:21:51 +01:00
Dan Brown
514db60617
Tests: Categorised up meta tests
Extracted robots.txt tests into its own file to fit into new folder.
Also tweaked open search tests a tad to specifically check long app
names.
2024-09-30 17:07:53 +01:00
Dan Brown
8bc6e75319
Code Blocks: Added SAS and R language options
For #5206
2024-09-30 16:47:55 +01:00
Maximilian Walter
2f74cfb42c
Add test for OpenSearch endpoint 2024-09-30 17:45:20 +02:00
Maximilian Walter
1302e3c959
Add missing XML declaration to OpenSearch endpoint 2024-09-30 17:45:20 +02:00
Maximilian Walter
a5b031f906
Translatable description for OpenSearch XML 2024-09-30 17:45:20 +02:00
Maximilian Walter
4f890c431c
Limit short-name for OpenSearch XML to 16 characters
The specification does not allow more than 16 characters.
2024-09-14 15:31:56 +02:00
Maximilian Walter
c110a97d8a
Remove unofficial method-attribute from OpenSearch-XML 2024-09-14 15:24:42 +02:00
Maximilian Walter
476c2be5a6
Add XML for OpenSearch 2024-09-09 22:54:33 +02:00
15 changed files with 122 additions and 32 deletions

View File

@ -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');
}
}

View File

@ -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',
];

View File

@ -71,10 +71,12 @@ const modeMap = {
ocaml: () => legacyLoad('oCaml'),
py: () => legacyLoad('python'),
python: () => legacyLoad('python'),
r: () => legacyLoad('r'),
rb: () => legacyLoad('ruby'),
rs: () => legacyLoad('rust'),
ruby: () => legacyLoad('ruby'),
rust: () => legacyLoad('rust'),
sas: () => legacyLoad('sas'),
scala: () => legacyLoad('scala'),
scheme: () => legacyLoad('scheme'),
shell: () => legacyLoad('shell'),

View File

@ -16,8 +16,10 @@ export {pascal} from '@codemirror/legacy-modes/mode/pascal';
export {powerShell} from '@codemirror/legacy-modes/mode/powershell';
export {properties} from '@codemirror/legacy-modes/mode/properties';
export {python} from '@codemirror/legacy-modes/mode/python';
export {r} from '@codemirror/legacy-modes/mode/r';
export {ruby} from '@codemirror/legacy-modes/mode/ruby';
export {rust} from '@codemirror/legacy-modes/mode/rust';
export {sas} from '@codemirror/legacy-modes/mode/sas';
export {scheme} from '@codemirror/legacy-modes/mode/scheme';
export {shell} from '@codemirror/legacy-modes/mode/shell';
export {

View File

@ -32,6 +32,9 @@
<link rel="manifest" href="{{ url('/manifest.json') }}">
<meta name="mobile-web-app-capable" content="yes">
<!-- OpenSearch -->
<link rel="search" type="application/opensearchdescription+xml" title="{{ setting('app-name') }}" href="{{ url('/opensearch.xml') }}">
@yield('head')
<!-- Custom Styles & Head Content -->

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<ShortName>{{ mb_strimwidth(setting('app-name'), 0, 16) }}</ShortName>
<Description>{{ trans('common.opensearch_description', ['appName' => setting('app-name')]) }}</Description>
<Image width="256" height="256" type="image/png">{{ setting('app-icon') ?: url('/icon.png') }}</Image>
<Image width="180" height="180" type="image/png">{{ setting('app-icon-180') ?: url('/icon-180.png') }}</Image>
<Image width="128" height="128" type="image/png">{{ setting('app-icon-128') ?: url('/icon-128.png') }}</Image>
<Image width="64" height="64" type="image/png">{{ setting('app-icon-64') ?: url('/icon-64.png') }}</Image>
<Image width="32" height="32" type="image/png">{{ setting('app-icon-32') ?: url('/icon-32.png') }}</Image>
<Url type="text/html" rel="results" template="{{ url('/search') }}?term={searchTerms}"/>
<Url type="application/opensearchdescription+xml" rel="self" template="{{ url('/opensearch.xml') }}"/>
</OpenSearchDescription>

View File

@ -26,7 +26,7 @@
'Bash', 'CSS', 'C', 'C++', 'C#', 'Clojure', 'Dart', 'Diff', 'Fortran', 'F#', 'Go', 'Haskell', 'HTML', 'INI',
'Java', 'JavaScript', 'JSON', 'Julia', 'Kotlin', 'LaTeX', 'Lua', 'MarkDown', 'MATLAB', 'MSSQL', 'MySQL',
'Nginx', 'OCaml', 'Octave', 'Pascal', 'Perl', 'PHP', 'PL/SQL', 'PostgreSQL', 'Powershell', 'Python',
'Ruby', 'Rust', 'Scala', 'Scheme', 'Shell', 'Smarty', 'SQL', 'SQLite', 'Swift',
'R', 'Ruby', 'Rust', 'SAS', 'Scala', 'Scheme', 'Shell', 'Smarty', 'SQL', 'SQLite', 'Swift',
'Twig', 'TypeScript', 'VBScript', 'VB.NET', 'XML', 'YAML',
];
@endphp

View File

@ -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 () {

View File

@ -1,6 +1,8 @@
<?php
namespace Tests;
namespace Tests\Meta;
use Tests\TestCase;
class HelpTest extends TestCase
{

View File

@ -1,6 +1,8 @@
<?php
namespace Tests;
namespace Tests\Meta;
use Tests\TestCase;
class LicensesTest extends TestCase
{

View File

@ -1,11 +1,12 @@
<?php
namespace Tests;
namespace Tests\Meta;
use BookStack\Entities\Repos\BaseRepo;
use BookStack\Entities\Repos\BookRepo;
use Illuminate\Support\Str;
use Illuminate\Testing\TestResponse;
use Tests\TestCase;
class OpenGraphTest extends TestCase
{

View File

@ -0,0 +1,42 @@
<?php
namespace Tests\Meta;
use Tests\TestCase;
class OpensearchTest extends TestCase
{
public function test_opensearch_endpoint()
{
$appName = 'MyAppNameThatsReallyLongLikeThis';
setting()->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) . '"]');
}
}

View File

@ -1,6 +1,8 @@
<?php
namespace Tests;
namespace Tests\Meta;
use Tests\TestCase;
class PwaManifestTest extends TestCase
{

35
tests/Meta/RobotsTest.php Normal file
View File

@ -0,0 +1,35 @@
<?php
namespace Tests\Meta;
use Tests\TestCase;
class RobotsTest extends TestCase
{
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: /");
}
}

View File

@ -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');