PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.7.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.7.0
2.11.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 All 78 releases
fluent-community / app / Http / Controllers / SpaceController.php

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

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