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

1,007 lines 32.5 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 /** @var Space $space */
379 $space = Space::where('slug', $slug)
380 ->firstOrFail();
381
382 $user = $this->getUser();
383
384 if (!$space->verifyUserPermisson($user, 'can_view_members', false)) {
385 return $this->sendError([
386 'message' => __('You are not allowed to view members of this space', 'fluent-community'),
387 'permission_failed' => true
388 ]);
389 }
390
391 $search = $request->getSafe('search', 'sanitize_text_field');
392
393 $pendingCount = 0;
394 if ($user && $user->can('can_add_member', $space)) {
395 $pendingCount = SpaceUserPivot::bySpace($space->id)
396 ->where('status', 'pending')
397 ->count();
398
399 if ($request->get('status') == 'pending') {
400 $pendingRequests = SpaceUserPivot::bySpace($space->id)
401 ->whereHas('xprofile', function ($q) use ($search) {
402 return $q->searchBy($search)
403 ->where('status', 'active');
404 })
405 ->with(['xprofile' => function ($q) {
406 $q->select(ProfileHelper::getXProfilePublicFields());
407 }])
408 ->where('status', 'pending')
409 ->paginate();
410
411 return apply_filters('fluent_community/space_members_api_response', [
412 'members' => $pendingRequests,
413 'pending_count' => $pendingCount
414 ], $pendingRequests, $request->all());
415 }
416 }
417
418 $spaceMembers = SpaceUserPivot::bySpace($space->id)
419 ->whereHas('xprofile', function ($q) use ($search) {
420 return $q->searchBy($search)
421 ->where('status', 'active');
422 })
423 ->with(['xprofile' => function ($q) {
424 $q->select(ProfileHelper::getXProfilePublicFields());
425 }])
426 ->where('status', 'active')
427 ->orderBy('created_at', 'ASC')
428 ->paginate();
429
430 return apply_filters('fluent_community/space_members_api_response', [
431 'members' => $spaceMembers,
432 'pending_count' => $pendingCount
433 ], $spaceMembers, $request->all());
434 }
435
436 public function join(Request $request, $slug)
437 {
438 $space = Space::where('slug', $slug)->first();
439
440 if (!$space) {
441 return $this->sendError([
442 'message' => __('Space not found', 'fluent-community')
443 ]);
444 }
445
446 $user = $this->getUser();
447
448 $membership = $space->getMembership(get_current_user_id());
449
450 if ($membership) {
451 return $this->sendError([
452 'message' => __('You are already a member of this space. Please reload this page', 'fluent-community')
453 ]);
454 }
455
456 $roles = $user->getCommunityRoles();
457 $isPrivileged = !!array_intersect($roles, ['admin', 'moderator']);
458
459 if (!$isPrivileged && $space->privacy == 'secret') {
460 return $this->sendError([
461 'message' => __('You are not allowed to join this space', 'fluent-community')
462 ]);
463 }
464
465 $status = 'active';
466 if (!$isPrivileged) {
467 if ($space->privacy != 'public') {
468 $status = apply_filters('fluent_community/space/join_status_for_private', 'pending', $space, $user);
469
470 if (!in_array($status, ['pending', 'active'])) {
471 $status = 'pending';
472 }
473 }
474 $role = 'member';
475 } else {
476 $role = $user->isCommunityAdmin() ? 'admin' : 'moderator';
477 }
478
479
480 $space->members()->attach(get_current_user_id(), [
481 'role' => $role,
482 'status' => $status
483 ]);
484
485 $space->membership = $space->getMembership(get_current_user_id());
486
487 if ($status == 'pending') {
488 do_action('fluent_community/space/join_requested', $space, $user->ID, 'self');
489 } else {
490 do_action('fluent_community/space/joined', $space, $user->ID, 'self');
491 }
492
493 $user->cacheAccessSpaces();
494
495 return [
496 'message' => ($status == 'active') ? __('You have joined this Space', 'fluent-community') : __('Your join request has been sent to the Space admin.', 'fluent-community'),
497 'membership' => $space->membership
498 ];
499 }
500
501 public function leave(Request $request, $slug)
502 {
503 $user = $this->getUser(true);
504 $space = Space::where('slug', $slug)->first();
505
506 if (!$space) {
507 return $this->sendError([
508 'message' => __('Space not found', 'fluent-community')
509 ]);
510 }
511
512 $membership = $space->getMembership($user->ID);
513
514 if (!$membership) {
515 return $this->sendError([
516 'message' => __('You are not a member of this community', 'fluent-community')
517 ]);
518 }
519
520 Helper::removeFromSpace($space, $user->ID, 'self');
521
522 return [
523 'message' => __('You have left this space', 'fluent-community')
524 ];
525 }
526
527 public function deleteBySlug(Request $request, $slug)
528 {
529 $space = Space::where('slug', $slug)->first();
530
531 if (!$space) {
532 return $this->sendError([
533 'message' => __('Space not found', 'fluent-community')
534 ]);
535 }
536
537 do_action('fluent_community/space/before_delete', $space);
538
539 Comment::whereHas('post', function ($q) use ($space) {
540 $q->where('space_id', $space->id);
541 })->delete();
542
543 Reaction::whereHas('feed', function ($q) use ($space) {
544 $q->where('space_id', $space->id);
545 })->delete();
546
547 Feed::where('space_id', $space->id)->delete();
548
549 SpaceUserPivot::where('space_id', $space->id)->delete();
550
551 $spaceId = $space->id;
552 $space->delete();
553
554 do_action('fluent_community/space/deleted', $spaceId);
555
556 return [
557 'message' => __('Space has been deleted successfully', 'fluent-community')
558 ];
559 }
560
561 public function deleteById(Request $request, $id)
562 {
563 $space = Space::findOrFail($id);
564
565 return $this->deleteBySlug($request, $space->slug);
566 }
567
568 public function addMember(Request $request, $slug)
569 {
570 $space = Space::where('slug', $slug)->first();
571
572 if (!$space) {
573 return $this->sendError([
574 'message' => __('Space not found', 'fluent-community')
575 ]);
576 }
577
578 $this->validate($request->all(), [
579 'user_id' => 'required|exists:users,ID'
580 ]);
581
582 $userId = $request->get('user_id');
583 $targetUser = User::findOrFail($userId);
584 $targetUser->syncXProfile();
585 $xprofile = $targetUser->xprofile;
586
587 if ($xprofile && $xprofile->status != 'active') {
588 return $this->sendError([
589 'message' => __('Selected user is not active', 'fluent-community')
590 ]);
591 }
592
593 $pivot = SpaceUserPivot::bySpace($space->id)
594 ->byUser($userId)
595 ->first();
596
597 $allowedRoles = ['member', 'moderator', 'admin'];
598 $requestedRole = $request->get('role', 'member');
599 $role = in_array($requestedRole, $allowedRoles, true) ? $requestedRole : 'member';
600
601 if ($pivot) {
602 if ($pivot->status == 'active') {
603 if ($role != $pivot->role) {
604 $pivot->role = $role;
605 $pivot->save();
606
607 do_action('fluent_community/space/member/role_updated', $space, $pivot);
608
609 return [
610 'message' => __('Member role updated', 'fluent-community')
611 ];
612 }
613
614 return $this->sendError([
615 'message' => __('Selected user is already a member of this community', 'fluent-community')
616 ]);
617 }
618
619 $pivot->status = 'active';
620 $pivot->save();
621 do_action('fluent_community/space/joined', $space, $userId, 'by_admin');
622
623 if ($role != 'member') {
624 do_action('fluent_community/space/member/role_updated', $space, $pivot);
625 }
626
627 return [
628 'message' => __('Member approved', 'fluent-community')
629 ];
630 }
631
632 $space->members()->attach($userId, [
633 'role' => $role,
634 'status' => 'active'
635 ]);
636
637 $targetUser->cacheAccessSpaces();
638
639 do_action('fluent_community/space/joined', $space, $userId, 'by_admin');
640
641 return [
642 'message' => __('User has been added to this Space', 'fluent-community')
643 ];
644 }
645
646 public function removeMember(Request $request, $slug)
647 {
648 $space = Space::where('slug', $slug)->first();
649
650 if (!$space) {
651 return $this->sendError([
652 'message' => __('Space not found', 'fluent-community')
653 ]);
654 }
655
656 $userId = $request->get('user_id');
657
658 $pivot = SpaceUserPivot::bySpace($space->id)
659 ->byUser($userId)
660 ->first();
661
662 if (!$pivot) {
663 return $this->sendError([
664 'message' => __('Selected user is not a member of this community', 'fluent-community')
665 ]);
666 }
667
668 $pivot->delete();
669
670 $targetUser = User::find($userId);
671
672 if ($targetUser) {
673 $targetUser->cacheAccessSpaces();
674 }
675
676 do_action('fluent_community/space/user_left', $space, $userId, 'by_admin');
677
678 return [
679 'message' => __('User has been removed from this community', 'fluent-community')
680 ];
681 }
682
683 public function getOtherUsers(Request $request)
684 {
685 $currentUser = $this->getUser(true);
686
687 $this->validate($request->all(), [
688 'space_id' => 'required|exists:fcom_spaces,id'
689 ]);
690
691 $isMod = $currentUser->isCommunityModerator() && current_user_can('list_users');
692
693 $spaceId = $request->get('space_id');
694 $space = Space::findOrFail($spaceId);
695
696 if (!$space->verifyUserPermisson($currentUser, 'can_add_member', false)) {
697 return $this->sendError([
698 'message' => __('You are not allowed to add members to this space', 'fluent-community')
699 ]);
700 }
701
702 $selects = ['ID', 'display_name'];
703 if ($isMod) {
704 $selects[] = 'user_email';
705 }
706
707 $userQuery = User::select(['ID'])
708 ->whereDoesntHave('space_pivot', function ($q) use ($space) {
709 $q->where('space_id', $space->id);
710 })
711 ->limit(100)
712 ->searchBy($request->getSafe('search'));
713
714 if (is_multisite()) {
715 global $wpdb;
716 $blogId = get_current_blog_id();
717 $blogPrefix = $wpdb->get_blog_prefix($blogId);
718 $userQuery->whereHas('usermeta', function ($q) use ($blogPrefix) {
719 $q->where('meta_key', $blogPrefix . 'capabilities');
720 });
721 }
722
723 $userIds = $userQuery->get()
724 ->pluck('ID')
725 ->toArray();
726
727 if ($userIds) {
728 update_meta_cache('user', $userIds);
729 }
730
731 $users = User::select($selects)
732 ->whereIn('ID', $userIds)
733 ->paginate(100);
734
735 $data = [
736 'users' => $users
737 ];
738 return apply_filters('fluent_community/space_non_members_api_response', $data, $request->all());
739 }
740
741 public function updateLinks(Request $request, $slug)
742 {
743 $space = Space::where('slug', $slug)->first();
744
745 if (!$space) {
746 return $this->sendError([
747 'message' => __('Space not found', 'fluent-community')
748 ]);
749 }
750
751 $links = $request->get('links', []);
752
753 $links = array_map(function ($link) {
754 return CustomSanitizer::santizeLinkItem($link);
755 }, $links);
756
757 $settings = $space->settings;
758 $settings['links'] = $links;
759 $space->settings = $settings;
760 $space->save();
761
762 return [
763 'message' => __('Links have been updated for the space', 'fluent-community'),
764 'links' => $links
765 ];
766 }
767
768 public function getSpaceGroups(Request $request)
769 {
770 if ($request->get('options_only')) {
771 $groups = SpaceGroup::orderBy('serial', 'ASC')
772 ->select(['id', 'title'])
773 ->get();
774
775 return [
776 'groups' => $groups
777 ];
778 }
779
780 $user = $this->getUser();
781
782 $groups = Helper::getAllCommunityGroups($user, false);
783
784 foreach ($groups as $group) {
785 foreach ($group->spaces as $space) {
786 $space->permalink = $space->getPermalink();
787 if ($space->type === 'community') {
788 $space = $space->formatSpaceData($user);
789 } else {
790 $space->topics = Utility::getTopicsBySpaceId($space->id);
791 }
792 }
793 }
794
795 $orphanedSpaces = BaseSpace::withoutGlobalScopes()
796 ->whereNull('parent_id')
797 ->whereIn('type', ['community', 'course'])
798 ->orderBy('title', 'ASC')
799 ->get();
800
801 foreach ($orphanedSpaces as $space) {
802 $space->permalink = $space->getPermalink();
803 if ($space->type === 'community') {
804 $space = $space->formatSpaceData($user);
805 } else {
806 $space->topics = Utility::getTopicsBySpaceId($space->id);
807 }
808 }
809
810 $data = [
811 'groups' => $groups,
812 'orphaned_spaces' => $orphanedSpaces
813 ];
814 return apply_filters('fluent_community/space_groups_api_response', $data, $request->all());
815 }
816
817 public function createSpaceGroup(Request $request)
818 {
819 $data = $request->all();
820
821 $this->validate($data, [
822 'title' => 'required|unique:fcom_spaces,title',
823 'slug' => 'required|unique:fcom_spaces,slug'
824 ]);
825
826
827 $formattedData = [
828 'title' => sanitize_text_field($data['title']),
829 'slug' => sanitize_title($data['slug']),
830 'description' => sanitize_textarea_field($data['description']),
831 'status' => 'active',
832 'type' => 'space_group',
833 'settings' => [
834 'always_show_spaces' => Arr::get($data, 'settings.always_show_spaces', 'yes'),
835 ],
836 'serial' => SpaceGroup::max('serial') + 1
837 ];
838
839 $group = SpaceGroup::create($formattedData);
840
841 return [
842 'message' => __('Space group has been created successfully', 'fluent-community'),
843 'group' => $group
844 ];
845 }
846
847 public function updateSpaceGroup(Request $request, $groupId)
848 {
849 $group = SpaceGroup::findOrFail($groupId);
850 $data = $request->all();
851
852 $this->validate($data, [
853 'title' => 'required'
854 ]);
855
856 $taken = BaseSpace::where('title', $data['title'])
857 ->where('id', '!=', $group->id)
858 ->first();
859
860 if ($taken) {
861 return $this->sendError([
862 'message' => __('The title is already taken. Please use a different title', 'fluent-community')
863 ]);
864 }
865
866 $formattedData = [
867 'title' => sanitize_text_field($data['title']),
868 'description' => sanitize_textarea_field($data['description']),
869 'status' => 'active',
870 'type' => 'space_group',
871 'settings' => [
872 'always_show_spaces' => Arr::get($data, 'settings.always_show_spaces', 'yes'),
873 ]
874 ];
875
876 $group->fill($formattedData)->save();
877
878 return [
879 'message' => __('Space group has been updated', 'fluent-community'),
880 'group' => $group
881 ];
882 }
883
884 public function deleteSpaceGroup(Request $request, $groupId)
885 {
886 $group = SpaceGroup::findOrFail($groupId);
887
888 if (!$group->spaces->isEmpty()) {
889 return $this->sendError([
890 'message' => __('You cannot delete this group. It has spaces', 'fluent-community')
891 ]);
892 }
893
894 $group->delete();
895
896 return [
897 'message' => __('Space group has been deleted successfully', 'fluent-community')
898 ];
899 }
900
901 public function updateSpaceGroupIndexes(Request $request)
902 {
903 $indexes = $request->get('indexes', []);
904
905 foreach ($indexes as $groupId => $indexNumber) {
906 $group = SpaceGroup::findOrFail($groupId);
907 $group->update([
908 'serial' => $indexNumber + 1
909 ]);
910 }
911
912 return [
913 'message' => __('Space group indexes have been updated.', 'fluent-community')
914 ];
915
916 }
917
918 public function updateSpaceIndexes(Request $request)
919 {
920 $indexes = $request->get('indexes', []);
921
922 foreach ($indexes as $index => $spaceId) {
923 $space = BaseSpace::withoutGlobalScopes()->findOrFail($spaceId);
924 $space->update([
925 'serial' => $index + 1
926 ]);
927 }
928
929 return [
930 'message' => __('Space indexes have been updated.', 'fluent-community')
931 ];
932 }
933
934 public function moveSpace(Request $request)
935 {
936 $spaceId = $request->getSafe('space_id', 'intval');
937 $groupId = $request->getSafe('group_id', 'intval');
938
939 $space = BaseSpace::withoutGlobalScopes()->findOrFail($spaceId);
940 $group = SpaceGroup::findOrFail($groupId);
941
942 $space->update([
943 'parent_id' => $group->id
944 ]);
945
946 return [
947 'message' => __('Space has been moved successfully', 'fluent-community')
948 ];
949 }
950
951 public function getLockScreenSettings(Request $request, $spaceSlug)
952 {
953 /** @var Space $space */
954 $space = Space::where('slug', $spaceSlug)->first();
955
956 $userId = $this->getUser() ? $this->getUser()->ID : null;
957
958 if (!$space || ($space->privacy == 'secret' && !$space->getMembership($userId) && !$space->isAdmin($userId, true))) {
959 return $this->sendError([
960 'message' => __('Space not found', 'fluent-community')
961 ], 404);
962 }
963
964 $lockscreen = $space->getLockscreen();
965
966 $lockscreen = apply_filters('fluent_community/get_lockscreen_settings', $lockscreen, $space);
967
968 return [
969 'lockscreen' => $lockscreen
970 ];
971 }
972
973 public function getMetaSettings(Request $request, $spaceSlug)
974 {
975 $space = Space::where('slug', $spaceSlug)->firstOrFail();
976 $metaSettings = apply_filters('fluent_community/space/meta_fields', [], $space);
977
978 if (!$metaSettings) {
979 return [
980 'meta_settings' => null
981 ];
982 }
983
984 return [
985 'meta_settings' => $metaSettings
986 ];
987 }
988
989 private function getActiveMemberCounts($spaceIds)
990 {
991 if (!$spaceIds) {
992 return [];
993 }
994
995 return SpaceUserPivot::whereIn('space_id', $spaceIds)
996 ->where('status', 'active')
997 ->whereHas('xprofile', function ($q) {
998 $q->where('status', 'active');
999 })
1000 ->whereHas('user')
1001 ->selectRaw('space_id, COUNT(*) as total')
1002 ->groupBy('space_id')
1003 ->pluck('total', 'space_id')
1004 ->toArray();
1005 }
1006 }
1007