From e73191ece84169d25abfb6cc1d509c516281237b Mon Sep 17 00:00:00 2001 From: NoobFaris Date: Tue, 16 Jun 2026 15:06:28 +0100 Subject: [PATCH] my feature --- src/controllers/users.controller.js | 34 +++++++++++++++++++++++++---- src/middlewares/validate.js | 34 ++++++++++++----------------- src/routes/users.routes.js | 9 ++++++-- src/validators/auth.validators.js | 18 ++++++++++++++- 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/controllers/users.controller.js b/src/controllers/users.controller.js index 843cd11..49ebaf3 100644 --- a/src/controllers/users.controller.js +++ b/src/controllers/users.controller.js @@ -1,3 +1,4 @@ +const User = require('../models/User.model'); const { sendSuccess } = require('../utils/response'); /** @@ -7,11 +8,8 @@ const { sendSuccess } = require('../utils/response'); */ const getCurrentUser = async (req, res, next) => { try { - // The authenticate middleware already attaches the user to req.user - // We need to exclude sensitive fields before sending the response const user = req.user.toObject(); - // Remove sensitive fields delete user.password; delete user.refreshTokenHash; delete user.resetPasswordToken; @@ -23,6 +21,34 @@ const getCurrentUser = async (req, res, next) => { } }; +/** + * Update current authenticated user's profile + * @route PATCH /api/users/me + * @access Private (requires authentication) + */ +const updateCurrentUser = async (req, res, next) => { + try { + const { fullName, walletAddress } = req.body; + + // Build update object with only allowed fields + const allowedUpdates = {}; + if (fullName !== undefined) allowedUpdates.fullName = fullName; + if (walletAddress !== undefined) allowedUpdates.walletAddress = walletAddress; + + // Update and return the new document + const updatedUser = await User.findByIdAndUpdate( + req.userId, + { $set: allowedUpdates }, + { new: true, runValidators: true } + ).select('-password -refreshTokenHash -resetPasswordToken -emailVerificationToken'); + + return sendSuccess(res, updatedUser, 200, 'Profile updated successfully'); + } catch (error) { + next(error); + } +}; + module.exports = { getCurrentUser, -}; + updateCurrentUser, +}; \ No newline at end of file diff --git a/src/middlewares/validate.js b/src/middlewares/validate.js index 5ca30a7..852d95e 100644 --- a/src/middlewares/validate.js +++ b/src/middlewares/validate.js @@ -1,22 +1,16 @@ -const validate = schema => { - return (req, res, next) => { - const { error } = schema.validate(req.body, { abortEarly: false }); - - if (error) { - const errors = error.details.map(detail => ({ - field: detail.path.join('.'), - message: detail.message, - })); - - return res.status(400).json({ - success: false, - message: 'Validation failed', - errors, - }); - } - - next(); - }; +/** + * Validation middleware factory + * Validates request body against a Joi schema + */ +const validate = (schema) => (req, res, next) => { + const { error } = schema.validate(req.body, { abortEarly: false }); + if (error) { + const err = new Error(error.details.map((d) => d.message).join(', ')); + err.statusCode = 400; + err.isOperational = true; + return next(err); + } + next(); }; -module.exports = validate; +module.exports = validate; \ No newline at end of file diff --git a/src/routes/users.routes.js b/src/routes/users.routes.js index 2feb8d1..2dd4a47 100644 --- a/src/routes/users.routes.js +++ b/src/routes/users.routes.js @@ -1,10 +1,15 @@ const express = require('express'); const authenticate = require('../middlewares/auth'); -const { getCurrentUser } = require('../controllers/users.controller'); +const { getCurrentUser, updateCurrentUser } = require('../controllers/users.controller'); +const { updateProfileSchema } = require('../validators/auth.validators'); +const validate = require('../middlewares/validate'); const router = express.Router(); // GET /api/users/me - Get current authenticated user's profile router.get('/me', authenticate, getCurrentUser); -module.exports = router; +// PATCH /api/users/me - Update current authenticated user's profile +router.patch('/me', authenticate, validate(updateProfileSchema), updateCurrentUser); + +module.exports = router; \ No newline at end of file diff --git a/src/validators/auth.validators.js b/src/validators/auth.validators.js index ea8150c..86c1867 100644 --- a/src/validators/auth.validators.js +++ b/src/validators/auth.validators.js @@ -64,6 +64,21 @@ const changePasswordSchema = Joi.object({ }), }); +const updateProfileSchema = Joi.object({ + fullName: Joi.string().min(2).max(100).messages({ + 'string.min': 'Full name must be at least 2 characters long', + 'string.max': 'Full name cannot exceed 100 characters', + }), + walletAddress: Joi.string() + .pattern(/^G[A-Z2-7]{55}$/) + .messages({ + 'string.pattern.base': + 'Wallet address must be a valid Stellar address (starts with G, 56 characters)', + }), +}).min(1).messages({ + 'object.min': 'At least one field (fullName or walletAddress) must be provided', +}); + module.exports = { registerSchema, loginSchema, @@ -71,4 +86,5 @@ module.exports = { forgotPasswordSchema, refreshTokenSchema, changePasswordSchema, -}; + updateProfileSchema, +}; \ No newline at end of file