1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-11-06 00:50:36 +03:00

API: Added comment CUD endpoints, drafted tests

Move some checks and made some tweaks to the repo to support consistency
between API and UI.
This commit is contained in:
Dan Brown
2025-10-23 10:21:33 +01:00
parent 3ad1e31fcc
commit cbf27d70c8
7 changed files with 167 additions and 18 deletions

View File

@@ -6,8 +6,12 @@ namespace BookStack\Activity\Controllers;
use BookStack\Activity\CommentRepo;
use BookStack\Activity\Models\Comment;
use BookStack\Entities\Queries\PageQueries;
use BookStack\Http\ApiController;
use BookStack\Permissions\Permission;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
/**
* The comment data model has a 'local_id' property, which is a unique integer ID
@@ -18,15 +22,26 @@ use Illuminate\Http\JsonResponse;
class CommentApiController extends ApiController
{
// TODO - Add tree-style comment listing to page-show responses.
// TODO - create
// TODO - update
// TODO - delete
// TODO - Test visibility controls
// TODO - Test permissions of each action
protected array $rules = [
'create' => [
'page_id' => ['required', 'integer'],
'reply_to' => ['nullable', 'integer'],
'html' => ['required', 'string'],
'content_ref' => ['string'],
],
'update' => [
'html' => ['required', 'string'],
'archived' => ['boolean'],
]
];
public function __construct(
protected CommentRepo $commentRepo,
protected PageQueries $pageQueries,
) {
}
@@ -42,13 +57,34 @@ class CommentApiController extends ApiController
]);
}
/**
* Create a new comment on a page.
* If commenting as a reply to an existing comment, the 'reply_to' parameter
* should be provided, set to the 'local_id' of the comment being replied to.
*/
public function create(Request $request): JsonResponse
{
$this->checkPermission(Permission::CommentCreateAll);
$input = $this->validate($request, $this->rules()['create']);
$page = $this->pageQueries->findVisibleByIdOrFail($input['page_id']);
$comment = $this->commentRepo->create(
$page,
$input['html'],
$input['reply_to'] ?? null,
$input['content_ref'] ?? '',
);
return response()->json($comment);
}
/**
* Read the details of a single comment, along with its direct replies.
*/
public function read(string $id): JsonResponse
{
$comment = $this->commentRepo->getQueryForVisible()
->where('id', '=', $id)->firstOrFail();
$comment = $this->commentRepo->getVisibleById(intval($id));
$replies = $this->commentRepo->getQueryForVisible()
->where('parent_id', '=', $comment->local_id)
@@ -67,4 +103,45 @@ class CommentApiController extends ApiController
return response()->json($comment);
}
/**
* Update the content or archived status of an existing comment.
*
* Only provide a new archived status if needing to actively change the archive state.
* Only top-level comments (non-replies) can be archived or unarchived.
*/
public function update(Request $request, string $id): JsonResponse
{
$comment = $this->commentRepo->getVisibleById(intval($id));
$this->checkOwnablePermission(Permission::CommentUpdate, $comment);
$input = $this->validate($request, $this->rules()['update']);
if (isset($input['archived'])) {
$archived = $input['archived'];
if ($archived) {
$this->commentRepo->archive($comment, false);
} else {
$this->commentRepo->unarchive($comment, false);
}
}
$comment = $this->commentRepo->update($comment, $input['html']);
return response()->json($comment);
}
/**
* Delete a single comment from the system.
*/
public function delete(string $id): Response
{
$comment = $this->commentRepo->getVisibleById(intval($id));
$this->checkOwnablePermission(Permission::CommentDelete, $comment);
$this->commentRepo->delete($comment);
return response('', 204);
}
}