66
77use BookStack \Activity \CommentRepo ;
88use BookStack \Activity \Models \Comment ;
9+ use BookStack \Entities \Queries \PageQueries ;
910use BookStack \Http \ApiController ;
11+ use BookStack \Permissions \Permission ;
1012use Illuminate \Http \JsonResponse ;
13+ use Illuminate \Http \Request ;
14+ use Illuminate \Http \Response ;
1115
1216/**
1317 * The comment data model has a 'local_id' property, which is a unique integer ID
1822class CommentApiController extends ApiController
1923{
2024 // TODO - Add tree-style comment listing to page-show responses.
21- // TODO - create
22- // TODO - update
23- // TODO - delete
2425
2526 // TODO - Test visibility controls
2627 // TODO - Test permissions of each action
2728
29+ protected array $ rules = [
30+ 'create ' => [
31+ 'page_id ' => ['required ' , 'integer ' ],
32+ 'reply_to ' => ['nullable ' , 'integer ' ],
33+ 'html ' => ['required ' , 'string ' ],
34+ 'content_ref ' => ['string ' ],
35+ ],
36+ 'update ' => [
37+ 'html ' => ['required ' , 'string ' ],
38+ 'archived ' => ['boolean ' ],
39+ ]
40+ ];
41+
2842 public function __construct (
2943 protected CommentRepo $ commentRepo ,
44+ protected PageQueries $ pageQueries ,
3045 ) {
3146 }
3247
@@ -42,13 +57,34 @@ public function list(): JsonResponse
4257 ]);
4358 }
4459
60+ /**
61+ * Create a new comment on a page.
62+ * If commenting as a reply to an existing comment, the 'reply_to' parameter
63+ * should be provided, set to the 'local_id' of the comment being replied to.
64+ */
65+ public function create (Request $ request ): JsonResponse
66+ {
67+ $ this ->checkPermission (Permission::CommentCreateAll);
68+
69+ $ input = $ this ->validate ($ request , $ this ->rules ()['create ' ]);
70+ $ page = $ this ->pageQueries ->findVisibleByIdOrFail ($ input ['page_id ' ]);
71+
72+ $ comment = $ this ->commentRepo ->create (
73+ $ page ,
74+ $ input ['html ' ],
75+ $ input ['reply_to ' ] ?? null ,
76+ $ input ['content_ref ' ] ?? '' ,
77+ );
78+
79+ return response ()->json ($ comment );
80+ }
81+
4582 /**
4683 * Read the details of a single comment, along with its direct replies.
4784 */
4885 public function read (string $ id ): JsonResponse
4986 {
50- $ comment = $ this ->commentRepo ->getQueryForVisible ()
51- ->where ('id ' , '= ' , $ id )->firstOrFail ();
87+ $ comment = $ this ->commentRepo ->getVisibleById (intval ($ id ));
5288
5389 $ replies = $ this ->commentRepo ->getQueryForVisible ()
5490 ->where ('parent_id ' , '= ' , $ comment ->local_id )
@@ -67,4 +103,45 @@ public function read(string $id): JsonResponse
67103
68104 return response ()->json ($ comment );
69105 }
106+
107+
108+ /**
109+ * Update the content or archived status of an existing comment.
110+ *
111+ * Only provide a new archived status if needing to actively change the archive state.
112+ * Only top-level comments (non-replies) can be archived or unarchived.
113+ */
114+ public function update (Request $ request , string $ id ): JsonResponse
115+ {
116+ $ comment = $ this ->commentRepo ->getVisibleById (intval ($ id ));
117+ $ this ->checkOwnablePermission (Permission::CommentUpdate, $ comment );
118+
119+ $ input = $ this ->validate ($ request , $ this ->rules ()['update ' ]);
120+
121+ if (isset ($ input ['archived ' ])) {
122+ $ archived = $ input ['archived ' ];
123+ if ($ archived ) {
124+ $ this ->commentRepo ->archive ($ comment , false );
125+ } else {
126+ $ this ->commentRepo ->unarchive ($ comment , false );
127+ }
128+ }
129+
130+ $ comment = $ this ->commentRepo ->update ($ comment , $ input ['html ' ]);
131+
132+ return response ()->json ($ comment );
133+ }
134+
135+ /**
136+ * Delete a single comment from the system.
137+ */
138+ public function delete (string $ id ): Response
139+ {
140+ $ comment = $ this ->commentRepo ->getVisibleById (intval ($ id ));
141+ $ this ->checkOwnablePermission (Permission::CommentDelete, $ comment );
142+
143+ $ this ->commentRepo ->delete ($ comment );
144+
145+ return response ('' , 204 );
146+ }
70147}
0 commit comments