mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Comments: Added wysiwyg link selector, updated tests, removed command
- Updated existing tests with recent back-end changes, mainly to use HTML data. - Removed old comment regen command that's no longer required.
This commit is contained in:
parent
adf0baebb9
commit
e9a19d5878
@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace BookStack\Console\Commands;
|
|
||||||
|
|
||||||
use BookStack\Activity\CommentRepo;
|
|
||||||
use BookStack\Activity\Models\Comment;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class RegenerateCommentContentCommand extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'bookstack:regenerate-comment-content
|
|
||||||
{--database= : The database connection to use}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Regenerate the stored HTML of all comments';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle(CommentRepo $commentRepo): int
|
|
||||||
{
|
|
||||||
$connection = DB::getDefaultConnection();
|
|
||||||
if ($this->option('database') !== null) {
|
|
||||||
DB::setDefaultConnection($this->option('database'));
|
|
||||||
}
|
|
||||||
|
|
||||||
Comment::query()->chunk(100, function ($comments) use ($commentRepo) {
|
|
||||||
foreach ($comments as $comment) {
|
|
||||||
$comment->html = $commentRepo->commentToHtml($comment->text);
|
|
||||||
$comment->save();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
DB::setDefaultConnection($connection);
|
|
||||||
$this->comment('Comment HTML content has been regenerated');
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,6 +27,7 @@ class CommentFactory extends Factory
|
|||||||
'html' => $html,
|
'html' => $html,
|
||||||
'text' => $text,
|
'text' => $text,
|
||||||
'parent_id' => null,
|
'parent_id' => null,
|
||||||
|
'local_id' => 1,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,9 @@
|
|||||||
<script src="{{ versioned_asset('libs/tinymce/tinymce.min.js') }}" nonce="{{ $cspNonce }}"></script>
|
<script src="{{ versioned_asset('libs/tinymce/tinymce.min.js') }}" nonce="{{ $cspNonce }}"></script>
|
||||||
@include('form.editor-translations')
|
@include('form.editor-translations')
|
||||||
@endpush
|
@endpush
|
||||||
|
@push('post-app-html')
|
||||||
|
@include('entities.selector-popup')
|
||||||
|
@endpush
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</section>
|
</section>
|
@ -68,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@yield('bottom')
|
@yield('bottom')
|
||||||
|
@stack('post-app-html')
|
||||||
|
|
||||||
@if($cspNonce ?? false)
|
@if($cspNonce ?? false)
|
||||||
<script src="{{ versioned_asset('dist/app.js') }}" nonce="{{ $cspNonce }}"></script>
|
<script src="{{ versioned_asset('dist/app.js') }}" nonce="{{ $cspNonce }}"></script>
|
||||||
|
@ -196,7 +196,7 @@ class WatchTest extends TestCase
|
|||||||
$notifications = Notification::fake();
|
$notifications = Notification::fake();
|
||||||
|
|
||||||
$this->asAdmin()->post("/comment/{$entities['page']->id}", [
|
$this->asAdmin()->post("/comment/{$entities['page']->id}", [
|
||||||
'text' => 'My new comment'
|
'html' => '<p>My new comment</p>'
|
||||||
]);
|
]);
|
||||||
$notifications->assertSentTo($editor, CommentCreationNotification::class);
|
$notifications->assertSentTo($editor, CommentCreationNotification::class);
|
||||||
}
|
}
|
||||||
@ -217,12 +217,12 @@ class WatchTest extends TestCase
|
|||||||
$notifications = Notification::fake();
|
$notifications = Notification::fake();
|
||||||
|
|
||||||
$this->actingAs($editor)->post("/comment/{$entities['page']->id}", [
|
$this->actingAs($editor)->post("/comment/{$entities['page']->id}", [
|
||||||
'text' => 'My new comment'
|
'html' => '<p>My new comment</p>'
|
||||||
]);
|
]);
|
||||||
$comment = $entities['page']->comments()->orderBy('id', 'desc')->first();
|
$comment = $entities['page']->comments()->orderBy('id', 'desc')->first();
|
||||||
|
|
||||||
$this->asAdmin()->post("/comment/{$entities['page']->id}", [
|
$this->asAdmin()->post("/comment/{$entities['page']->id}", [
|
||||||
'text' => 'My new comment response',
|
'html' => '<p>My new comment response</p>',
|
||||||
'parent_id' => $comment->local_id,
|
'parent_id' => $comment->local_id,
|
||||||
]);
|
]);
|
||||||
$notifications->assertSentTo($editor, CommentCreationNotification::class);
|
$notifications->assertSentTo($editor, CommentCreationNotification::class);
|
||||||
@ -257,7 +257,7 @@ class WatchTest extends TestCase
|
|||||||
|
|
||||||
// Comment post
|
// Comment post
|
||||||
$this->actingAs($admin)->post("/comment/{$entities['page']->id}", [
|
$this->actingAs($admin)->post("/comment/{$entities['page']->id}", [
|
||||||
'text' => 'My new comment response',
|
'html' => '<p>My new comment response</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$notifications->assertSentTo($editor, function (CommentCreationNotification $notification) use ($editor, $admin, $entities) {
|
$notifications->assertSentTo($editor, function (CommentCreationNotification $notification) use ($editor, $admin, $entities) {
|
||||||
@ -376,7 +376,7 @@ class WatchTest extends TestCase
|
|||||||
$this->permissions->disableEntityInheritedPermissions($page);
|
$this->permissions->disableEntityInheritedPermissions($page);
|
||||||
|
|
||||||
$this->asAdmin()->post("/comment/{$page->id}", [
|
$this->asAdmin()->post("/comment/{$page->id}", [
|
||||||
'text' => 'My new comment response',
|
'html' => '<p>My new comment response</p>',
|
||||||
])->assertOk();
|
])->assertOk();
|
||||||
|
|
||||||
$notifications->assertNothingSentTo($editor);
|
$notifications->assertNothingSentTo($editor);
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Commands;
|
|
||||||
|
|
||||||
use BookStack\Activity\Models\Comment;
|
|
||||||
use Tests\TestCase;
|
|
||||||
|
|
||||||
class RegenerateCommentContentCommandTest extends TestCase
|
|
||||||
{
|
|
||||||
public function test_regenerate_comment_content_command()
|
|
||||||
{
|
|
||||||
Comment::query()->forceCreate([
|
|
||||||
'html' => 'some_old_content',
|
|
||||||
'text' => 'some_fresh_content',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertDatabaseHas('comments', [
|
|
||||||
'html' => 'some_old_content',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$exitCode = \Artisan::call('bookstack:regenerate-comment-content');
|
|
||||||
$this->assertTrue($exitCode === 0, 'Command executed successfully');
|
|
||||||
|
|
||||||
$this->assertDatabaseMissing('comments', [
|
|
||||||
'html' => 'some_old_content',
|
|
||||||
]);
|
|
||||||
$this->assertDatabaseHas('comments', [
|
|
||||||
'html' => "<p>some_fresh_content</p>\n",
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,7 +27,7 @@ class CommentTest extends TestCase
|
|||||||
'local_id' => 1,
|
'local_id' => 1,
|
||||||
'entity_id' => $page->id,
|
'entity_id' => $page->id,
|
||||||
'entity_type' => Page::newModelInstance()->getMorphClass(),
|
'entity_type' => Page::newModelInstance()->getMorphClass(),
|
||||||
'text' => $comment->text,
|
'text' => null,
|
||||||
'parent_id' => 2,
|
'parent_id' => 2,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -43,17 +43,17 @@ class CommentTest extends TestCase
|
|||||||
$this->postJson("/comment/$page->id", $comment->getAttributes());
|
$this->postJson("/comment/$page->id", $comment->getAttributes());
|
||||||
|
|
||||||
$comment = $page->comments()->first();
|
$comment = $page->comments()->first();
|
||||||
$newText = 'updated text content';
|
$newHtml = '<p>updated text content</p>';
|
||||||
$resp = $this->putJson("/comment/$comment->id", [
|
$resp = $this->putJson("/comment/$comment->id", [
|
||||||
'text' => $newText,
|
'html' => $newHtml,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$resp->assertStatus(200);
|
$resp->assertStatus(200);
|
||||||
$resp->assertSee($newText);
|
$resp->assertSee($newHtml, false);
|
||||||
$resp->assertDontSee($comment->text);
|
$resp->assertDontSee($comment->html, false);
|
||||||
|
|
||||||
$this->assertDatabaseHas('comments', [
|
$this->assertDatabaseHas('comments', [
|
||||||
'text' => $newText,
|
'html' => $newHtml,
|
||||||
'entity_id' => $page->id,
|
'entity_id' => $page->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -80,46 +80,28 @@ class CommentTest extends TestCase
|
|||||||
$this->assertActivityExists(ActivityType::COMMENT_DELETE);
|
$this->assertActivityExists(ActivityType::COMMENT_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_comments_converts_markdown_input_to_html()
|
public function test_scripts_cannot_be_injected_via_comment_html()
|
||||||
{
|
|
||||||
$page = $this->entities->page();
|
|
||||||
$this->asAdmin()->postJson("/comment/$page->id", [
|
|
||||||
'text' => '# My Title',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertDatabaseHas('comments', [
|
|
||||||
'entity_id' => $page->id,
|
|
||||||
'entity_type' => $page->getMorphClass(),
|
|
||||||
'text' => '# My Title',
|
|
||||||
'html' => "<h1>My Title</h1>\n",
|
|
||||||
]);
|
|
||||||
|
|
||||||
$pageView = $this->get($page->getUrl());
|
|
||||||
$pageView->assertSee('<h1>My Title</h1>', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function test_html_cannot_be_injected_via_comment_content()
|
|
||||||
{
|
{
|
||||||
$this->asAdmin();
|
$this->asAdmin();
|
||||||
$page = $this->entities->page();
|
$page = $this->entities->page();
|
||||||
|
|
||||||
$script = '<script>const a = "script";</script>\n\n# sometextinthecomment';
|
$script = '<script>const a = "script";</script><p onclick="1">My lovely comment</p>';
|
||||||
$this->postJson("/comment/$page->id", [
|
$this->postJson("/comment/$page->id", [
|
||||||
'text' => $script,
|
'html' => $script,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$pageView = $this->get($page->getUrl());
|
$pageView = $this->get($page->getUrl());
|
||||||
$pageView->assertDontSee($script, false);
|
$pageView->assertDontSee($script, false);
|
||||||
$pageView->assertSee('sometextinthecomment');
|
$pageView->assertSee('<p>My lovely comment</p>', false);
|
||||||
|
|
||||||
$comment = $page->comments()->first();
|
$comment = $page->comments()->first();
|
||||||
$this->putJson("/comment/$comment->id", [
|
$this->putJson("/comment/$comment->id", [
|
||||||
'text' => $script . 'updated',
|
'html' => $script . '<p>updated</p>',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$pageView = $this->get($page->getUrl());
|
$pageView = $this->get($page->getUrl());
|
||||||
$pageView->assertDontSee($script, false);
|
$pageView->assertDontSee($script, false);
|
||||||
$pageView->assertSee('sometextinthecommentupdated');
|
$pageView->assertSee('<p>My lovely comment</p><p>updated</p>');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_reply_comments_are_nested()
|
public function test_reply_comments_are_nested()
|
||||||
@ -127,15 +109,17 @@ class CommentTest extends TestCase
|
|||||||
$this->asAdmin();
|
$this->asAdmin();
|
||||||
$page = $this->entities->page();
|
$page = $this->entities->page();
|
||||||
|
|
||||||
$this->postJson("/comment/$page->id", ['text' => 'My new comment']);
|
$this->postJson("/comment/$page->id", ['html' => '<p>My new comment</p>']);
|
||||||
$this->postJson("/comment/$page->id", ['text' => 'My new comment']);
|
$this->postJson("/comment/$page->id", ['html' => '<p>My new comment</p>']);
|
||||||
|
|
||||||
$respHtml = $this->withHtml($this->get($page->getUrl()));
|
$respHtml = $this->withHtml($this->get($page->getUrl()));
|
||||||
$respHtml->assertElementCount('.comment-branch', 3);
|
$respHtml->assertElementCount('.comment-branch', 3);
|
||||||
$respHtml->assertElementNotExists('.comment-branch .comment-branch');
|
$respHtml->assertElementNotExists('.comment-branch .comment-branch');
|
||||||
|
|
||||||
$comment = $page->comments()->first();
|
$comment = $page->comments()->first();
|
||||||
$resp = $this->postJson("/comment/$page->id", ['text' => 'My nested comment', 'parent_id' => $comment->local_id]);
|
$resp = $this->postJson("/comment/$page->id", [
|
||||||
|
'html' => '<p>My nested comment</p>', 'parent_id' => $comment->local_id
|
||||||
|
]);
|
||||||
$resp->assertStatus(200);
|
$resp->assertStatus(200);
|
||||||
|
|
||||||
$respHtml = $this->withHtml($this->get($page->getUrl()));
|
$respHtml = $this->withHtml($this->get($page->getUrl()));
|
||||||
@ -147,7 +131,7 @@ class CommentTest extends TestCase
|
|||||||
{
|
{
|
||||||
$page = $this->entities->page();
|
$page = $this->entities->page();
|
||||||
|
|
||||||
$this->asAdmin()->postJson("/comment/$page->id", ['text' => 'My great comment to see in the editor']);
|
$this->asAdmin()->postJson("/comment/$page->id", ['html' => '<p>My great comment to see in the editor</p>']);
|
||||||
|
|
||||||
$respHtml = $this->withHtml($this->get($page->getUrl('/edit')));
|
$respHtml = $this->withHtml($this->get($page->getUrl('/edit')));
|
||||||
$respHtml->assertElementContains('.comment-box .content', 'My great comment to see in the editor');
|
$respHtml->assertElementContains('.comment-box .content', 'My great comment to see in the editor');
|
||||||
@ -164,4 +148,34 @@ class CommentTest extends TestCase
|
|||||||
$pageResp = $this->asAdmin()->get($page->getUrl());
|
$pageResp = $this->asAdmin()->get($page->getUrl());
|
||||||
$pageResp->assertSee('Wolfeschlegels…');
|
$pageResp->assertSee('Wolfeschlegels…');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_comment_editor_js_loaded_with_create_or_edit_permissions()
|
||||||
|
{
|
||||||
|
$editor = $this->users->editor();
|
||||||
|
$page = $this->entities->page();
|
||||||
|
|
||||||
|
$resp = $this->actingAs($editor)->get($page->getUrl());
|
||||||
|
$resp->assertSee('tinymce.min.js?', false);
|
||||||
|
$resp->assertSee('window.editor_translations', false);
|
||||||
|
$resp->assertSee('component="entity-selector"', false);
|
||||||
|
|
||||||
|
$this->permissions->removeUserRolePermissions($editor, ['comment-create-all']);
|
||||||
|
$this->permissions->grantUserRolePermissions($editor, ['comment-update-own']);
|
||||||
|
|
||||||
|
$resp = $this->actingAs($editor)->get($page->getUrl());
|
||||||
|
$resp->assertDontSee('tinymce.min.js?', false);
|
||||||
|
$resp->assertDontSee('window.editor_translations', false);
|
||||||
|
$resp->assertDontSee('component="entity-selector"', false);
|
||||||
|
|
||||||
|
Comment::factory()->create([
|
||||||
|
'created_by' => $editor->id,
|
||||||
|
'entity_type' => 'page',
|
||||||
|
'entity_id' => $page->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$resp = $this->actingAs($editor)->get($page->getUrl());
|
||||||
|
$resp->assertSee('tinymce.min.js?', false);
|
||||||
|
$resp->assertSee('window.editor_translations', false);
|
||||||
|
$resp->assertSee('component="entity-selector"', false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user