Files
freeplanet_serverside/src/routes/viaggiRoutes.js
2025-12-30 11:36:42 +01:00

1053 lines
29 KiB
JavaScript

const express = require('express');
const router = express.Router();
const path = require('path');
const multer = require('multer');
const fs = require('fs');
const tools = require('../tools/general');
const { Contribtype } = require('../models/contribtype'); // Adatta al tuo path
// Import Controllers
const rideController = require('../controllers/rideController');
const rideRequestController = require('../controllers/rideRequestController');
const chatController = require('../controllers/chatController');
const feedbackController = require('../controllers/feedbackController');
// const geocodingController = require('../controllers/geocodingController');
const geoRoutes = require('./geoRoutes'); // 👈 Importa geoRoutes
router.use('/geo', geoRoutes); // 👈 Monta come sub-router
// Middleware di autenticazione (usa il tuo esistente)
const { authenticate } = require('../middleware/authenticate');
// ============================================================
// 🚗 RIDES - Gestione Viaggi
// ============================================================
/**
* @route POST /api/viaggi/rides
* @desc Crea nuovo viaggio (offerta o richiesta)
* @access Private
*/
router.post('/rides', authenticate, rideController.createRide);
/**
* @route GET /api/viaggi/rides
* @desc Ottieni lista viaggi con filtri
* @access Public
*/
router.get('/rides', rideController.getRides);
/**
* @route GET /api/viaggi/rides/search
* @desc Ricerca viaggi avanzata
* @access Public
*/
router.get('/rides/search', rideController.searchRides);
/**
* @route GET /api/viaggi/rides/stats
* @desc Statistiche per widget homepage
* @access Private
*/
router.get('/rides/stats', authenticate, rideController.getRidesStats);
/**
* @route GET /api/viaggi/rides/my
* @desc I miei viaggi (come driver e passenger)
* @access Private
*/
router.get('/rides/my', authenticate, rideController.getMyRides);
/**
* @route GET /api/viaggi/rides/match
* @desc Match automatico offerta/richiesta
* @access Private
* @note ⚠️ IMPORTANTE: Questa route DEVE stare PRIMA di /rides/:id
*/
//router.get('/rides/match', authenticate, rideController.findMatches);
router.get('/rides/cancelled', authenticate, rideController.getCancelledRides);
router.get('/rides/statscomm', authenticate, rideController.getCommunityStatsComm);
router.get('/rides/community', authenticate, rideController.getCommunityRides);
router.get('/rides/calendar', authenticate, rideController.getCalendarRides);
/**
* @route POST /api/viaggi/rides/:rideId/request
* @desc Richiedi posto su un viaggio
* @access Private
*/
router.post('/rides/:rideId/request', authenticate, rideRequestController.createRequestFromRide);
/**
* @route GET /api/viaggi/rides/:id
* @desc Dettaglio singolo viaggio
* @access Public
*/
router.get('/rides/:id', rideController.getRideById);
/**
* @route PUT /api/viaggi/rides/:id
* @desc Aggiorna viaggio
* @access Private (solo owner)
*/
router.put('/rides/:id', authenticate, rideController.updateRide);
/**
* @route DELETE /api/viaggi/rides/:id
* @desc Cancella viaggio
* @access Private (solo owner)
*/
router.delete('/rides/:id', authenticate, rideController.deleteRide);
/**
* @route POST /api/viaggi/rides/:id/complete
* @desc Completa un viaggio
* @access Private (solo driver)
*/
router.post('/rides/:id/complete', authenticate, rideController.completeRide);
router.post('/rides/:rideId/favorite', authenticate, rideController.toggleFavoriteRide);
// ============================================================
// 📊 WIDGET & STATS
// ============================================================
/**
* @route GET /api/viaggi/widget/data
* @desc Dati completi per widget homepage
* @access Private
*/
router.get('/widget/data', authenticate, rideController.getWidgetData);
/**
* @route GET /api/viaggi/cities/suggestions
* @desc Suggerimenti città per autocomplete (basato su viaggi esistenti)
* @access Public
*/
router.get('/cities/suggestions', rideController.getCitySuggestions);
/**
* @route GET /api/viaggi/cities/recents
* @desc città recenti per autocomplete
* @access Public
*/
router.get('/cities/recent', authenticate, rideController.getRecentCities);
// ============================================================
// 📩 REQUESTS - Richieste Passaggio
// ============================================================
/**
* @route POST /api/viaggi/requests
* @desc Crea richiesta passaggio per un viaggio
* @access Private
*/
router.post('/requests', authenticate, rideRequestController.createRequest);
// ⚠️ IMPORTANTE: Route specifiche PRIMA di quelle con :id
/**
* @route GET /api/viaggi/requests/received
* @desc Richieste ricevute (sono conducente)
* @access Private
*/
router.get('/requests/received', authenticate, rideRequestController.getReceivedRequests);
/**
* @route GET /api/viaggi/requests/sent
* @desc Richieste inviate (sono passeggero)
* @access Private
*/
router.get('/requests/sent', authenticate, rideRequestController.getSentRequests);
/**
* @route GET /api/viaggi/requests/pending
* @desc Richieste pendenti (per il conducente)
* @access Private
*/
router.get('/requests/pending', authenticate, rideRequestController.getPendingRequests);
/**
* @route GET /api/viaggi/requests/my
* @desc Le mie richieste (come passeggero)
* @access Private
*/
router.get('/requests/my', authenticate, rideRequestController.getMyRequests);
/**
* @route GET /api/viaggi/requests/ride/:rideId
* @desc Richieste per un viaggio specifico
* @access Private (solo owner del viaggio)
*/
router.get('/requests/ride/:rideId', authenticate, rideRequestController.getRequestsForRide);
// ⚠️ Route con :id DOPO tutte le route specifiche
/**
* @route GET /api/viaggi/requests/:id
* @desc Dettaglio singola richiesta
* @access Private (driver o passenger)
*/
router.get('/requests/:id', authenticate, rideRequestController.getRequestById);
/**
* @route POST /api/viaggi/requests/:id/accept
* @desc Accetta richiesta passaggio
* @access Private (solo driver)
*/
router.post('/requests/:id/accept', authenticate, rideRequestController.acceptRequest);
/**
* @route POST /api/viaggi/requests/:id/reject
* @desc Rifiuta richiesta passaggio
* @access Private (solo driver)
*/
router.post('/requests/:id/reject', authenticate, rideRequestController.rejectRequest);
/**
* @route POST /api/viaggi/requests/:id/cancel
* @desc Cancella richiesta/prenotazione
* @access Private (driver o passenger)
*/
router.post('/requests/:id/cancel', authenticate, rideRequestController.cancelRequest);
// ============================================================
// 💬 CHAT - Messaggistica
// ============================================================
/**
* @route GET /api/viaggi/chats
* @desc Lista tutte le mie chat
* @access Private
*/
router.get('/chats', authenticate, chatController.getUserChats);
/**
* @route GET /api/viaggi/chats/unread/count
* @desc Conta messaggi non letti totali
* @access Private
*/
router.get('/chats/unread/count', authenticate, chatController.getUnreadCount);
/**
* @route POST /api/viaggi/chats/direct
* @desc Ottieni o crea chat diretta con utente
* @access Private
*/
router.post('/chats/direct', authenticate, chatController.getOrCreateDirectChat);
/**
* @route GET /api/viaggi/chats/:id
* @desc Dettaglio chat
* @access Private (solo partecipanti)
*/
router.get('/chats/:chatId', authenticate, chatController.getChatById);
/**
* @route GET /api/viaggi/chats/:id/messages
* @desc Messaggi di una chat
* @access Private (solo partecipanti)
*/
router.get('/chats/:chatId/messages', authenticate, chatController.getChatMessages);
/**
* @route POST /api/viaggi/chats/:id/messages
* @desc Invia messaggio
* @access Private (solo partecipanti)
*/
router.post('/chats/:chatId/messages', authenticate, chatController.sendMessage);
/**
* @route PUT /api/viaggi/chats/:id/read
* @desc Segna chat come letta
* @access Private (solo partecipanti)
* @fix Corretto: markAsRead → markChatAsRead
*/
router.put('/chats/:chatId/read', authenticate, chatController.markChatAsRead);
/**
* @route PUT /api/viaggi/chats/:id/block
* @desc Blocca/sblocca chat
* @access Private (solo partecipanti)
*/
router.put('/chats/:chatId/block', authenticate, chatController.toggleBlockChat);
/**
* @route PUT /api/viaggi/chats/:id/mute
* @desc Muta/smuta notifiche di una chat
* @access Private (solo partecipanti)
* @fix Aggiunta route mancante
*/
router.put('/chats/:chatId/mute', authenticate, chatController.toggleMuteChat);
/**
* @route DELETE /api/viaggi/chats/:chatId/messages/:messageId
* @desc Elimina messaggio
* @access Private (solo mittente)
* @fix Corretto: /messages/:id → /chats/:chatId/messages/:messageId
*/
router.delete('/chats/:chatId/messages/:messageId', authenticate, chatController.deleteMessage);
/**
* @route DELETE /api/viaggi/chats/:id
* @desc Elimina chat (soft delete)
* @access Private (solo partecipanti)
*/
router.delete('/chats/:chatId', authenticate, chatController.deleteChat);
// ============================================================
// ⭐ FEEDBACK - Recensioni
// ============================================================
/**
* @route POST /api/viaggi/feedback
* @desc Crea feedback per un viaggio
* @access Private
*/
router.post('/feedback', authenticate, feedbackController.createFeedback);
/**
* @route GET /api/viaggi/feedback/my/received
* @desc I miei feedback ricevuti
* @access Private
*/
router.get('/feedback/my/received', authenticate, feedbackController.getMyReceivedFeedbacks);
/**
* @route GET /api/viaggi/feedback/my/given
* @desc I miei feedback lasciati
* @access Private
*/
router.get('/feedback/my/given', authenticate, feedbackController.getMyGivenFeedbacks);
/**
* @route GET /api/viaggi/feedback/user/:userId
* @desc Feedback di un utente
* @access Public
*/
router.get('/feedback/user/:userId', feedbackController.getFeedbacksForUser);
/**
* @route GET /api/viaggi/feedback/user/:userId/stats
* @desc Statistiche feedback utente
* @access Public
*/
router.get('/feedback/user/:userId/stats', feedbackController.getUserFeedbackStats);
/**
* @route GET /api/viaggi/feedback/ride/:rideId
* @desc Feedback per un viaggio
* @access Public
*/
router.get('/feedback/ride/:rideId', feedbackController.getRideFeedback);
/**
* @route GET /api/viaggi/feedback/can-leave/:rideId/:toUserId
* @desc Verifica se posso lasciare feedback
* @access Private
*/
router.get('/feedback/can-leave/:rideId/:toUserId', authenticate, feedbackController.canLeaveFeedback);
/**
* @route POST /api/viaggi/feedback/:id/response
* @desc Rispondi a un feedback
* @access Private (solo destinatario)
*/
router.post('/feedback/:id/response', authenticate, feedbackController.respondToFeedback);
/**
* @route POST /api/viaggi/feedback/:id/report
* @desc Segnala feedback
* @access Private
*/
router.post('/feedback/:id/report', authenticate, feedbackController.reportFeedback);
/**
* @route POST /api/viaggi/feedback/:id/helpful
* @desc Segna feedback come utile
* @access Private
*/
router.post('/feedback/:id/helpful', authenticate, feedbackController.markAsHelpful);
// ============================================================
// 🗺️ GEO - Geocoding & Mappe (Open Source)
// ============================================================
// /* /**
// * @route GET /api/viaggi/geo/autocomplete
// * @desc Autocomplete città (Photon)
// * @access Public
// */
// router.get('/geo/autocomplete', geocodingController.autocomplete);
// /**
// * @route GET /api/viaggi/geo/cities/it
// * @desc Cerca città italiane
// * @access Public
// */
// router.get('/geo/cities/it', geocodingController.searchItalianCities);
// /**
// * @route GET /api/viaggi/geo/geocode
// * @desc Indirizzo → Coordinate
// * @access Public
// */
// router.get('/geo/geocode', geocodingController.geocode);
// /**
// * @route GET /api/viaggi/geo/reverse
// * @desc Coordinate → Indirizzo
// * @access Public
// */
// router.get('/geo/reverse', geocodingController.reverseGeocode);
// /**
// * @route GET /api/viaggi/geo/route
// * @desc Calcola percorso tra punti
// * @access Public
// */
// router.get('/geo/route', geocodingController.getRoute);
// /**
// * @route GET /api/viaggi/geo/distance
// * @desc Calcola distanza e durata
// * @access Public
// */
// router.get('/geo/distance', geocodingController.getDistance);
// /**
// * @route GET /api/viaggi/geo/suggest-waypoints
// * @desc Suggerisci città intermedie sul percorso
// * @access Public
// */
// router.get('/geo/suggest-waypoints', geocodingController.suggestWaypoints);
/// ============================================================
// 🔧 UTILITY & DRIVER PROFILE
// ============================================================
/**
* @route GET /api/viaggi/driver/user/:userId
* @desc Profilo pubblico del conducente
* @access Public
*/
router.get('/driver/user/:userId', async (req, res) => {
try {
const { userId } = req.params;
const idapp = req.query.idapp;
const { User } = require('../models/user');
const Ride = require('../models/viaggi/Ride');
const Feedback = require('../models/viaggi/Feedback');
// Dati utente
const user = await User.findById(userId).select(
'username name surname profile.img profile.Biografia profile.driverProfile profile.preferences.languages'
);
if (!user) {
return res.status(404).json({
success: false,
message: 'Utente non trovato',
});
}
// Statistiche viaggi
const [ridesAsDriver, ridesAsPassenger, completedRides] = await Promise.all([
Ride.countDocuments({ idapp, userId, type: 'offer' }),
Ride.countDocuments({ idapp, 'confirmedPassengers.userId': userId }),
Ride.countDocuments({ idapp, userId, status: 'completed' }),
]);
// Ultimi viaggi come driver
const recentRides = await Ride.find({
idapp,
userId,
type: 'offer',
status: { $in: ['active', 'completed'] },
})
.select('departure destination departureDate status')
.sort({ departureDate: -1 })
.limit(5);
// Statistiche feedback
let feedbackStats = { averageRating: 0, totalFeedback: 0 };
try {
feedbackStats = await Feedback.getStatsForUser(idapp, userId);
} catch (e) {
console.log('Feedback stats non disponibili');
}
// Ultimi feedback ricevuti
let recentFeedback = [];
try {
recentFeedback = await Feedback.find({
idapp,
toUserId: userId,
isPublic: true,
})
.populate('fromUserId', 'username name profile.img')
.sort({ createdAt: -1 })
.limit(3);
} catch (e) {
console.log('Recent feedback non disponibili');
}
res.status(200).json({
success: true,
data: {
user: {
_id: user._id,
username: user.username,
name: user.name,
surname: user.surname,
img: user.profile?.img,
bio: user.profile?.Biografia,
driverProfile: user.profile?.driverProfile,
languages: user.profile?.preferences?.languages,
},
stats: {
ridesAsDriver,
ridesAsPassenger,
completedRides,
...feedbackStats,
},
recentRides,
recentFeedback,
},
});
} catch (error) {
console.error('Errore recupero profilo driver:', error);
res.status(500).json({
success: false,
message: 'Errore durante il recupero del profilo',
error: error.message,
});
}
});
/**
* @route GET /api/viaggi/driver/vehicles
* @desc Ottieni veicoli dell'utente corrente
* @access Private
*/
router.get('/driver/vehicles', authenticate, async (req, res) => {
try {
const idapp = req.user.idapp;
const userId = req.user._id; // Assumo che ci sia un middleware di autenticazione
if (!userId) {
return res.status(401).json({
success: false,
message: 'Autenticazione richiesta',
});
}
const { User } = require('../models/user');
const user = await User.findById(userId).select('profile.driverProfile.vehicles');
const vehicles = user?.profile?.driverProfile?.vehicles || [];
res.status(200).json({
success: true,
data: vehicles,
});
} catch (error) {
console.error('Errore recupero veicoli:', error);
res.status(500).json({
success: false,
message: 'Errore durante il recupero dei veicoli',
error: error.message,
});
}
});
/**
* @route PUT /api/viaggi/driver/profile
* @desc Aggiorna profilo conducente
* @access Private
*/
router.put('/driver/profile', authenticate, async (req, res) => {
try {
const userId = req.user._id;
const { idapp, driverProfile, preferences } = req.body;
const { User } = require('../models/user');
const updateData = {};
if (driverProfile) {
// Merge con dati esistenti
Object.keys(driverProfile).forEach((key) => {
updateData[`profile.driverProfile.${key}`] = driverProfile[key];
});
}
if (preferences) {
Object.keys(preferences).forEach((key) => {
updateData[`profile.preferences.${key}`] = preferences[key];
});
}
const user = await User.findByIdAndUpdate(userId, { $set: updateData }, { new: true }).select(
'profile.driverProfile profile.preferences'
);
res.status(200).json({
success: true,
message: 'Profilo aggiornato',
data: user.profile,
});
} catch (error) {
console.error('Errore aggiornamento profilo:', error);
res.status(500).json({
success: false,
message: "Errore durante l'aggiornamento",
error: error.message,
});
}
});
/**
* @route POST /api/viaggi/driver/vehicles
* @desc Aggiungi veicolo
* @access Private
*/
router.post('/driver/vehicles', authenticate, async (req, res) => {
try {
const userId = req.user._id;
const vehicle = req.body.vehicle ? req.body.vehicle : req.body;
const { User } = require('../models/user');
const user = await User.findByIdAndUpdate(
userId,
{
$push: { 'profile.driverProfile.vehicles': vehicle },
$set: { 'profile.driverProfile.isDriver': true },
},
{ new: true }
).select('profile.driverProfile.vehicles');
res.status(201).json({
success: true,
message: 'Veicolo aggiunto',
data: user.profile.driverProfile.vehicles,
});
} catch (error) {
console.error('Errore aggiunta veicolo:', error);
res.status(500).json({
success: false,
message: "Errore durante l'aggiunta del veicolo",
error: error.message,
});
}
});
/**
* @route PUT /api/viaggi/driver/vehicles/:vehicleId
* @desc Aggiorna veicolo
* @access Private
*/
router.put('/driver/vehicles/:vehicleId', authenticate, async (req, res) => {
try {
const userId = req.user._id;
const { vehicleId } = req.params;
const vehicle = req.body;
const { User } = require('../models/user');
const user = await User.findOneAndUpdate(
{
_id: userId,
'profile.driverProfile.vehicles._id': vehicleId,
},
{
$set: { 'profile.driverProfile.vehicles.$': { ...vehicle, _id: vehicleId } },
},
{ new: true }
).select('profile.driverProfile.vehicles');
if (!user) {
return res.status(404).json({
success: false,
message: 'Veicolo non trovato',
});
}
res.status(200).json({
success: true,
message: 'Veicolo aggiornato',
data: user.profile.driverProfile.vehicles,
});
} catch (error) {
console.error('Errore aggiornamento veicolo:', error);
res.status(500).json({
success: false,
message: "Errore durante l'aggiornamento",
error: error.message,
});
}
});
/**
* @route GET /api/viaggi/driver/vehicles/:vehicleId
* @desc Ottieni dettagli di un veicolo specifico
* @access Private
*/
router.get('/driver/vehicles/:vehicleId', authenticate, async (req, res) => {
try {
const userId = req.user._id;
const { vehicleId } = req.params;
const { User } = require('../models/user');
const user = await User.findOne({
_id: userId,
'profile.driverProfile.vehicles._id': vehicleId,
}).select('profile.driverProfile.vehicles');
if (!user) {
return res.status(404).json({
success: false,
message: 'Veicolo non trovato',
});
}
// Trova il veicolo specifico nell'array
const vehicle = user.profile.driverProfile.vehicles.find((v) => v._id.toString() === vehicleId);
if (!vehicle) {
return res.status(404).json({
success: false,
message: 'Veicolo non trovato',
});
}
res.status(200).json({
success: true,
data: vehicle,
});
} catch (error) {
console.error('Errore recupero veicolo:', error);
res.status(500).json({
success: false,
message: 'Errore durante il recupero del veicolo',
error: error.message,
});
}
});
/**
* @route DELETE /api/viaggi/driver/vehicles/:vehicleId
* @desc Rimuovi veicolo
* @access Private
*/
router.delete('/driver/vehicles/:vehicleId', authenticate, async (req, res) => {
try {
const userId = req.user._id;
const { vehicleId } = req.params;
const { User } = require('../models/user');
await User.findByIdAndUpdate(userId, {
$pull: { 'profile.driverProfile.vehicles': { _id: vehicleId } },
});
res.status(200).json({
success: true,
message: 'Veicolo rimosso',
});
} catch (error) {
console.error('Errore rimozione veicolo:', error);
res.status(500).json({
success: false,
message: 'Errore durante la rimozione',
error: error.message,
});
}
});
/**
* @route POST /api/viaggi/driver/vehicles/:vehicleId/default
* @desc Imposta veicolo come predefinito
* @access Private
*/
router.post('/driver/vehicles/:vehicleId/default', authenticate, async (req, res) => {
try {
const userId = req.user._id;
const { vehicleId } = req.params;
const { User } = require('../models/user');
// Prima rimuovi isDefault da tutti
await User.updateOne({ _id: userId }, { $set: { 'profile.driverProfile.vehicles.$[].isDefault': false } });
// Poi imposta quello selezionato
await User.updateOne(
{ _id: userId, 'profile.driverProfile.vehicles._id': vehicleId },
{ $set: { 'profile.driverProfile.vehicles.$.isDefault': true } }
);
res.status(200).json({
success: true,
message: 'Veicolo predefinito impostato',
});
} catch (error) {
console.error('Errore impostazione default:', error);
res.status(500).json({
success: false,
message: "Errore durante l'operazione",
error: error.message,
});
}
});
// ============================================================
// 📊 CONTRIB TYPES - Tipi di Contributo
// ============================================================
/**
* @route GET /api/viaggi/contrib-types
* @desc Lista tipi di contributo disponibili
* @access Public
*/
router.get('/contrib-types', async (req, res) => {
try {
const idapp = req.query.idapp;
const contribTypes = await Contribtype.find({ idapp });
res.status(200).json({
success: true,
data: contribTypes,
});
} catch (error) {
console.error('Errore recupero contrib types:', error);
res.status(500).json({
success: false,
message: 'Errore durante il recupero',
error: error.message,
});
}
});
const vehiclePhotoStorage = multer.diskStorage({
destination: (req, file, cb) => {
const webServerDir = tools.getdirByIdApp(req.user.idapp) + '/upload/vehicles';
if (!fs.existsSync(webServerDir)) {
fs.mkdirSync(webServerDir, { recursive: true });
}
console.log('📁 Destinazione foto veicolo:', webServerDir);
cb(null, webServerDir);
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
const ext = path.extname(file.originalname);
const filename = 'vehicle-' + uniqueSuffix + ext;
console.log('📝 Nome file generato:', filename);
cb(null, filename);
},
});
const uploadVehiclePhoto = multer({
storage: vehiclePhotoStorage,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB
},
fileFilter: (req, file, cb) => {
console.log('🔍 File ricevuto:', {
fieldname: file.fieldname,
originalname: file.originalname,
mimetype: file.mimetype,
});
const allowedMimes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/gif'];
if (allowedMimes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('Solo immagini sono ammesse'), false);
}
},
});
/**
* @route POST /api/viaggi/upload/vehicle-photos
* @desc Upload multiple foto veicolo (max 5)
* @access Private
*/
router.post(
'/upload/vehicle-photos',
authenticate,
(req, res, next) => {
console.log('🚀 Request ricevuta per upload multiple foto veicolo');
next();
},
uploadVehiclePhoto.array('photos', 5),
(err, req, res, next) => {
if (err) {
console.error('❌ Errore multer:', err);
return res.status(400).json({
success: false,
message: err.message || 'Errore durante upload',
});
}
next();
},
async (req, res) => {
try {
console.log('✅ Files ricevuti:', req.files);
if (!req.files || req.files.length === 0) {
return res.status(400).json({
success: false,
message: 'Nessuna foto caricata',
});
}
const photoUrls = req.files.map((file) => `/upload/vehicles/${file.filename}`);
res.status(200).json({
success: true,
message: `${req.files.length} foto caricate con successo`,
data: {
urls: photoUrls,
count: req.files.length,
},
});
} catch (error) {
console.error('❌ Errore upload foto veicolo:', error);
// Elimina tutti i file in caso di errore
if (req.files && req.files.length > 0) {
req.files.forEach((file) => {
if (file.path) {
fs.unlinkSync(file.path);
}
});
}
res.status(500).json({
success: false,
message: "Errore durante l'upload delle foto",
error: error.message,
});
}
}
);
/**
* @route POST /api/viaggi/upload/vehicle-photo
* @desc Upload foto veicolo
* @access Private
*/
router.post(
'/upload/vehicle-photo',
authenticate,
(req, res, next) => {
console.log('🚀 Request ricevuta per upload foto veicolo');
console.log('📋 Headers:', req.headers);
console.log('📦 Body type:', typeof req.body);
next();
},
uploadVehiclePhoto.single('photo'),
(err, req, res, next) => {
// Gestione errori multer
if (err) {
console.error('❌ Errore multer:', err);
return res.status(400).json({
success: false,
message: err.message || 'Errore durante upload',
});
}
next();
},
async (req, res) => {
try {
console.log('✅ File ricevuto:', req.file);
console.log('📄 Body:', req.body);
if (!req.file) {
return res.status(400).json({
success: false,
message: 'Nessuna foto caricata - req.file è undefined',
});
}
const photoUrl = `/upload/vehicles/${req.file.filename}`;
res.status(200).json({
success: true,
message: 'Foto caricata con successo',
data: {
url: photoUrl,
filename: req.file.filename,
},
});
} catch (error) {
console.error('❌ Errore upload foto veicolo:', error);
if (req.file && req.file.path) {
fs.unlinkSync(req.file.path);
}
res.status(500).json({
success: false,
message: "Errore durante l'upload della foto",
error: error.message,
});
}
}
);
/**
* @route DELETE /api/viaggi/upload/vehicle-photo
* @desc Elimina foto veicolo
* @access Private
*/
router.delete('/upload/vehicle-photo', authenticate, async (req, res) => {
try {
const { photoUrl } = req.body;
if (!photoUrl) {
return res.status(400).json({
success: false,
message: 'URL foto non fornito',
});
}
// Estrai il filename dall'URL
const filename = photoUrl.split('/').pop();
const filepath = path.join(vehiclesDir, filename);
// Verifica che il file esista
if (fs.existsSync(filepath)) {
fs.unlinkSync(filepath);
}
res.status(200).json({
success: true,
message: 'Foto eliminata con successo',
});
} catch (error) {
console.error('❌ Errore eliminazione foto:', error);
res.status(500).json({
success: false,
message: "Errore durante l'eliminazione della foto",
error: error.message,
});
}
});
// ============================================
// EXPORT ROUTES
// ============================================
module.exports = router;