PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 1.0.96
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v1.0.96
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 / SpaceController.php

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

818 lines 25.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\Functions\Utility;
6 use FluentCommunity\App\Models\Space;
7 use FluentCommunity\App\Models\Feed;
8 use FluentCommunity\App\Models\BaseSpace;
9 use FluentCommunity\App\Models\SpaceGroup;
10 use FluentCommunity\App\Models\User;
11 use FluentCommunity\App\Services\CustomSanitizer;
12 use FluentCommunity\App\Services\FeedsHelper;
13 use FluentCommunity\App\Services\Helper;
14 use FluentCommunity\App\Services\LockscreenService;
15 use FluentCommunity\App\Services\ProfileHelper;
16 use FluentCommunity\Framework\Http\Request\Request;
17 use FluentCommunity\App\Models\Comment;
18 use FluentCommunity\App\Models\Reaction;
19 use FluentCommunity\App\Models\SpaceUserPivot;
20 use FluentCommunity\Framework\Support\Arr;
21
22 class SpaceController extends Controller
23 {
24 public function get()
25 {
26 $spaces = Space::orderBy('title', 'ASC')
27 ->whereHas('space_pivot', function ($q) {
28 $q->where('user_id', get_current_user_id());
29 })
30 ->get();
31
32 return [
33 'spaces' => $spaces
34 ];
35 }
36
37 public function create(Request $request)
38 {
39 $currentUser = $this->getUser(true);
40 $currentUser->verifyCommunityPermission('community_admin');
41
42 $data = $request->get('space', []);
43
44 if (empty($data['slug'])) {
45 $data['slug'] = sanitize_title($data['title'], '');
46 } else {
47 $data['slug'] = sanitize_title($data['slug'], '');
48 }
49
50 $data['title'] = sanitize_text_field($data['title']);
51 $data['privacy'] = sanitize_text_field($data['privacy']);
52
53 $this->validate($data, [
54 'title' => 'required',
55 'slug' => 'required|unique:fcom_spaces,slug',
56 'privacy' => 'required|in:public,private,secret',
57 'parent_id' => 'required|exists:fcom_spaces,id'
58 ], [
59 'parent_id.required' => __('Please select a menu group', 'fluent-community')
60 ]);
61
62 $spaceGroup = SpaceGroup::findOrFail($data['parent_id']);
63
64 $spaceData = apply_filters('fluent_community/space/create_data', [
65 'title' => sanitize_text_field($data['title']),
66 'slug' => $data['slug'],
67 'privacy' => $data['privacy'],
68 'description' => sanitize_textarea_field($data['description']),
69 'settings' => [
70 'restricted_post_only' => Arr::get($data, 'settings.restricted_post_only', 'no'),
71 'emoji' => CustomSanitizer::sanitizeEmoji(Arr::get($data, 'settings.emoji', '')),
72 'can_request_join' => Arr::get($data, 'settings.can_request_join', 'no'),
73 'custom_lock_screen' => Arr::get($data, 'settings.custom_lock_screen', 'no'),
74 'layout_style' => Arr::get($data, 'settings.layout_style', 'timeline'),
75 'show_sidebar' => Arr::get($data, 'settings.show_sidebar', 'yes'),
76 'shape_svg' => CustomSanitizer::sanitizeSvg(Arr::get($data, 'settings.shape_svg', '')),
77 'hide_members_count' => Arr::get($data, 'settings.hide_members_count', 'no') == 'yes' ? 'yes' : 'no',
78 ],
79 'parent_id' => $spaceGroup->id,
80 'serial' => BaseSpace::where('parent_id', $spaceGroup->id)->max('serial') + 1
81 ]);
82
83 $space = Space::create($spaceData);
84
85 $imageTypes = ['cover_photo', 'logo'];
86 $metaData = [];
87 foreach ($imageTypes as $type) {
88 if (!empty($data[$type])) {
89 $media = Helper::getMediaFromUrl($data[$type]);
90 if (!$media || $media->is_active) {
91 continue;
92 }
93 $metaData[$type] = $media->public_url;
94 $media->update([
95 'is_active' => true,
96 'user_id' => get_current_user_id(),
97 'sub_object_id' => $space->id,
98 'object_source' => 'space_' . $type
99 ]);
100 }
101 }
102
103 if ($metaData) {
104 $space->updateCustomData($metaData, false);
105 }
106
107 $space->members()->attach(get_current_user_id(), [
108 'role' => 'admin'
109 ]);
110
111 $currentUser->cacheAccessSpaces();
112 do_action('fluent_community/space/created', $space, $data);
113
114 return [
115 'message' => __('Space has been created successfully', 'fluent-community'),
116 'space' => $space
117 ];
118 }
119
120 public function discover(Request $request)
121 {
122
123 $currentUser = $this->getUser();
124
125 $spaces = Space::orderBy('title', 'ASC')
126 ->with(['space_pivot' => function ($q) {
127 $q->where('user_id', get_current_user_id());
128 }])
129 ->where(function ($q) {
130 $q->whereHas('space_pivot', function ($q) {
131 $q->where('user_id', get_current_user_id());
132 })
133 ->orWhereIn('privacy', ['public', 'private']);
134 })
135 ->get();
136
137 foreach ($spaces as $space) {
138 if(Arr::get($space->settings, 'hide_members_count') == 'yes' && (!$currentUser || !$space->verifyUserPermisson($currentUser, 'can_view_members', false))) {
139 $space->members_count = 0;
140 continue;
141 }
142
143 $space->members_count = $space->members()->wherePivot('status', 'active')->count();
144 }
145
146 return [
147 'spaces' => $spaces
148 ];
149 }
150
151 public function getBySlug(Request $request, $spaceSlug)
152 {
153 $user = $this->getUser();
154 $space = Space::where('slug', $spaceSlug)
155 ->firstOrFail();
156
157 $space->permissions = $space->getUserPermissions($user);
158 $space->description_rendered = FeedsHelper::mdToHtml($space->description);
159 $space->membership = $space->getMembership(get_current_user_id());
160 $space->topics = Utility::getTopicsBySpaceId($space->id);
161
162 if (!Helper::isSiteAdmin()) {
163 $space->lockscreen_config = LockscreenService::getLockscreenConfig($space, $space->membership);
164 }
165
166 if ($space->privacy == 'secret' && !$space->membership) {
167 return $this->sendError([
168 'message' => __('You are not allowed to view this space', 'fluent-community'),
169 'error_type' => 'restricted'
170 ]);
171 }
172
173 do_action_ref_array('fluent_community/space', [&$space]);
174
175 return [
176 'space' => $space
177 ];
178 }
179
180 public function patchBySlug(Request $request, $slug)
181 {
182 $space = Space::where('slug', $slug)
183 ->first();
184
185 if (!$space) {
186 return $this->sendError([
187 'message' => 'Space not found'
188 ]);
189 }
190
191 $space->verifyUserPermisson($this->getUser(), 'community_admin');
192
193 $data = $request->get('data', []);
194
195 if (!empty($data['title'])) {
196 $taken = Space::where('title', $data['title'])
197 ->where('id', '!=', $space->id)
198 ->first();
199 if ($taken) {
200 return $this->sendError([
201 'message' => 'Space title is already taken. Please use a different title'
202 ]);
203 }
204 }
205
206 $mediaTypes = ['cover_photo', 'logo'];
207 foreach ($mediaTypes as $type) {
208 if (!empty($data[$type])) {
209 $media = Helper::getMediaFromUrl($data[$type]);
210 if (!$media) {
211 unset($data[$type]);
212 continue;
213 }
214
215 if (!$media || $media->is_active) {
216 return $this->sendError([
217 'message' => 'Invalid media image. Please upload a new one.'
218 ]);
219 }
220
221 $data[$type] = $media->public_url;
222
223 $media->update([
224 'is_active' => true,
225 'user_id' => get_current_user_id(),
226 'sub_object_id' => $space->id,
227 'object_source' => 'space_' . $type
228 ]);
229 } else if (isset($data[$type])) {
230 $data[$type] = '';
231 }
232 }
233
234 $data = apply_filters('fluent_community/space/update_data', $data, $space);
235
236 $space->updateCustomData($data, true);
237
238 if (Arr::has($data, 'topic_ids')) {
239 $topicIds = (array)Arr::get($data, 'topic_ids', []);
240 $space->syncTopics($topicIds);
241 }
242
243 return [
244 'message' => __('Space has been updated', 'fluent-community')
245 ];
246 }
247
248 public function getMembers(Request $request, $slug)
249 {
250 $space = Space::where('slug', $slug)
251 ->firstOrFail();
252
253 $user = $this->getUser();
254
255 if (!$space->verifyUserPermisson($user, 'can_view_members', false)) {
256 return $this->sendError([
257 'message' => __('You are not allowed to view members of this space', 'fluent-community'),
258 'permission_failed' => true
259 ]);
260 }
261 $search = $request->getSafe('search', 'sanitize_text_field');
262
263 $pendingCount = 0;
264 if ($user && $user->can('can_add_member', $space)) {
265 $pendingCount = SpaceUserPivot::bySpace($space->id)
266 ->where('status', 'pending')
267 ->count();
268
269 if ($request->get('status') == 'pending') {
270 $pendingRequests = SpaceUserPivot::bySpace($space->id)
271 ->whereHas('xprofile', function ($q) use ($search) {
272 return $q->searchBy($search)
273 ->where('status', 'active');
274 })
275 ->with(['xprofile' => function ($q) {
276 $q->select(ProfileHelper::getXProfilePublicFields());
277 }])
278 ->where('status', 'pending')
279 ->paginate();
280
281 return [
282 'members' => $pendingRequests,
283 'pending_count' => $pendingCount
284 ];
285 }
286 }
287
288 $spaceMembers = SpaceUserPivot::bySpace($space->id)
289 ->whereHas('xprofile', function ($q) use ($search) {
290 return $q->searchBy($search)
291 ->where('status', 'active');
292 })
293 ->with(['xprofile' => function ($q) {
294 $q->select(ProfileHelper::getXProfilePublicFields());
295 }])
296 ->where('status', 'active')
297 ->paginate();
298
299 return [
300 'members' => $spaceMembers,
301 'pending_count' => $pendingCount
302 ];
303 }
304
305 public function join(Request $request, $slug)
306 {
307 $space = Space::where('slug', $slug)->first();
308
309 if (!$space) {
310 return $this->sendError([
311 'message' => 'Space not found'
312 ]);
313 }
314
315 $user = $this->getUser();
316
317 $membership = $space->getMembership(get_current_user_id());
318
319 if ($membership) {
320 return $this->sendError([
321 'message' => 'You are already a member of this space. Please reload this page'
322 ]);
323 }
324
325 $roles = $user->getCommunityRoles();
326
327 if (!$roles && $space->privacy == 'secret') {
328 return $this->sendError([
329 'message' => 'You are not allowed to join this space'
330 ]);
331 }
332
333 $status = 'active';
334 if (!$roles) {
335 if ($space->privacy != 'public') {
336 $status = apply_filters('fluent_community/space/join_status_for_private', 'pending', $space, $user);
337
338 if (!in_array($status, ['pending', 'active'])) {
339 $status = 'pending';
340 }
341 }
342 $role = 'member';
343 } else {
344 $role = $user->isCommunityAdmin() ? 'admin' : 'moderator';
345 }
346
347
348 $space->members()->attach(get_current_user_id(), [
349 'role' => $role,
350 'status' => $status
351 ]);
352
353 $space->membership = $space->getMembership(get_current_user_id());
354
355 if ($status == 'pending') {
356 do_action('fluent_community/space/join_requested', $space, $user->ID, 'self');
357 } else {
358 do_action('fluent_community/space/joined', $space, $user->ID, 'self');
359 }
360
361 $user->cacheAccessSpaces();
362
363 return [
364 'message' => ($status == 'active') ? __('You have joined this Space', 'fluent-community') : __('Your join request has been sent to the Space admin.', 'fluent-community'),
365 'membership' => $space->membership
366 ];
367 }
368
369 public function leave(Request $request, $slug)
370 {
371 $user = $this->getUser(true);
372 $space = Space::where('slug', $slug)->first();
373
374 if (!$space) {
375 return $this->sendError([
376 'message' => 'Space not found'
377 ]);
378 }
379
380 $membership = $space->getMembership($user->ID);
381
382 if (!$membership) {
383 return $this->sendError([
384 'message' => 'You are not a member of this community'
385 ]);
386 }
387
388 Helper::removeFromSpace($space, $user->ID, 'self');
389
390 return [
391 'message' => __('You have left this space', 'fluent-community')
392 ];
393 }
394
395 public function delete(Request $request, $slug)
396 {
397 $space = Space::where('slug', $slug)->first();
398
399 if (!$space) {
400 return $this->sendError([
401 'message' => 'Space not found'
402 ]);
403 }
404
405 if (!Helper::isSiteAdmin()) {
406 return $this->sendError([
407 'message' => 'You are not allowed to delete this community'
408 ]);
409 }
410
411 do_action('fluent_community/space/before_delete', $space);
412
413 Comment::whereHas('post', function ($q) use ($space) {
414 $q->where('space_id', $space->id);
415 })->delete();
416
417 Reaction::whereHas('feed', function ($q) use ($space) {
418 $q->where('space_id', $space->id);
419 })->delete();
420
421 Feed::where('space_id', $space->id)->delete();
422
423 SpaceUserPivot::where('space_id', $space->id)->delete();
424
425 $spaceId = $space->id;
426 $space->delete();
427
428 do_action('fluent_community/space/deleted', $spaceId);
429
430 return [
431 'message' => __('Space has been deleted successfully', 'fluent-community')
432 ];
433 }
434
435 public function addMember(Request $request, $slug)
436 {
437 $space = Space::where('slug', $slug)->first();
438
439 if (!$space) {
440 return $this->sendError([
441 'message' => 'Space not found'
442 ]);
443 }
444
445 $this->validate($request->all(), [
446 'user_id' => 'required|exists:users,ID'
447 ]);
448
449 $userId = $request->get('user_id');
450 $targetUser = User::findOrFail($userId);
451 $xprofile = $targetUser->syncXProfile();
452
453 if ($xprofile && $xprofile->status != 'active') {
454 return $this->sendError([
455 'message' => __('Selected user is not active', 'fluent-community')
456 ]);
457 }
458
459 $admin = User::find(get_current_user_id());
460 $admin->verifySpacePermission('can_add_member', $space);
461
462 $pivot = SpaceUserPivot::bySpace($space->id)
463 ->byUser($userId)
464 ->first();
465
466 $role = $request->get('role', 'member');
467
468 if ($pivot) {
469 if ($pivot->status == 'active') {
470 if ($role != $pivot->role) {
471 $pivot->role = $role;
472 $pivot->save();
473
474 do_action('fluent_community/space/member/role_updated', $space, $pivot);
475
476 return [
477 'message' => 'Member role updated'
478 ];
479 }
480
481 return $this->sendError([
482 'message' => 'Selected user is already a member of this community'
483 ]);
484 }
485
486 $pivot->status = 'active';
487 $pivot->save();
488 do_action('fluent_community/space/joined', $space, $userId, 'by_admin');
489
490 if ($role != 'member') {
491 do_action('fluent_community/space/member/role_updated', $space, $pivot);
492 }
493
494 return [
495 'message' => 'Member approved'
496 ];
497 }
498
499 $space->members()->attach($userId, [
500 'role' => $role,
501 'status' => 'active'
502 ]);
503
504 $targetUser->cacheAccessSpaces();
505
506 do_action('fluent_community/space/joined', $space, $userId, 'by_admin');
507
508 return [
509 'message' => 'User has been added to this community'
510 ];
511 }
512
513 public function removeMember(Request $request, $slug)
514 {
515 $space = Space::where('slug', $slug)->first();
516
517 if (!$space) {
518 return $this->sendError([
519 'message' => 'Space not found'
520 ]);
521 }
522
523 $userId = $request->get('user_id');
524
525 $admin = User::find(get_current_user_id());
526 $admin->verifySpacePermission('can_remove_member', $space);
527
528 $pivot = SpaceUserPivot::bySpace($space->id)
529 ->byUser($userId)
530 ->first();
531
532 if (!$pivot) {
533 return $this->sendError([
534 'message' => 'Selected user is not a member of this community'
535 ]);
536 }
537
538 $pivot->delete();
539
540 $targetUser = User::find($userId);
541
542 if ($targetUser) {
543 $targetUser->cacheAccessSpaces();
544 }
545
546 do_action('fluent_community/space/user_left', $space, $userId, 'by_admin');
547
548 return [
549 'message' => __('User has been removed from this community', 'fluent-community')
550 ];
551 }
552
553 public function getOtherUsers(Request $request)
554 {
555 $currentUser = $this->getUser(true);
556
557 $this->validate($request->all(), [
558 'space_id' => 'required|exists:fcom_spaces,id'
559 ]);
560
561 $isMod = $currentUser->isCommunityModerator() && current_user_can('list_users');
562
563 $spaceId = $request->get('space_id');
564
565 $selects = ['ID', 'display_name'];
566
567 if ($isMod) {
568 $selects[] = 'user_email';
569 }
570
571 $users = User::whereDoesntHave('spaces', function ($q) use ($spaceId) {
572 return $q->where('space_id', $spaceId);
573 })
574 ->select($selects)
575 ->searchBy($request->get('search'))
576 ->paginate();
577
578 return [
579 'users' => $users
580 ];
581 }
582
583 public function updateLinks(Request $request, $slug)
584 {
585 $space = Space::where('slug', $slug)->first();
586
587 if (!$space) {
588 return $this->sendError([
589 'message' => 'Space not found'
590 ]);
591 }
592
593 $space->verifyUserPermisson($this->getUser(), 'community_admin');
594
595 $links = $request->get('links', []);
596
597 $links = array_map(function ($link) {
598 return CustomSanitizer::santizeLinkItem($link);
599 }, $links);
600
601 $settings = $space->settings;
602 $settings['links'] = $links;
603 $space->settings = $settings;
604 $space->save();
605
606 return [
607 'message' => __('Links have been updated for the space', 'fluent-community'),
608 'links' => $links
609 ];
610 }
611
612 public function getSpaceGroups(Request $request)
613 {
614 $user = $this->getUser(true);
615 if (!$user->isCommunityModerator()) {
616 return $this->sendError([
617 'message' => 'You are not allowed to create space group'
618 ]);
619 }
620
621 $user = $this->getUser();
622
623 $groups = Helper::getAllCommunityGroups($user, false);
624
625 foreach ($groups as $group) {
626 foreach ($group->spaces as $space) {
627 $space->permalink = $space->getPermalink();
628 }
629 }
630
631 return [
632 'groups' => $groups
633 ];
634 }
635
636 public function createSpaceGroup(Request $request)
637 {
638 $user = $this->getUser(true);
639 if (!$user->isCommunityModerator()) {
640 return $this->sendError([
641 'message' => 'You are not allowed to create space group'
642 ]);
643 }
644
645 $data = $request->all();
646
647 $this->validate($data, [
648 'title' => 'required|unique:fcom_spaces,title',
649 'slug' => 'required|unique:fcom_spaces,slug'
650 ]);
651
652
653 $formattedData = [
654 'title' => sanitize_text_field($data['title']),
655 'slug' => sanitize_title($data['slug']),
656 'description' => sanitize_textarea_field($data['description']),
657 'status' => 'active',
658 'type' => 'space_group',
659 'settings' => [
660 'always_show_spaces' => Arr::get($data, 'settings.always_show_spaces', 'yes'),
661 ],
662 'serial' => SpaceGroup::max('serial') + 1
663 ];
664
665 $group = SpaceGroup::create($formattedData);
666
667 return [
668 'message' => __('Space group has been created successfully', 'fluent-community'),
669 'group' => $group
670 ];
671 }
672
673 public function updateSpaceGroup(Request $request, $groupId)
674 {
675 $user = $this->getUser();
676 if (!$user || !$user->isCommunityModerator()) {
677 return $this->sendError([
678 'message' => 'You are not allowed to create space group'
679 ]);
680 }
681
682 $group = SpaceGroup::findOrFail($groupId);
683 $data = $request->all();
684
685 $this->validate($data, [
686 'title' => 'required'
687 ]);
688
689 $taken = BaseSpace::where('title', $data['title'])
690 ->where('id', '!=', $group->id)
691 ->first();
692
693 if ($taken) {
694 return $this->sendError([
695 'message' => 'The title is already taken. Please use a different title'
696 ]);
697 }
698
699 $formattedData = [
700 'title' => sanitize_text_field($data['title']),
701 'description' => sanitize_textarea_field($data['description']),
702 'status' => 'active',
703 'type' => 'space_group',
704 'settings' => [
705 'always_show_spaces' => Arr::get($data, 'settings.always_show_spaces', 'yes'),
706 ]
707 ];
708
709 $group->fill($formattedData)->save();
710
711 return [
712 'message' => __('Space group has been created updated', 'fluent-community'),
713 'group' => $group
714 ];
715 }
716
717 public function deleteSpaceGroup(Request $request, $groupId)
718 {
719
720 $user = $this->getUser();
721 if (!$user || !$user->isCommunityModerator()) {
722 return $this->sendError([
723 'message' => 'You are not allowed to create space group'
724 ]);
725 }
726
727 $group = SpaceGroup::findOrFail($groupId);
728
729 if (!$group->spaces->isEmpty()) {
730 return $this->sendError([
731 'message' => 'You can not delete this group. It has spaces'
732 ]);
733 }
734
735 $group->delete();
736
737 return [
738 'message' => __('Space group has been deleted successfully', 'fluent-community')
739 ];
740 }
741
742 public function updateSpaceGroupIndexes(Request $request)
743 {
744 $indexes = $request->get('indexes', []);
745
746 foreach ($indexes as $groupId => $indexNumber) {
747 $group = SpaceGroup::findOrFail($groupId);
748 $group->update([
749 'serial' => $indexNumber + 1
750 ]);
751 }
752
753 return [
754 'message' => __('Space group indexes have been updated.', 'fluent-community')
755 ];
756
757 }
758
759 public function updateSpaceIndexes(Request $request)
760 {
761 $indexes = $request->get('indexes', []);
762
763 foreach ($indexes as $index => $spaceId) {
764 $space = BaseSpace::withoutGlobalScopes()->findOrFail($spaceId);
765 $space->update([
766 'serial' => $index + 1
767 ]);
768 }
769
770 return [
771 'message' => __('Space indexes have been updated.', 'fluent-community')
772 ];
773 }
774
775 public function moveSpace(Request $request)
776 {
777 $spaceId = $request->getSafe('space_id', 'intval');
778 $groupId = $request->getSafe('group_id', 'intval');
779
780 $space = BaseSpace::withoutGlobalScopes()->findOrFail($spaceId);
781 $group = SpaceGroup::findOrFail($groupId);
782
783 $space->update([
784 'parent_id' => $groupId
785 ]);
786
787 return [
788 'message' => __('Space has been moved successfully', 'fluent-community')
789 ];
790 }
791
792 public function getLockScreenSettings(Request $request, $spaceSlug)
793 {
794 $space = Space::where('slug', $spaceSlug)->firstOrFail();
795 $lockscreen = $space->getLockscreen();
796
797 return [
798 'lockscreen' => $lockscreen
799 ];
800 }
801
802 public function updateLockscreenSettings(Request $request, $spaceSlug)
803 {
804 $space = Space::where('slug', $spaceSlug)->firstOrFail();
805
806 $settingFields = $request->get('lockscreen', []);
807
808 $formattedFields = LockscreenService::formatLockscreenFields($settingFields);
809
810 $space->setLockscreen($formattedFields);
811
812 return [
813 'message' => 'Lockscreen settings have been updated successfully.',
814 'community' => $space
815 ];
816 }
817 }
818