parent
28dda39260
commit
78ebcb6f38
|
@ -5,10 +5,10 @@ namespace BookStack\Entities\Tools\Markdown;
|
||||||
use BookStack\Facades\Theme;
|
use BookStack\Facades\Theme;
|
||||||
use BookStack\Theming\ThemeEvents;
|
use BookStack\Theming\ThemeEvents;
|
||||||
use League\CommonMark\Block\Element\ListItem;
|
use League\CommonMark\Block\Element\ListItem;
|
||||||
use League\CommonMark\CommonMarkConverter;
|
|
||||||
use League\CommonMark\Environment;
|
use League\CommonMark\Environment;
|
||||||
use League\CommonMark\Extension\Table\TableExtension;
|
use League\CommonMark\Extension\Table\TableExtension;
|
||||||
use League\CommonMark\Extension\TaskList\TaskListExtension;
|
use League\CommonMark\Extension\TaskList\TaskListExtension;
|
||||||
|
use League\CommonMark\MarkdownConverter;
|
||||||
|
|
||||||
class MarkdownToHtml
|
class MarkdownToHtml
|
||||||
{
|
{
|
||||||
|
@ -26,7 +26,7 @@ class MarkdownToHtml
|
||||||
$environment->addExtension(new TaskListExtension());
|
$environment->addExtension(new TaskListExtension());
|
||||||
$environment->addExtension(new CustomStrikeThroughExtension());
|
$environment->addExtension(new CustomStrikeThroughExtension());
|
||||||
$environment = Theme::dispatch(ThemeEvents::COMMONMARK_ENVIRONMENT_CONFIGURE, $environment) ?? $environment;
|
$environment = Theme::dispatch(ThemeEvents::COMMONMARK_ENVIRONMENT_CONFIGURE, $environment) ?? $environment;
|
||||||
$converter = new CommonMarkConverter([], $environment);
|
$converter = new MarkdownConverter($environment);
|
||||||
|
|
||||||
$environment->addBlockRenderer(ListItem::class, new CustomListItemRenderer(), 10);
|
$environment->addBlockRenderer(ListItem::class, new CustomListItemRenderer(), 10);
|
||||||
|
|
||||||
|
|
|
@ -112,12 +112,12 @@ class SearchIndex
|
||||||
*
|
*
|
||||||
* @returns array<string, int>
|
* @returns array<string, int>
|
||||||
*/
|
*/
|
||||||
protected function generateTermScoreMapFromText(string $text, int $scoreAdjustment = 1): array
|
protected function generateTermScoreMapFromText(string $text, float $scoreAdjustment = 1): array
|
||||||
{
|
{
|
||||||
$termMap = $this->textToTermCountMap($text);
|
$termMap = $this->textToTermCountMap($text);
|
||||||
|
|
||||||
foreach ($termMap as $term => $count) {
|
foreach ($termMap as $term => $count) {
|
||||||
$termMap[$term] = $count * $scoreAdjustment;
|
$termMap[$term] = floor($count * $scoreAdjustment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $termMap;
|
return $termMap;
|
||||||
|
|
|
@ -126,7 +126,7 @@ class CspService
|
||||||
|
|
||||||
protected function getAllowedIframeHosts(): array
|
protected function getAllowedIframeHosts(): array
|
||||||
{
|
{
|
||||||
$hosts = config('app.iframe_hosts', '');
|
$hosts = config('app.iframe_hosts') ?? '';
|
||||||
|
|
||||||
return array_filter(explode(' ', $hosts));
|
return array_filter(explode(' ', $hosts));
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ class TagFactory extends Factory
|
||||||
public function definition()
|
public function definition()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => $this->faker->city,
|
'name' => $this->faker->city(),
|
||||||
'value' => $this->faker->sentence(3),
|
'value' => $this->faker->sentence(3),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ class WebhookFactory extends Factory
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => 'My webhook for ' . $this->faker->country(),
|
'name' => 'My webhook for ' . $this->faker->country(),
|
||||||
'endpoint' => $this->faker->url,
|
'endpoint' => $this->faker->url(),
|
||||||
'active' => true,
|
'active' => true,
|
||||||
'timeout' => 3,
|
'timeout' => 3,
|
||||||
];
|
];
|
||||||
|
|
|
@ -22,11 +22,11 @@ class UserFactory extends Factory
|
||||||
*/
|
*/
|
||||||
public function definition()
|
public function definition()
|
||||||
{
|
{
|
||||||
$name = $this->faker->name;
|
$name = $this->faker->name();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'email' => $this->faker->email,
|
'email' => $this->faker->email(),
|
||||||
'slug' => Str::slug($name . '-' . Str::random(5)),
|
'slug' => Str::slug($name . '-' . Str::random(5)),
|
||||||
'password' => Str::random(10),
|
'password' => Str::random(10),
|
||||||
'remember_token' => Str::random(10),
|
'remember_token' => Str::random(10),
|
||||||
|
|
|
@ -22,9 +22,9 @@ class BookFactory extends Factory
|
||||||
public function definition()
|
public function definition()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => $this->faker->sentence,
|
'name' => $this->faker->sentence(),
|
||||||
'slug' => Str::random(10),
|
'slug' => Str::random(10),
|
||||||
'description' => $this->faker->paragraph,
|
'description' => $this->faker->paragraph(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,9 @@ class ChapterFactory extends Factory
|
||||||
public function definition()
|
public function definition()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => $this->faker->sentence,
|
'name' => $this->faker->sentence(),
|
||||||
'slug' => Str::random(10),
|
'slug' => Str::random(10),
|
||||||
'description' => $this->faker->paragraph,
|
'description' => $this->faker->paragraph(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ class PageFactory extends Factory
|
||||||
$html = '<p>' . implode('</p>', $this->faker->paragraphs(5)) . '</p>';
|
$html = '<p>' . implode('</p>', $this->faker->paragraphs(5)) . '</p>';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'name' => $this->faker->sentence,
|
'name' => $this->faker->sentence(),
|
||||||
'slug' => Str::random(10),
|
'slug' => Str::random(10),
|
||||||
'html' => $html,
|
'html' => $html,
|
||||||
'text' => strip_tags($html),
|
'text' => strip_tags($html),
|
||||||
|
|
|
@ -21,9 +21,9 @@ class ImageFactory extends Factory
|
||||||
public function definition()
|
public function definition()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => $this->faker->slug . '.jpg',
|
'name' => $this->faker->slug() . '.jpg',
|
||||||
'url' => $this->faker->url,
|
'url' => $this->faker->url(),
|
||||||
'path' => $this->faker->url,
|
'path' => $this->faker->url(),
|
||||||
'type' => 'gallery',
|
'type' => 'gallery',
|
||||||
'uploaded_to' => 0,
|
'uploaded_to' => 0,
|
||||||
];
|
];
|
||||||
|
|
|
@ -29,6 +29,8 @@ The testing database will also need migrating and seeding beforehand. This can b
|
||||||
|
|
||||||
Once done you can run `composer test` in the application root directory to run all tests. Tests can be ran in parallel by running them via `composer t`. This will use Laravel's built-in parallel testing functionality, and attempt to create and seed a database instance for each testing thread. If required these parallel testing instances can be reset, before testing again, by running `composer t-reset`.
|
Once done you can run `composer test` in the application root directory to run all tests. Tests can be ran in parallel by running them via `composer t`. This will use Laravel's built-in parallel testing functionality, and attempt to create and seed a database instance for each testing thread. If required these parallel testing instances can be reset, before testing again, by running `composer t-reset`.
|
||||||
|
|
||||||
|
If the codebase needs to be tested with deprecations, this can be done via uncommenting the relevant line within the TestCase@setUp function.
|
||||||
|
|
||||||
## Code Standards
|
## Code Standards
|
||||||
|
|
||||||
PHP code standards are managed by [using PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer).
|
PHP code standards are managed by [using PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer).
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
class="notification pos"
|
class="notification pos"
|
||||||
role="alert">
|
role="alert">
|
||||||
@icon('check-circle') <span>{!! nl2br(htmlentities(session()->get('success'))) !!}</span><div class="dismiss">@icon('close')</div>
|
@icon('check-circle') <span>@if(session()->has('success')){!! nl2br(htmlentities(session()->get('success'))) !!}@endif</span><div class="dismiss">@icon('close')</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div component="notification"
|
<div component="notification"
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
class="notification warning"
|
class="notification warning"
|
||||||
role="alert">
|
role="alert">
|
||||||
@icon('info') <span>{!! nl2br(htmlentities(session()->get('warning'))) !!}</span><div class="dismiss">@icon('close')</div>
|
@icon('info') <span>@if(session()->has('warning')){!! nl2br(htmlentities(session()->get('warning'))) !!}@endif</span><div class="dismiss">@icon('close')</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div component="notification"
|
<div component="notification"
|
||||||
|
@ -25,5 +25,5 @@
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
class="notification neg"
|
class="notification neg"
|
||||||
role="alert">
|
role="alert">
|
||||||
@icon('danger') <span>{!! nl2br(htmlentities(session()->get('error'))) !!}</span><div class="dismiss">@icon('close')</div>
|
@icon('danger') <span>@if(session()->has('error')){!! nl2br(htmlentities(session()->get('error'))) !!}@endif</span><div class="dismiss">@icon('close')</div>
|
||||||
</div>
|
</div>
|
|
@ -4,13 +4,13 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@icon('star'){!! trans('entities.meta_created' . ($entity->createdBy ? '_name' : ''), [
|
@icon('star'){!! trans('entities.meta_created' . ($entity->createdBy ? '_name' : ''), [
|
||||||
'timeLength' => $entity->created_at->formatLocalized('%e %B %Y %H:%M:%S'),
|
'timeLength' => $entity->created_at->isoFormat('D MMMM Y HH:mm:ss'),
|
||||||
'user' => e($entity->createdBy->name ?? ''),
|
'user' => e($entity->createdBy->name ?? ''),
|
||||||
]) !!}
|
]) !!}
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@icon('edit'){!! trans('entities.meta_updated' . ($entity->updatedBy ? '_name' : ''), [
|
@icon('edit'){!! trans('entities.meta_updated' . ($entity->updatedBy ? '_name' : ''), [
|
||||||
'timeLength' => $entity->updated_at->formatLocalized('%e %B %Y %H:%M:%S'),
|
'timeLength' => $entity->updated_at->isoFormat('D MMMM Y HH:mm:ss'),
|
||||||
'user' => e($entity->updatedBy->name ?? '')
|
'user' => e($entity->updatedBy->name ?? '')
|
||||||
]) !!}
|
]) !!}
|
||||||
</div>
|
</div>
|
|
@ -17,7 +17,7 @@
|
||||||
@if($revision->createdBy) {{ $revision->createdBy->name }} @else {{ trans('common.deleted_user') }} @endif
|
@if($revision->createdBy) {{ $revision->createdBy->name }} @else {{ trans('common.deleted_user') }} @endif
|
||||||
<br>
|
<br>
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<small>{{ $revision->created_at->formatLocalized('%e %B %Y %H:%M:%S') }}</small>
|
<small>{{ $revision->created_at->isoFormat('D MMMM Y HH:mm:ss') }}</small>
|
||||||
<small>({{ $revision->created_at->diffForHumans() }})</small>
|
<small>({{ $revision->created_at->diffForHumans() }})</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -160,9 +160,9 @@ class ExportTest extends TestCase
|
||||||
$page = $this->entities->page();
|
$page = $this->entities->page();
|
||||||
|
|
||||||
$resp = $this->asEditor()->get($page->getUrl('/export/html'));
|
$resp = $this->asEditor()->get($page->getUrl('/export/html'));
|
||||||
$resp->assertSee($page->created_at->formatLocalized('%e %B %Y %H:%M:%S'));
|
$resp->assertSee($page->created_at->isoFormat('D MMMM Y HH:mm:ss'));
|
||||||
$resp->assertDontSee($page->created_at->diffForHumans());
|
$resp->assertDontSee($page->created_at->diffForHumans());
|
||||||
$resp->assertSee($page->updated_at->formatLocalized('%e %B %Y %H:%M:%S'));
|
$resp->assertSee($page->updated_at->isoFormat('D MMMM Y HH:mm:ss'));
|
||||||
$resp->assertDontSee($page->updated_at->diffForHumans());
|
$resp->assertDontSee($page->updated_at->diffForHumans());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -310,7 +310,7 @@ class PageContentTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->asEditor();
|
$this->asEditor();
|
||||||
$page = $this->entities->page();
|
$page = $this->entities->page();
|
||||||
config()->push('app.allow_content_scripts', 'true');
|
config()->set('app.allow_content_scripts', 'true');
|
||||||
|
|
||||||
$script = 'abc123<script>console.log("hello-test")</script>abc123';
|
$script = 'abc123<script>console.log("hello-test")</script>abc123';
|
||||||
$page->html = "no escape {$script}";
|
$page->html = "no escape {$script}";
|
||||||
|
@ -355,7 +355,7 @@ class PageContentTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->asEditor();
|
$this->asEditor();
|
||||||
$page = $this->entities->page();
|
$page = $this->entities->page();
|
||||||
config()->push('app.allow_content_scripts', 'true');
|
config()->set('app.allow_content_scripts', 'true');
|
||||||
|
|
||||||
$script = '<p onmouseenter="console.log(\'test\')">Hello</p>';
|
$script = '<p onmouseenter="console.log(\'test\')">Hello</p>';
|
||||||
$page->html = "escape {$script}";
|
$page->html = "escape {$script}";
|
||||||
|
|
|
@ -43,6 +43,10 @@ abstract class TestCase extends BaseTestCase
|
||||||
{
|
{
|
||||||
$this->entities = new EntityProvider();
|
$this->entities = new EntityProvider();
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
// We can uncomment the below to run tests with failings upon deprecations.
|
||||||
|
// Can't leave on since some deprecations can only be fixed upstream.
|
||||||
|
// $this->withoutDeprecationHandling();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue