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.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 1.40 All 43 releases
← All changes | app/Http/Controllers/UserController.php +50 -124 2.0.10 → 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;
@@ -188,149 +189,74 @@
188 189 200
189 190 );
190 191 }
191 192
193 + /** Update the authenticated member's display name. */
192 194 public function updateDisplayName(Request $request, $user_id)
193 195 {
194 - $user_id = absint($user_id);
195 - $currentUserId = get_current_user_id();
196 -
197 - if ($currentUserId !== $user_id && !PermissionManager::isAdmin($currentUserId)) {
198 - return $this->sendError(
199 - __('You do not have permission to update this display name', 'fluent-boards'),
200 - 403
201 - );
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);
202 203 }
203 -
204 - $displayName = $request->getSafe('display_name', 'sanitize_text_field');
205 -
206 - if(!$displayName) {
207 - return $this->sendError('Display name is required', 400);
208 - }
209 -
210 - $updateResult = wp_update_user([
211 - 'ID' => $user_id,
212 - 'display_name' => $displayName,
213 - ]);
214 -
215 - if (is_wp_error($updateResult)) {
216 - return $this->sendError(
217 - $updateResult->get_error_message(),
218 - 400
219 - );
220 - }
221 -
222 - $user = User::findOrFail($user_id);
223 - $user = Helper::sanitizeUserCollections($user);
224 - $user->fbs_role = PermissionManager::isFluentBoardsAdmin($user_id) ? 'fbs_admin' : 'member';
225 - $user->is_wp_admin = user_can($user_id, 'manage_options') ? 'yes' : 'no';
226 -
227 - if (defined('FLUENTCRM')) {
228 - $subscriber = Subscriber::where('user_id', $user_id)->first();
229 - $user->fluentcrm_subscriber = $subscriber ?? null;
230 - }
231 -
232 - return $this->sendSuccess([
233 - 'message' => __('Display name has been updated', 'fluent-boards'),
234 - 'user' => $user,
235 - ], 200);
236 -
237 204 }
238 205
206 + /** Upload a profile photo for the authenticated member. */
239 207 public function updateProfilePhoto(Request $request, $user_id)
240 -{
241 - $user_id = absint($user_id);
242 - $currentUserId = get_current_user_id();
243 -
244 - // Only the user themself OR an admin can change the profile picture
245 - if ($currentUserId !== $user_id && !PermissionManager::isAdmin($currentUserId)) {
246 - return $this->sendError(
247 - __('You do not have permission to update this profile photo', 'fluent-boards'),
248 - 403
249 - );
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 + }
250 217 }
251 218
252 - // We’ll use native WordPress upload handling
253 - if (empty($_FILES['photo']) || !empty($_FILES['photo']['error'])) {
254 - return $this->sendError(
255 - __('No photo uploaded or upload error', 'fluent-boards'),
256 - 400
257 - );
258 - }
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 + }
259 224
260 - // Limit file size to 2MB for profile photos
261 - $maxSize = 2 * 1024 * 1024;
262 - if ($_FILES['photo']['size'] > $maxSize) {
263 - return $this->sendError(
264 - __('Photo must be under 2MB', 'fluent-boards'),
265 - 400
266 - );
225 + return $this->sendSuccess(MCPAccessService::getProfileState((int) $id));
267 226 }
268 227
269 - $file = $_FILES['photo'];
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'));
270 234
271 - // Validate MIME type server-side (client-sent type is spoofable)
272 - $fileType = wp_check_filetype($file['name'], [
273 - 'jpg|jpeg|jpe' => 'image/jpeg',
274 - 'gif' => 'image/gif',
275 - 'png' => 'image/png',
276 - 'webp' => 'image/webp',
277 - ]);
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 + }
278 239
279 - if (!$fileType['type']) {
280 - return $this->sendError(
281 - __('Invalid image type', 'fluent-boards'),
282 - 400
283 - );
284 - }
240 + nocache_headers();
285 241
286 - // Load WordPress upload helpers
287 - if (!function_exists('wp_handle_upload')) {
288 - require_once ABSPATH . 'wp-admin/includes/file.php';
242 + return $this->sendSuccess($result);
289 243 }
290 244
291 - $overrides = [
292 - 'test_form' => false,
293 - 'mimes' => [
294 - 'jpg|jpeg|jpe' => 'image/jpeg',
295 - 'gif' => 'image/gif',
296 - 'png' => 'image/png',
297 - 'webp' => 'image/webp',
298 - ],
299 - ];
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 + }
300 250
301 - $uploaded = wp_handle_upload($file, $overrides);
251 + $result = MCPAccessService::revokeConnection((int) $id, sanitize_text_field($uuid));
302 252
303 - if (isset($uploaded['error'])) {
304 - return $this->sendError(
305 - $uploaded['error'],
306 - 400
307 - );
308 - }
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 + }
309 257
310 - $photoUrl = esc_url_raw($uploaded['url']);
311 -
312 - // Store custom profile photo in user meta
313 - update_user_meta($user_id, 'fbs_profile_photo', $photoUrl);
314 -
315 - // Reload user and sanitize same as in getMemberInfo()
316 - $user = User::findOrFail($user_id);
317 - $user = Helper::sanitizeUserCollections($user);
318 -
319 - // Override photo field if your sanitizer does not already use the meta
320 - $user->photo = $photoUrl;
321 -
322 - $user->fbs_role = PermissionManager::isFluentBoardsAdmin($user_id) ? 'fbs_admin' : 'member';
323 - $user->is_wp_admin = user_can($user_id, 'manage_options') ? 'yes' : 'no';
324 -
325 - if (defined('FLUENTCRM')) {
326 - $subscriber = Subscriber::where('user_id', $user_id)->first();
327 - $user->fluentcrm_subscriber = $subscriber ?? null;
258 + return $this->sendSuccess([
259 + 'message' => __('Connection revoked.', 'fluent-boards'),
260 + ]);
328 261 }
329 -
330 - return $this->sendSuccess([
331 - 'message' => __('Profile photo has been updated', 'fluent-boards'),
332 - 'photo_url' => $photoUrl,
333 - 'user' => $user,
334 - ], 200);
335 -}
336 262 }