Skip to content

Commit e1961b8

Browse files
authored
Merge pull request #134 from RustyRory/feat/133-dashboard-admin
feat(backoffice): Fixes #133 - Dashboard Admin
2 parents 07767a4 + 1241a7b commit e1961b8

60 files changed

Lines changed: 11131 additions & 408 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

saintBarthVolleyApp/backend/package-lock.json

Lines changed: 23 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

saintBarthVolleyApp/backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"bcrypt": "^6.0.0",
2020
"chalk": "^5.6.2",
2121
"cheerio": "^1.2.0",
22+
"cookie-parser": "^1.4.7",
2223
"cors": "^2.8.5",
2324
"dotenv": "^17.2.3",
2425
"express": "^5.2.1",

saintBarthVolleyApp/backend/src/app.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
import express from 'express';
33
import cors from 'cors';
44
import dotenv from 'dotenv';
5+
import cookieParser from 'cookie-parser';
56
dotenv.config();
67

78
// Création de l'application Express
89
const app = express();
910

11+
// Middlewares
12+
app.use(cookieParser());
13+
app.use(express.json());
14+
1015
// Middlewares
1116
app.use(
1217
cors({

saintBarthVolleyApp/backend/src/controllers/usersController.js

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,51 @@
11
import User from '../models/User.js';
22

3-
// GET all users
3+
// GET /api/users
44
export const getAllUsers = async (req, res) => {
55
try {
6-
const users = await User.find().select('-passwordHash'); // Ne jamais renvoyer les passwords
6+
const users = await User.find().select('-passwordHash');
77
res.json(users);
88
} catch (err) {
9-
res.status(500).json({ message: err.message });
9+
console.error('GET ALL USERS ERROR:', err);
10+
res.status(500).json({ message: 'Erreur serveur' });
1011
}
1112
};
1213

13-
// GET single user
1414
export const getUserById = async (req, res) => {
1515
try {
1616
const user = await User.findById(req.params.id).select('-passwordHash');
17-
if (!user) return res.status(404).json({ message: 'User not found' });
17+
if (!user) return res.status(404).json({ message: 'Utilisateur introuvable' });
1818
res.json(user);
1919
} catch (err) {
20-
res.status(500).json({ message: err.message });
20+
console.error('GET USER ERROR:', err);
21+
res.status(500).json({ message: 'Erreur serveur' });
2122
}
2223
};
2324

24-
// POST create user
2525
export const createUser = async (req, res) => {
2626
try {
27-
const { email, password, role, firstName, lastName } = req.body;
28-
const user = new User({ email, role, firstName, lastName });
29-
await user.setPassword(password);
27+
const { email, firstName, lastName, role } = req.body;
28+
const user = new User({ email, firstName, lastName, role });
3029
await user.save();
31-
res.status(201).json({ message: 'User created', userId: user._id });
30+
res.status(201).json(user);
3231
} catch (err) {
33-
res.status(400).json({ message: err.message });
32+
res.status(500).json({ message: err.message });
3433
}
3534
};
3635

37-
// PUT update user
3836
export const updateUser = async (req, res) => {
3937
try {
40-
const { email, role, firstName, lastName, isActive, password } = req.body;
41-
const user = await User.findById(req.params.id);
42-
if (!user) return res.status(404).json({ message: 'User not found' });
43-
44-
if (email) user.email = email;
45-
if (role) user.role = role;
46-
if (firstName) user.firstName = firstName;
47-
if (lastName) user.lastName = lastName;
48-
if (isActive !== undefined) user.isActive = isActive;
49-
if (password) await user.setPassword(password);
50-
51-
await user.save();
52-
res.json({ message: 'User updated' });
38+
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true }).select('-passwordHash');
39+
res.json(user);
5340
} catch (err) {
54-
res.status(400).json({ message: err.message });
41+
res.status(500).json({ message: err.message });
5542
}
5643
};
5744

58-
// DELETE user
5945
export const deleteUser = async (req, res) => {
6046
try {
61-
const user = await User.findByIdAndDelete(req.params.id);
62-
if (!user) return res.status(404).json({ message: 'User not found' });
63-
res.json({ message: 'User deleted' });
47+
await User.findByIdAndDelete(req.params.id);
48+
res.json({ message: 'Utilisateur supprimé' });
6449
} catch (err) {
6550
res.status(500).json({ message: err.message });
6651
}

saintBarthVolleyApp/backend/src/middlewares/authMiddleware.js

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,26 @@ import User from '../models/User.js';
77
*/
88
export const authMiddleware = async (req, res, next) => {
99
try {
10-
const authHeader = req.headers.authorization;
10+
let token;
1111

12-
// Vérification présence header
13-
if (!authHeader || !authHeader.startsWith('Bearer ')) {
14-
return res.status(401).json({ message: 'Token manquant ou invalide' });
12+
// 1️⃣ Header Authorization
13+
if (req.headers.authorization?.startsWith('Bearer ')) {
14+
token = req.headers.authorization.split(' ')[1];
1515
}
1616

17-
const token = authHeader.split(' ')[1];
17+
// 2️⃣ Cookie httpOnly
18+
if (!token && req.cookies?.token) {
19+
token = req.cookies.token;
20+
}
1821

19-
// Vérification du token
20-
const decoded = jwt.verify(token, process.env.JWT_SECRET);
22+
if (!token) return res.status(401).json({ message: 'Token manquant' });
2123

22-
// Récupération utilisateur
24+
const decoded = jwt.verify(token, process.env.JWT_SECRET);
2325
const user = await User.findById(decoded.id).select('-passwordHash');
2426

25-
if (!user) {
26-
return res.status(401).json({ message: 'Utilisateur introuvable' });
27-
}
28-
29-
// Compte désactivé
30-
if (!user.isActive) {
31-
return res.status(403).json({ message: 'Compte désactivé' });
32-
}
27+
if (!user) return res.status(401).json({ message: 'Utilisateur introuvable' });
28+
if (!user.isActive) return res.status(403).json({ message: 'Compte désactivé' });
3329

34-
// Injection user dans la requête
3530
req.user = user;
3631
next();
3732
} catch (err) {

saintBarthVolleyApp/backend/src/routes/auth.js

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -49,55 +49,41 @@ router.post('/register', async (req, res) => {
4949
* POST /auth/login
5050
* Connexion utilisateur
5151
*/
52+
5253
router.post('/login', async (req, res) => {
5354
try {
5455
const { email, password } = req.body;
55-
56-
if (!email || !password) {
57-
return res.status(400).json({ message: 'Email ou mot de passe manquant' });
58-
}
56+
if (!email || !password) return res.status(400).json({ message: 'Email ou mot de passe manquant' });
5957

6058
const user = await User.findOne({ email });
61-
if (!user) {
62-
return res.status(401).json({ message: 'Identifiants invalides' });
63-
}
64-
65-
// Compte non validé par l’admin
66-
if (!user.isActive) {
67-
return res.status(403).json({
68-
message: 'Compte non activé. Contactez un administrateur.',
69-
});
70-
}
59+
if (!user) return res.status(401).json({ message: 'Identifiants invalides' });
60+
if (!user.isActive) return res.status(403).json({ message: 'Compte non activé' });
7161

7262
const isPasswordValid = await user.comparePassword(password);
73-
if (!isPasswordValid) {
74-
return res.status(401).json({ message: 'Identifiants invalides' });
75-
}
63+
if (!isPasswordValid) return res.status(401).json({ message: 'Identifiants invalides' });
7664

77-
// Mise à jour last login
7865
user.lastLoginAt = new Date();
7966
await user.save();
8067

81-
// Génération JWT
82-
const token = jwt.sign(
83-
{
84-
id: user._id,
85-
role: user.role,
86-
},
87-
process.env.JWT_SECRET,
88-
{ expiresIn: '1d' },
89-
);
90-
91-
res.json({
92-
token,
93-
user: {
94-
id: user._id,
95-
email: user.email,
96-
role: user.role,
97-
firstName: user.firstName,
98-
lastName: user.lastName,
99-
},
100-
});
68+
const token = jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '1d' });
69+
70+
// 🔹 Stockage cookie httpOnly
71+
res
72+
.cookie('token', token, {
73+
httpOnly: true,
74+
secure: process.env.NODE_ENV === 'production',
75+
sameSite: 'lax', // 'strict' bloque localhost
76+
maxAge: 24 * 60 * 60 * 1000,
77+
})
78+
.json({
79+
user: {
80+
id: user._id,
81+
email: user.email,
82+
role: user.role,
83+
firstName: user.firstName,
84+
lastName: user.lastName,
85+
},
86+
});
10187
} catch (err) {
10288
console.error('LOGIN ERROR:', err);
10389
res.status(500).json({ message: 'Erreur serveur' });
Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
import express from 'express';
22
import * as usersController from '../controllers/usersController.js';
3+
import { authMiddleware, requireRole } from '../middlewares/authMiddleware.js';
4+
35
const router = express.Router();
46

5-
// Routes CRUD utilisateurs
6-
router.get('/', usersController.getAllUsers);
7-
router.get('/:id', usersController.getUserById);
8-
router.post('/', usersController.createUser);
9-
router.put('/:id', usersController.updateUser);
10-
router.delete('/:id', usersController.deleteUser);
7+
// 🔹 Toutes les routes sont protégées
8+
router.use(authMiddleware);
9+
10+
// GET /api/users => liste tous les utilisateurs (admin uniquement)
11+
router.get('/', requireRole('admin'), usersController.getAllUsers);
12+
13+
// GET /api/users/:id => voir un utilisateur (admin/éditeur)
14+
router.get('/:id', requireRole('admin', 'editor'), usersController.getUserById);
15+
16+
// POST /api/users => créer un utilisateur (admin uniquement)
17+
router.post('/', requireRole('admin'), usersController.createUser);
18+
19+
// PUT /api/users/:id => modifier un utilisateur (admin uniquement)
20+
router.put('/:id', requireRole('admin'), usersController.updateUser);
21+
22+
// DELETE /api/users/:id => supprimer un utilisateur (admin uniquement)
23+
router.delete('/:id', requireRole('admin'), usersController.deleteUser);
1124

1225
export default router;

saintBarthVolleyApp/frontend/.next/dev/build-manifest.json

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
11
{
22
"pages": {
3-
"/_app": []
3+
"/_app": [
4+
"static/chunks/node_modules_next_dist_compiled_8ca6b690._.js",
5+
"static/chunks/node_modules_next_dist_shared_lib_8bac8163._.js",
6+
"static/chunks/node_modules_next_dist_client_5a8a528e._.js",
7+
"static/chunks/node_modules_next_dist_b3fb3b5f._.js",
8+
"static/chunks/node_modules_next_app_72f3d36f.js",
9+
"static/chunks/[next]_entry_page-loader_ts_742e4b53._.js",
10+
"static/chunks/node_modules_react-dom_4411d9bd._.js",
11+
"static/chunks/node_modules_7f09fef0._.js",
12+
"static/chunks/[root-of-the-server]__45f039c3._.js",
13+
"static/chunks/pages__app_2da965e7._.js",
14+
"static/chunks/turbopack-pages__app_0fce199e._.js"
15+
],
16+
"/_error": [
17+
"static/chunks/node_modules_next_dist_compiled_8ca6b690._.js",
18+
"static/chunks/node_modules_next_dist_shared_lib_9a2a7093._.js",
19+
"static/chunks/node_modules_next_dist_client_5a8a528e._.js",
20+
"static/chunks/node_modules_next_dist_a183fb77._.js",
21+
"static/chunks/node_modules_next_error_1cfbb379.js",
22+
"static/chunks/[next]_entry_page-loader_ts_43b523b5._.js",
23+
"static/chunks/node_modules_react-dom_4411d9bd._.js",
24+
"static/chunks/node_modules_7f09fef0._.js",
25+
"static/chunks/[root-of-the-server]__092393de._.js",
26+
"static/chunks/pages__error_2da965e7._.js",
27+
"static/chunks/turbopack-pages__error_af01c4e3._.js"
28+
]
429
},
530
"devFiles": [],
631
"polyfillFiles": [
Binary file not shown.

0 commit comments

Comments
 (0)