mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-11-06 00:50:36 +03:00
API: Built out tests for comment API endpoints
This commit is contained in:
@@ -50,8 +50,8 @@ class CommentRepo
|
|||||||
// Validate parent ID
|
// Validate parent ID
|
||||||
if ($parentId !== null) {
|
if ($parentId !== null) {
|
||||||
$parentCommentExists = Comment::query()
|
$parentCommentExists = Comment::query()
|
||||||
->where('entity_id', '=', $entity->id)
|
->where('commentable_id', '=', $entity->id)
|
||||||
->where('entity_type', '=', $entity->getMorphClass())
|
->where('commentable_type', '=', $entity->getMorphClass())
|
||||||
->where('local_id', '=', $parentId)
|
->where('local_id', '=', $parentId)
|
||||||
->exists();
|
->exists();
|
||||||
if (!$parentCommentExists) {
|
if (!$parentCommentExists) {
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ class CommentApiController extends ApiController
|
|||||||
{
|
{
|
||||||
// TODO - Add tree-style comment listing to page-show responses.
|
// TODO - Add tree-style comment listing to page-show responses.
|
||||||
|
|
||||||
// TODO - Test visibility controls
|
|
||||||
// TODO - Test permissions of each action
|
|
||||||
|
|
||||||
protected array $rules = [
|
protected array $rules = [
|
||||||
'create' => [
|
'create' => [
|
||||||
'page_id' => ['required', 'integer'],
|
'page_id' => ['required', 'integer'],
|
||||||
@@ -34,7 +31,7 @@ class CommentApiController extends ApiController
|
|||||||
'content_ref' => ['string'],
|
'content_ref' => ['string'],
|
||||||
],
|
],
|
||||||
'update' => [
|
'update' => [
|
||||||
'html' => ['required', 'string'],
|
'html' => ['string'],
|
||||||
'archived' => ['boolean'],
|
'archived' => ['boolean'],
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
@@ -85,6 +82,7 @@ class CommentApiController extends ApiController
|
|||||||
public function read(string $id): JsonResponse
|
public function read(string $id): JsonResponse
|
||||||
{
|
{
|
||||||
$comment = $this->commentRepo->getVisibleById(intval($id));
|
$comment = $this->commentRepo->getVisibleById(intval($id));
|
||||||
|
$comment->load('createdBy', 'updatedBy');
|
||||||
|
|
||||||
$replies = $this->commentRepo->getQueryForVisible()
|
$replies = $this->commentRepo->getQueryForVisible()
|
||||||
->where('parent_id', '=', $comment->local_id)
|
->where('parent_id', '=', $comment->local_id)
|
||||||
@@ -117,17 +115,19 @@ class CommentApiController extends ApiController
|
|||||||
$this->checkOwnablePermission(Permission::CommentUpdate, $comment);
|
$this->checkOwnablePermission(Permission::CommentUpdate, $comment);
|
||||||
|
|
||||||
$input = $this->validate($request, $this->rules()['update']);
|
$input = $this->validate($request, $this->rules()['update']);
|
||||||
|
$hasHtml = isset($input['html']);
|
||||||
|
|
||||||
if (isset($input['archived'])) {
|
if (isset($input['archived'])) {
|
||||||
$archived = $input['archived'];
|
if ($input['archived']) {
|
||||||
if ($archived) {
|
$this->commentRepo->archive($comment, !$hasHtml);
|
||||||
$this->commentRepo->archive($comment, false);
|
|
||||||
} else {
|
} else {
|
||||||
$this->commentRepo->unarchive($comment, false);
|
$this->commentRepo->unarchive($comment, !$hasHtml);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($hasHtml) {
|
||||||
$comment = $this->commentRepo->update($comment, $input['html']);
|
$comment = $this->commentRepo->update($comment, $input['html']);
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json($comment);
|
return response()->json($comment);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Comment extends Model implements Loggable, OwnableInterface
|
|||||||
*/
|
*/
|
||||||
public function entity(): MorphTo
|
public function entity(): MorphTo
|
||||||
{
|
{
|
||||||
return $this->morphTo('entity');
|
return $this->morphTo('commentable');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace Activity;
|
namespace Activity;
|
||||||
|
|
||||||
use BookStack\Activity\ActivityType;
|
use BookStack\Activity\Models\Comment;
|
||||||
use BookStack\Facades\Activity;
|
use BookStack\Permissions\Permission;
|
||||||
use Tests\Api\TestsApi;
|
use Tests\Api\TestsApi;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
@@ -13,31 +13,238 @@ class CommentsApiTest extends TestCase
|
|||||||
|
|
||||||
public function test_endpoint_permission_controls()
|
public function test_endpoint_permission_controls()
|
||||||
{
|
{
|
||||||
// TODO
|
$user = $this->users->editor();
|
||||||
|
$this->permissions->grantUserRolePermissions($user, [Permission::CommentDeleteAll, Permission::CommentUpdateAll]);
|
||||||
|
|
||||||
|
$page = $this->entities->page();
|
||||||
|
$comment = Comment::factory()->make();
|
||||||
|
$page->comments()->save($comment);
|
||||||
|
$this->actingAsForApi($user);
|
||||||
|
|
||||||
|
$actions = [
|
||||||
|
['GET', '/api/comments'],
|
||||||
|
['GET', "/api/comments/{$comment->id}"],
|
||||||
|
['POST', "/api/comments"],
|
||||||
|
['PUT', "/api/comments/{$comment->id}"],
|
||||||
|
['DELETE', "/api/comments/{$comment->id}"],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($actions as [$method, $endpoint]) {
|
||||||
|
$resp = $this->call($method, $endpoint);
|
||||||
|
$this->assertNotPermissionError($resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
$comment = Comment::factory()->make();
|
||||||
|
$page->comments()->save($comment);
|
||||||
|
$this->getJson("/api/comments")->assertSee(['id' => $comment->id]);
|
||||||
|
|
||||||
|
$this->permissions->removeUserRolePermissions($user, [
|
||||||
|
Permission::CommentDeleteAll, Permission::CommentDeleteOwn,
|
||||||
|
Permission::CommentUpdateAll, Permission::CommentUpdateOwn,
|
||||||
|
Permission::CommentCreateAll
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertPermissionError($this->json('delete', "/api/comments/{$comment->id}"));
|
||||||
|
$this->assertPermissionError($this->json('put', "/api/comments/{$comment->id}"));
|
||||||
|
$this->assertPermissionError($this->json('post', "/api/comments"));
|
||||||
|
$this->assertNotPermissionError($this->json('get', "/api/comments/{$comment->id}"));
|
||||||
|
|
||||||
|
$this->permissions->disableEntityInheritedPermissions($page);
|
||||||
|
$this->json('get', "/api/comments/{$comment->id}")->assertStatus(404);
|
||||||
|
$this->getJson("/api/comments")->assertDontSee(['id' => $comment->id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_index()
|
public function test_index()
|
||||||
{
|
{
|
||||||
// TODO
|
$page = $this->entities->page();
|
||||||
|
Comment::query()->delete();
|
||||||
|
|
||||||
|
$comments = Comment::factory()->count(10)->make();
|
||||||
|
$page->comments()->saveMany($comments);
|
||||||
|
|
||||||
|
$firstComment = $comments->first();
|
||||||
|
$resp = $this->actingAsApiEditor()->getJson('/api/comments');
|
||||||
|
$resp->assertJson([
|
||||||
|
'data' => [
|
||||||
|
[
|
||||||
|
'id' => $firstComment->id,
|
||||||
|
'commentable_id' => $page->id,
|
||||||
|
'commentable_type' => 'page',
|
||||||
|
'parent_id' => null,
|
||||||
|
'local_id' => $firstComment->local_id,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$resp->assertJsonCount(10, 'data');
|
||||||
|
$resp->assertJson(['total' => 10]);
|
||||||
|
|
||||||
|
$filtered = $this->getJson("/api/comments?filter[id]={$firstComment->id}");
|
||||||
|
$filtered->assertJsonCount(1, 'data');
|
||||||
|
$filtered->assertJson(['total' => 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_create()
|
public function test_create()
|
||||||
{
|
{
|
||||||
// TODO
|
$page = $this->entities->page();
|
||||||
|
|
||||||
|
$resp = $this->actingAsApiEditor()->postJson('/api/comments', [
|
||||||
|
'page_id' => $page->id,
|
||||||
|
'html' => '<p>My wonderful comment</p>',
|
||||||
|
'content_ref' => 'test-content-ref',
|
||||||
|
]);
|
||||||
|
$resp->assertOk();
|
||||||
|
$id = $resp->json('id');
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('comments', [
|
||||||
|
'id' => $id,
|
||||||
|
'commentable_id' => $page->id,
|
||||||
|
'commentable_type' => 'page',
|
||||||
|
'html' => '<p>My wonderful comment</p>',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$comment = Comment::query()->findOrFail($id);
|
||||||
|
$this->assertIsInt($comment->local_id);
|
||||||
|
|
||||||
|
$reply = $this->actingAsApiEditor()->postJson('/api/comments', [
|
||||||
|
'page_id' => $page->id,
|
||||||
|
'html' => '<p>My wonderful reply</p>',
|
||||||
|
'content_ref' => 'test-content-ref',
|
||||||
|
'reply_to' => $comment->local_id,
|
||||||
|
]);
|
||||||
|
$reply->assertOk();
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('comments', [
|
||||||
|
'id' => $reply->json('id'),
|
||||||
|
'commentable_id' => $page->id,
|
||||||
|
'commentable_type' => 'page',
|
||||||
|
'html' => '<p>My wonderful reply</p>',
|
||||||
|
'parent_id' => $comment->local_id,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_read()
|
public function test_read()
|
||||||
{
|
{
|
||||||
// TODO
|
$page = $this->entities->page();
|
||||||
|
$user = $this->users->viewer();
|
||||||
|
$comment = Comment::factory()->make([
|
||||||
|
'html' => '<p>A lovely comment <script>hello</script></p>',
|
||||||
|
'created_by' => $user->id,
|
||||||
|
'updated_by' => $user->id,
|
||||||
|
]);
|
||||||
|
$page->comments()->save($comment);
|
||||||
|
$comment->refresh();
|
||||||
|
$reply = Comment::factory()->make([
|
||||||
|
'parent_id' => $comment->local_id,
|
||||||
|
'html' => '<p>A lovely<script>angry</script>reply</p>',
|
||||||
|
]);
|
||||||
|
$page->comments()->save($reply);
|
||||||
|
|
||||||
|
$resp = $this->actingAsApiEditor()->getJson("/api/comments/{$comment->id}");
|
||||||
|
$resp->assertJson([
|
||||||
|
'id' => $comment->id,
|
||||||
|
'commentable_id' => $page->id,
|
||||||
|
'commentable_type' => 'page',
|
||||||
|
'html' => '<p>A lovely comment </p>',
|
||||||
|
'archived' => false,
|
||||||
|
'created_by' => [
|
||||||
|
'id' => $user->id,
|
||||||
|
'name' => $user->name,
|
||||||
|
],
|
||||||
|
'updated_by' => [
|
||||||
|
'id' => $user->id,
|
||||||
|
'name' => $user->name,
|
||||||
|
],
|
||||||
|
'replies' => [
|
||||||
|
[
|
||||||
|
'id' => $reply->id,
|
||||||
|
'html' => '<p>A lovelyreply</p>'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_update()
|
public function test_update()
|
||||||
{
|
{
|
||||||
// TODO
|
$page = $this->entities->page();
|
||||||
|
$user = $this->users->editor();
|
||||||
|
$this->permissions->grantUserRolePermissions($user, [Permission::CommentUpdateAll]);
|
||||||
|
$comment = Comment::factory()->make([
|
||||||
|
'html' => '<p>A lovely comment</p>',
|
||||||
|
'created_by' => $this->users->viewer()->id,
|
||||||
|
'updated_by' => $this->users->viewer()->id,
|
||||||
|
'parent_id' => null,
|
||||||
|
]);
|
||||||
|
$page->comments()->save($comment);
|
||||||
|
|
||||||
|
$this->actingAsForApi($user)->putJson("/api/comments/{$comment->id}", [
|
||||||
|
'html' => '<p>A lovely updated comment</p>',
|
||||||
|
])->assertOk();
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('comments', [
|
||||||
|
'id' => $comment->id,
|
||||||
|
'html' => '<p>A lovely updated comment</p>',
|
||||||
|
'archived' => 0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->putJson("/api/comments/{$comment->id}", [
|
||||||
|
'archived' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('comments', [
|
||||||
|
'id' => $comment->id,
|
||||||
|
'html' => '<p>A lovely updated comment</p>',
|
||||||
|
'archived' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->putJson("/api/comments/{$comment->id}", [
|
||||||
|
'archived' => false,
|
||||||
|
'html' => '<p>A lovely updated again comment</p>',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('comments', [
|
||||||
|
'id' => $comment->id,
|
||||||
|
'html' => '<p>A lovely updated again comment</p>',
|
||||||
|
'archived' => 0,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_cannot_archive_replies()
|
||||||
|
{
|
||||||
|
$page = $this->entities->page();
|
||||||
|
$user = $this->users->editor();
|
||||||
|
$this->permissions->grantUserRolePermissions($user, [Permission::CommentUpdateAll]);
|
||||||
|
$comment = Comment::factory()->make([
|
||||||
|
'html' => '<p>A lovely comment</p>',
|
||||||
|
'created_by' => $this->users->viewer()->id,
|
||||||
|
'updated_by' => $this->users->viewer()->id,
|
||||||
|
'parent_id' => 90,
|
||||||
|
]);
|
||||||
|
$page->comments()->save($comment);
|
||||||
|
|
||||||
|
$resp = $this->actingAsForApi($user)->putJson("/api/comments/{$comment->id}", [
|
||||||
|
'archived' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($this->errorResponse('Only top-level comments can be archived.', 400), $resp->json());
|
||||||
|
$this->assertDatabaseHas('comments', [
|
||||||
|
'id' => $comment->id,
|
||||||
|
'archived' => 0,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_destroy()
|
public function test_destroy()
|
||||||
{
|
{
|
||||||
// TODO
|
$page = $this->entities->page();
|
||||||
|
$user = $this->users->editor();
|
||||||
|
$this->permissions->grantUserRolePermissions($user, [Permission::CommentDeleteAll]);
|
||||||
|
$comment = Comment::factory()->make([
|
||||||
|
'html' => '<p>A lovely comment</p>',
|
||||||
|
]);
|
||||||
|
$page->comments()->save($comment);
|
||||||
|
|
||||||
|
$this->actingAsForApi($user)->deleteJson("/api/comments/{$comment->id}")->assertStatus(204);
|
||||||
|
$this->assertDatabaseMissing('comments', [
|
||||||
|
'id' => $comment->id,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ abstract class TestCase extends BaseTestCase
|
|||||||
{
|
{
|
||||||
if ($response->status() === 403 && $response instanceof JsonResponse) {
|
if ($response->status() === 403 && $response instanceof JsonResponse) {
|
||||||
$errMessage = $response->getData(true)['error']['message'] ?? '';
|
$errMessage = $response->getData(true)['error']['message'] ?? '';
|
||||||
return $errMessage === 'You do not have permission to perform the requested action.';
|
return str_contains($errMessage, 'do not have permission');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response->status() === 302
|
return $response->status() === 302
|
||||||
|
|||||||
Reference in New Issue
Block a user