PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / trunk
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses vtrunk
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 trunk, at app/Http/Controllers/CommentsController.php

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