PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.11.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.11.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
← All changes | app/Http/Controllers/SpaceController.php +135 -19 2.6.02.11.0 View file →
@@ -8,8 +8,9 @@
8 8 use FluentCommunity\App\Models\SpaceGroup;
9 9 use FluentCommunity\App\Models\User;
10 10 use FluentCommunity\App\Services\CustomSanitizer;
11 11 use FluentCommunity\App\Services\Helper;
12 +use FluentCommunity\App\Services\SpaceMenuService;
12 13 use FluentCommunity\App\Functions\Utility;
13 14 use FluentCommunity\App\Services\ProfileHelper;
14 15 use FluentCommunity\Framework\Http\Request\Request;
15 16 use FluentCommunity\App\Models\Comment;
@@ -159,9 +160,10 @@
159 160 $q->where('user_id', get_current_user_id());
160 161 }])
161 162 ->where(function ($q) {
162 163 $q->whereHas('space_pivot', function ($q) {
163 - $q->where('user_id', get_current_user_id());
164 + $q->where('user_id', get_current_user_id())
165 + ->where('status', 'active');
164 166 })
165 167 ->orWhereIn('privacy', ['public', 'private']);
166 168 })
167 169 ->when($type == 'joined', function ($q) {
@@ -185,8 +187,10 @@
185 187
186 188 $memberCounts = $this->getActiveMemberCounts($spaces->pluck('id')->toArray());
187 189
188 190 foreach ($spaces as $space) {
191 + $space->description_rendered = wpautop($space->description);
192 +
189 193 $shouldHideMembersCount = Arr::get($space->settings, 'hide_members_count') == 'yes';
190 194 $canViewMembers = $currentUser && $space->verifyUserPermisson($currentUser, 'can_view_members', false);
191 195
192 196 if ($shouldHideMembersCount && !$canViewMembers) {
@@ -194,9 +198,8 @@
194 198 continue;
195 199 }
196 200
197 201 $space->members_count = (int)Arr::get($memberCounts, $space->id, 0);
198 - $space->description_rendered = wpautop($space->description);
199 202 }
200 203
201 204 $data = [
202 205 'spaces' => $spaces,
@@ -207,11 +210,23 @@
207 210 }
208 211
209 212 public function getAllSpaces(Request $request)
210 213 {
211 - $spaces = Space::paginate();
214 + $currentUser = $this->getUser();
212 215
213 - $currentUser = $this->getUser();
216 + $spacesQuery = Space::query();
217 +
218 + if (!($currentUser && $currentUser->isCommunityModerator())) {
219 + $spacesQuery->where(function ($q) {
220 + $q->whereHas('space_pivot', function ($q) {
221 + $q->where('user_id', get_current_user_id())
222 + ->where('status', 'active');
223 + })
224 + ->orWhereIn('privacy', ['public', 'private']);
225 + });
226 + }
227 + $spaces = $spacesQuery->paginate();
228 +
214 229 $memberCounts = $this->getActiveMemberCounts($spaces->pluck('id')->toArray());
215 230
216 231 foreach ($spaces as $space) {
217 232 $shouldHideMembersCount = Arr::get($space->settings, 'hide_members_count') == 'yes';
@@ -235,17 +250,18 @@
235 250
236 251 public function getBySlug(Request $request, $spaceSlug)
237 252 {
238 253 $user = $this->getUser();
239 - $space = Space::where('slug', $spaceSlug)
240 - ->firstOrFail();
254 + $space = Space::where('slug', $spaceSlug)->first();
241 255
242 256 $userId = $user ? $user->ID : null;
243 - if ($space->privacy == 'secret' && !$space->getMembership($userId) && !$space->isAdmin($userId, true)) {
257 +
258 + // A hidden secret space must be indistinguishable from a non-existent one, so its
259 + // existence cannot be enumerated by slug. Both return an identical 404.
260 + if (!$space || ($space->privacy == 'secret' && !$space->getMembership($userId) && !$space->isAdmin($userId, true))) {
244 261 return $this->sendError([
245 - 'message' => __('You are not allowed to view this space', 'fluent-community'),
246 - 'error_type' => 'restricted'
247 - ]);
262 + 'message' => __('Space not found', 'fluent-community')
263 + ], 404);
248 264 }
249 265
250 266 $space = $space->formatSpaceData($user);
251 267
@@ -372,8 +388,9 @@
372 388 }
373 389
374 390 public function getMembers(Request $request, $slug)
375 391 {
392 + /** @var Space $space */
376 393 $space = Space::where('slug', $slug)
377 394 ->firstOrFail();
378 395
379 396 $user = $this->getUser();
@@ -411,20 +428,37 @@
411 428 ], $pendingRequests, $request->all());
412 429 }
413 430 }
414 431
432 + $defaultDirections = [
433 + 'last_activity' => 'DESC',
434 + 'display_name' => 'ASC',
435 + 'created_at' => 'DESC',
436 + ];
437 +
438 + $sortBy = $request->getSafe('sort_by', 'sanitize_text_field', 'created_at');
439 + $sortColumn = in_array($sortBy, array_keys($defaultDirections), true) ? $sortBy : 'created_at';
440 + $sortDir = strtoupper($request->getSafe('sort_dir', 'sanitize_text_field', ''));
441 + $sortDirection = in_array($sortDir, ['ASC', 'DESC'], true) ? $sortDir : ($sortColumn === 'created_at' ? 'ASC' : $defaultDirections[$sortColumn]);
442 +
443 + $profileSort = $sortColumn !== 'created_at';
444 + $orderColumn = $profileSort ? 'fcom_xprofile.' . $sortColumn : 'fcom_space_user.created_at';
445 +
415 446 $spaceMembers = SpaceUserPivot::bySpace($space->id)
416 447 ->whereHas('xprofile', function ($q) use ($search) {
417 - return $q->searchBy($search)
418 - ->where('status', 'active');
448 + $q->searchBy($search)->where('status', 'active');
419 449 })
450 + ->where('fcom_space_user.status', 'active')
420 451 ->with(['xprofile' => function ($q) {
421 452 $q->select(ProfileHelper::getXProfilePublicFields());
422 453 }])
423 - ->where('status', 'active')
424 - ->orderBy('created_at', 'ASC')
454 + ->when($profileSort, function ($q) {
455 + $q->join('fcom_xprofile', 'fcom_xprofile.user_id', '=', 'fcom_space_user.user_id')
456 + ->select('fcom_space_user.*');
457 + })
458 + ->orderBy($orderColumn, $sortDirection)
425 459 ->paginate();
426 -
460 +
427 461 return apply_filters('fluent_community/space_members_api_response', [
428 462 'members' => $spaceMembers,
429 463 'pending_count' => $pendingCount
430 464 ], $spaceMembers, $request->all());
@@ -720,8 +754,12 @@
720 754 $userIds = $userQuery->get()
721 755 ->pluck('ID')
722 756 ->toArray();
723 757
758 + if ($userIds) {
759 + update_meta_cache('user', $userIds);
760 + }
761 +
724 762 $users = User::select($selects)
725 763 ->whereIn('ID', $userIds)
726 764 ->paginate(100);
727 765
@@ -757,8 +795,61 @@
757 795 'links' => $links
758 796 ];
759 797 }
760 798
799 + public function getPrimaryMenu(Request $request, $slug)
800 + {
801 + $space = Space::where('slug', $slug)->first();
802 +
803 + if (!$space) {
804 + return $this->sendError([
805 + 'message' => __('Space not found', 'fluent-community'),
806 + ]);
807 + }
808 +
809 + // Lighter than formatSpaceData(), but listeners like fcom-chat need membership too.
810 + $user = $this->getUser();
811 + $space->permissions = $space->getUserPermissions($user);
812 + $space->membership = $space->getMembership($user ? $user->ID : null);
813 +
814 + return [
815 + 'menu_items' => SpaceMenuService::getManagerItems($space),
816 + ];
817 + }
818 +
819 + public function updatePrimaryMenu(Request $request, $slug)
820 + {
821 + $space = Space::where('slug', $slug)->first();
822 +
823 + if (!$space) {
824 + return $this->sendError([
825 + 'message' => __('Space not found', 'fluent-community'),
826 + ]);
827 + }
828 +
829 + $incoming = $request->get('menu_items', []);
830 +
831 + if (!is_array($incoming)) {
832 + return $this->sendError([
833 + 'message' => __('Menu items must be a list.', 'fluent-community'),
834 + ], 422);
835 + }
836 +
837 + $menuItems = CustomSanitizer::sanitizeSpaceMenuItems($incoming);
838 +
839 + SpaceMenuService::storeMenu($space, $menuItems);
840 +
841 + // No re-fetch needed — unlike formatSpaceData(), this doesn't make $space unsaveable.
842 + $user = $this->getUser();
843 + $space->permissions = $space->getUserPermissions($user);
844 + $space->membership = $space->getMembership($user ? $user->ID : null);
845 +
846 + return [
847 + 'message' => __('Menu has been updated for the space', 'fluent-community'),
848 + 'menu_items' => SpaceMenuService::getManagerItems($space),
849 + ];
850 + }
851 +
761 852 public function getSpaceGroups(Request $request)
762 853 {
763 854 if ($request->get('options_only')) {
764 855 $groups = SpaceGroup::orderBy('serial', 'ASC')
@@ -815,13 +906,28 @@
815 906 'title' => 'required|unique:fcom_spaces,title',
816 907 'slug' => 'required|unique:fcom_spaces,slug'
817 908 ]);
818 909
910 + $title = sanitize_text_field(Arr::get($data, 'title', ''));
911 + $slug = sanitize_title(Arr::get($data, 'slug', ''));
912 + $desc = sanitize_textarea_field(Arr::get($data, 'description', ''));
819 913
914 + if (!$title) {
915 + return $this->sendError([
916 + 'message' => __('Please enter a valid group title.', 'fluent-community')
917 + ]);
918 + }
919 +
920 + if (!$slug) {
921 + return $this->sendError([
922 + 'message' => __('Please enter a valid group slug.', 'fluent-community')
923 + ]);
924 + }
925 +
820 926 $formattedData = [
821 - 'title' => sanitize_text_field($data['title']),
822 - 'slug' => sanitize_title($data['slug']),
823 - 'description' => sanitize_textarea_field($data['description']),
927 + 'title' => $title,
928 + 'slug' => $slug,
929 + 'description' => $desc,
824 930 'status' => 'active',
825 931 'type' => 'space_group',
826 932 'settings' => [
827 933 'always_show_spaces' => Arr::get($data, 'settings.always_show_spaces', 'yes'),
@@ -942,9 +1048,19 @@
942 1048 }
943 1049
944 1050 public function getLockScreenSettings(Request $request, $spaceSlug)
945 1051 {
946 - $space = Space::where('slug', $spaceSlug)->firstOrFail();
1052 + /** @var Space $space */
1053 + $space = Space::where('slug', $spaceSlug)->first();
1054 +
1055 + $userId = $this->getUser() ? $this->getUser()->ID : null;
1056 +
1057 + if (!$space || ($space->privacy == 'secret' && !$space->getMembership($userId) && !$space->isAdmin($userId, true))) {
1058 + return $this->sendError([
1059 + 'message' => __('Space not found', 'fluent-community')
1060 + ], 404);
1061 + }
1062 +
947 1063 $lockscreen = $space->getLockscreen();
948 1064
949 1065 $lockscreen = apply_filters('fluent_community/get_lockscreen_settings', $lockscreen, $space);
950 1066