diff --git a/.kiro/specs/beach-litter-mapping/tasks.md b/.kiro/specs/beach-litter-mapping/tasks.md index 7a0bf1a..07041e8 100644 --- a/.kiro/specs/beach-litter-mapping/tasks.md +++ b/.kiro/specs/beach-litter-mapping/tasks.md @@ -125,7 +125,7 @@ - Add profile editing functionality - _Requirements: 6.3, 6.4, 6.5_ -- [-] 16. Implement notification preferences +- [x] 16. Implement notification preferences - Create notification settings interface - Build area of interest selector with map - Implement radius configuration (1-50km) diff --git a/server/src/controllers/userController.ts b/server/src/controllers/userController.ts index 0662587..1fed7e4 100644 --- a/server/src/controllers/userController.ts +++ b/server/src/controllers/userController.ts @@ -54,20 +54,40 @@ export class UserController { }); } - // Find or create user to get database ID - const dbUserId = await userService.findOrCreateUser(req.userId); - - if (dbUserId !== id) { - return res.status(403).json({ - error: { - code: 'FORBIDDEN', - message: 'You can only update your own profile', - timestamp: new Date().toISOString(), - }, - }); + // Check if the ID in the URL is a Clerk ID or database ID + const isClerkId = id.startsWith('user_'); + let dbUserId: string; + + // If it's a Clerk ID, it should match the authenticated user's Clerk ID + // If it's a database ID, we need to get the database ID for the authenticated user + if (isClerkId) { + // Direct Clerk ID comparison + if (req.userId !== id) { + return res.status(403).json({ + error: { + code: 'FORBIDDEN', + message: 'You can only update your own profile', + timestamp: new Date().toISOString(), + }, + }); + } + // Convert Clerk ID to database ID for the update + dbUserId = await userService.findOrCreateUser(req.userId); + } else { + // Database ID comparison - need to get the database ID for the authenticated user + dbUserId = await userService.findOrCreateUser(req.userId); + if (dbUserId !== id) { + return res.status(403).json({ + error: { + code: 'FORBIDDEN', + message: 'You can only update your own profile', + timestamp: new Date().toISOString(), + }, + }); + } } - const updatedProfile = await userService.updateUserProfile(id, { + const updatedProfile = await userService.updateUserProfile(dbUserId, { firstName, lastName, username, @@ -168,17 +188,38 @@ export class UserController { }); } - // Find or create user to get database ID - const dbUserId = await userService.findOrCreateUser(req.userId); - - if (dbUserId !== id) { - return res.status(403).json({ - error: { - code: 'FORBIDDEN', - message: 'You can only update your own preferences', - timestamp: new Date().toISOString(), - }, - }); + // Check if the ID in the URL is a Clerk ID or database ID + const isClerkId = id.startsWith('user_'); + + // If it's a Clerk ID, it should match the authenticated user's Clerk ID + // If it's a database ID, we need to get the database ID for the authenticated user + if (isClerkId) { + // Direct Clerk ID comparison + if (req.userId !== id) { + return res.status(403).json({ + error: { + code: 'FORBIDDEN', + message: 'You can only update your own preferences', + timestamp: new Date().toISOString(), + }, + }); + } + // Convert Clerk ID to database ID for the update + const dbUserId = await userService.findOrCreateUser(req.userId); + // Update the id variable to use database ID for the service call + req.params.id = dbUserId; + } else { + // Database ID comparison - need to get the database ID for the authenticated user + const dbUserId = await userService.findOrCreateUser(req.userId); + if (dbUserId !== id) { + return res.status(403).json({ + error: { + code: 'FORBIDDEN', + message: 'You can only update your own preferences', + timestamp: new Date().toISOString(), + }, + }); + } } // Validate areasOfInterest if provided @@ -216,7 +257,7 @@ export class UserController { } } - const updatedPreferences = await userService.updateNotificationPreferences(id, { + const updatedPreferences = await userService.updateNotificationPreferences(req.params.id, { notificationEmail, notificationInApp, areasOfInterest,