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

462 lines 15.2 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\Framework\Support\Arr;
16
17 class CommentsController extends Controller
18 {
19 public function getComments(Request $request, $feed_id)
20 {
21 $feed = Feed::withoutGlobalScopes()->findOrFail($feed_id);
22
23 $canViewComments = apply_filters('fluent_community/can_view_comments_' . $feed->type, true, $feed);
24
25 if (!$canViewComments) {
26 return [
27 'comments' => []
28 ];
29 }
30
31 $comments = Comment::where('post_id', $feed->id)
32 ->orderBy('created_at', 'asc')
33 ->with([
34 'xprofile' => function ($q) {
35 $q->select(ProfileHelper::getXProfilePublicFields());
36 }
37 ])
38 ->get();
39
40 $userId = $this->getUserId();
41
42 if ($userId) {
43 $likedIds = FeedsHelper::getLikedIdsByUserFeedId($feed->id, get_current_user_id());
44
45 if ($likedIds) {
46 $comments->each(function ($comment) use ($likedIds) {
47 if (in_array($comment->id, $likedIds)) {
48 $comment->liked = 1;
49 }
50 });
51 }
52 }
53
54 return [
55 'comments' => $comments
56 ];
57 }
58
59 public function store(Request $request, $feedId)
60 {
61 $user = $this->getUser(true);
62 do_action('fluent_community/check_rate_limit/create_comment', $user);
63
64 $text = $this->validateCommentText($request->all());
65 $feed = Feed::withoutGlobalScopes()->findOrFail($feedId);
66
67 $this->verifyCreateCommentPermission($feed);
68
69 $requestData = $request->all();
70
71 // Check for duplicate
72 $exist = Comment::where('user_id', get_current_user_id())
73 ->where('message', $text)
74 ->where('post_id', $feed->id)
75 ->first();
76
77 if ($exist) {
78 return $this->sendError([
79 'message' => __('No duplicate comment please!', 'fluent-community')
80 ]);
81 }
82
83 $mentions = FeedsHelper::getMentions($text, $feed->space_id);
84 $commentHtml = $this->generateCommentHtml($text, $mentions);
85 $commentData = $this->prepareCommentData($feed->id, $text, $commentHtml);
86
87 if ($parentId = $request->get('parent_id')) {
88 $parentId = (int)$parentId;
89 $parentComment = Comment::where('id', $parentId)
90 ->where('post_id', $feed->id)
91 ->first();
92
93 if (!$parentComment) {
94 return $this->sendError([
95 'message' => __('Invalid parent comment', 'fluent-community')
96 ]);
97 }
98
99 $commentData['parent_id'] = $parentId;
100 }
101 [$commentData, $media] = $this->prepareCommentMedia($commentData, $requestData);
102 $comment = Comment::create($commentData);
103
104 $feed->comments_count = $feed->comments_count + 1;
105 $feed->save();
106
107 if ($media) {
108 $media->fill([
109 'is_active' => 1,
110 'feed_id' => $feed->id,
111 'object_source' => 'comment',
112 'sub_object_id' => $comment->id
113 ]);
114 $media->save();
115 }
116
117 $this->loadCommentRelations($comment);
118
119 $mentionedUsers = $mentions ? $mentions['users'] : null;
120 do_action('fluent_community/comment_added_' . $feed->type, $comment, $feed, $mentionedUsers);
121 do_action('fluent_community/comment_added', $comment, $feed, $mentionedUsers);
122
123 return [
124 'comment' => $comment,
125 'message' => __('Comment has been added', 'fluent-community'),
126 ];
127 }
128
129 public function update(Request $request, $feedId, $commentId)
130 {
131 $text = $this->validateCommentText($request->all());
132 $feed = Feed::withoutGlobalScopes()->findOrFail($feedId);
133 $this->verifySpacePermission($feed);
134
135 $requestData = $request->all();
136 $comment = Comment::findOrFail($commentId);
137 $user = User::find(get_current_user_id());
138
139 if (!$user->can('edit_any_comment') && $comment->user_id != get_current_user_id()) {
140 return $this->sendError([
141 'message' => __('You are not allowed to edit this comment', 'fluent-community')
142 ]);
143 }
144
145 $mentions = FeedsHelper::getMentions($text, $feed->space_id);
146 $commentHtml = $this->generateCommentHtml($text, $mentions);
147
148 $commentData = $this->prepareCommentData($feed->id, $text, $commentHtml);
149
150 [$commentData, $media] = $this->prepareCommentMedia($commentData, $requestData, $comment);
151
152 $comment->update($commentData);
153
154 if ($media) {
155 $media->fill([
156 'is_active' => 1,
157 'feed_id' => $feed->id,
158 'object_source' => 'comment',
159 'sub_object_id' => $comment->id
160 ]);
161 $media->save();
162
163 // remove other media
164 $otherMedias = Media::where('object_source', 'comment')
165 ->where('sub_object_id', $comment->id)
166 ->where('id', '!=', $media->id)
167 ->get();
168
169 if (!$otherMedias->isEmpty()) {
170 do_action('fluent_community/comment/media_deleted', $otherMedias);
171 }
172 } else {
173 // remove other media
174 $otherMedias = Media::where('object_source', 'comment')
175 ->where('sub_object_id', $comment->id)
176 ->get();
177
178 if (!$otherMedias->isEmpty()) {
179 do_action('fluent_community/comment/media_deleted', $otherMedias);
180 }
181 }
182
183 $this->loadCommentRelations($comment);
184
185 return [
186 'comment' => $comment,
187 'message' => __('Comment has been updated', 'fluent-community'),
188 ];
189 }
190
191 private function prepareCommentMedia($commentData, $requestData, $exisitngComment = null)
192 {
193 $mediaImages = Arr::get($requestData, 'media_images', []);
194
195 if ($mediaImages) {
196 $uploadedImages = Helper::getMediaByProvider($mediaImages);
197 if ($uploadedImages) {
198 $mediaItems = Helper::getMediaItemsFromUrl($uploadedImages);
199 if ($mediaItems) {
200 $firstMedia = $mediaItems[0];
201 $commentData['meta']['media_preview'] = [
202 'image' => $firstMedia->public_url,
203 'type' => 'image',
204 'provider' => 'upload',
205 'height' => $firstMedia->settings ? Arr::get($firstMedia->settings, 'height', 0) : 0,
206 'width' => $firstMedia->settings ? Arr::get($firstMedia->settings, 'width', 0) : 0,
207 ];
208 return [$commentData, $firstMedia];
209 }
210 }
211 }
212
213 if (empty($requestData['meta']['media_preview']['image'])) {
214 return [$commentData, null];
215 }
216
217 if ($exisitngComment) {
218 $image = sanitize_url(Arr::get($requestData, 'meta.media_preview.image', ''));
219 $existingMedia = Media::where('media_url', $image)
220 ->where('object_source', 'comment')
221 ->where('sub_object_id', $exisitngComment->id)
222 ->first();
223
224 if ($existingMedia) {
225 $commentData['meta'] = $exisitngComment->meta;
226 return [$commentData, $existingMedia];
227 }
228 }
229
230 $commentData['meta']['media_preview'] = array_filter([
231 'image' => sanitize_url(Arr::get($requestData, 'meta.media_preview.image', '')),
232 'type' => Arr::get($requestData, 'meta.media_preview.type', 'image'),
233 'provider' => Arr::get($requestData, 'meta.media_preview.provider', ''),
234 'height' => Arr::get($requestData, 'meta.media_preview.height', 0),
235 'width' => Arr::get($requestData, 'meta.media_preview.width', 0),
236 ]);
237
238 return [$commentData, null];
239 }
240
241 private function validateCommentText($data)
242 {
243 $text = trim(Arr::get($data, 'comment'));
244 $text = CustomSanitizer::unslashMarkdown($text);
245
246 $hasMedia = Arr::get($data, 'media_images', []) || Arr::get($data, 'meta.media_preview.image', false);
247
248 if (!$text && !$hasMedia) {
249 throw new \Exception(esc_html__('Please provide your reply text', 'fluent-community'), 422);
250 }
251
252 $maxCommentLength = apply_filters('fluent_community/max_comment_char_length', 10000);
253 if ($text && strlen($text) > $maxCommentLength) {
254 throw new \Exception(esc_html__('Comment text is too long', 'fluent-community'), 422);
255 }
256
257 return $text;
258 }
259
260 private function verifyCreateCommentPermission($feed)
261 {
262 if (Arr::get($feed->meta, 'comments_disabled') === 'yes') {
263 throw new \Exception(esc_html__('Comments are disabled for this post', 'fluent-community'));
264 }
265
266 $this->verifySpacePermission($feed);
267 }
268
269 private function verifySpacePermission($feed)
270 {
271 if ($feed->space_id && $feed->space) {
272 $user = $this->getUser(true);
273 $user->verifySpacePermission('registered', $feed->space);
274 }
275 }
276
277 private function generateCommentHtml($text, $mentions)
278 {
279 $htmlText = $mentions ? $mentions['text'] : $text;
280 return wp_kses_post(FeedsHelper::mdToHtml($htmlText));
281 }
282
283 private function prepareCommentData($feedId, $text, $commentHtml)
284 {
285 return [
286 'post_id' => $feedId,
287 'message' => $text,
288 'message_rendered' => $commentHtml,
289 'type' => 'comment',
290 'meta' => [],
291 ];
292 }
293
294 private function loadCommentRelations($comment)
295 {
296 $comment->load('media');
297 $comment->load([
298 'xprofile' => function ($q) {
299 $q->select(ProfileHelper::getXProfilePublicFields());
300 }
301 ]);
302 }
303
304 public function addOrRemovePostReact(Request $request, $feed_id)
305 {
306 $feed = Feed::withoutGlobalScopes()->findOrFail($feed_id);
307 $type = $request->get('react_type', 'like');
308 $willRemove = $request->get('remove');
309
310 $react = Reaction::where('user_id', get_current_user_id())
311 ->where('object_id', $feed->id)
312 ->where('type', $type)
313 ->objectType('feed')
314 ->first();
315
316 if ($willRemove) {
317 if ($react) {
318 $react->delete();
319 if ($type == 'like') {
320 $feed->reactions_count = $feed->reactions_count - 1;
321 $feed->save();
322 }
323 }
324
325 return [
326 'message' => 'Reaction has been removed',
327 'new_count' => $feed->reactions_count
328 ];
329 }
330
331 if ($react) {
332 return [
333 'message' => 'You have already reacted to this post',
334 'new_count' => $feed->reactions_count
335 ];
336 }
337
338 $react = Reaction::create([
339 'user_id' => get_current_user_id(),
340 'object_id' => $feed->id,
341 'type' => $type,
342 'object_type' => 'feed'
343 ]);
344
345 if ($type == 'like') {
346 $feed->reactions_count = $feed->reactions_count + 1;
347 $feed->save();
348
349 $react->load('xprofile');
350 do_action('fluent_community/feed/react_added', $react, $feed);
351 }
352
353 return [
354 'message' => 'Reaction has been added',
355 'new_count' => $feed->reactions_count
356 ];
357 }
358
359 public function deleteComment(Request $request, $feedId, $commentId)
360 {
361 $feed = Feed::withoutGlobalScopes()->findOrFail($feedId);
362 $comment = Comment::findOrFail($commentId);
363
364 if ($comment->post_id != $feed->id) {
365 return $this->sendError([
366 'message' => 'Invalid comment'
367 ]);
368 }
369
370 $user = User::find(get_current_user_id());
371 if (!$user->can('delete_any_comment') && $comment->user_id != get_current_user_id()) {
372 return $this->sendError([
373 'message' => 'You are not allowed to delete this comment'
374 ]);
375 }
376
377 do_action('fluent_community/comment/media_deleted', $comment->media);
378
379 $comment->delete();
380
381 $feed->comments_count = Comment::where('post_id', $feed->id)->count();
382 $feed->save();
383
384 do_action('fluent_community/comment_deleted_' . $feed->type, $commentId, $feed);
385 do_action('fluent_community/comment_deleted', $commentId, $feed);
386
387 return [
388 'message' => __('Selected comment has been deleted', 'fluent-community')
389 ];
390 }
391
392 public function toggoleReaction(Request $request, $feedId, $commentId)
393 {
394 $feed = Feed::withoutGlobalScopes()->findOrFail($feedId);
395 $comment = Comment::findOrFail($commentId);
396
397 if ($comment->post_id != $feed->id) {
398 return $this->sendError([
399 'message' => 'Invalid comment'
400 ]);
401 }
402
403 $user = User::findOrFail(get_current_user_id());
404
405 if ($feed->space_id) {
406 $user->verifySpacePermission('registered', $feed->space);
407 }
408
409 $reactionState = !!$request->get('state', false);
410
411 if ($reactionState) {
412 // add or update the reaction
413 $reaction = Reaction::firstOrCreate([
414 'user_id' => get_current_user_id(),
415 'object_id' => $comment->id,
416 'object_type' => 'comment',
417 'parent_id' => $feed->id
418 ]);
419
420 if ($reaction->wasRecentlyCreated) {
421 $comment->reactions_count = $comment->reactions_count + 1;
422 $comment->save();
423 }
424 } else {
425 // remove the reaction
426 $deleted = Reaction::where('user_id', get_current_user_id())
427 ->where('object_id', $comment->id)
428 ->where('object_type', 'comment')
429 ->delete();
430
431 if ($deleted) {
432 $comment->reactions_count = $comment->reactions_count - 1;
433 $comment->save();
434 }
435 }
436
437 return [
438 'message' => 'Reaction has been toggled',
439 'reactions_count' => $comment->reactions_count,
440 'liked' => $reactionState
441 ];
442 }
443
444 public function show(Request $request, $id)
445 {
446 $comment = Comment::with([
447 'xprofile' => function ($q) {
448 return $q->select(ProfileHelper::getXProfilePublicFields());
449 }
450 ])->findOrFail($id);
451
452 // Just to verify the permission
453 $feed = Feed::withoutGlobalScopes()
454 ->byUserAccess($this->getUserId())
455 ->findOrFail($comment->post_id);
456
457 return [
458 'comment' => $comment
459 ];
460 }
461 }
462