const express = require('express'); const { User, UserAddress } = require('../models'); // Import from models/index.js to get models with associations const { authenticateToken } = require('../middleware/auth'); const { uploadProfileImage } = require('../middleware/upload'); const logger = require('../utils/logger'); const userService = require('../services/UserService'); const fs = require('fs').promises; const path = require('path'); const router = express.Router(); router.get('/profile', authenticateToken, async (req, res, next) => { try { const user = await User.findByPk(req.user.id, { attributes: { exclude: ['password'] } }); const reqLogger = logger.withRequestId(req.id); reqLogger.info("User profile fetched", { userId: req.user.id }); res.json(user); } catch (error) { const reqLogger = logger.withRequestId(req.id); reqLogger.error("User profile fetch failed", { error: error.message, stack: error.stack, userId: req.user.id }); next(error); } }); // Address routes (must come before /:id route) router.get('/addresses', authenticateToken, async (req, res, next) => { try { const addresses = await UserAddress.findAll({ where: { userId: req.user.id }, order: [['isPrimary', 'DESC'], ['createdAt', 'ASC']] }); const reqLogger = logger.withRequestId(req.id); reqLogger.info("User addresses fetched", { userId: req.user.id, addressCount: addresses.length }); res.json(addresses); } catch (error) { const reqLogger = logger.withRequestId(req.id); reqLogger.error("User addresses fetch failed", { error: error.message, stack: error.stack, userId: req.user.id }); next(error); } }); router.post('/addresses', authenticateToken, async (req, res, next) => { try { const address = await userService.createUserAddress(req.user.id, req.body); res.status(201).json(address); } catch (error) { const reqLogger = logger.withRequestId(req.id); reqLogger.error("User address creation failed", { error: error.message, stack: error.stack, userId: req.user.id, addressData: logger.sanitize(req.body) }); next(error); } }); router.put('/addresses/:id', authenticateToken, async (req, res, next) => { try { const address = await userService.updateUserAddress(req.user.id, req.params.id, req.body); res.json(address); } catch (error) { const reqLogger = logger.withRequestId(req.id); reqLogger.error("User address update failed", { error: error.message, stack: error.stack, userId: req.user.id, addressId: req.params.id }); if (error.message === 'Address not found') { return res.status(404).json({ error: 'Address not found' }); } next(error); } }); router.delete('/addresses/:id', authenticateToken, async (req, res, next) => { try { await userService.deleteUserAddress(req.user.id, req.params.id); res.status(204).send(); } catch (error) { const reqLogger = logger.withRequestId(req.id); reqLogger.error("User address deletion failed", { error: error.message, stack: error.stack, userId: req.user.id, addressId: req.params.id }); if (error.message === 'Address not found') { return res.status(404).json({ error: 'Address not found' }); } next(error); } }); // User availability routes (must come before /:id route) router.get('/availability', authenticateToken, async (req, res, next) => { try { const user = await User.findByPk(req.user.id, { attributes: ['defaultAvailableAfter', 'defaultAvailableBefore', 'defaultSpecifyTimesPerDay', 'defaultWeeklyTimes'] }); res.json({ generalAvailableAfter: user.defaultAvailableAfter, generalAvailableBefore: user.defaultAvailableBefore, specifyTimesPerDay: user.defaultSpecifyTimesPerDay, weeklyTimes: user.defaultWeeklyTimes }); } catch (error) { next(error); } }); router.put('/availability', authenticateToken, async (req, res, next) => { try { const { generalAvailableAfter, generalAvailableBefore, specifyTimesPerDay, weeklyTimes } = req.body; await User.update({ defaultAvailableAfter: generalAvailableAfter, defaultAvailableBefore: generalAvailableBefore, defaultSpecifyTimesPerDay: specifyTimesPerDay, defaultWeeklyTimes: weeklyTimes }, { where: { id: req.user.id } }); res.json({ message: 'Availability updated successfully' }); } catch (error) { next(error); } }); router.get('/:id', async (req, res, next) => { try { const user = await User.findByPk(req.params.id, { attributes: { exclude: ['password', 'email', 'phone', 'address'] } }); if (!user) { return res.status(404).json({ error: 'User not found' }); } const reqLogger = logger.withRequestId(req.id); reqLogger.info("Public user profile fetched", { requestedUserId: req.params.id }); res.json(user); } catch (error) { const reqLogger = logger.withRequestId(req.id); reqLogger.error("Public user profile fetch failed", { error: error.message, stack: error.stack, requestedUserId: req.params.id }); next(error); } }); router.put('/profile', authenticateToken, async (req, res, next) => { try { // Use UserService to handle update and email notification const updatedUser = await userService.updateProfile(req.user.id, req.body); res.json(updatedUser); } catch (error) { console.error('Profile update error:', error); next(error); } }); // Upload profile image endpoint router.post('/profile/image', authenticateToken, (req, res) => { uploadProfileImage(req, res, async (err) => { if (err) { const reqLogger = logger.withRequestId(req.id); reqLogger.error("Profile image upload error", { error: err.message, userId: req.user.id }); return res.status(400).json({ error: err.message }); } if (!req.file) { return res.status(400).json({ error: 'No file uploaded' }); } try { // Delete old profile image if exists const user = await User.findByPk(req.user.id); if (user.imageFilename) { const oldImagePath = path.join(__dirname, '../uploads/profiles', user.imageFilename); try { await fs.unlink(oldImagePath); } catch (unlinkErr) { const reqLogger = logger.withRequestId(req.id); reqLogger.warn("Error deleting old profile image", { error: unlinkErr.message, userId: req.user.id, oldImagePath }); } } // Update user with new image filename await user.update({ imageFilename: req.file.filename }); const reqLogger = logger.withRequestId(req.id); reqLogger.info("Profile image uploaded successfully", { userId: req.user.id, filename: req.file.filename }); res.json({ message: 'Profile image uploaded successfully', filename: req.file.filename, imageUrl: `/uploads/profiles/${req.file.filename}` }); } catch (error) { const reqLogger = logger.withRequestId(req.id); reqLogger.error("Profile image database update failed", { error: error.message, stack: error.stack, userId: req.user.id }); res.status(500).json({ error: 'Failed to update profile image' }); } }); }); module.exports = router;