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

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