Skip to content

Commit 3aac819

Browse files
authored
Merge pull request #75 from RustyRory/feat/74-collection-club
feat(backend): Fixes #74 - Collection Clubs
2 parents 425c306 + 52f568c commit 3aac819

12 files changed

Lines changed: 230 additions & 60 deletions

File tree

app/backend/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PORT=3000

app/backend/eslint.config.mjs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import prettierPlugin from "eslint-plugin-prettier";
2+
3+
export default [
4+
{
5+
files: ["**/*.js"],
6+
7+
languageOptions: {
8+
ecmaVersion: 2021,
9+
sourceType: "module", // <- Important !
10+
globals: {
11+
process: "readonly",
12+
console: "readonly",
13+
__dirname: "readonly",
14+
},
15+
},
16+
17+
plugins: {
18+
prettier: prettierPlugin,
19+
},
20+
21+
rules: {
22+
"no-unused-vars": "warn",
23+
"no-undef": "error",
24+
"no-console": "off",
25+
"prettier/prettier": [
26+
"error",
27+
{
28+
semi: true,
29+
singleQuote: true,
30+
trailingComma: "es5",
31+
printWidth: 100,
32+
endOfLine: "auto",
33+
},
34+
],
35+
},
36+
},
37+
];

app/backend/package.json

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
{
22
"name": "backend",
3-
"version": "0.2.0",
3+
"version": "1.0.0",
44
"description": "",
5-
"main": "server.js",
5+
"main": "index.js",
66
"scripts": {
77
"start": "node server.js",
88
"dev": "nodemon server.js",
9-
"lint": "echo 'No backend lint yet' && exit 0",
10-
"format": "echo 'No backend format yet' && exit 0",
9+
"lint": "eslint src/**/*.js",
10+
"lint:fix": "eslint src/**/*.js --fix",
11+
"format": "prettier --write \"src/**/*.js\"",
12+
"prepare-commit": "npm run format && npm run lint:fix",
1113
"test": "echo \"Error: no test specified\" && exit 0"
1214
},
15+
"keywords": [],
1316
"author": "",
1417
"license": "ISC",
1518
"dependencies": {
@@ -20,6 +23,12 @@
2023
"mongoose": "^9.1.5"
2124
},
2225
"devDependencies": {
23-
"nodemon": "^3.1.11"
26+
"@eslint/js": "^9.39.2",
27+
"eslint": "^9.39.2",
28+
"eslint-config-prettier": "^10.1.8",
29+
"eslint-plugin-prettier": "^5.5.5",
30+
"globals": "^17.0.0",
31+
"nodemon": "^3.1.11",
32+
"prettier": "^3.8.1"
2433
}
2534
}

app/backend/server.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
const dotenv = require('dotenv');
1+
import dotenv from 'dotenv';
22
dotenv.config();
33

4-
const app = require('./src/app');
54
const mongoose = require('mongoose');
5+
const app = require('./src/app');
66

7-
const PORT = process.env.PORT ;
8-
const MONGO_URI = process.env.MONGO_URI;
7+
const PORT = process.env.PORT || 5000;
8+
const MONGO_URI = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/saintbarthvolley';
99

10+
// Connexion à MongoDB
1011
mongoose.connect(MONGO_URI)
1112
.then(() => {
1213
console.log('MongoDB connecté');
14+
15+
// Lancer le serveur
1316
app.listen(PORT, () => {
1417
console.log(`Serveur lancé sur http://localhost:${PORT}`);
1518
});
1619
})
17-
.catch(err => console.error(err));
20+
.catch(err => console.error('Erreur MongoDB:', err));

app/backend/src/app.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
const express = require('express');
2-
const cors = require('cors');
1+
import express from "express";
2+
import cors from "cors";
33

44
const app = express();
55

66
app.use(cors());
77
app.use(express.json());
88

99
// Route test
10-
app.get('/', (req, res) => {
11-
res.send('API Volley fonctionne !');
10+
app.get("/", (req, res) => {
11+
res.send("API Volley fonctionne !");
1212
});
1313

1414
// Importer les routes
15-
const usersRoutes = require('./routes/users');
16-
app.use('/api/users', usersRoutes);
15+
const usersRoutes = require("./routes/users");
16+
const clubsRoutes = require("./routes/clubs");
1717

18+
app.use("/api/users", usersRoutes);
19+
app.use("/api/clubs", clubsRoutes);
1820

19-
module.exports = app;
21+
export default app;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import Club from "../models/Club";
2+
3+
// GET all clubs
4+
export const getAllClubs = async (req, res) => {
5+
try {
6+
const clubs = await Club.find();
7+
res.json(clubs);
8+
} catch (err) {
9+
res.status(500).json({ message: err.message });
10+
}
11+
};
12+
13+
// GET single club
14+
export const getClubById = async (req, res) => {
15+
try {
16+
const club = await Club.findById(req.params.id);
17+
if (!club) return res.status(404).json({ message: "Club non trouvé" });
18+
res.json(club);
19+
} catch (err) {
20+
res.status(500).json({ message: err.message });
21+
}
22+
};
23+
24+
// POST create club
25+
export const createClub = async (req, res) => {
26+
try {
27+
const club = new Club(req.body);
28+
await club.save();
29+
res.status(201).json({ message: "Club créé", clubId: club._id });
30+
} catch (err) {
31+
res.status(400).json({ message: err.message });
32+
}
33+
};
34+
35+
// PUT update club
36+
export const updateClub = async (req, res) => {
37+
try {
38+
const club = await Club.findById(req.params.id);
39+
if (!club) return res.status(404).json({ message: "Club non trouvé" });
40+
41+
Object.assign(club, req.body); // Met à jour tous les champs reçus
42+
await club.save();
43+
res.json({ message: "Club mis à jour" });
44+
} catch (err) {
45+
res.status(400).json({ message: err.message });
46+
}
47+
};
48+
49+
// DELETE club
50+
export const deleteClub = async (req, res) => {
51+
try {
52+
const club = await Club.findByIdAndDelete(req.params.id);
53+
if (!club) return res.status(404).json({ message: "Club non trouvé" });
54+
res.json({ message: "Club supprimé" });
55+
} catch (err) {
56+
res.status(500).json({ message: err.message });
57+
}
58+
};

app/backend/src/controllers/usersController.js

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,47 @@
1-
const User = require('../models/User');
1+
import User from "../models/User.js";
22

33
// GET all users
4-
exports.getAllUsers = async (req, res) => {
4+
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"); // Ne jamais renvoyer les passwords
77
res.json(users);
88
} catch (err) {
99
res.status(500).json({ message: err.message });
1010
}
1111
};
1212

1313
// GET single user
14-
exports.getUserById = async (req, res) => {
14+
export const getUserById = async (req, res) => {
1515
try {
16-
const user = await User.findById(req.params.id).select('-passwordHash');
17-
if (!user) return res.status(404).json({ message: 'Utilisateur non trouvé' });
16+
const user = await User.findById(req.params.id).select("-passwordHash");
17+
if (!user)
18+
return res.status(404).json({ message: "Utilisateur non trouvé" });
1819
res.json(user);
1920
} catch (err) {
2021
res.status(500).json({ message: err.message });
2122
}
2223
};
2324

2425
// POST create user
25-
exports.createUser = async (req, res) => {
26+
export const createUser = async (req, res) => {
2627
try {
2728
const { email, password, role, firstName, lastName } = req.body;
2829
const user = new User({ email, role, firstName, lastName });
2930
await user.setPassword(password);
3031
await user.save();
31-
res.status(201).json({ message: 'Utilisateur créé', userId: user._id });
32+
res.status(201).json({ message: "Utilisateur créé", userId: user._id });
3233
} catch (err) {
3334
res.status(400).json({ message: err.message });
3435
}
3536
};
3637

3738
// PUT update user
38-
exports.updateUser = async (req, res) => {
39+
export const updateUser = async (req, res) => {
3940
try {
4041
const { email, role, firstName, lastName, isActive, password } = req.body;
4142
const user = await User.findById(req.params.id);
42-
if (!user) return res.status(404).json({ message: 'Utilisateur non trouvé' });
43+
if (!user)
44+
return res.status(404).json({ message: "Utilisateur non trouvé" });
4345

4446
if (email) user.email = email;
4547
if (role) user.role = role;
@@ -49,18 +51,19 @@ exports.updateUser = async (req, res) => {
4951
if (password) await user.setPassword(password);
5052

5153
await user.save();
52-
res.json({ message: 'Utilisateur mis à jour' });
54+
res.json({ message: "Utilisateur mis à jour" });
5355
} catch (err) {
5456
res.status(400).json({ message: err.message });
5557
}
5658
};
5759

5860
// DELETE user
59-
exports.deleteUser = async (req, res) => {
61+
export const deleteUser = async (req, res) => {
6062
try {
6163
const user = await User.findByIdAndDelete(req.params.id);
62-
if (!user) return res.status(404).json({ message: 'Utilisateur non trouvé' });
63-
res.json({ message: 'Utilisateur supprimé' });
64+
if (!user)
65+
return res.status(404).json({ message: "Utilisateur non trouvé" });
66+
res.json({ message: "Utilisateur supprimé" });
6467
} catch (err) {
6568
res.status(500).json({ message: err.message });
6669
}

app/backend/src/models/Club.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import mongoose from "mongoose";
2+
3+
const ClubSchema = new mongoose.Schema(
4+
{
5+
name: { type: String, required: true },
6+
subtitle: { type: String, default: "" },
7+
homeDescription: { type: String, default: "" },
8+
clubDescription: { type: String, default: "" },
9+
ownerDescription: { type: String, default: "" },
10+
logo: { type: String, default: "" }, // URL ou chemin du logo
11+
photo: { type: String, default: "" }, // URL ou chemin de la photo principale
12+
email: { type: String, default: "" },
13+
phone: { type: String, default: "" },
14+
address: { type: String, default: "" },
15+
16+
// Liens sociaux
17+
social_links: {
18+
facebook: { type: String, default: "" },
19+
instagram: { type: String, default: "" },
20+
youtube: { type: String, default: "" },
21+
sporteasy: { type: String, default: "" },
22+
website: { type: String, default: "" },
23+
other: { type: String, default: "" },
24+
},
25+
26+
// Informations légales
27+
legal_info: {
28+
associationName: { type: String, default: "" },
29+
legalForm: { type: String, default: "" },
30+
siret: { type: String, default: "" },
31+
rna: { type: String, default: "" },
32+
headOffice: { type: String, default: "" },
33+
publicationDate: { type: Date, default: null },
34+
responsible: { type: String, default: "" },
35+
hostingProvider: { type: String, default: "" },
36+
updatedAt: { type: Date, default: null },
37+
},
38+
},
39+
{ timestamps: true },
40+
); // createdAt et updatedAt automatiques
41+
42+
export default mongoose.model("Club", ClubSchema);

app/backend/src/models/User.js

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,36 @@
1-
const mongoose = require('mongoose');
2-
const bcrypt = require('bcrypt');
1+
import mongoose from "mongoose";
2+
import bcrypt from "bcrypt";
33

4-
const UserSchema = new mongoose.Schema({
5-
email: {
6-
type: String,
7-
required: true,
8-
unique: true,
9-
lowercase: true,
10-
trim: true
4+
const UserSchema = new mongoose.Schema(
5+
{
6+
email: {
7+
type: String,
8+
required: true,
9+
unique: true,
10+
lowercase: true,
11+
trim: true,
12+
},
13+
passwordHash: { type: String, required: true },
14+
role: { type: String, enum: ["admin", "editor"], default: "editor" },
15+
firstName: { type: String, required: true },
16+
lastName: { type: String, required: true },
17+
isActive: { type: Boolean, default: true },
18+
lastLoginAt: { type: Date, default: null },
19+
passwordUpdatedAt: { type: Date, default: null },
1120
},
12-
passwordHash: { type: String, required: true },
13-
role: { type: String, enum: ['admin', 'editor'], default: 'editor' },
14-
firstName: { type: String, required: true },
15-
lastName: { type: String, required: true },
16-
isActive: { type: Boolean, default: true },
17-
lastLoginAt: { type: Date, default: null },
18-
passwordUpdatedAt: { type: Date, default: null }
19-
}, { timestamps: true });
21+
{ timestamps: true },
22+
);
2023

2124
// Comparer un mot de passe
22-
UserSchema.methods.comparePassword = async function(password) {
25+
UserSchema.methods.comparePassword = async function (password) {
2326
return await bcrypt.compare(password, this.passwordHash);
2427
};
2528

2629
// Définir ou changer le mot de passe
27-
UserSchema.methods.setPassword = async function(password) {
30+
UserSchema.methods.setPassword = async function (password) {
2831
const salt = await bcrypt.genSalt(10);
2932
this.passwordHash = await bcrypt.hash(password, salt);
3033
this.passwordUpdatedAt = new Date();
3134
};
3235

33-
module.exports = mongoose.model('User', UserSchema);
36+
export default mongoose.model("User", UserSchema);

app/backend/src/routes/clubs.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import express from "express";
2+
import * as clubsController from "../controllers/clubsController.js";
3+
const router = express.Router();
4+
5+
// Routes CRUD clubs
6+
router.get("/", clubsController.getAllClubs);
7+
router.get("/:id", clubsController.getClubById);
8+
router.post("/", clubsController.createClub);
9+
router.put("/:id", clubsController.updateClub);
10+
router.delete("/:id", clubsController.deleteClub);
11+
12+
export default router;

0 commit comments

Comments
 (0)