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 +133 -5 1.23 → 2.2.0 View file →
@@ -4,8 +4,9 @@
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;
8 9 use FluentBoards\App\Services\PermissionManager;
9 10 use FluentBoards\App\Services\UserService;
10 11 use FluentBoards\Framework\Http\Request\Request;
11 12 use FluentCrm\App\Models\Subscriber;
@@ -30,8 +31,9 @@
30 31 }
31 32
32 33 public function memberAssociatedTaskUsers($user_id)
33 34 {
35 + $user_id = absint($user_id);
34 36 try {
35 37 $uniqueUsers = $this->userService->memberAssociatedTaskUsers($user_id);
36 38
37 39 return $this->sendSuccess([
@@ -45,9 +47,9 @@
45 47
46 48 public function searchFluentBoardsUser(Request $request)
47 49 {
48 50 try {
49 - $search_input = $request->searchInput . trim('');
51 + $search_input = $request->getSafe('searchInput', 'sanitize_text_field', '');
50 52
51 53 $boardUsers = $this->userService->searchFluentBoardsUser($search_input);
52 54
53 55 return $this->sendSuccess($boardUsers, 200);
@@ -57,10 +59,11 @@
57 59 }
58 60
59 61 public function searchMemberUser(Request $request, $user_id)
60 62 {
63 + $user_id = absint($user_id);
61 64 try {
62 - $search_input = $request->searchInput . trim('');
65 + $search_input = $request->getSafe('searchInput', 'sanitize_text_field', '');
63 66 $searchResult = $this->userService->searchMemberUser($search_input, $user_id);
64 67
65 68 return $this->sendSuccess([
66 69 'users' => $searchResult,
@@ -71,14 +74,25 @@
71 74 }
72 75
73 76 public function getMemberAssociatedTasks(Request $request, $user_id)
74 77 {
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 +
75 88 $requestData = [
76 - 'page' =>$request->getSafe('page', 'intval'),
89 + 'page' => $request->getSafe('page', 'intval', 1),
77 90 'taskType' => $request->getSafe('taskType', 'sanitize_text_field'),
78 - 'boardIds' => $boardIds = $request->getSafe('boardIds'),
91 + 'boardIds' => $boardIds,
79 92 'orderBy' => $request->getSafe('orderBy', 'sanitize_text_field'),
80 93 'order' => $request->getSafe('order', 'sanitize_text_field'),
94 + 'per_page' => $perPage
81 95 ];
82 96 try {
83 97 return $this->sendSuccess(
84 98 $this->userService->getMemberAssociatedTasks($user_id, $requestData)
@@ -87,11 +101,32 @@
87 101 return $this->sendError($e->getMessage(), 404);
88 102 }
89 103 }
90 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 +
91 125 public function getMemberRelatedAcitivies(Request $request, $user_id)
92 126 {
93 - $page = $request->getSafe('page');
127 + $user_id = absint($user_id);
128 + $page = $request->getSafe('page', 'intval', 1);
94 129 try {
95 130 return $this->sendSuccess(
96 131 $this->userService->getMemberRelatedAcitivies($user_id, $page)
97 132 , 200);
@@ -101,8 +136,20 @@
101 136 }
102 137
103 138 public function getMemberInfo($user_id)
104 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);
105 152 $user = User::findOrFail($user_id);
106 153
107 154 $user = Helper::sanitizeUserCollections($user);
108 155
@@ -121,8 +168,9 @@
121 168 }
122 169
123 170 public function getMemberBoards($user_id)
124 171 {
172 + $user_id = absint($user_id);
125 173 try {
126 174 return $this->sendSuccess(
127 175 [
128 176 'boards' => $this->userService->getMemberBoards($user_id)
@@ -129,6 +177,86 @@
129 177 ], 200);
130 178 } catch (\Exception $e) {
131 179 return $this->sendError($e->getMessage(), 404);
132 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 + ]);
133 261 }
134 262 }