From 7983cfed7cc6d159cb25b4fe14a9f2da904a34da Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 25 Jan 2024 15:31:12 +0100 Subject: [PATCH] MVC join tables offer and user --- backend/database/database.sql | 80 +++++++++++--------- backend/src/controllers/offerControllers.js | 16 ++++ backend/src/controllers/userControllers.js | 18 +++++ backend/src/models/OfferCompetenceManager.js | 48 ++++++++++++ backend/src/models/UserCompetenceManager.js | 48 ++++++++++++ backend/src/models/UserManager.js | 45 +++++------ backend/src/models/index.js | 6 ++ backend/src/router.js | 14 +++- 8 files changed, 214 insertions(+), 61 deletions(-) create mode 100644 backend/src/models/OfferCompetenceManager.js create mode 100644 backend/src/models/UserCompetenceManager.js diff --git a/backend/database/database.sql b/backend/database/database.sql index 89420fd..663574f 100644 --- a/backend/database/database.sql +++ b/backend/database/database.sql @@ -26,35 +26,27 @@ CREATE TABLE user ( -- id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) -- ); --- INSERT INTO --- competence (name) --- values ("html"), --- ("css"), --- ("javascript"), --- ("angular"), --- ("react"), --- ("php"), --- ("symphony"), --- ("git"), --- ("github"), --- ("trello"); - --- CREATE --- TABLE --- competence ( --- id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, --- -- name VARCHAR(100), --- html TEXT, --- css TEXT, --- javascript TEXT, --- angular TEXT, --- react TEXT, --- php TEXT, --- symphony TEXT, --- git TEXT, --- github TEXT, --- trello TEXT --- ); +DROP TABLE IF EXISTS competence; + +CREATE TABLE +competence ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) + ); + +INSERT INTO + competence (name) +values ("html"), + ("css"), + ("javascript"), + ("angular"), + ("react"), + ("php"), + ("symphony"), + ("git"), + ("github"), + ("trello"); + DROP TABLE IF EXISTS cv; CREATE TABLE cv ( @@ -113,12 +105,28 @@ VALUES ( Nationalité française, en règle avec les obligations du service national JDC et jouissant de ses droits civiques.", "Junior", "Présent", "25k €/an", "Votre spécialité consiste à développer des logiciels au profit du ministère des Armées au sein d'un centre de développement. Sous la conduite d'un chef de projet, vous assurez la maintenance d'applications existantes et vous concevez de nouveaux logiciels liés aux besoins des armées. Vous soutenez les forces déployées depuis le territoire national et vous pouvez éventuellement être projetés sur des postes en dehors de votre compétence principale de développeur. Au bout de 4 à 6 ans, vous pouvez évoluer vers les métiers de la cybersécurité.", "marie@externatic.fr" ); -DROP TABLE IF EXISTS user_competence; --- Créer la table "user_competence" -CREATE TABLE user_competence ( - user_id INT, html BOOLEAN, css BOOLEAN, javascript BOOLEAN, angular BOOLEAN, react BOOLEAN, php BOOLEAN, symphony BOOLEAN, git BOOLEAN, github BOOLEAN, trello BOOLEAN, PRIMARY KEY (user_id), FOREIGN KEY (user_id) REFERENCES user (id) -); - CREATE TABLE upload ( id int(11) PRIMARY KEY NOT NULL AUTO_INCREMENT, url varchar(255) NOT NULL, unique (url), created_at timestamp default CURRENT_TIMESTAMP -); \ No newline at end of file +); + +DROP TABLE IF EXISTS user_competence; + +CREATE TABLE +user_competence ( + id int PRIMARY KEY NOT NULL AUTO_INCREMENT, + user_id INT NOT NULL, + competence_id INT NOT NULL, + FOREIGN KEY (user_id) REFERENCES user (id), + FOREIGN KEY (competence_id) REFERENCES competence (id) + ); + +DROP TABLE IF EXISTS offer_competence; + +CREATE TABLE +offer_competence ( + id int PRIMARY KEY NOT NULL AUTO_INCREMENT, + offer_id INT NOT NULL, + competence_id INT NOT NULL, + FOREIGN KEY (offer_id) REFERENCES offer (id), + FOREIGN KEY (competence_id) REFERENCES competence (id) + ); \ No newline at end of file diff --git a/backend/src/controllers/offerControllers.js b/backend/src/controllers/offerControllers.js index bf0e50b..ec093d8 100644 --- a/backend/src/controllers/offerControllers.js +++ b/backend/src/controllers/offerControllers.js @@ -70,7 +70,23 @@ const deleteOfferById = async (req, res) => { } }; +const addSkills = async (req, res) => { + try { + const offerId = +req.params.id; + + await models.offerCompetence.addOfferCompetences(offerId, req.body); + const competences = await models.offerCompetence.getOfferCompetences( + offerId + ); + + return res.status(201).send(competences); + } catch (err) { + return res.status(400).json({ message: err.message }); + } +}; + module.exports = { + addSkills, getOffers, getOfferById, postOffer, diff --git a/backend/src/controllers/userControllers.js b/backend/src/controllers/userControllers.js index 557501b..c55486b 100644 --- a/backend/src/controllers/userControllers.js +++ b/backend/src/controllers/userControllers.js @@ -119,6 +119,23 @@ const getProfile = (req, res) => { res.send(req.user); }; +const addSkills = async (req, res) => { + try { + const userId = +req.params.id; + // sécurité + if (req.user.id !== userId && !req.user.is_admin) { + return res.status(403).send({ error: "You do not have permission" }); + } + + await models.userCompetence.addUserCompetences(userId, req.body); + const competences = await models.userCompetence.getUserCompetences(userId); + + return res.status(201).send(competences); + } catch (err) { + return res.status(400).json({ message: err.message }); + } +}; + module.exports = { getUsers, postUser, @@ -128,4 +145,5 @@ module.exports = { getUserById, postSkills, getSkills, + addSkills, }; diff --git a/backend/src/models/OfferCompetenceManager.js b/backend/src/models/OfferCompetenceManager.js new file mode 100644 index 0000000..3cb36d0 --- /dev/null +++ b/backend/src/models/OfferCompetenceManager.js @@ -0,0 +1,48 @@ +const AbstractManager = require("./AbstractManager"); + +class OfferCompetenceManager extends AbstractManager { + constructor() { + super({ table: "offer_competence" }); + } + + async addOfferCompetences(offerId, body) { + const uniqValues = new Set(body.competences ?? []); + const [offerCompetences] = await this.database.query( + `SELECT competence_id from ${this.table} where offer_id = ?`, + [offerId] + ); + + offerCompetences.forEach((offerCompetence) => { + if (uniqValues.has(offerCompetence.competence_id)) { + uniqValues.delete(offerCompetence.competence_id); + } + }); + + if (!uniqValues.size) { + return []; + } + + const sqlValues = []; + let sql = `insert into ${this.table} (offer_id, competence_id) VALUES`; + + [...uniqValues.values()].forEach((competenceId) => { + sql += `${sqlValues.length > 0 ? "," : ""} (?,?)`; + sqlValues.push(offerId); + sqlValues.push(competenceId); + }); + + const [result] = await this.database.query(sql, sqlValues); + return result; + } + + async getOfferCompetences(offerId) { + const [result] = await this.database.query( + `SELECT competence.* FROM competence LEFT JOIN ${this.table} ON competence.id = ${this.table}.competence_id WHERE ${this.table}.offer_id = ?`, + offerId + ); + + return result; + } +} + +module.exports = OfferCompetenceManager; diff --git a/backend/src/models/UserCompetenceManager.js b/backend/src/models/UserCompetenceManager.js new file mode 100644 index 0000000..a900057 --- /dev/null +++ b/backend/src/models/UserCompetenceManager.js @@ -0,0 +1,48 @@ +const AbstractManager = require("./AbstractManager"); + +class UserCompetenceManager extends AbstractManager { + constructor() { + super({ table: "user_competence" }); + } + + async addUserCompetences(userId, body) { + const uniqValues = new Set(body.competences ?? []); + const [userCompetences] = await this.database.query( + `SELECT competence_id from ${this.table} where user_id = ?`, + [userId] + ); + + userCompetences.forEach((userCompetence) => { + if (uniqValues.has(userCompetence.competence_id)) { + uniqValues.delete(userCompetence.competence_id); + } + }); + + if (!uniqValues.size) { + return []; + } + + const sqlValues = []; + let sql = `insert into ${this.table} (user_id, competence_id) VALUES`; + + [...uniqValues.values()].forEach((competenceId) => { + sql += `${sqlValues.length > 0 ? "," : ""} (?,?)`; + sqlValues.push(userId); + sqlValues.push(competenceId); + }); + + const [result] = await this.database.query(sql, sqlValues); + return result; + } + + async getUserCompetences(userId) { + const [result] = await this.database.query( + `SELECT competence.* FROM competence LEFT JOIN ${this.table} ON competence.id = ${this.table}.competence_id WHERE ${this.table}.user_id = ?`, + userId + ); + + return result; + } +} + +module.exports = UserCompetenceManager; diff --git a/backend/src/models/UserManager.js b/backend/src/models/UserManager.js index aec5103..7e830dc 100644 --- a/backend/src/models/UserManager.js +++ b/backend/src/models/UserManager.js @@ -20,26 +20,26 @@ class UserManager extends AbstractManager { 0, ] ); - const userId = rows.insertId; - - const [userCompetence] = await this.database.query( - "INSERT INTO user_competence (user_id, html, css, javascript, angular, react, php, symphony, git, github, trello) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - [ - userId, - user.html, - user.css, - user.javascript, - user.angular, - user.react, - user.php, - user.symphony, - user.git, - user.github, - user.trello, - ] - ); - - return { userCompetence, rows }; + // const userId = rows.insertId; + + // const [userCompetence] = await this.database.query( + // "INSERT INTO user_competence (user_id, html, css, javascript, angular, react, php, symphony, git, github, trello) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + // [ + // userId, + // user.html, + // user.css, + // user.javascript, + // user.angular, + // user.react, + // user.php, + // user.symphony, + // user.git, + // user.github, + // user.trello, + // ] + // ); + + return { rows }; }); } @@ -96,10 +96,7 @@ class UserManager extends AbstractManager { } getProfile(id) { - return this.database.query( - `SELECT * FROM user LEFT JOIN user_competence ON user.id = user_competence.user_id WHERE user.id = ?;`, - [id] - ); + return this.database.query(`SELECT * FROM user WHERE id = ?;`, [id]); } addAvatar(userId, avatarId) { diff --git a/backend/src/models/index.js b/backend/src/models/index.js index 9dbf225..f024442 100644 --- a/backend/src/models/index.js +++ b/backend/src/models/index.js @@ -36,6 +36,8 @@ const ExperienceManager = require("./ExperienceManager"); const CourseManager = require("./CourseManager"); const CvManager = require("./CvManager"); const UploadManager = require("./UploadManager"); +const UserCompetenceManager = require("./UserCompetenceManager"); +const OfferCompetenceManager = require("./OfferCompetenceManager"); models.user = new UserManager(); models.offer = new OfferManager(); @@ -43,6 +45,8 @@ models.experience = new ExperienceManager(); models.course = new CourseManager(); models.cv = new CvManager(); models.upload = new UploadManager(); +models.userCompetence = new UserCompetenceManager(); +models.offerCompetence = new OfferCompetenceManager(); models.user.setDatabase(pool); models.offer.setDatabase(pool); @@ -50,6 +54,8 @@ models.experience.setDatabase(pool); models.course.setDatabase(pool); models.cv.setDatabase(pool); models.upload.setDatabase(pool); +models.userCompetence.setDatabase(pool); +models.offerCompetence.setDatabase(pool); // bonus: use a proxy to personalize error message, // when asking for a non existing model const handler = { diff --git a/backend/src/router.js b/backend/src/router.js index 89db3e3..9090b39 100644 --- a/backend/src/router.js +++ b/backend/src/router.js @@ -27,11 +27,17 @@ router.get("/users/:id([0-9]+)/cvs", authMiddleware, cvControllers.getCv); router.get("/users/:id([0-9]+)", authMiddleware, userControllers.getUserById); router.get("/users/me", authMiddleware, userControllers.getProfile); router.post("/users", userControllers.postUser); +router.post( + "/users/:id([0-9]+)/add/skills", + authMiddleware, + userControllers.addSkills +); + router.put("/users/:id([0-9]+)", authMiddleware, userControllers.updateUser); router.post("/user/skills", userControllers.postSkills); router.get("/user/skills", userControllers.getSkills); -router.post("/user/skills/:id([0-9]+)", userControllers.postSkills); +// router.post("/user/skills/:id([0-9]+)", userControllers.postSkills); router.post("/login", userControllers.postLogin); /* OFFERS. */ @@ -55,6 +61,12 @@ router.delete( authAdminMiddleware, offerControllers.deleteOfferById ); +router.post( + "/offers/:id([0-9]+)/add/skills", + authMiddleware, + authAdminMiddleware, + offerControllers.addSkills +); /* EXPERIENCES. */ router.get(