Initial commit

This commit is contained in:
Lorenzo Sanesi
2026-03-26 22:46:03 +01:00
commit 18e0e04700
80 changed files with 13114 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
const express = require('express');
// Il router è ora una factory function che riceve l'istanza di sequelize
module.exports = (sequelize) => {
const router = express.Router();
// --- Middleware per simulare un utente loggato ---
const { User } = sequelize.models;
const MOCK_USER_NAME = 'Mario Rossi';
let MOCK_USER_ID = null;
router.use(async (req, res, next) => {
if (!MOCK_USER_ID) {
const user = await User.findOne({ where: { name: MOCK_USER_NAME } });
if (user) {
MOCK_USER_ID = user.id;
}
}
req.userId = MOCK_USER_ID;
next();
});
// --- Monta i router da file separati ---
router.use(require('./initial-data.routes')(sequelize));
router.use('/bets', require('./bets.routes')(sequelize));
router.use('/groups', require('./groups.routes')(sequelize));
router.use('/friend-requests', require('./friends.routes')(sequelize));
router.use('/users', require('./users.routes')(sequelize));
return router;
};
+39
View File
@@ -0,0 +1,39 @@
const express = require('express');
const router = express.Router();
// Modello Mongoose per le Scommesse
const Bet = require('../models/bet.model');
// Il router è ora una factory function che riceve l'istanza di sequelize
module.exports = (sequelize) => {
const { populateBetsWithUsers } = require('../utils/populateBets')(sequelize);
// POST /api/bets
router.post('/', async (req, res) => {
try {
const betData = req.body;
// Assicura che gli ID utente dal frontend siano correttamente parsati come interi per lo schema MongoDB
const participants = betData.participants.map(p => ({
...p,
user: parseInt(p.user, 10)
}));
const bet = new Bet({
...betData,
participants,
startDate: new Date(),
status: 'ACTIVE'
});
await bet.save();
// Popola nuovamente la scommessa creata per restituire oggetti utente completi
const populatedMongoBet = await Bet.findById(bet._id);
const finalBet = (await populateBetsWithUsers([populatedMongoBet]))[0];
res.status(201).json(finalBet);
} catch (error) {
res.status(400).json({ message: 'Error creating bet', error: error.message });
}
});
return router;
};
+73
View File
@@ -0,0 +1,73 @@
const express = require('express');
const router = express.Router();
const { Op } = require('sequelize');
module.exports = (sequelize) => {
const { User, Friendship, FriendRequest } = sequelize.models;
// POST /api/friend-requests
router.post('/', async (req, res) => {
try {
const { identifier } = req.body;
const toUser = await User.findOne({ where: { [Op.or]: [{ email: identifier }, { name: identifier }] } });
if (!toUser) return res.status(404).json({ message: 'Utente non trovato.' });
if (toUser.id === req.userId) return res.status(400).json({ message: 'Non puoi aggiungere te stesso.'});
const user1Id = Math.min(req.userId, toUser.id);
const user2Id = Math.max(req.userId, toUser.id);
const friendshipExists = await Friendship.findOne({ where: { user1Id, user2Id } });
if (friendshipExists) return res.status(400).json({ message: 'Siete già amici.'});
const requestExists = await FriendRequest.findOne({
where: { [Op.or]: [{ fromUserId: req.userId, toUserId: toUser.id }, { fromUserId: toUser.id, toUserId: req.userId }] }
});
if (requestExists) return res.status(400).json({ message: 'Richiesta già inviata.'});
const friendRequest = await FriendRequest.create({ fromUserId: req.userId, toUserId: toUser.id });
const populatedReq = await FriendRequest.findByPk(friendRequest.id, {
include: [{ model: User, as: 'fromUser' }, { model: User, as: 'toUser' }]
});
res.status(201).json(populatedReq);
} catch (error) {
res.status(400).json({ message: 'Error sending friend request', error: error.message });
}
});
// POST /api/friend-requests/:id/accept
router.post('/:id/accept', async (req, res) => {
const t = await sequelize.transaction();
try {
const request = await FriendRequest.findByPk(req.params.id, { transaction: t });
if (!request || request.toUserId !== req.userId) {
await t.rollback();
return res.status(404).json({ message: 'Request not found or not for you.' });
}
const user1Id = Math.min(request.fromUserId, request.toUserId);
const user2Id = Math.max(request.fromUserId, request.toUserId);
await Friendship.create({ user1Id, user2Id }, { transaction: t });
await request.destroy({ transaction: t });
await t.commit();
const newFriend = await User.findByPk(request.fromUserId);
res.status(200).json({ message: 'Friend request accepted', newFriend });
} catch (error) {
await t.rollback();
res.status(400).json({ message: 'Error accepting friend request', error: error.message });
}
});
// DELETE /api/friend-requests/:id
router.delete('/:id', async (req, res) => {
try {
const count = await FriendRequest.destroy({ where: { id: req.params.id } });
if (count === 0) return res.status(404).json({ message: 'Request not found.' });
res.status(200).json({ message: 'Friend request cancelled/declined.' });
} catch (error) {
res.status(400).json({ message: 'Error deleting friend request', error: error.message });
}
});
return router;
};
+54
View File
@@ -0,0 +1,54 @@
const express = require('express');
const router = express.Router();
module.exports = (sequelize) => {
const { User, Group } = sequelize.models;
// POST /api/groups
router.post('/', async (req, res) => {
try {
const { name, members } = req.body;
const group = await Group.create({ name });
await group.setMembers(members);
const populatedGroup = await Group.findByPk(group.id, {
include: [{ model: User, as: 'members', through: { attributes: [] } }]
});
res.status(201).json(populatedGroup);
} catch (error) {
res.status(400).json({ message: 'Error creating group', error: error.message });
}
});
// PUT /api/groups/:id/members
router.put('/:id/members', async (req, res) => {
try {
const { userIds } = req.body;
const group = await Group.findByPk(req.params.id);
if (!group) return res.status(404).json({ message: 'Group not found' });
await group.addMembers(userIds);
const populatedGroup = await Group.findByPk(group.id, {
include: [{ model: User, as: 'members', through: { attributes: [] } }]
});
res.json(populatedGroup);
} catch (error) {
res.status(400).json({ message: 'Error adding members to group', error: error.message });
}
});
// DELETE /api/groups/:id/members/:userId
router.delete('/:id/members/:userId', async (req, res) => {
try {
const group = await Group.findByPk(req.params.id);
if (!group) return res.status(404).json({ message: 'Group not found' });
await group.removeMember(req.params.userId);
const populatedGroup = await Group.findByPk(group.id, {
include: [{ model: User, as: 'members', through: { attributes: [] } }]
});
res.json(populatedGroup);
} catch (error) {
res.status(400).json({ message: 'Error removing member from group', error: error.message });
}
});
return router;
};
+32
View File
@@ -0,0 +1,32 @@
const express = require('express');
module.exports = ({ sequelize, mongoose }) => {
const router = express.Router();
router.get('/health', async (req, res) => {
try {
await sequelize.authenticate();
const pgStatus = 'connected';
const mongoStatus =
mongoose.connection.readyState === 1 ? 'connected' : 'disconnected';
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
services: {
postgres: pgStatus,
mongodb: mongoStatus,
},
});
} catch (error) {
res.status(503).json({
status: 'unhealthy',
timestamp: new Date().toISOString(),
error: error.message,
});
}
});
return router;
};
@@ -0,0 +1,59 @@
const express = require('express');
const router = express.Router();
const { Op } = require('sequelize');
// Modello Mongoose per le Scommesse
const Bet = require('../models/bet.model');
module.exports = (sequelize) => {
const { User, Friendship, FriendRequest } = sequelize.models;
const { populateBetsWithUsers } = require('../utils/populateBets')(sequelize);
// GET /api/initial-data
router.get('/initial-data', async (req, res) => {
try {
// --- Query PostgreSQL ---
const currentUser = await User.findByPk(req.userId);
const users = await User.findAll();
const friendships = await Friendship.findAll({
where: { [Op.or]: [{ user1Id: req.userId }, { user2Id: req.userId }] },
include: [{ model: User, as: 'user1' }, { model: User, as: 'user2' }]
});
const friends = friendships.map(f => (f.user1Id === req.userId ? f.user2 : f.user1));
const receivedFriendRequests = await FriendRequest.findAll({
where: { toUserId: req.userId, status: 'PENDING' },
include: [{ model: User, as: 'fromUser' }, { model: User, as: 'toUser' }]
});
const sentFriendRequests = await FriendRequest.findAll({
where: { fromUserId: req.userId, status: 'PENDING' },
include: [{ model: User, as: 'fromUser' }, { model: User, as: 'toUser' }]
});
const userGroups = await currentUser.getGroups({
include: [{ model: User, as: 'members', through: { attributes: [] } }]
});
// --- Query MongoDB ---
const mongoBets = await Bet.find({ 'participants.user': req.userId }).sort({ startDate: -1 });
const mongoPublicBets = await Bet.find({ isPublic: true, 'participants.user': { $ne: req.userId } });
// --- Data Stitching ---
const bets = await populateBetsWithUsers(mongoBets);
const publicBets = await populateBetsWithUsers(mongoPublicBets);
res.json({
currentUser, users, friends, receivedFriendRequests, sentFriendRequests,
bets, publicBets, groups: userGroups
});
} catch (error) {
console.error('Error fetching initial data:', error);
res.status(500).json({ message: 'Error fetching initial data', error: error.message });
}
});
return router;
};
+25
View File
@@ -0,0 +1,25 @@
const express = require('express');
const router = express.Router();
module.exports = (sequelize) => {
const { User } = sequelize.models;
// PUT /api/users/current
router.put('/current', async (req, res) => {
try {
const { name, email } = req.body;
const user = await User.findByPk(req.userId);
if (!user) return res.status(404).json({ message: 'User not found' });
user.name = name;
user.email = email;
await user.save();
res.json(user);
} catch (error) {
res.status(400).json({ message: 'Error updating user', error: error.message });
}
});
return router;
};
+26
View File
@@ -0,0 +1,26 @@
const express = require('express');
const { validate } = require('../../middleware/validation');
const {
createBetSchema,
updateBetSchema,
} = require('../../shared/validators/schemas/bet.schema');
module.exports = ({ betsController }) => {
const router = express.Router();
const controller = {
getAllBets: (req, res, next) => betsController.getAllBets(req, res, next),
getBetById: (req, res, next) => betsController.getBetById(req, res, next),
createBet: (req, res, next) => betsController.createBet(req, res, next),
updateBet: (req, res, next) => betsController.updateBet(req, res, next),
deleteBet: (req, res, next) => betsController.deleteBet(req, res, next),
};
router.get('/', controller.getAllBets);
router.get('/:id', controller.getBetById);
router.post('/', validate(createBetSchema), controller.createBet);
router.put('/:id', validate(updateBetSchema), controller.updateBet);
router.delete('/:id', controller.deleteBet);
return router;
};
+26
View File
@@ -0,0 +1,26 @@
const express = require('express');
const { validate } = require('../../middleware/validation');
const {
sendFriendRequestSchema,
} = require('../../shared/validators/schemas/friendRequest.schema');
module.exports = ({ friendsController }) => {
const router = express.Router();
const controller = {
getFriends: (req, res, next) => friendsController.getFriends(req, res, next),
getPendingRequests: (req, res, next) =>
friendsController.getPendingRequests(req, res, next),
sendRequest: (req, res, next) => friendsController.sendRequest(req, res, next),
acceptRequest: (req, res, next) => friendsController.acceptRequest(req, res, next),
rejectRequest: (req, res, next) => friendsController.rejectRequest(req, res, next),
};
router.get('/', controller.getFriends);
router.get('/pending', controller.getPendingRequests);
router.post('/', validate(sendFriendRequestSchema), controller.sendRequest);
router.post('/:id/accept', controller.acceptRequest);
router.delete('/:id', controller.rejectRequest);
return router;
};
+31
View File
@@ -0,0 +1,31 @@
const express = require('express');
const { validate } = require('../../middleware/validation');
const {
createGroupSchema,
updateGroupSchema,
addMembersSchema,
} = require('../../shared/validators/schemas/group.schema');
module.exports = ({ groupsController }) => {
const router = express.Router();
const controller = {
getAllGroups: (req, res, next) => groupsController.getAllGroups(req, res, next),
getGroupById: (req, res, next) => groupsController.getGroupById(req, res, next),
createGroup: (req, res, next) => groupsController.createGroup(req, res, next),
updateGroup: (req, res, next) => groupsController.updateGroup(req, res, next),
deleteGroup: (req, res, next) => groupsController.deleteGroup(req, res, next),
addMembers: (req, res, next) => groupsController.addMembers(req, res, next),
removeMember: (req, res, next) => groupsController.removeMember(req, res, next),
};
router.get('/', controller.getAllGroups);
router.get('/:id', controller.getGroupById);
router.post('/', validate(createGroupSchema), controller.createGroup);
router.put('/:id', validate(updateGroupSchema), controller.updateGroup);
router.delete('/:id', controller.deleteGroup);
router.put('/:id/members', validate(addMembersSchema), controller.addMembers);
router.delete('/:id/members/:userId', controller.removeMember);
return router;
};
+21
View File
@@ -0,0 +1,21 @@
const express = require('express');
module.exports = (container) => {
const router = express.Router();
const controllers = {
groupsController: container.resolve('groupsController'),
betsController: container.resolve('betsController'),
usersController: container.resolve('usersController'),
friendsController: container.resolve('friendsController'),
initialDataController: container.resolve('initialDataController'),
};
router.use('/groups', require('./groups.routes')(controllers));
router.use('/bets', require('./bets.routes')(controllers));
router.use('/users', require('./users.routes')(controllers));
router.use('/friend-requests', require('./friends.routes')(controllers));
router.use('/initial-data', require('./initialData.routes')(controllers));
return router;
};
@@ -0,0 +1,13 @@
const express = require('express');
module.exports = ({ initialDataController }) => {
const router = express.Router();
const controller = {
getInitialData: (req, res, next) => initialDataController.getInitialData(req, res, next),
};
router.get('/', controller.getInitialData);
return router;
};
+15
View File
@@ -0,0 +1,15 @@
const express = require('express');
const { validate } = require('../../middleware/validation');
const { updateUserSchema } = require('../../shared/validators/schemas/user.schema');
module.exports = ({ usersController }) => {
const router = express.Router();
const controller = {
updateCurrentUser: (req, res, next) => usersController.updateCurrentUser(req, res, next),
};
router.put('/current', validate(updateUserSchema), controller.updateCurrentUser);
return router;
};