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

990 lines 31.9 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\Space;
6 use FluentCommunity\App\Models\Feed;
7 use FluentCommunity\App\Models\BaseSpace;
8 use FluentCommunity\App\Models\SpaceGroup;
9 use FluentCommunity\App\Models\User;
10 use FluentCommunity\App\Services\CustomSanitizer;
11 use FluentCommunity\App\Services\Helper;
12 use FluentCommunity\App\Functions\Utility;
13 use FluentCommunity\App\Services\ProfileHelper;
14 use FluentCommunity\Framework\Http\Request\Request;
15 use FluentCommunity\App\Models\Comment;
16 use FluentCommunity\App\Models\Reaction;
17 use FluentCommunity\App\Models\SpaceUserPivot;
18 use FluentCommunity\Framework\Support\Arr;
19
20 class SpaceController extends Controller
21 {
22 public function get()
23 {
24 $spaces = Space::orderBy('title', 'ASC')
25 ->whereHas('space_pivot', function ($q) {
26 $q->where('user_id', get_current_user_id());
27 })
28 ->get();
29
30 $data = [
31 'spaces' => $spaces
32 ];
33
34 return apply_filters('fluent_community/spaces_api_response', $data, $this->request->all());
35 }
36
37 public function create(Request $request)
38 {
39 $currentUser = $this->getUser(true);
40
41 $data = $request->get('space', []);
42
43 $slug = Arr::get($data, 'slug') ?: Arr::get($data, 'title');
44
45 $slug = preg_replace('/[^a-zA-Z0-9-_]/', '', $slug);
46
47 $data['slug'] = sanitize_title($slug, '');
48 $data['title'] = sanitize_text_field(Arr::get($data, 'title'));
49 $data['privacy'] = sanitize_text_field(Arr::get($data, 'privacy'));
50
51 $this->validate($data, [
52 'title' => 'required',
53 'slug' => 'unique:fcom_spaces,slug',
54 'privacy' => 'required|in:public,private,secret'
55 ]);
56
57 if (Arr::get($data, 'settings.topic_required') === 'yes' && !array_filter((array)Arr::get($data, 'topic_ids', []))) {
58 return $this->sendError([
59 'message' => __('Please select at least one topic when members are required to select a topic.', 'fluent-community')
60 ]);
61 }
62
63 $spaceGroup = null;
64 if (!empty($data['parent_id'])) {
65 $spaceGroup = SpaceGroup::findOrFail($data['parent_id']);
66 $serial = BaseSpace::query()->withoutGlobalScopes()->where('parent_id', $spaceGroup->id)->max('serial') + 1;
67 } else {
68 $serial = BaseSpace::query()->withoutGlobalScopes()->max('serial') + 1;
69 }
70
71 $settings = CustomSanitizer::santizeSpaceSettings(Arr::get($data, 'settings', []), $data['privacy']);
72
73 if (is_wp_error($settings)) {
74 return $this->sendError([
75 'message' => $settings->get_error_message()
76 ]);
77 }
78
79 $spaceData = apply_filters('fluent_community/space/create_data', [
80 'title' => sanitize_text_field($data['title']),
81 'slug' => $data['slug'],
82 'privacy' => $data['privacy'],
83 'description' => sanitize_textarea_field(Arr::get($data, 'description', '')),
84 'settings' => $settings,
85 'parent_id' => $spaceGroup ? $spaceGroup->id : null,
86 'serial' => $serial ?: 1
87 ]);
88
89 $ogImage = Arr::get($data, 'settings.og_image', '');
90 $ogMedia = null;
91 if ($ogImage) {
92 $ogMedia = Helper::getMediaFromUrl($ogImage);
93 if ($ogMedia && !$ogMedia->is_active) {
94 $spaceData['settings']['og_image'] = $ogMedia->public_url;
95 }
96 }
97
98 $space = Space::create($spaceData);
99 if ($ogMedia && !$ogMedia->is_active) {
100 $ogMedia->update([
101 'is_active' => true,
102 'user_id' => get_current_user_id(),
103 'sub_object_id' => $space->id,
104 'object_source' => 'space_og_image'
105 ]);
106 }
107
108 $imageTypes = ['cover_photo', 'logo'];
109 $metaData = [];
110 foreach ($imageTypes as $type) {
111 if (!empty($data[$type])) {
112 $media = Helper::getMediaFromUrl($data[$type]);
113 if (!$media || $media->is_active) {
114 continue;
115 }
116 $metaData[$type] = $media->public_url;
117 $media->update([
118 'is_active' => true,
119 'user_id' => get_current_user_id(),
120 'sub_object_id' => $space->id,
121 'object_source' => 'space_' . $type
122 ]);
123 }
124 }
125
126 if ($metaData) {
127 $space->updateCustomData($metaData, false);
128 }
129
130 $space->members()->attach(get_current_user_id(), [
131 'role' => 'admin'
132 ]);
133
134 if (Arr::has($data, 'topic_ids')) {
135 $topicsConfig = Helper::getTopicsConfig();
136 $topicIds = (array)Arr::get($data, 'topic_ids', []);
137 $topicIds = array_slice($topicIds, 0, $topicsConfig['max_topics_per_space']);
138 $space->syncTopics($topicIds);
139 }
140
141 $currentUser->cacheAccessSpaces();
142 do_action('fluent_community/space/created', $space, $data);
143
144 return [
145 'message' => __('Space has been created successfully', 'fluent-community'),
146 'space' => $space
147 ];
148 }
149
150 public function discover(Request $request)
151 {
152 $start = microtime(true);
153 $currentUser = $this->getUser();
154 $type = $request->getSafe('type');
155 $search = $request->getSafe('search');
156 $sortBy = $request->getSafe('sort_by', 'sanitize_text_field', 'alphabetical');
157
158 $spaces = Space::with(['space_pivot' => function ($q) {
159 $q->where('user_id', get_current_user_id());
160 }])
161 ->where(function ($q) {
162 $q->whereHas('space_pivot', function ($q) {
163 $q->where('user_id', get_current_user_id());
164 })
165 ->orWhereIn('privacy', ['public', 'private']);
166 })
167 ->when($type == 'joined', function ($q) {
168 $q->whereHas('space_pivot', function ($q) {
169 $q->where('user_id', get_current_user_id());
170 });
171 })
172 ->when($search, function ($q) use ($search) {
173 $q->where('title', 'like', '%' . $search . '%');
174 })
175 ->when($sortBy == 'alphabetical', function ($q) {
176 $q->orderBy('title', 'ASC');
177 })
178 ->when($sortBy == 'oldest', function ($q) {
179 $q->orderBy('created_at', 'ASC');
180 })
181 ->when($sortBy == 'latest', function ($q) {
182 $q->orderBy('created_at', 'DESC');
183 })
184 ->paginate();
185
186 $memberCounts = $this->getActiveMemberCounts($spaces->pluck('id')->toArray());
187
188 foreach ($spaces as $space) {
189 $shouldHideMembersCount = Arr::get($space->settings, 'hide_members_count') == 'yes';
190 $canViewMembers = $currentUser && $space->verifyUserPermisson($currentUser, 'can_view_members', false);
191
192 if ($shouldHideMembersCount && !$canViewMembers) {
193 $space->members_count = 0;
194 continue;
195 }
196
197 $space->members_count = (int)Arr::get($memberCounts, $space->id, 0);
198 $space->description_rendered = wpautop($space->description);
199 }
200
201 $data = [
202 'spaces' => $spaces,
203 'execution_time' => microtime(true) - $start
204 ];
205
206 return apply_filters('fluent_community/spaces_api_response', $data, $request->all());
207 }
208
209 public function getAllSpaces(Request $request)
210 {
211 $spaces = Space::paginate();
212
213 $currentUser = $this->getUser();
214 $memberCounts = $this->getActiveMemberCounts($spaces->pluck('id')->toArray());
215
216 foreach ($spaces as $space) {
217 $shouldHideMembersCount = Arr::get($space->settings, 'hide_members_count') == 'yes';
218 $canViewMembers = $currentUser && $space->verifyUserPermisson($currentUser, 'can_view_members', false);
219
220 if ($shouldHideMembersCount && !$canViewMembers) {
221 $space->members_count = 0;
222 continue;
223 }
224
225 $space->members_count = (int)Arr::get($memberCounts, $space->id, 0);
226
227 $space->formatSpaceData($currentUser);
228 do_action_ref_array('fluent_community/space', [&$space]);
229 }
230
231 return apply_filters('fluent_community/all_spaces_api_response', [
232 'spaces' => $spaces
233 ], $request->all());
234 }
235
236 public function getBySlug(Request $request, $spaceSlug)
237 {
238 $user = $this->getUser();
239 $space = Space::where('slug', $spaceSlug)
240 ->firstOrFail();
241
242 $userId = $user ? $user->ID : null;
243 if ($space->privacy == 'secret' && !$space->getMembership($userId) && !$space->isAdmin($userId, true)) {
244 return $this->sendError([
245 'message' => __('You are not allowed to view this space', 'fluent-community'),
246 'error_type' => 'restricted'
247 ]);
248 }
249
250 $space = $space->formatSpaceData($user);
251
252 do_action_ref_array('fluent_community/space', [&$space]);
253
254 $data = [
255 'space' => $space
256 ];
257
258 return apply_filters('fluent_community/space_api_response', $data, $request->all());
259 }
260
261 public function patchBySlug(Request $request, $slug)
262 {
263 $space = Space::where('slug', $slug)
264 ->first();
265
266 if (!$space) {
267 return $this->sendError([
268 'message' => __('Space not found', 'fluent-community')
269 ]);
270 }
271
272 $data = $request->get('data', []);
273
274 if (Arr::has($data, 'title') && !trim(sanitize_text_field(Arr::get($data, 'title', '')))) {
275 return $this->sendError([
276 'message' => __('Space title is required.', 'fluent-community')
277 ]);
278 }
279
280 if (!empty($data['slug'])) {
281 $taken = Space::where('slug', $data['slug'])
282 ->where('id', '!=', $space->id)
283 ->first();
284
285 if ($taken) {
286 return $this->sendError([
287 'message' => __('Slug is already taken. Please use a different slug', 'fluent-community')
288 ]);
289 }
290 }
291
292 $topicRequired = Arr::has($data, 'settings.topic_required')
293 ? Arr::get($data, 'settings.topic_required')
294 : Arr::get($space->settings, 'topic_required');
295
296 if ($topicRequired === 'yes') {
297 $topicIds = Arr::has($data, 'topic_ids')
298 ? (array)Arr::get($data, 'topic_ids', [])
299 : array_column(Utility::getTopicsBySpaceId($space->id), 'id');
300
301 if (!array_filter($topicIds)) {
302 return $this->sendError([
303 'message' => __('Please select at least one topic when members are required to select a topic.', 'fluent-community')
304 ]);
305 }
306 }
307
308 $mediaTypes = ['cover_photo', 'logo'];
309 foreach ($mediaTypes as $type) {
310 if (!empty($data[$type])) {
311 $media = Helper::getMediaFromUrl($data[$type]);
312 if (!$media || $media->is_active) {
313 unset($data[$type]);
314 continue;
315 }
316
317 $data[$type] = $media->public_url;
318
319 $media->update([
320 'is_active' => true,
321 'user_id' => get_current_user_id(),
322 'sub_object_id' => $space->id,
323 'object_source' => 'space_' . $type
324 ]);
325 } else if (isset($data[$type])) {
326 $data[$type] = '';
327 }
328 }
329
330 $data = apply_filters('fluent_community/space/update_data', $data, $space);
331
332 if (isset($data['parent_id']) && !$data['parent_id']) {
333 $data['parent_id'] = '';
334 }
335
336 $space = $space->updateCustomData($data, true);
337
338 if (is_wp_error($space)) {
339 return $this->sendError([
340 'message' => $space->get_error_message()
341 ]);
342 }
343
344 if (Arr::has($data, 'topic_ids')) {
345 $topicsConfig = Helper::getTopicsConfig();
346 $topicIds = (array)Arr::get($data, 'topic_ids', []);
347 $topicIds = array_slice($topicIds, 0, $topicsConfig['max_topics_per_space']);
348 $space->syncTopics($topicIds);
349 }
350
351 do_action('fluent_community/space/updated', $space, $data);
352 $slugUpdated = $slug != $space->slug;
353
354 $metaSettings = $request->get('meta_settings', []);
355 if($metaSettings) {
356 foreach ($metaSettings as $metaProvider => $metaData) {
357 do_action('fluent_community/space/update_meta_settings_'.$metaProvider, $metaData, $space);
358 }
359 }
360
361 return [
362 'message' => __('Settings have been updated', 'fluent-community'),
363 'redirect_url' => $slugUpdated ? $space->getPermalink() : ''
364 ];
365 }
366
367 public function patchById(Request $request, $id)
368 {
369 $space = Space::findOrFail($id);
370
371 return $this->patchBySlug($request, $space->slug);
372 }
373
374 public function getMembers(Request $request, $slug)
375 {
376 $space = Space::where('slug', $slug)
377 ->firstOrFail();
378
379 $user = $this->getUser();
380
381 if (!$space->verifyUserPermisson($user, 'can_view_members', false)) {
382 return $this->sendError([
383 'message' => __('You are not allowed to view members of this space', 'fluent-community'),
384 'permission_failed' => true
385 ]);
386 }
387
388 $search = $request->getSafe('search', 'sanitize_text_field');
389
390 $pendingCount = 0;
391 if ($user && $user->can('can_add_member', $space)) {
392 $pendingCount = SpaceUserPivot::bySpace($space->id)
393 ->where('status', 'pending')
394 ->count();
395
396 if ($request->get('status') == 'pending') {
397 $pendingRequests = SpaceUserPivot::bySpace($space->id)
398 ->whereHas('xprofile', function ($q) use ($search) {
399 return $q->searchBy($search)
400 ->where('status', 'active');
401 })
402 ->with(['xprofile' => function ($q) {
403 $q->select(ProfileHelper::getXProfilePublicFields());
404 }])
405 ->where('status', 'pending')
406 ->paginate();
407
408 return apply_filters('fluent_community/space_members_api_response', [
409 'members' => $pendingRequests,
410 'pending_count' => $pendingCount
411 ], $pendingRequests, $request->all());
412 }
413 }
414
415 $spaceMembers = SpaceUserPivot::bySpace($space->id)
416 ->whereHas('xprofile', function ($q) use ($search) {
417 return $q->searchBy($search)
418 ->where('status', 'active');
419 })
420 ->with(['xprofile' => function ($q) {
421 $q->select(ProfileHelper::getXProfilePublicFields());
422 }])
423 ->where('status', 'active')
424 ->orderBy('created_at', 'ASC')
425 ->paginate();
426
427 return apply_filters('fluent_community/space_members_api_response', [
428 'members' => $spaceMembers,
429 'pending_count' => $pendingCount
430 ], $spaceMembers, $request->all());
431 }
432
433 public function join(Request $request, $slug)
434 {
435 $space = Space::where('slug', $slug)->first();
436
437 if (!$space) {
438 return $this->sendError([
439 'message' => __('Space not found', 'fluent-community')
440 ]);
441 }
442
443 $user = $this->getUser();
444
445 $membership = $space->getMembership(get_current_user_id());
446
447 if ($membership) {
448 return $this->sendError([
449 'message' => __('You are already a member of this space. Please reload this page', 'fluent-community')
450 ]);
451 }
452
453 $roles = $user->getCommunityRoles();
454 $isPrivileged = !!array_intersect($roles, ['admin', 'moderator']);
455
456 if (!$isPrivileged && $space->privacy == 'secret') {
457 return $this->sendError([
458 'message' => __('You are not allowed to join this space', 'fluent-community')
459 ]);
460 }
461
462 $status = 'active';
463 if (!$isPrivileged) {
464 if ($space->privacy != 'public') {
465 $status = apply_filters('fluent_community/space/join_status_for_private', 'pending', $space, $user);
466
467 if (!in_array($status, ['pending', 'active'])) {
468 $status = 'pending';
469 }
470 }
471 $role = 'member';
472 } else {
473 $role = $user->isCommunityAdmin() ? 'admin' : 'moderator';
474 }
475
476
477 $space->members()->attach(get_current_user_id(), [
478 'role' => $role,
479 'status' => $status
480 ]);
481
482 $space->membership = $space->getMembership(get_current_user_id());
483
484 if ($status == 'pending') {
485 do_action('fluent_community/space/join_requested', $space, $user->ID, 'self');
486 } else {
487 do_action('fluent_community/space/joined', $space, $user->ID, 'self');
488 }
489
490 $user->cacheAccessSpaces();
491
492 return [
493 'message' => ($status == 'active') ? __('You have joined this Space', 'fluent-community') : __('Your join request has been sent to the Space admin.', 'fluent-community'),
494 'membership' => $space->membership
495 ];
496 }
497
498 public function leave(Request $request, $slug)
499 {
500 $user = $this->getUser(true);
501 $space = Space::where('slug', $slug)->first();
502
503 if (!$space) {
504 return $this->sendError([
505 'message' => __('Space not found', 'fluent-community')
506 ]);
507 }
508
509 $membership = $space->getMembership($user->ID);
510
511 if (!$membership) {
512 return $this->sendError([
513 'message' => __('You are not a member of this community', 'fluent-community')
514 ]);
515 }
516
517 Helper::removeFromSpace($space, $user->ID, 'self');
518
519 return [
520 'message' => __('You have left this space', 'fluent-community')
521 ];
522 }
523
524 public function deleteBySlug(Request $request, $slug)
525 {
526 $space = Space::where('slug', $slug)->first();
527
528 if (!$space) {
529 return $this->sendError([
530 'message' => __('Space not found', 'fluent-community')
531 ]);
532 }
533
534 do_action('fluent_community/space/before_delete', $space);
535
536 Comment::whereHas('post', function ($q) use ($space) {
537 $q->where('space_id', $space->id);
538 })->delete();
539
540 Reaction::whereHas('feed', function ($q) use ($space) {
541 $q->where('space_id', $space->id);
542 })->delete();
543
544 Feed::where('space_id', $space->id)->delete();
545
546 SpaceUserPivot::where('space_id', $space->id)->delete();
547
548 $spaceId = $space->id;
549 $space->delete();
550
551 do_action('fluent_community/space/deleted', $spaceId);
552
553 return [
554 'message' => __('Space has been deleted successfully', 'fluent-community')
555 ];
556 }
557
558 public function deleteById(Request $request, $id)
559 {
560 $space = Space::findOrFail($id);
561
562 return $this->deleteBySlug($request, $space->slug);
563 }
564
565 public function addMember(Request $request, $slug)
566 {
567 $space = Space::where('slug', $slug)->first();
568
569 if (!$space) {
570 return $this->sendError([
571 'message' => __('Space not found', 'fluent-community')
572 ]);
573 }
574
575 $this->validate($request->all(), [
576 'user_id' => 'required|exists:users,ID'
577 ]);
578
579 $userId = $request->get('user_id');
580 $targetUser = User::findOrFail($userId);
581 $targetUser->syncXProfile();
582 $xprofile = $targetUser->xprofile;
583
584 if ($xprofile && $xprofile->status != 'active') {
585 return $this->sendError([
586 'message' => __('Selected user is not active', 'fluent-community')
587 ]);
588 }
589
590 $pivot = SpaceUserPivot::bySpace($space->id)
591 ->byUser($userId)
592 ->first();
593
594 $allowedRoles = ['member', 'moderator', 'admin'];
595 $requestedRole = $request->get('role', 'member');
596 $role = in_array($requestedRole, $allowedRoles, true) ? $requestedRole : 'member';
597
598 if ($pivot) {
599 if ($pivot->status == 'active') {
600 if ($role != $pivot->role) {
601 $pivot->role = $role;
602 $pivot->save();
603
604 do_action('fluent_community/space/member/role_updated', $space, $pivot);
605
606 return [
607 'message' => __('Member role updated', 'fluent-community')
608 ];
609 }
610
611 return $this->sendError([
612 'message' => __('Selected user is already a member of this community', 'fluent-community')
613 ]);
614 }
615
616 $pivot->status = 'active';
617 $pivot->save();
618 do_action('fluent_community/space/joined', $space, $userId, 'by_admin');
619
620 if ($role != 'member') {
621 do_action('fluent_community/space/member/role_updated', $space, $pivot);
622 }
623
624 return [
625 'message' => __('Member approved', 'fluent-community')
626 ];
627 }
628
629 $space->members()->attach($userId, [
630 'role' => $role,
631 'status' => 'active'
632 ]);
633
634 $targetUser->cacheAccessSpaces();
635
636 do_action('fluent_community/space/joined', $space, $userId, 'by_admin');
637
638 return [
639 'message' => __('User has been added to this Space', 'fluent-community')
640 ];
641 }
642
643 public function removeMember(Request $request, $slug)
644 {
645 $space = Space::where('slug', $slug)->first();
646
647 if (!$space) {
648 return $this->sendError([
649 'message' => __('Space not found', 'fluent-community')
650 ]);
651 }
652
653 $userId = $request->get('user_id');
654
655 $pivot = SpaceUserPivot::bySpace($space->id)
656 ->byUser($userId)
657 ->first();
658
659 if (!$pivot) {
660 return $this->sendError([
661 'message' => __('Selected user is not a member of this community', 'fluent-community')
662 ]);
663 }
664
665 $pivot->delete();
666
667 $targetUser = User::find($userId);
668
669 if ($targetUser) {
670 $targetUser->cacheAccessSpaces();
671 }
672
673 do_action('fluent_community/space/user_left', $space, $userId, 'by_admin');
674
675 return [
676 'message' => __('User has been removed from this community', 'fluent-community')
677 ];
678 }
679
680 public function getOtherUsers(Request $request)
681 {
682 $currentUser = $this->getUser(true);
683
684 $this->validate($request->all(), [
685 'space_id' => 'required|exists:fcom_spaces,id'
686 ]);
687
688 $isMod = $currentUser->isCommunityModerator() && current_user_can('list_users');
689
690 $spaceId = $request->get('space_id');
691 $space = Space::findOrFail($spaceId);
692
693 if (!$space->verifyUserPermisson($currentUser, 'can_add_member', false)) {
694 return $this->sendError([
695 'message' => __('You are not allowed to add members to this space', 'fluent-community')
696 ]);
697 }
698
699 $selects = ['ID', 'display_name'];
700 if ($isMod) {
701 $selects[] = 'user_email';
702 }
703
704 $userQuery = User::select(['ID'])
705 ->whereDoesntHave('space_pivot', function ($q) use ($space) {
706 $q->where('space_id', $space->id);
707 })
708 ->limit(100)
709 ->searchBy($request->getSafe('search'));
710
711 if (is_multisite()) {
712 global $wpdb;
713 $blogId = get_current_blog_id();
714 $blogPrefix = $wpdb->get_blog_prefix($blogId);
715 $userQuery->whereHas('usermeta', function ($q) use ($blogPrefix) {
716 $q->where('meta_key', $blogPrefix . 'capabilities');
717 });
718 }
719
720 $userIds = $userQuery->get()
721 ->pluck('ID')
722 ->toArray();
723
724 $users = User::select($selects)
725 ->whereIn('ID', $userIds)
726 ->paginate(100);
727
728 $data = [
729 'users' => $users
730 ];
731 return apply_filters('fluent_community/space_non_members_api_response', $data, $request->all());
732 }
733
734 public function updateLinks(Request $request, $slug)
735 {
736 $space = Space::where('slug', $slug)->first();
737
738 if (!$space) {
739 return $this->sendError([
740 'message' => __('Space not found', 'fluent-community')
741 ]);
742 }
743
744 $links = $request->get('links', []);
745
746 $links = array_map(function ($link) {
747 return CustomSanitizer::santizeLinkItem($link);
748 }, $links);
749
750 $settings = $space->settings;
751 $settings['links'] = $links;
752 $space->settings = $settings;
753 $space->save();
754
755 return [
756 'message' => __('Links have been updated for the space', 'fluent-community'),
757 'links' => $links
758 ];
759 }
760
761 public function getSpaceGroups(Request $request)
762 {
763 if ($request->get('options_only')) {
764 $groups = SpaceGroup::orderBy('serial', 'ASC')
765 ->select(['id', 'title'])
766 ->get();
767
768 return [
769 'groups' => $groups
770 ];
771 }
772
773 $user = $this->getUser();
774
775 $groups = Helper::getAllCommunityGroups($user, false);
776
777 foreach ($groups as $group) {
778 foreach ($group->spaces as $space) {
779 $space->permalink = $space->getPermalink();
780 if ($space->type === 'community') {
781 $space = $space->formatSpaceData($user);
782 } else {
783 $space->topics = Utility::getTopicsBySpaceId($space->id);
784 }
785 }
786 }
787
788 $orphanedSpaces = BaseSpace::withoutGlobalScopes()
789 ->whereNull('parent_id')
790 ->whereIn('type', ['community', 'course'])
791 ->orderBy('title', 'ASC')
792 ->get();
793
794 foreach ($orphanedSpaces as $space) {
795 $space->permalink = $space->getPermalink();
796 if ($space->type === 'community') {
797 $space = $space->formatSpaceData($user);
798 } else {
799 $space->topics = Utility::getTopicsBySpaceId($space->id);
800 }
801 }
802
803 $data = [
804 'groups' => $groups,
805 'orphaned_spaces' => $orphanedSpaces
806 ];
807 return apply_filters('fluent_community/space_groups_api_response', $data, $request->all());
808 }
809
810 public function createSpaceGroup(Request $request)
811 {
812 $data = $request->all();
813
814 $this->validate($data, [
815 'title' => 'required|unique:fcom_spaces,title',
816 'slug' => 'required|unique:fcom_spaces,slug'
817 ]);
818
819
820 $formattedData = [
821 'title' => sanitize_text_field($data['title']),
822 'slug' => sanitize_title($data['slug']),
823 'description' => sanitize_textarea_field($data['description']),
824 'status' => 'active',
825 'type' => 'space_group',
826 'settings' => [
827 'always_show_spaces' => Arr::get($data, 'settings.always_show_spaces', 'yes'),
828 ],
829 'serial' => SpaceGroup::max('serial') + 1
830 ];
831
832 $group = SpaceGroup::create($formattedData);
833
834 return [
835 'message' => __('Space group has been created successfully', 'fluent-community'),
836 'group' => $group
837 ];
838 }
839
840 public function updateSpaceGroup(Request $request, $groupId)
841 {
842 $group = SpaceGroup::findOrFail($groupId);
843 $data = $request->all();
844
845 $this->validate($data, [
846 'title' => 'required'
847 ]);
848
849 $taken = BaseSpace::where('title', $data['title'])
850 ->where('id', '!=', $group->id)
851 ->first();
852
853 if ($taken) {
854 return $this->sendError([
855 'message' => __('The title is already taken. Please use a different title', 'fluent-community')
856 ]);
857 }
858
859 $formattedData = [
860 'title' => sanitize_text_field($data['title']),
861 'description' => sanitize_textarea_field($data['description']),
862 'status' => 'active',
863 'type' => 'space_group',
864 'settings' => [
865 'always_show_spaces' => Arr::get($data, 'settings.always_show_spaces', 'yes'),
866 ]
867 ];
868
869 $group->fill($formattedData)->save();
870
871 return [
872 'message' => __('Space group has been updated', 'fluent-community'),
873 'group' => $group
874 ];
875 }
876
877 public function deleteSpaceGroup(Request $request, $groupId)
878 {
879 $group = SpaceGroup::findOrFail($groupId);
880
881 if (!$group->spaces->isEmpty()) {
882 return $this->sendError([
883 'message' => __('You cannot delete this group. It has spaces', 'fluent-community')
884 ]);
885 }
886
887 $group->delete();
888
889 return [
890 'message' => __('Space group has been deleted successfully', 'fluent-community')
891 ];
892 }
893
894 public function updateSpaceGroupIndexes(Request $request)
895 {
896 $indexes = $request->get('indexes', []);
897
898 foreach ($indexes as $groupId => $indexNumber) {
899 $group = SpaceGroup::findOrFail($groupId);
900 $group->update([
901 'serial' => $indexNumber + 1
902 ]);
903 }
904
905 return [
906 'message' => __('Space group indexes have been updated.', 'fluent-community')
907 ];
908
909 }
910
911 public function updateSpaceIndexes(Request $request)
912 {
913 $indexes = $request->get('indexes', []);
914
915 foreach ($indexes as $index => $spaceId) {
916 $space = BaseSpace::withoutGlobalScopes()->findOrFail($spaceId);
917 $space->update([
918 'serial' => $index + 1
919 ]);
920 }
921
922 return [
923 'message' => __('Space indexes have been updated.', 'fluent-community')
924 ];
925 }
926
927 public function moveSpace(Request $request)
928 {
929 $spaceId = $request->getSafe('space_id', 'intval');
930 $groupId = $request->getSafe('group_id', 'intval');
931
932 $space = BaseSpace::withoutGlobalScopes()->findOrFail($spaceId);
933 $group = SpaceGroup::findOrFail($groupId);
934
935 $space->update([
936 'parent_id' => $group->id
937 ]);
938
939 return [
940 'message' => __('Space has been moved successfully', 'fluent-community')
941 ];
942 }
943
944 public function getLockScreenSettings(Request $request, $spaceSlug)
945 {
946 $space = Space::where('slug', $spaceSlug)->firstOrFail();
947 $lockscreen = $space->getLockscreen();
948
949 $lockscreen = apply_filters('fluent_community/get_lockscreen_settings', $lockscreen, $space);
950
951 return [
952 'lockscreen' => $lockscreen
953 ];
954 }
955
956 public function getMetaSettings(Request $request, $spaceSlug)
957 {
958 $space = Space::where('slug', $spaceSlug)->firstOrFail();
959 $metaSettings = apply_filters('fluent_community/space/meta_fields', [], $space);
960
961 if (!$metaSettings) {
962 return [
963 'meta_settings' => null
964 ];
965 }
966
967 return [
968 'meta_settings' => $metaSettings
969 ];
970 }
971
972 private function getActiveMemberCounts($spaceIds)
973 {
974 if (!$spaceIds) {
975 return [];
976 }
977
978 return SpaceUserPivot::whereIn('space_id', $spaceIds)
979 ->where('status', 'active')
980 ->whereHas('xprofile', function ($q) {
981 $q->where('status', 'active');
982 })
983 ->whereHas('user')
984 ->selectRaw('space_id, COUNT(*) as total')
985 ->groupBy('space_id')
986 ->pluck('total', 'space_id')
987 ->toArray();
988 }
989 }
990