PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.2.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.2.0
2.2.1 2.2.0 2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 All 44 releases
← All changes | app/Http/Controllers/UserController.php +163 -5 1.13 → 2.2.0 View file →
@@ -4,11 +4,15 @@
4 4
5 5 use FluentBoards\App\Models\Board;
6 6 use FluentBoards\App\Models\User;
7 7 use FluentBoards\App\Services\Helper;
8 +use FluentBoards\App\Services\MCPAccessService;
9 +use FluentBoards\App\Services\PermissionManager;
8 10 use FluentBoards\App\Services\UserService;
9 11 use FluentBoards\Framework\Http\Request\Request;
12 +use FluentCrm\App\Models\Subscriber;
10 13
14 +
11 15 class UserController extends Controller
12 16 {
13 17 private UserService $userService;
14 18
@@ -27,8 +31,9 @@
27 31 }
28 32
29 33 public function memberAssociatedTaskUsers($user_id)
30 34 {
35 + $user_id = absint($user_id);
31 36 try {
32 37 $uniqueUsers = $this->userService->memberAssociatedTaskUsers($user_id);
33 38
34 39 return $this->sendSuccess([
@@ -42,9 +47,9 @@
42 47
43 48 public function searchFluentBoardsUser(Request $request)
44 49 {
45 50 try {
46 - $search_input = $request->searchInput . trim('');
51 + $search_input = $request->getSafe('searchInput', 'sanitize_text_field', '');
47 52
48 53 $boardUsers = $this->userService->searchFluentBoardsUser($search_input);
49 54
50 55 return $this->sendSuccess($boardUsers, 200);
@@ -54,10 +59,11 @@
54 59 }
55 60
56 61 public function searchMemberUser(Request $request, $user_id)
57 62 {
63 + $user_id = absint($user_id);
58 64 try {
59 - $search_input = $request->searchInput . trim('');
65 + $search_input = $request->getSafe('searchInput', 'sanitize_text_field', '');
60 66 $searchResult = $this->userService->searchMemberUser($search_input, $user_id);
61 67
62 68 return $this->sendSuccess([
63 69 'users' => $searchResult,
@@ -68,12 +74,29 @@
68 74 }
69 75
70 76 public function getMemberAssociatedTasks(Request $request, $user_id)
71 77 {
72 - $page = $request->getSafe('page');
78 + $user_id = absint($user_id);
79 + // Sanitize boardIds array
80 + $rawBoardIds = $request->getSafe('boardIds');
81 + $boardIds = [];
82 + if (is_array($rawBoardIds)) {
83 + $boardIds = array_filter(array_map('intval', $rawBoardIds));
84 + }
85 +
86 + $perPage = max(1, min(absint($request->getSafe('per_page', 'intval', 15)), 50));
87 +
88 + $requestData = [
89 + 'page' => $request->getSafe('page', 'intval', 1),
90 + 'taskType' => $request->getSafe('taskType', 'sanitize_text_field'),
91 + 'boardIds' => $boardIds,
92 + 'orderBy' => $request->getSafe('orderBy', 'sanitize_text_field'),
93 + 'order' => $request->getSafe('order', 'sanitize_text_field'),
94 + 'per_page' => $perPage
95 + ];
73 96 try {
74 97 return $this->sendSuccess(
75 - $this->userService->getMemberAssociatedTasks($user_id, $page)
98 + $this->userService->getMemberAssociatedTasks($user_id, $requestData)
76 99 , 200);
77 100 } catch (\Exception $e) {
78 101 return $this->sendError($e->getMessage(), 404);
79 102 }
@@ -78,11 +101,32 @@
78 101 return $this->sendError($e->getMessage(), 404);
79 102 }
80 103 }
81 104
105 + /**
106 + * Return profile task counts using the same categories shown on the dashboard.
107 + */
108 + public function getMemberTaskCounts(Request $request, $user_id)
109 + {
110 + $user_id = absint($user_id);
111 + $rawBoardIds = $request->getSafe('boardIds');
112 + $boardIds = is_array($rawBoardIds)
113 + ? array_filter(array_map('intval', $rawBoardIds))
114 + : [];
115 +
116 + try {
117 + return $this->sendSuccess([
118 + 'counts' => $this->userService->getMemberTaskCounts($user_id, $boardIds),
119 + ], 200);
120 + } catch (\Exception $e) {
121 + return $this->sendError($e->getMessage(), 404);
122 + }
123 + }
124 +
82 125 public function getMemberRelatedAcitivies(Request $request, $user_id)
83 126 {
84 - $page = $request->getSafe('page');
127 + $user_id = absint($user_id);
128 + $page = $request->getSafe('page', 'intval', 1);
85 129 try {
86 130 return $this->sendSuccess(
87 131 $this->userService->getMemberRelatedAcitivies($user_id, $page)
88 132 , 200);
@@ -92,13 +136,127 @@
92 136 }
93 137
94 138 public function getMemberInfo($user_id)
95 139 {
140 + if(!PermissionManager::isFluentBoardsUser($user_id)) {
141 + return $this->sendError(
142 + [
143 + 'message' => __('You are not authorized to access this resource', 'fluent-boards'),
144 + 'code' => 'fluent_boards_unauthorized',
145 + 'status' => 403
146 + ],
147 + 403
148 + );
149 + }
150 +
151 + $user_id = absint($user_id);
96 152 $user = User::findOrFail($user_id);
97 153
98 154 $user = Helper::sanitizeUserCollections($user);
99 155
156 + $user->fbs_role = PermissionManager::isFluentBoardsAdmin($user_id) ? 'fbs_admin' : 'member';
157 +
158 + $user->is_wp_admin = user_can($user_id, 'manage_options') ? 'yes' : 'no';
159 +
160 + if (defined('FLUENTCRM')) {
161 + $subscriber = Subscriber::where('user_id', $user_id)->first();
162 + $user->fluentcrm_subscriber = $subscriber ?? null;
163 + }
164 +
100 165 return [
101 166 'user' => $user
102 167 ];
168 + }
169 +
170 + public function getMemberBoards($user_id)
171 + {
172 + $user_id = absint($user_id);
173 + try {
174 + return $this->sendSuccess(
175 + [
176 + 'boards' => $this->userService->getMemberBoards($user_id)
177 + ], 200);
178 + } catch (\Exception $e) {
179 + return $this->sendError($e->getMessage(), 404);
180 + }
181 + }
182 +
183 + public function getMemberStats($user_id)
184 + {
185 + $user_id = absint($user_id);
186 +
187 + return $this->sendSuccess(
188 + $this->userService->getMemberStats($user_id),
189 + 200
190 + );
191 + }
192 +
193 + /** Update the authenticated member's display name. */
194 + public function updateDisplayName(Request $request, $user_id)
195 + {
196 + try {
197 + return $this->sendSuccess([
198 + 'message' => __('Display name has been updated', 'fluent-boards'),
199 + 'user' => $this->userService->updateDisplayName($user_id, $request->get('display_name')),
200 + ]);
201 + } catch (\Exception $e) {
202 + return $this->sendError(['message' => $e->getMessage()], $e->getCode() === 403 ? 403 : 400);
203 + }
204 + }
205 +
206 + /** Upload a profile photo for the authenticated member. */
207 + public function updateProfilePhoto(Request $request, $user_id)
208 + {
209 + try {
210 + return $this->sendSuccess([
211 + 'message' => __('Profile photo has been updated', 'fluent-boards'),
212 + 'user' => $this->userService->updateProfilePhoto($user_id, $_FILES['photo'] ?? []),
213 + ]);
214 + } catch (\Exception $e) {
215 + return $this->sendError(['message' => $e->getMessage()], $e->getCode() === 403 ? 403 : 400);
216 + }
217 + }
218 +
219 + public function getMcpConnections(Request $request, $id)
220 + {
221 + if (!current_user_can('list_app_passwords', (int) $id)) {
222 + return $this->sendError(['message' => __('You are not allowed to list application passwords.', 'fluent-boards')], 403);
223 + }
224 +
225 + return $this->sendSuccess(MCPAccessService::getProfileState((int) $id));
226 + }
227 +
228 + /**
229 + * Create an MCP connection key. The password is only ever in this response.
230 + */
231 + public function createMcpConnection(Request $request, $id)
232 + {
233 + $result = MCPAccessService::createConnection((int) $id, (string) $request->get('name'));
234 +
235 + if (is_wp_error($result)) {
236 + $data = $result->get_error_data();
237 + return $this->sendError(['message' => $result->get_error_message()], $data['status'] ?? 400);
238 + }
239 +
240 + nocache_headers();
241 +
242 + return $this->sendSuccess($result);
243 + }
244 +
245 + public function revokeMcpConnection(Request $request, $id, $uuid)
246 + {
247 + if (!current_user_can('delete_app_password', (int) $id, $uuid)) {
248 + return $this->sendError(['message' => __('You are not allowed to delete this application password.', 'fluent-boards')], 403);
249 + }
250 +
251 + $result = MCPAccessService::revokeConnection((int) $id, sanitize_text_field($uuid));
252 +
253 + if (is_wp_error($result)) {
254 + $data = $result->get_error_data();
255 + return $this->sendError(['message' => $result->get_error_message()], $data['status'] ?? 400);
256 + }
257 +
258 + return $this->sendSuccess([
259 + 'message' => __('Connection revoked.', 'fluent-boards'),
260 + ]);
103 261 }
104 262 }