PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.9.1
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.9.1
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / app / Http / Controllers / CommentsController.php

CommentsController.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.9.1, at app/Http/Controllers/CommentsController.php

752 lines 28.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\App\Http\Controllers;
4
5 use FluentCommunity\App\Models\Media;
6 use FluentCommunity\App\Models\User;
7 use FluentCommunity\App\Services\CustomSanitizer;
8 use FluentCommunity\App\Services\FeedsHelper;
9 use FluentCommunity\App\Services\Helper;
10 use FluentCommunity\App\Services\ProfileHelper;
11 use FluentCommunity\Framework\Http\Request\Request;
12 use FluentCommunity\App\Models\Comment;
13 use FluentCommunity\App\Models\Feed;
14 use FluentCommunity\App\Models\Reaction;
15 use FluentCommunity\App\Models\XProfile;
16 use FluentCommunity\Framework\Support\Arr;
17
18 class CommentsController extends Controller
19 {
20 public function getComments(Request $request, $feed_id)
21 {
22 $feed = Feed::withoutGlobalScopes()
23 ->byUserAccess(get_current_user_id())
24 ->findOrFail($feed_id);
25
26 if (!in_array($feed->status, FeedsHelper::getViewableByLinkStatuses(), true) && !$feed->hasEditAccess($this->getUserId())) {
27 return $this->sendError([
28 'message' => __('Sorry, you do not have permission to view this post', 'fluent-community')
29 ], 404);
30 }
31
32 $canViewComments = apply_filters('fluent_community/can_view_comments_' . $feed->type, true, $feed);
33
34 if (!$canViewComments) {
35 return [
36 'comments' => []
37 ];
38 }
39
40 $comments = Comment::where('post_id', $feed->id)
41 ->byContentModerationAccessStatus($this->getUser())
42 ->orderBy('created_at', 'asc')
43 ->with([
44 'xprofile' => function ($q) {
45 $q->select(ProfileHelper::getXProfilePublicFields());
46 }
47 ])
48 ->whereHas('xprofile', function ($q) {
49 $q->where('status', 'active');
50 })
51 ->get();
52
53 $comments = apply_filters('fluent_community/comments_query_response', $comments, $request->all());
54
55 $userId = $this->getUserId();
56
57 if ($userId) {
58 $likedIds = FeedsHelper::getLikedIdsByUserFeedId($feed->id, get_current_user_id());
59 if ($likedIds) {
60 $comments->each(function ($comment) use ($likedIds) {
61 if (in_array($comment->id, $likedIds)) {
62 $comment->liked = 1;
63 }
64 });
65 }
66 }
67
68 $data = [
69 'comments' => $comments
70 ];
71
72 return apply_filters('fluent_community/comments_api_response', $data, $request->all());
73 }
74
75 public function store(Request $request, $feedId)
76 {
77 $user = $this->getUser(true);
78 do_action('fluent_community/check_rate_limit/create_comment', $user);
79
80 $text = $this->validateCommentText($request->all());
81 $feed = Feed::withoutGlobalScopes()->findOrFail($feedId);
82
83 if (!in_array($feed->status, FeedsHelper::getViewableByLinkStatuses(), true)) {
84 return $this->sendError([
85 'message' => __('This post is not published yet', 'fluent-community')
86 ]);
87 }
88
89 $this->verifyCreateCommentPermission($feed);
90
91 $requestData = $request->all();
92
93 [$markdown, $inlineMedias] = FeedsHelper::replaceImageUrlsWithRealMediaArchive($text);
94 $mentions = FeedsHelper::getMentions($markdown, $feed->space_id, true);
95 $commentHtml = $this->generateCommentHtml($markdown, $mentions);
96
97 $commentData = $this->prepareCommentData($feed->id, $text, $commentHtml);
98
99 if (!empty($requestData['parent_id'])) {
100 $parentId = (int)$requestData['parent_id'];
101 $parentComment = Comment::where('id', $parentId)
102 ->where('post_id', $feed->id)
103 ->first();
104
105 if (!$parentComment) {
106 return $this->sendError([
107 'message' => __('Invalid parent comment', 'fluent-community')
108 ]);
109 }
110
111 $commentData['parent_id'] = $parentId;
112 }
113
114 [$commentData, $mediaItems] = $this->prepareCommentMedia($commentData, $requestData);
115
116 $commentData['is_admin'] = $user->hasSpacePermission('community_moderator', $feed->space);
117
118 if ($mentionUserIds = Arr::get($mentions, 'user_ids', [])) {
119 $commentData['meta']['mentioned_user_ids'] = $mentionUserIds;
120 }
121
122 do_action('fluent_community/before_comment_create', $commentData, $feed);
123
124 $commentData = apply_filters('fluent_community/comment/comment_data', $commentData, $feed);
125
126 // Only comments with text are duplicate checked
127 $shouldCheckDuplicate = $text && !apply_filters('fluent_community/disable_duplicate_comment_check', false, get_current_user_id(), $feed->id);
128
129 // Serialize a member's concurrent submissions by locking their profile row,
130 // so parallel matching requests cannot pass the duplicate check and both insert.
131 $comment = Helper::dbTransaction(function () use ($commentData, $feed, $text, $shouldCheckDuplicate) {
132 XProfile::where('user_id', get_current_user_id())->lockForUpdate()->first();
133
134 if ($shouldCheckDuplicate && Comment::where('user_id', get_current_user_id())->where('message', $text)->where('post_id', $feed->id)->first()) {
135 return null;
136 }
137
138 $newComment = Comment::create($commentData);
139 Feed::withoutGlobalScopes()->where('id', $feed->id)->increment('comments_count');
140
141 return $newComment;
142 });
143
144 if (!$comment) {
145 return $this->sendError([
146 'message' => __('No duplicate comment please!', 'fluent-community')
147 ]);
148 }
149
150 $feed->comments_count = $feed->comments_count + 1;
151
152
153 // Merge and save all media in one loop
154 $mediaItems = $mediaItems ? (is_array($mediaItems) ? $mediaItems : [$mediaItems]) : [];
155
156 if ($inlineMedias) {
157 $mediaItems = array_merge($mediaItems, $inlineMedias);
158 }
159
160 if ($mediaItems) {
161 foreach ($mediaItems as $media) {
162 $media->fill([
163 'is_active' => 1,
164 'feed_id' => $feed->id,
165 'object_source' => 'comment',
166 'sub_object_id' => $comment->id
167 ]);
168 $media->save();
169 }
170 }
171
172 $this->loadCommentRelations($comment);
173
174 if ($comment->status != 'published') {
175 do_action('fluent_community/comment/new_comment_' . $comment->status, $comment, $feed);
176 /* translators: %$s is replaced by the status of the comment */
177 $message = sprintf(__('Your comment has been marked as %s', 'fluent-community'), $comment->status);
178 $response = [
179 'comment' => $comment,
180 'message' => $message
181 ];
182 return apply_filters('fluent_community/comment/new_comment_response', $response, $comment);
183 }
184
185 do_action('fluent_community/comment_added_' . $feed->type, $comment, $feed);
186 do_action('fluent_community/comment_added', $comment, $feed, Arr::get($mentions, 'users', []));
187
188 return [
189 'comment' => $comment,
190 'message' => __('Comment has been added', 'fluent-community'),
191 ];
192 }
193
194 public function update(Request $request, $feedId, $commentId)
195 {
196 $text = $this->validateCommentText($request->all());
197
198 $feed = Feed::withoutGlobalScopes()->findOrFail($feedId);
199 $this->verifySpacePermission($feed);
200
201 $requestData = $request->all();
202 $comment = Comment::findOrFail($commentId);
203
204 if ($comment->post_id != $feed->id) {
205 return $this->sendError([
206 'message' => __('Invalid comment', 'fluent-community')
207 ]);
208 }
209
210 $user = $this->getUser(true);
211
212 $requestData['is_admin'] = $user->hasPermissionOrInCurrentSpace('community_moderator', $feed->space);
213
214 if ($comment->user_id != get_current_user_id() && !$user->can('edit_any_comment', $feed->space)) {
215 return $this->sendError([
216 'message' => __('You are not allowed to edit this comment', 'fluent-community')
217 ]);
218 }
219
220 [$markdown, $inlineMedias] = FeedsHelper::replaceImageUrlsWithRealMediaArchive($text, $feed);
221
222 $mentions = FeedsHelper::getMentions($markdown, $feed->space_id);
223
224 $commentHtml = $this->generateCommentHtml($markdown, $mentions);
225
226 $commentData = $this->prepareCommentData($feed->id, $text, $commentHtml);
227
228 [$commentData, $mediaItems] = $this->prepareCommentMedia($commentData, $requestData, $comment);
229
230 $commentData = apply_filters('fluent_community/comment/update_comment_data', $commentData, $feed, $requestData, $comment);
231
232 $comment->fill($commentData);
233
234 $dirty = $comment->getDirty();
235
236 if ($dirty) {
237 $comment->save();
238 }
239
240 // Merge and save all media in one loop
241 $mediaItems = $mediaItems ? (is_array($mediaItems) ? $mediaItems : [$mediaItems]) : [];
242
243 if ($inlineMedias) {
244 $mediaItems = array_merge($mediaItems, $inlineMedias);
245 }
246
247 $allMediaIds = [];
248
249 if ($mediaItems) {
250 foreach ($mediaItems as $media) {
251 $media->fill([
252 'is_active' => 1,
253 'feed_id' => $feed->id,
254 'object_source' => 'comment',
255 'sub_object_id' => $comment->id
256 ]);
257 $media->save();
258 $allMediaIds[] = $media->id;
259 }
260 }
261
262 // Remove old media not in current list
263 $otherMedias = Media::where('object_source', 'comment')
264 ->when($allMediaIds, function ($q) use ($allMediaIds) {
265 $q->whereNotIn('id', $allMediaIds);
266 })
267 ->where('sub_object_id', $comment->id)
268 ->get();
269
270 if (!$otherMedias->isEmpty()) {
271 do_action('fluent_community/comment/media_deleted', $otherMedias);
272 }
273
274 $this->loadCommentRelations($comment);
275
276 if ($dirty) {
277 do_action('fluent_community/comment_updated', $comment, $feed);
278 do_action('fluent_community/comment_updated_' . $feed->type, $comment, $feed);
279 }
280
281 return [
282 'comment' => $comment,
283 'message' => __('Comment has been updated', 'fluent-community'),
284 ];
285 }
286
287 public function patchComment(Request $request, $feedId, $commentId)
288 {
289 $feed = Feed::withoutGlobalScopes()->findOrFail($feedId);
290
291 $comment = Comment::findOrFail($commentId);
292
293 if ($comment->post_id != $feed->id) {
294 return $this->sendError([
295 'message' => __('Invalid comment', 'fluent-community')
296 ]);
297 }
298
299 $user = $this->getUser(true);
300
301 $isMod = $user && $user->hasPermissionOrInCurrentSpace('community_moderator', $feed->space);
302 $isAdmin = $user && $user->hasPermissionOrInCurrentSpace('community_admin', $feed->space);
303
304 if (!$isMod && !$isAdmin) {
305 return $this->sendError([
306 'message' => __('You do not have permission to perform this action', 'fluent-community')
307 ]);
308 }
309
310 $allData = $request->all();
311 $validKeys = ['is_sticky'];
312
313 $data = Arr::only($allData, $validKeys);
314
315 $data = array_map('intval', $data);
316
317 if (isset($data['is_sticky'])) {
318 if ($comment->parent_id) {
319 return $this->sendError([
320 'message' => __('You cannot pin a reply comment', 'fluent-community')
321 ]);
322 }
323
324 $data['is_sticky'] = $data['is_sticky'] ? 1 : 0;
325 if ($data['is_sticky']) {
326 Comment::where('post_id', $feed->id)->update(['is_sticky' => 0]);
327 }
328 }
329
330 if ($data) {
331 $comment->fill($data);
332 $dirty = $comment->getDirty();
333 if ($dirty) {
334 $comment->save();
335 do_action('fluent_community/comment/updated', $comment, $dirty);
336 }
337 }
338
339 return apply_filters('fluent_community/comment/patch_comment_response', [
340 'comment' => $comment,
341 'message' => __('Comment updated', 'fluent-community')
342 ], $comment, $feed, $request->all());
343 }
344
345 private function prepareCommentMedia($commentData, $requestData, $exisitngComment = null)
346 {
347 $mediaImages = Arr::get($requestData, 'media_images', []);
348
349 if ($mediaImages) {
350 if ($exisitngComment) {
351 $mediaItems = [];
352 $mediaData = [];
353 foreach ($mediaImages as $mediaImage) {
354 $id = Arr::get($mediaImage, 'media_id');
355 if ($id) {
356 $media = Media::where('sub_object_id', $exisitngComment->id)
357 ->where('object_source', 'comment')
358 ->find($id);
359 } else {
360 $media = Helper::getMediaFromUrl($mediaImage);
361 }
362
363 if ($media) {
364 $mediaItems[] = $media;
365 $mediaData[] = [
366 'media_id' => $media->id,
367 'url' => $media->public_url,
368 'type' => 'image',
369 'width' => Arr::get($media->settings, 'width'),
370 'height' => Arr::get($media->settings, 'height'),
371 'provider' => Arr::get($media->settings, 'provider', 'uploader')
372 ];
373 }
374 }
375 $commentData['meta']['media_items'] = $mediaData;
376 return [$commentData, $mediaItems];
377 }
378
379 $uploadedImages = Helper::getMediaByProvider($mediaImages);
380 if ($uploadedImages) {
381 $mediaItems = Helper::getMediaItemsFromUrl($uploadedImages);
382 if ($mediaItems) {
383 $mediaPreviews = [];
384 foreach ($mediaItems as $mediaItem) {
385 $mediaData = [
386 'media_id' => $mediaItem->id,
387 'url' => $mediaItem->public_url,
388 'type' => 'image',
389 'width' => Arr::get($mediaItem->settings, 'width'),
390 'height' => Arr::get($mediaItem->settings, 'height'),
391 'provider' => Arr::get($mediaItem->settings, 'provider', 'uploader')
392 ];
393
394 $mediaPreviews[] = array_filter($mediaData);
395 }
396 $commentData['meta']['media_items'] = $mediaPreviews;
397 return [$commentData, $mediaItems];
398 }
399 }
400 }
401
402 if (empty($requestData['meta']['media_preview']['image'])) {
403 return [$commentData, []];
404 }
405
406 if ($exisitngComment) {
407 $image = sanitize_url(Arr::get($requestData, 'meta.media_preview.image', ''));
408 $existingMedia = Media::where('media_url', $image)
409 ->where('object_source', 'comment')
410 ->where('sub_object_id', $exisitngComment->id)
411 ->first();
412
413 if ($existingMedia) {
414 $commentData['meta'] = $exisitngComment->meta;
415 return [$commentData, [$existingMedia]];
416 }
417 }
418
419 // type/provider reach :class bindings and width/height a :style binding in
420 // _MediaPreview.vue. Neither is an executable sink, but the stored values are
421 // request-supplied so they are normalised here rather than trusted.
422 $commentData['meta']['media_preview'] = array_filter([
423 'image' => sanitize_url(Arr::get($requestData, 'meta.media_preview.image', '')),
424 'type' => sanitize_text_field(Arr::get($requestData, 'meta.media_preview.type', 'image')),
425 'provider' => sanitize_text_field(Arr::get($requestData, 'meta.media_preview.provider', '')),
426 'height' => (int) Arr::get($requestData, 'meta.media_preview.height', 0),
427 'width' => (int) Arr::get($requestData, 'meta.media_preview.width', 0),
428 ]);
429
430 return [$commentData, []];
431 }
432
433 private function validateCommentText($data)
434 {
435 $text = trim(Arr::get($data, 'comment'));
436 $text = CustomSanitizer::unslashMarkdown($text);
437
438 // Decode HTML entities (e.g., &#x20; for space) and strip all whitespace for validation
439 $textForValidation = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
440 $textForValidation = preg_replace('/\s+/u', '', $textForValidation);
441
442 $hasMedia = Arr::get($data, 'media_images', []) || Arr::get($data, 'meta.media_preview.image', false);
443
444 $isReply = !empty($data['parent_id']);
445 if (!$textForValidation && !$hasMedia) {
446 if ($isReply) {
447 throw new \Exception(esc_html__('Reply cannot be empty.', 'fluent-community'), 422);
448 } else {
449 throw new \Exception(esc_html__('Comment cannot be empty.', 'fluent-community'), 422);
450 }
451 }
452
453 $maxCommentLength = apply_filters('fluent_community/max_comment_char_length', 10000);
454 if ($text && strlen($text) > $maxCommentLength) {
455 /* translators: %s is the maximum allowed character count */
456 throw new \Exception(esc_html(sprintf(__('The comment is too long. Please keep it under %s characters.', 'fluent-community'), number_format($maxCommentLength))), 422);
457 }
458
459 return $text;
460 }
461
462 private function verifyCreateCommentPermission($feed)
463 {
464 if (Arr::get($feed->meta, 'comments_disabled') === 'yes') {
465 throw new \Exception(esc_html__('Comments are disabled for this post', 'fluent-community'));
466 }
467
468 $this->verifySpacePermission($feed);
469 }
470
471 private function verifySpacePermission($feed)
472 {
473 if ($feed->space_id && $feed->space) {
474 $user = $this->getUser(true);
475 $user->verifySpacePermission('can_comment', $feed->space);
476
477 if ($feed->space->type == 'course' && Arr::get($feed->space->settings, 'disable_comments') === 'yes') {
478 throw new \Exception(esc_html__('Comments are disabled for this course', 'fluent-community'));
479 }
480 }
481 }
482
483 private function generateCommentHtml($text, $mentions)
484 {
485 $htmlText = $mentions ? $mentions['text'] : $text;
486 return wp_kses_post(FeedsHelper::mdToHtml($htmlText));
487 }
488
489 private function prepareCommentData($feedId, $text, $commentHtml)
490 {
491 return [
492 'post_id' => $feedId,
493 'message' => $text,
494 'message_rendered' => $commentHtml,
495 'type' => 'comment',
496 'meta' => [],
497 ];
498 }
499
500 private function loadCommentRelations($comment)
501 {
502 $comment->load('media');
503 $comment->load([
504 'xprofile' => function ($q) {
505 $q->select(ProfileHelper::getXProfilePublicFields());
506 }
507 ]);
508 }
509
510 public function addOrRemovePostReact(Request $request, $feed_id)
511 {
512 $userId = get_current_user_id();
513 $feed = Feed::withoutGlobalScopes()->byUserAccess($userId)->findOrFail($feed_id);
514 $type = $request->get('react_type', 'like');
515 $type = in_array($type, ['like', 'bookmark'], true) ? $type : 'like';
516 $willRemove = $request->get('remove');
517
518 if (!in_array($feed->status, FeedsHelper::getViewableByLinkStatuses(), true)) {
519 return $this->sendError([
520 'message' => __('This post is not published yet', 'fluent-community')
521 ]);
522 }
523
524 if (!$willRemove && (int) $userId === (int) $feed->user_id && apply_filters('fluent_community/disable_self_post_react', false, $feed)) {
525 return $this->sendError([
526 'message' => __('You cannot react to your own post', 'fluent-community')
527 ]);
528 }
529
530 $react = Reaction::where('user_id', $userId)
531 ->where('object_id', $feed->id)
532 ->where('type', $type)
533 ->objectType('feed')
534 ->first();
535
536 if ($willRemove) {
537 if ($react) {
538 $react->delete();
539 if ($type == 'like') {
540 $feed->reactions_count = $feed->reactions_count - 1;
541 $feed->timestamps = false; // Don't update the updated_at timestamp
542 $feed->save();
543 do_action('fluent_community/feed/react_removed', $feed);
544 }
545 }
546
547 return [
548 'message' => __('Reaction has been removed', 'fluent-community'),
549 'new_count' => $feed->reactions_count
550 ];
551 }
552
553 if ($react) {
554 return [
555 'message' => __('You have already reacted to this post', 'fluent-community'),
556 'new_count' => $feed->reactions_count
557 ];
558 }
559
560 $react = Reaction::create([
561 'user_id' => get_current_user_id(),
562 'object_id' => $feed->id,
563 'type' => $type,
564 'object_type' => 'feed'
565 ]);
566
567 if ($type == 'like') {
568 $feed->reactions_count = $feed->reactions_count + 1;
569 $feed->timestamps = false; // Don't update the updated_at timestamp
570 $feed->save();
571
572 $react->load('xprofile');
573 do_action('fluent_community/feed/react_added', $react, $feed);
574 }
575
576 return [
577 'message' => __('Reaction has been added', 'fluent-community'),
578 'new_count' => $feed->reactions_count
579 ];
580 }
581
582 public function deleteComment(Request $request, $feedId, $commentId)
583 {
584 $feed = Feed::withoutGlobalScopes()->findOrFail($feedId);
585 $comment = Comment::findOrFail($commentId);
586
587 if ($comment->post_id != $feed->id) {
588 return $this->sendError([
589 'message' => __('Invalid comment', 'fluent-community')
590 ]);
591 }
592
593 $user = User::find(get_current_user_id());
594 if ($comment->user_id != get_current_user_id() && !$user->can('delete_any_comment', $feed->space)) {
595 return $this->sendError([
596 'message' => __('You are not allowed to delete this comment', 'fluent-community')
597 ]);
598 }
599
600 do_action('fluent_community/before_comment_delete', $comment);
601
602 if ($comment->media) {
603 do_action('fluent_community/comment/media_deleted', $comment->media);
604 }
605
606 $comment->delete();
607
608 $feed->comments_count = Comment::where('post_id', $feed->id)->count();
609 $feed->timestamps = false; // Don't update the updated_at timestamp
610 $feed->save();
611
612 do_action('fluent_community/comment_deleted_' . $feed->type, $commentId, $feed);
613 do_action('fluent_community/comment_deleted', $commentId, $feed);
614
615 return [
616 'message' => __('Selected comment has been deleted', 'fluent-community')
617 ];
618 }
619
620 public function toggleReaction(Request $request, $feedId, $commentId)
621 {
622 $feed = Feed::withoutGlobalScopes()->byUserAccess(get_current_user_id())->findOrFail($feedId);
623 $comment = Comment::findOrFail($commentId);
624
625 if ($comment->post_id != $feed->id) {
626 return $this->sendError([
627 'message' => __('Invalid comment', 'fluent-community')
628 ]);
629 }
630
631 $user = User::findOrFail(get_current_user_id());
632
633 if ($feed->space_id) {
634 $user->verifySpacePermission('registered', $feed->space);
635 }
636
637 $userId = get_current_user_id();
638 $reactionState = !!$request->get('state', false);
639
640 if ($reactionState && (int) $userId === (int) $comment->user_id && apply_filters('fluent_community/disable_self_comment_react', false, $feed)) {
641 return $this->sendError([
642 'message' => __('You cannot react to your own comment', 'fluent-community')
643 ]);
644 }
645
646 if ($reactionState) {
647 // Serialize concurrent reactions on this comment by locking its row,
648 // so parallel add requests cannot each insert a duplicate reaction.
649 $reaction = Helper::dbTransaction(function () use ($comment, $feed) {
650 XProfile::where('user_id', get_current_user_id())->lockForUpdate()->first();
651
652 $reaction = Reaction::firstOrCreate([
653 'user_id' => get_current_user_id(),
654 'object_id' => $comment->id,
655 'object_type' => 'comment',
656 'parent_id' => $feed->id
657 ]);
658
659 if ($reaction->wasRecentlyCreated) {
660 Comment::where('id', $comment->id)->increment('reactions_count');
661 $comment->reactions_count = $comment->reactions_count + 1;
662 }
663
664 return $reaction;
665 });
666
667 if ($reaction->wasRecentlyCreated) {
668 do_action('fluent_community/comment/react_added', $reaction, $comment, $feed);
669 }
670 } else {
671 // remove the reaction
672 $deleted = Reaction::where('user_id', get_current_user_id())
673 ->where('object_id', $comment->id)
674 ->where('object_type', 'comment')
675 ->delete();
676
677 if ($deleted) {
678 $comment->reactions_count = $comment->reactions_count - 1;
679 $comment->save();
680 do_action('fluent_community/comment/react_removed', $comment, $feed);
681 }
682 }
683
684 return [
685 'message' => __('Reaction has been toggled', 'fluent-community'),
686 'reactions_count' => $comment->reactions_count,
687 'liked' => $reactionState
688 ];
689 }
690
691 public function show(Request $request, $id)
692 {
693
694 $testComment = Comment::query()->findOrFail($id);
695
696 $comment = Comment::byContentModerationAccessStatus($this->getUser(), $testComment->space)
697 ->with([
698 'xprofile' => function ($q) {
699 return $q->select(ProfileHelper::getXProfilePublicFields());
700 }
701 ])->findOrFail($id);
702
703 // Just to verify the permission
704 Feed::withoutGlobalScopes()
705 ->byUserAccess($this->getUserId())
706 ->findOrFail($comment->post_id);
707
708 if ($request->get('context') == 'edit') {
709 $meta = $comment->meta;
710 unset($comment->meta);
711 $images = Arr::get($meta, 'media_items', []);
712 if ($images) {
713 $comment->media_images = $images;
714 } else {
715 $preview = Arr::get($meta, 'media_preview', []);
716 if ($preview) {
717 $previewUrl = Arr::get($preview, 'image');
718 $provider = Arr::get($preview, 'provider');
719 if ($previewUrl && $provider == 'uploader') {
720 $media = Media::where('media_url', $previewUrl)
721 ->where('object_source', 'comment')
722 ->where('sub_object_id', $comment->id)
723 ->first();
724 if ($media) {
725 $comment->media_images = [
726 [
727 'media_id' => $media->id,
728 'url' => $media->public_url,
729 'type' => $media->media_type,
730 'width' => Arr::get($media->settings, 'width'),
731 'height' => Arr::get($media->settings, 'height'),
732 'provider' => Arr::get($media->settings, 'provider', 'uploader')
733 ]
734 ];
735 }
736 } else {
737 $comment->meta = [
738 'media_preview' => $preview
739 ];
740 }
741 }
742 }
743 }
744
745 $data = [
746 'comment' => $comment
747 ];
748
749 return apply_filters('fluent_community/comment_api_response', $data, $request->all());
750 }
751 }
752