From a0ce9bdd13bb632a2f7d0e96a9325bc63d5cf374 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 14:27:39 +0400 Subject: [PATCH 01/21] Refactoring ArticleCtrl to have less utils methods --- controller/ArticleCtrl.js | 94 +++++++++------------------------------ 1 file changed, 21 insertions(+), 73 deletions(-) diff --git a/controller/ArticleCtrl.js b/controller/ArticleCtrl.js index e603b60..c8ca863 100644 --- a/controller/ArticleCtrl.js +++ b/controller/ArticleCtrl.js @@ -13,7 +13,7 @@ const ARTICLES_THUMB = process.env.THUMB_URL + "articles/"; const Article = db.article; const form = formidable({ uploadDir: ARTICLES_IMG, keepExtensions: true }); -//! ******************** CHECKERS ******************** +//! ******************** UTILS ******************** /** * ? CHECK ARTICLE DATA @@ -62,73 +62,6 @@ exports.checkArticleUnique = (name, text, article, res) => { } } -/** - * ? CHECK ARTICLES FOR UNIQUE - * * Checks the articles for uniqueness based on the given id. - * - * @param {string} id - The id to compare against. - * @param {Array} articles - The array of articles to check. - * @param {Object} fields - The object containing the fields to check against. - * @param {Object} res - The response object. - */ -exports.checkArticlesForUnique = (id, articles, fields, res) => { - for (let article of articles) { - if (article.id !== id) { - this.checkArticleUnique(fields.name, fields.text, article, res) - } - } -} - -//! ******************** GETTERS ******************** - -/** - * ? GET ARTICLE CREATED - * * Returns an object containing the details of an article. - * - * @param {string} name - The name of the article. - * @param {string} text - The text of the article. - * @param {string} image - The image of the article. - * @param {string} alt - The alt text for the image. - * @param {string} cat - The category of the article. - * @return {object} An object containing the details of the article. - */ -exports.getArticleCreated = (name, text, image, alt, cat) => { - - return { - name: name, - text: text, - image: image, - alt: alt, - cat: cat - } -} - -/** - * ? GET ARTICLE UPDATED - * * Returns an object containing updated article information. - * - * @param {string} name - The name of the article. - * @param {string} text - The text content of the article. - * @param {string} image - The URL of the article image. - * @param {string} alt - The alternative text for the article image. - * @param {string} likes - The list of user Ids as article likes. - * @param {string} cat - The category that the article belongs to. - * @return {object} - An object containing the updated article information. - */ -exports.getArticleUpdated = (name, text, image, alt, likes, cat) => { - - return { - name: name, - text: text, - image: image, - alt: alt, - likes: likes, - cat: cat - } -} - -//! ******************** SETTER ******************** - /** * ? SET IMAGE * * Sets the image for an article. @@ -185,6 +118,8 @@ exports.readArticle = (req, res) => { //! ******************** PRIVATE ******************** +// TODO : create a method to like an article + /** * ? CREATE ARTICLE * * Creates an article based on the request data. @@ -211,9 +146,13 @@ exports.createArticle = (req, res, next) => { let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; this.setImage(image, files.image.newFilename); - let article = this.getArticleCreated( - fields.name, fields.text, image, fields.alt, fields.cat - ); + let article = { + name: fields.name, + text: fields.text, + image: image, + alt: fields.alt, + cat: fields.cat + } Article .create(article) @@ -249,12 +188,21 @@ exports.updateArticle = (req, res, next) => { Article .findAll() .then((articles) => { - this.checkArticlesForUnique(id, articles, fields, res); + for (let article of articles) { + if (article.id !== id) this.checkArticleUnique(fields.name, fields.text, article, res); + } let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; if (files.image) this.setImage(image, files.image.newFilename); - let article = this.getArticleUpdated(fields.name, fields.text, image, fields.alt, fields.likes, fields.cat); + let article = { + name: fields.name, + text: fields.text, + image: image, + alt: fields.alt, + likes: fields.likes, + cat: fields.cat + } Article .update(article, { where: { id: id }}) From b0690fc14610970c87c49f28d0e624eab9e8f6d7 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 14:29:05 +0400 Subject: [PATCH 02/21] Refactoring AuthCtrl to remove useless utils methods --- controller/AuthCtrl.js | 116 ++++++++--------------------------------- 1 file changed, 23 insertions(+), 93 deletions(-) diff --git a/controller/AuthCtrl.js b/controller/AuthCtrl.js index 448237d..71fa8b4 100644 --- a/controller/AuthCtrl.js +++ b/controller/AuthCtrl.js @@ -12,95 +12,6 @@ const form = formidable(); const recaptcha = new Recaptcha({ secret: process.env.RECAPTCHA_SECRET }); const User = db.user; - -//! ******************** CHECKER ******************** - -/** - * ? CHECK AUTH DATA - * * Validates the provided email and sends an error response if the email is invalid. - * - * @param {string} email - The email to be validated. - * @param {object} res - The response object used to send the error response. - * @return {object} - The error response containing a message. - */ -exports.checkAuthData = (email, res) => { - if (!nem.checkEmail(email)) { - return res.status(403).json({ message: process.env.CHECK_EMAIL }); - } -} - -//! ******************** GETTER ******************** - -/** - * ? GET USER - * * Returns a user object with the provided details. - * - * @param {string} name - The name of the user. - * @param {string} email - The email of the user. - * @param {string} image - The image URL of the user. - * @param {string} pass - The password of the user. - * @param {string} role - The role of the user. - * @param {string} created - The date of creation of the user. - * @param {string} updated - The date of last update of the user. - * @return {Object} - The user object with the provided details. - */ -exports.getUser = (name, email, image, pass, role, created, updated) => { - - return { - name: name, - email: email, - image: image, - pass: pass, - role: role, - created: created, - updated: updated - } -} - -//! ******************** SETTER ******************** - -/** - * ? SET MAILER - * * Set the mailer and send an email. - * - * @param {Object} fields - The fields for the email. - * @param {Object} res - The response object. - * @return {Object} A message indicating that the email was sent. - * @throws {Error} If an error occurs while sending the email. - */ -exports.setMailer = (fields, res) => { - const mailer = nem.getMailer(); - - (async function(){ - try { - let mail = nem.getMessage(fields); - - await mailer.sendMail(mail, function() { - res.status(202).json({ message: process.env.AUTH_MESSAGE }); - }); - } catch(e){ console.error(e); } - })(); -} - -/** - * ? SET MESSAGE - * * Sets a message in the fields object and returns the modified fields object. - * - * @param {object} fields - The fields object to modify. - * @param {string} pass - The password to include in the message. - * @return {object} The modified fields object. - */ -exports.setMessage = (fields, pass) => { - fields.html = ` -

${fields.html}

- ${pass} - `; - - return fields; -} - -//! ******************** PUBLIC ******************** - /** * ? READ AVATAR * * Retrieves the avatar information for a specific user. @@ -187,7 +98,8 @@ exports.forgotPass = (req, res, next) => { form.parse(req, (err, fields) => { if (err) { next(err); return } - this.checkAuthData(fields.email, res); + if (!nem.checkEmail(fields.email)) return res.status(403).json({ message: process.env.CHECK_EMAIL }); + User .findOne({ where: { email: fields.email }}) @@ -195,16 +107,34 @@ exports.forgotPass = (req, res, next) => { if (user !== null) { let pass = nem.getPassword(); - fields.html = this.setMessage(fields, pass); + fields.html = `

${fields.html}

${pass}`; bcrypt .hash(pass, 10) .then((hash) => { - let newUser = this.getUser(user.name, user.email, user.image, hash, user.role, user.created, user.updated); + let newUser = { + name: user.name, + email: user.email, + image: user.image, + pass: hash, + role: user.role + } User .update(newUser, { where: { id: user.id }}) - .then(() => { this.setMailer(fields, res) }) + .then(() => { + const mailer = nem.getMailer(); + + (async function(){ + try { + let mail = nem.getMessage(fields); + + await mailer.sendMail(mail, function() { + res.status(202).json({ message: process.env.AUTH_MESSAGE }); + }); + } catch(e){ console.error(e); } + })(); + }) .catch(() => res.status(400).json({ message: process.env.USER_NOT_UPDATED })); }) .catch(() => res.status(400).json({ message: process.env.USER_NOT_PASS })); From 4c144cc74bdc1d322ec1f1fa0fdc7245d1684ab3 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 14:32:28 +0400 Subject: [PATCH 03/21] Blank lines --- controller/AuthCtrl.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/controller/AuthCtrl.js b/controller/AuthCtrl.js index 71fa8b4..ff2a7fe 100644 --- a/controller/AuthCtrl.js +++ b/controller/AuthCtrl.js @@ -100,12 +100,10 @@ exports.forgotPass = (req, res, next) => { if (!nem.checkEmail(fields.email)) return res.status(403).json({ message: process.env.CHECK_EMAIL }); - User .findOne({ where: { email: fields.email }}) .then((user) => { if (user !== null) { - let pass = nem.getPassword(); fields.html = `

${fields.html}

${pass}`; @@ -124,11 +122,9 @@ exports.forgotPass = (req, res, next) => { .update(newUser, { where: { id: user.id }}) .then(() => { const mailer = nem.getMailer(); - (async function(){ try { let mail = nem.getMessage(fields); - await mailer.sendMail(mail, function() { res.status(202).json({ message: process.env.AUTH_MESSAGE }); }); From 532fae2e094e622eb3d1a08dee328badddc3edfc Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 14:59:49 +0400 Subject: [PATCH 04/21] Refactoring GalleryCtrl to have less utils methods --- controller/GalleryCtrl.js | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/controller/GalleryCtrl.js b/controller/GalleryCtrl.js index 8be308d..76c3737 100644 --- a/controller/GalleryCtrl.js +++ b/controller/GalleryCtrl.js @@ -14,7 +14,7 @@ const form = formidable(); const Gallery = db.gallery; const Image = db.image; -//! ******************** CHECKERS ******************** +//! ******************** UTILS ******************** /** * ? CHECK GALLERY DATA @@ -29,13 +29,8 @@ exports.checkGalleryData = (name, author, res) => { const MAX = process.env.STRING_MAX; const MIN = process.env.STRING_MIN; - if (!nem.checkRange(author, MIN, MAX)) { - return res.status(403).json({ message: process.env.CHECK_NAME }); - } - - if (!nem.checkRange(name, MIN, MAX)) { - return res.status(403).json({ message: process.env.CHECK_NAME }); - } + if (!nem.checkRange(author, MIN, MAX)) return res.status(403).json({ message: process.env.CHECK_NAME }); + if (!nem.checkRange(name, MIN, MAX)) return res.status(403).json({ message: process.env.CHECK_NAME }); } /** @@ -49,26 +44,7 @@ exports.checkGalleryData = (name, author, res) => { * @throws {Error} If the name is not unique. */ exports.checkGalleryUnique = (name, gallery, res) => { - if (gallery.name === name) { - return res.status(403).json({ message: process.env.DISPO_NAME }); - } -} - -/** - * ? CHECK GALLERIES FOR UNIQUE - * * Checks if the given name is unique in the array of galleries. - * - * @param {type} id - The ID to compare with the galleries' IDs. - * @param {type} galleries - The array of galleries to check. - * @param {type} name - The name parameter to pass to the "checkGalleryUnique" function. - * @param {type} res - The res parameter to pass to the "checkGalleryUnique" function. - */ -exports.checkGalleriesForUnique = (id, galleries, name, res) => { - for (let gallery of galleries) { - if (gallery.id !== id) { - this.checkGalleryUnique(name, gallery, res) - } - } + if (gallery.name === name) return res.status(403).json({ message: process.env.DISPO_NAME }); } //! ******************** PUBLIC ******************** @@ -167,7 +143,9 @@ exports.updateGallery = (req, res, next) => { Gallery .findAll() .then((galleries) => { - this.checkGalleriesForUnique(id, galleries, fields.name, res); + for (let gallery of galleries) { + if (gallery.id !== id) this.checkGalleryUnique(fields.name, gallery, res); + } let gallery = { name: fields.name, From 3b92202e4d312e2af266f699f1a652b9dbefa532 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 15:00:17 +0400 Subject: [PATCH 05/21] Blank lines & comments to ImageCtrl --- controller/ImageCtrl.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/controller/ImageCtrl.js b/controller/ImageCtrl.js index 4c4fab4..feeb02c 100644 --- a/controller/ImageCtrl.js +++ b/controller/ImageCtrl.js @@ -14,7 +14,7 @@ const form = formidable({ uploadDir: GALLERIES_IMG, keepExtensions: true }); const Gallery = db.gallery; const Image = db.image; -//! ******************** CHECKER ******************** +//! ******************** UTILS ******************** /** * ? CHECK IMAGE DATA @@ -30,8 +30,6 @@ exports.checkImageData = (description, res) => { } } -//! ******************** SETTER ******************** - /** * ? SET IMAGE * * Sets the image & thumbnail for a gallery. @@ -47,8 +45,6 @@ exports.setImage = (image, newFilename) => { nem.setThumbnail(input, process.env.THUMB_URL + output); } -//! ******************** GETTER ******************** - /** * ? GET IMAGE * * Retrieves an image with the given name, description & gallery ID. @@ -59,7 +55,6 @@ exports.setImage = (image, newFilename) => { * @return {object} - An object containing the name, description & gallery ID of the image. */ exports.getImage = (name, description, galleryId) => { - return { name: name, description: description, @@ -80,7 +75,6 @@ exports.getImage = (name, description, galleryId) => { */ exports.listImages = (req, res) => { Image.belongsTo(Gallery, { foreignKey: "galleryId" }); - Image .findAll({ where: { galleryId: req.params.id }, From 5c3b4b061e4beca74ae27245f9ef04342e54f751 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 15:00:49 +0400 Subject: [PATCH 06/21] Refactoring LinkCtrl to have less utils methods --- controller/LinkCtrl.js | 42 +++++++----------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/controller/LinkCtrl.js b/controller/LinkCtrl.js index 9eadf46..c1965d3 100644 --- a/controller/LinkCtrl.js +++ b/controller/LinkCtrl.js @@ -9,7 +9,7 @@ require("dotenv").config(); const form = formidable(); const Link = db.link; -//! ******************** CHECKERS ******************** +//! ******************** UTILS ******************** /** * ? CHECK LINK DATA @@ -24,13 +24,11 @@ const Link = db.link; exports.checkLinkData = (name, url, cat, res) => { const MAX = process.env.STRING_MAX; const MIN = process.env.STRING_MIN; - let alert = ""; if (!nem.checkRange(cat, MIN, MAX)) alert = process.env.CHECK_CAT; if (!nem.checkUrl("https://" + url)) alert = process.env.CHECK_URL; if (!nem.checkRange(name, MIN, MAX)) alert = process.env.CHECK_NAME; - if (alert !== "") return res.status(403).json({ message: alert }); } @@ -45,30 +43,8 @@ exports.checkLinkData = (name, url, cat, res) => { * @return {object} - The response object with the appropriate status & message. */ exports.checkLinkUnique = (name, url, link, res) => { - if (link.name === name) { - return res.status(403).json({ message: process.env.DISPO_NAME }); - } - - if (link.url === url) { - return res.status(403).json({ message: process.env.DISPO_URL }); - } -} - -/** - * ? CHECK LINKS FOR UNIQUE - * * Checks the links for uniqueness based on the given ID. - * - * @param {string} id - The ID to compare against the links. - * @param {Array} links - An array of links to check. - * @param {Object} fields - An object containing the fields to check against the links. - * @param {Object} res - The response object to handle the result. - */ -exports.checkLinksForUnique = (id, links, fields, res) => { - for (let link of links) { - if (link.id !== id) { - this.checkLinkUnique(fields.name, fields.url, link, res); - } - } + if (link.name === name) return res.status(403).json({ message: process.env.DISPO_NAME }); + if (link.url === url) return res.status(403).json({ message: process.env.DISPO_URL }); } //! ******************** PUBLIC ******************** @@ -104,15 +80,12 @@ exports.listLinks = (req, res) => { exports.createLink = (req, res, next) => { form.parse(req, (err, fields) => { if (err) { next(err); return } - this.checkLinkData(fields.name, fields.url, fields.cat, res); Link .findAll() .then((links) => { - for (let link of links) { - this.checkLinkUnique(fields.name, fields.url, link, res); - } + for (let link of links) this.checkLinkUnique(fields.name, fields.url, link, res); Link .create(fields) .then(() => res.status(201).json({ message: process.env.LINK_CREATED })) @@ -134,17 +107,16 @@ exports.createLink = (req, res, next) => { */ exports.updateLink = (req, res, next) => { const id = parseInt(req.params.id); - form.parse(req, (err, fields) => { if (err) { next(err); return } - this.checkLinkData(fields.name, fields.url, fields.cat, res); Link .findAll() .then((links) => { - this.checkLinksForUnique(id, links, fields, res); - + for (let link of links) { + if (link.id !== id) this.checkLinkUnique(fields.name, fields.url, link, res); + } Link .update(fields, { where: { id: id }}) .then(() => res.status(200).json({ message: process.env.LINK_UPDATED })) From 44a2155a6f77d116c9324330018890605db01ac0 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 15:01:47 +0400 Subject: [PATCH 07/21] Refactoring OrderCtrl to have less utils methods --- controller/OrderCtrl.js | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/controller/OrderCtrl.js b/controller/OrderCtrl.js index 7c8dfef..f2c6fe5 100644 --- a/controller/OrderCtrl.js +++ b/controller/OrderCtrl.js @@ -10,30 +10,7 @@ const form = formidable(); const Order = db.order; const User = db.user; -//! ******************** SETTERS ******************** - -/** - * ? SET MAILER - * * Sets the mailer and sends an email. - * - * @param {Object} fields - The fields used to generate the email message. - * @param {Object} res - The response object used to send the HTTP response. - * @return {Object} A message indicating that the email was sent. - * @throws {Error} If an error occurs while sending the email. - */ -exports.setMailer = (fields, res) => { - const mailer = nem.getMailer(); - - (async function(){ - try { - let mail = nem.getMessage(fields); - - await mailer.sendMail(mail, function() { - res.status(202).json({ message: process.env.ORDER_MESSAGE }); - }); - } catch(e){ console.error(e); } - })(); -} +//! ******************** UTILS ******************** /** * ? SET MESSAGE @@ -122,7 +99,6 @@ exports.listUserOrders = (req, res) => { exports.createOrder = (req, res, next) => { form.parse(req, (err, fields) => { if (err) { next(err); return } - let message = this.setMessage(fields.total, fields.paymentId, fields.products); Order @@ -132,7 +108,16 @@ exports.createOrder = (req, res, next) => { .findByPk(fields.userId) .then((user) => { message.email = user.email; - this.setMailer(message, res); + const mailer = nem.getMailer(); + + (async function(){ + try { + let mail = nem.getMessage(fields); + await mailer.sendMail(mail, function() { + res.status(202).json({ message: process.env.ORDER_MESSAGE }); + }); + } catch(e){ console.error(e); } + })(); }) .catch(() => res.status(404).json({ message: process.env.USER_NOT_FOUND })); }) From 3706ead19b981cf483de57ce3d04daefac21a5ef Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 15:02:08 +0400 Subject: [PATCH 08/21] Refactoring ProductCtrl to have less utils methods --- controller/ProductCtrl.js | 48 +++++++-------------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/controller/ProductCtrl.js b/controller/ProductCtrl.js index 38a7ac0..6b0500a 100644 --- a/controller/ProductCtrl.js +++ b/controller/ProductCtrl.js @@ -13,7 +13,7 @@ const PRODUCTS_THUMB = process.env.THUMB_URL + "products/"; const form = formidable({ uploadDir: PRODUCTS_IMG, keepExtensions: true }); const Product = db.product; -//! ******************** CHECKERS ******************** +//! ******************** UTILS ******************** /** * ? CHECK PRODUCT DATA @@ -57,34 +57,10 @@ exports.checkProductData = (name, description, alt, price, cat, res) => { * @return {object} The JSON response object with the appropriate message and status code. */ exports.checkProductUnique = (name, description, product, res) => { - if (product.name === name) { - return res.status(403).json({ message: process.env.DISPO_NAME }); - } - - if (product.description === description) { - return res.status(403).json({ message: process.env.DISPO_DESCRIPTION }); - } -} - -/** - * ? CHECK PRODUCTS FOR UNIQUE - * * Checks if a product is unique based on its ID & fields. - * - * @param {string} id - The ID of the product to check uniqueness against. - * @param {Array} products - An array of products to check for uniqueness. - * @param {Object} fields - An object containing the fields to check for uniqueness. - * @param {Object} res - The response object to send the result to. - */ -exports.checkProductsForUnique = (id, products, fields, res) => { - for (let product of products) { - if (product.id !== id) { - this.checkProductUnique(fields.name, fields.description, product, res) - } - } + if (product.name === name) return res.status(403).json({ message: process.env.DISPO_NAME }); + if (product.description === description) return res.status(403).json({ message: process.env.DISPO_DESCRIPTION }); } -//! ******************** GETTERS ******************** - /** * ? GET PRODUCT * * Returns a product object with the given properties. @@ -99,7 +75,6 @@ exports.checkProductsForUnique = (id, products, fields, res) => { * @return {object} The product object with the given properties. */ exports.getProduct = (name, description, image, alt, price, options, cat) => { - return { name: name, description: description, @@ -111,8 +86,6 @@ exports.getProduct = (name, description, image, alt, price, options, cat) => { } } -//! ******************** SETTER ******************** - /** * ? SET IMAGE * * Sets the image for a product. @@ -125,12 +98,7 @@ exports.setImage = (name, newFilename) => { let output = "products/" + name; nem.setThumbnail(input, process.env.THUMB_URL + output); - nem.setThumbnail( - input, - process.env.IMG_URL + output, - process.env.IMG_WIDTH, - process.env.IMG_HEIGHT - ); + nem.setThumbnail(input, process.env.IMG_URL + output, process.env.IMG_WIDTH, process.env.IMG_HEIGHT); } //! ******************** PUBLIC ******************** @@ -226,13 +194,14 @@ exports.updateProduct = (req, res, next) => { form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkProductData(fields.name, fields.description, fields.alt, fields.price, fields.cat, res); Product .findAll() .then((products) => { - this.checkProductsForUnique(id, products, fields, res); + for (let product of products) { + if (product.id !== id) this.checkProductUnique(fields.name, fields.description, product, res); + } let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; if (files.image) this.setImage(image, files.image.newFilename); @@ -243,7 +212,7 @@ exports.updateProduct = (req, res, next) => { Product .update(product, { where: { id: id }}) .then(() => { - if (files.image) fs.unlink(PRODUCTS_IMG + files.image.newFilename, () => { }); + if (files.image) fs.unlink(PRODUCTS_IMG + files.image.newFilename, () => {}); res.status(200).json({ message: process.env.PRODUCT_UPDATED }); }) .catch(() => res.status(400).json({ message: process.env.PRODUCT_NOT_UPDATED })); @@ -269,7 +238,6 @@ exports.deleteProduct = (req, res) => { .then(product => { fs.unlink(PRODUCTS_THUMB + product.image, () => { fs.unlink(PRODUCTS_IMG + product.image, () => { - Product .destroy({ where: { id: id }}) .then(() => res.status(204).json({ message: process.env.PRODUCT_DELETED })) From 4cf846fc1a69c296e287a90b39f0b341f6999ccf Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 15:02:24 +0400 Subject: [PATCH 09/21] Refactoring UserCtrl to have less utils methods --- controller/UserCtrl.js | 172 ++++++++++------------------------------- 1 file changed, 39 insertions(+), 133 deletions(-) diff --git a/controller/UserCtrl.js b/controller/UserCtrl.js index 6678463..1430090 100644 --- a/controller/UserCtrl.js +++ b/controller/UserCtrl.js @@ -14,7 +14,7 @@ const USERS_THUMB = process.env.THUMB_URL + "users/"; const form = formidable({ uploadDir: USERS_IMG, keepExtensions: true }); const User = db.user; -//! ******************** CHECKERS ******************** +//! ******************** UTILS ******************** /** * ? CHECK USER DATA @@ -48,9 +48,7 @@ exports.checkUserData = (name, email, role, res) => { * @return {object} - The response object with an error message if the password is invalid. */ exports.checkUserPass = (pass, res) => { - if (!nem.checkPass(pass)) { - return res.status(403).json({ message: process.env.CHECK_PASS }) - } + if (!nem.checkPass(pass)) return res.status(403).json({ message: process.env.CHECK_PASS }); } /** @@ -64,129 +62,8 @@ exports.checkUserPass = (pass, res) => { * @return {object} The JSON response containing the error message if the name or email is not unique. */ exports.checkUserUnique = (name, email, user, res) => { - if (user.name === name) { - return res.status(403).json({ message: process.env.DISPO_NAME }); - } - - if (user.email === email) { - return res.status(403).json({ message: process.env.DISPO_EMAIL }); - } -} - -/** - * ? CHECK USERS FOR UNIQUE - * * Checks if users in the given array have unique fields except for the user with the given id, - * * & calls the checkUserUnique function for each non-matching user. - * - * @param {string} id - The id of the user to exclude from the uniqueness check. - * @param {Array} users - The array of user objects to check. - * @param {Object} fields - The fields object containing the name & email fields to check for uniqueness. - * @param {Object} res - The response object to send the result of the uniqueness check. - */ -exports.checkUsersForUnique = (id, users, fields, res) => { - for (let user of users) { - if (user.id !== id) { - this.checkUserUnique(fields.name, fields.email, user, res) - } - } -} - -//! ******************** GETTERS ******************** - -/** - * ? GET USER CREATED - * * Returns an object with the user's information. - * - * @param {string} name - The name of the user. - * @param {string} email - The email of the user. - * @param {string} image - The image of the user. - * @param {string} pass - The password of the user. - * @param {string} role - The role of the user. - * @param {string} created - The creation date of the user. - * @param {string} updated - The update date of the user. - * @return {Object} - An object containing the user's information. - */ -exports.getUserCreated = (name, email, image, pass, role, created, updated) => { - - return { - name: name, - email: email, - image: image, - pass: pass, - role: role, - created: created, - updated: updated - } -} - -/** - * ? GET USER WITH PASSWORD - * * Returns a user object with the password field. - * - * @param {string} name - The name of the user. - * @param {string} email - The email address of the user. - * @param {string} image - The image URL of the user. - * @param {string} pass - The password of the user. - * @param {string} role - The role of the user. - * @param {string} updated - The date of the last update. - * @return {object} - The user object with the provided properties. - */ -exports.getUserWithPass = (name, email, image, pass, role, updated) => { - - return { - name: name, - email: email, - image: image, - pass: pass, - role: role, - updated: updated - } -} - -/** - * ? GET USER NO PASSWORD - * * Returns a user object without the password field. - * - * @param {string} name - The name of the user. - * @param {string} email - The email address of the user. - * @param {string} image - The URL of the user's profile image. - * @param {string} role - The role of the user. - * @param {string} updated - The date when the user was last updated. - * @return {Object} - The user object without the password field. - */ -exports.getUserNoPass = (name, email, image, role, updated) => { - - return { - name: name, - email: email, - image: image, - role: role, - updated: updated - } -} - -//! ******************** SETTERS ******************** - -/** - * ? SET MESSAGE - * * Sets the message using the provided fields & sends it via email. - * - * @param {object} fields - The fields containing the necessary information to construct the message. - * @param {object} res - The response object used to send the HTTP response. - * @return {undefined} This function does not return anything. - */ -exports.setMessage = (fields, res) => { - const mailer = nem.getMailer(); - - (async function () { - try { - let mail = nem.getMessage(fields); - - await mailer.sendMail(mail, function () { - res.status(202).json({ message: process.env.USER_MESSAGE }); - }); - } catch (e) { console.error(e); } - })(); + if (user.name === name) return res.status(403).json({ message: process.env.DISPO_NAME }); + if (user.email === email) return res.status(403).json({ message: process.env.DISPO_EMAIL }); } //! ******************** PUBLIC ******************** @@ -219,7 +96,13 @@ exports.createUser = (req, res, next) => { bcrypt .hash(fields.pass, 10) .then((hash) => { - let user = this.getUserCreated(fields.name, fields.email, image, hash, fields.role, fields.created, fields.updated); + let user = { + name: fields.name, + email: fields.email, + image: image, + pass: hash, + role: fields.role + } User .create(user) @@ -247,8 +130,18 @@ exports.sendMessage = (req, res, next) => { form.parse(req, (err, fields) => { if (err) { next(err); return } - fields.html = `

${fields.html}

`; - this.setMessage(fields, res); + const mailer = nem.getMailer(); + fields.html = `

${fields.html}

`; + + (async function () { + try { + let mail = nem.getMessage(fields); + + await mailer.sendMail(mail, function () { + res.status(202).json({ message: process.env.USER_MESSAGE }); + }); + } catch (e) { console.error(e); } + })(); }) } @@ -324,7 +217,9 @@ exports.updateUser = (req, res, next) => { User .findAll() .then((users) => { - this.checkUsersForUnique(id, users, fields, res); + for (let user of users) { + if (user.id !== id) this.checkUserUnique(fields.name, fields.email, user, res); + } let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; if (files.image) nem.setThumbnail("users/" + files.image.newFilename, USERS_THUMB + image); @@ -335,7 +230,13 @@ exports.updateUser = (req, res, next) => { bcrypt .hash(fields.pass, 10) .then((hash) => { - let user = this.getUserWithPass(fields.name, fields.email, image, hash, fields.role, fields.updated); + let user = { + name: fields.name, + email: fields.email, + image: image, + pass: hash, + role: fields.role + } User .update(user, { where: { id: id }}) @@ -348,7 +249,12 @@ exports.updateUser = (req, res, next) => { .catch(() => res.status(400).json({ message: process.env.USER_NOT_PASS })); } else { - let user = this.getUserNoPass(fields.name, fields.email, image, fields.role, fields.updated); + let user = { + name: fields.name, + email: fields.email, + image: image, + role: fields.role + } User .update(user, { where: { id: id }}) From 5c9a3d53e1242be66d54ab4523da44f709712686 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sat, 16 Dec 2023 15:09:10 +0400 Subject: [PATCH 10/21] Remove useless created & updated fields --- controller/UserCtrl.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/controller/UserCtrl.js b/controller/UserCtrl.js index 1430090..8852e41 100644 --- a/controller/UserCtrl.js +++ b/controller/UserCtrl.js @@ -168,9 +168,7 @@ exports.listUsers = (req, res) => { name: user.name, email: user.email, image: user.image, - role: user.role, - created: user.created, - updated: user.updated, + role: user.role }; usersList.push(userSafe); From 74d2a1c7dcd49b392bd4d2d3a34a794e95ee68ed Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 01:52:44 +0400 Subject: [PATCH 11/21] Complete refactoring of ArticleCtrl --- controller/ArticleCtrl.js | 177 ++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 102 deletions(-) diff --git a/controller/ArticleCtrl.js b/controller/ArticleCtrl.js index c8ca863..e35e937 100644 --- a/controller/ArticleCtrl.js +++ b/controller/ArticleCtrl.js @@ -7,8 +7,10 @@ const nem = require("nemjs"); require("dotenv").config(); -const ARTICLES_IMG = process.env.IMG_URL + "articles/"; -const ARTICLES_THUMB = process.env.THUMB_URL + "articles/"; +const { ARTICLE_NOT_FOUND, ARTICLES_NOT_FOUND, IMG_EXT, IMG_URL, THUMB_URL } = process.env; + +const ARTICLES_IMG = IMG_URL + "articles/"; +const ARTICLES_THUMB = THUMB_URL + "articles/"; const Article = db.article; const form = formidable({ uploadDir: ARTICLES_IMG, keepExtensions: true }); @@ -18,7 +20,6 @@ const form = formidable({ uploadDir: ARTICLES_IMG, keepExtensions: true }); /** * ? CHECK ARTICLE DATA * * Checks the validity of article data. - * * @param {string} name - The name of the article. * @param {string} text - The text of the article. * @param {string} alt - The alternative text for the article. @@ -27,25 +28,21 @@ const form = formidable({ uploadDir: ARTICLES_IMG, keepExtensions: true }); * @return {object} The response object with an error message if the article is not correct. */ exports.checkArticleData = (name, text, alt, cat, res) => { - const STR_MAX = process.env.STRING_MAX; - const STR_MIN = process.env.STRING_MIN; - const TXT_MAX = process.env.TEXT_MAX; - const TXT_MIN = process.env.TEXT_MIN; - - let alert = ""; - - if (!nem.checkRange(cat, STR_MIN, STR_MAX)) alert = process.env.CHECK_CAT; - if (!nem.checkRange(alt, STR_MIN, STR_MAX)) alert = process.env.CHECK_NAME; - if (!nem.checkRange(text, TXT_MIN, TXT_MAX)) alert = process.env.CHECK_TEXT; - if (!nem.checkRange(name, STR_MIN, STR_MAX)) alert = process.env.CHECK_NAME; - - if (alert !== "") return res.status(403).json({ message: alert }); + const { CHECK_CAT, CHECK_NAME, CHECK_TEXT, STRING_MAX, STRING_MIN, TEXT_MAX, TEXT_MIN } = process.env; + + if ( + !nem.checkRange(cat, STRING_MIN, STRING_MAX) || + !nem.checkRange(alt, STRING_MIN, STRING_MAX) || + !nem.checkRange(text, TEXT_MIN, TEXT_MAX) || + !nem.checkRange(name, STRING_MIN, STRING_MAX) + ) { + return res.status(403).json({ message: CHECK_CAT || CHECK_NAME || CHECK_TEXT || CHECK_NAME }); + } } /** * ? CHECK ARTICLE UNIQUE * * Checks if an article is unique based on its name & text. - * * @param {string} name - The name of the article. * @param {string} text - The text of the article. * @param {object} article - The existing article to compare with. @@ -53,33 +50,26 @@ exports.checkArticleData = (name, text, alt, cat, res) => { * @return {object} The response object with an error message if the article is not unique. */ exports.checkArticleUnique = (name, text, article, res) => { - if (article.name === name) { - return res.status(403).json({ message: process.env.DISPO_NAME }); - } + const { DISPO_NAME, DISPO_TEXT } = process.env; - if (article.text === text) { - return res.status(403).json({ message: process.env.DISPO_TEXT }); - } + if (article.name === name) return res.status(403).json({ message: DISPO_NAME }); + if (article.text === text) return res.status(403).json({ message: DISPO_TEXT }); } /** * ? SET IMAGE * * Sets the image for an article. - * * @param {string} name - The name of the article. * @param {string} newFilename - The new filename of the image. */ exports.setImage = (name, newFilename) => { - let input = "articles/" + newFilename; - let output = "articles/" + name; - - nem.setThumbnail(input, process.env.THUMB_URL + output); - nem.setThumbnail( - input, - process.env.IMG_URL + output, - process.env.IMG_WIDTH, - process.env.IMG_HEIGHT - ); + const { IMG_HEIGHT, IMG_WIDTH } = process.env; + + const INPUT = "articles/" + newFilename; + const OUTPUT = "articles/" + name; + + nem.setThumbnail(INPUT, THUMB_URL + OUTPUT); + nem.setThumbnail(INPUT, IMG_URL + OUTPUT, IMG_WIDTH, IMG_HEIGHT); } //! ******************** PUBLIC ******************** @@ -94,10 +84,9 @@ exports.setImage = (name, newFilename) => { * @throws {Error} If the articles are not found in the database. */ exports.listArticles = (req, res) => { - Article - .findAll() + Article.findAll() .then((articles) => { res.status(200).json(articles) }) - .catch(() => res.status(404).json({ message: process.env.ARTICLES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: ARTICLES_NOT_FOUND })); } /** @@ -110,16 +99,13 @@ exports.listArticles = (req, res) => { * @throws {Error} If the article is not found in the database. */ exports.readArticle = (req, res) => { - Article - .findByPk(parseInt(req.params.id)) + Article.findByPk(parseInt(req.params.id)) .then((article) => { res.status(200).json(article) }) - .catch(() => res.status(404).json({ message: process.env.ARTICLE_NOT_FOUND })); + .catch(() => res.status(404).json({ message: ARTICLE_NOT_FOUND })); } //! ******************** PRIVATE ******************** -// TODO : create a method to like an article - /** * ? CREATE ARTICLE * * Creates an article based on the request data. @@ -131,39 +117,34 @@ exports.readArticle = (req, res) => { * @throws {Error} If the article is not created in the database. */ exports.createArticle = (req, res, next) => { + const { ARTICLE_CREATED, ARTICLE_NOT_CREATED } = process.env; + form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkArticleData(fields.name, fields.text, fields.alt, fields.cat, res); + const { name, text, alt, cat } = fields; + const { image } = files; - Article - .findAll() + const IMG = nem.getName(name) + "." + IMG_EXT; + + this.checkArticleData(name, text, alt, cat, res); + + Article.findAll() .then((articles) => { - for (let article of articles) { - this.checkArticleUnique(fields.name, fields.text, article, res) - } - - let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; - this.setImage(image, files.image.newFilename); - - let article = { - name: fields.name, - text: fields.text, - image: image, - alt: fields.alt, - cat: fields.cat - } - - Article - .create(article) + for (const article of articles) this.checkArticleUnique(name, text, article, res); + if (image && image.newFilename) this.setImage(IMG, image.newFilename); + + const article = { ...fields, image: IMG }; + + Article.create(article) .then(() => { - fs.unlink(ARTICLES_IMG + files.image.newFilename, () => { - res.status(201).json({ message: process.env.ARTICLE_CREATED }) - }) + if (image && image.newFilename) { + fs.unlink(ARTICLES_IMG + image.newFilename, () => { res.status(201).json({ message: ARTICLE_CREATED })}) + } }) - .catch(() => res.status(400).json({ message: process.env.ARTICLE_NOT_CREATED })); + .catch(() => res.status(400).json({ message: ARTICLE_NOT_CREATED })); }) - .catch(() => res.status(404).json({ message: process.env.ARTICLES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: ARTICLES_NOT_FOUND })); }) } @@ -178,41 +159,34 @@ exports.createArticle = (req, res, next) => { * @throws {Error} If the article is not updated in the database. */ exports.updateArticle = (req, res, next) => { - const id = parseInt(req.params.id); + const { ARTICLE_UPDATED, ARTICLE_NOT_UPDATED } = process.env; form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkArticleData(fields.name, fields.text, fields.alt, fields.cat, res); + const { name, text, alt, cat } = fields; + const { image } = files; + + const ID = parseInt(req.params.id); + const IMG = nem.getName(name) + "." + IMG_EXT; + + this.checkArticleData(name, text, alt, cat, res); - Article - .findAll() + Article.findAll() .then((articles) => { - for (let article of articles) { - if (article.id !== id) this.checkArticleUnique(fields.name, fields.text, article, res); - } - - let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; - if (files.image) this.setImage(image, files.image.newFilename); - - let article = { - name: fields.name, - text: fields.text, - image: image, - alt: fields.alt, - likes: fields.likes, - cat: fields.cat - } - - Article - .update(article, { where: { id: id }}) + articles.filter(article => article.id !== ID).forEach(article => this.checkArticleUnique(name, text, article, res)); + + if (image && image.newFilename) this.setImage(IMG, image.newFilename); + const article = { ...fields, image: IMG }; + + Article.update(article, { where: { id: ID }}) .then(() => { - if (files.image) fs.unlink(ARTICLES_IMG + files.image.newFilename, () => { }); - res.status(200).json({ message: process.env.ARTICLE_UPDATED }); + if (image && image.newFilename) fs.unlink(ARTICLES_IMG + image.newFilename, () => {}); + res.status(200).json({ message: ARTICLE_UPDATED }); }) - .catch(() => res.status(400).json({ message: process.env.ARTICLE_NOT_UPDATED })); + .catch(() => res.status(400).json({ message: ARTICLE_NOT_UPDATED })); }) - .catch(() => res.status(404).json({ message: process.env.ARTICLES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: ARTICLES_NOT_FOUND })); }) } @@ -226,20 +200,19 @@ exports.updateArticle = (req, res, next) => { * @throws {Error} If the article is not deleted in the database. */ exports.deleteArticle = (req, res) => { - const id = parseInt(req.params.id); + const { ARTICLE_DELETED, ARTICLE_NOT_DELETED } = process.env; + const ID = parseInt(req.params.id); - Article - .findByPk(id) + Article.findByPk(ID) .then(article => { fs.unlink(ARTICLES_THUMB + article.image, () => { fs.unlink(ARTICLES_IMG + article.image, () => { - Article - .destroy({ where: { id: id }}) - .then(() => res.status(204).json({ message: process.env.ARTICLE_DELETED })) - .catch(() => res.status(400).json({ message: process.env.ARTICLE_NOT_DELETED })) - }); + Article.destroy({ where: { id: ID }}) + .then(() => res.status(204).json({ message: ARTICLE_DELETED })) + .catch(() => res.status(400).json({ message: ARTICLE_NOT_DELETED })); + }) }) }) - .catch(() => res.status(404).json({ message: process.env.ARTICLE_NOT_FOUND })); + .catch(() => res.status(404).json({ message: ARTICLE_NOT_FOUND })); } From c9c9eb06fa30e90477c3285f32940f0ae6de1f39 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 01:53:03 +0400 Subject: [PATCH 12/21] Complete refactoring of UserCtrl --- controller/UserCtrl.js | 217 +++++++++++++++++------------------------ 1 file changed, 92 insertions(+), 125 deletions(-) diff --git a/controller/UserCtrl.js b/controller/UserCtrl.js index 8852e41..7b9b6c6 100644 --- a/controller/UserCtrl.js +++ b/controller/UserCtrl.js @@ -8,6 +8,8 @@ const nem = require("nemjs"); require("dotenv").config(); +const { IMG_EXT, USER_NOT_FOUND, USER_NOT_PASS, USERS_NOT_FOUND } = process.env; + const USERS_IMG = process.env.IMG_URL + "users/"; const USERS_THUMB = process.env.THUMB_URL + "users/"; @@ -19,7 +21,6 @@ const User = db.user; /** * ? CHECK USER DATA * * Validates user data & returns a JSON response with an error message if any validation fails. - * * @param {string} name - The user's name. * @param {string} email - The user's email. * @param {string} role - The user's role. @@ -27,34 +28,33 @@ const User = db.user; * @return {object} - JSON response with an error message if any validation fails. */ exports.checkUserData = (name, email, role, res) => { - const MAX = process.env.STRING_MAX; - const MIN = process.env.STRING_MIN; - - let alert = ""; - - if (!nem.checkRange(role, MIN, MAX)) alert = process.env.CHECK_ROLE; - if (!nem.checkEmail(email)) alert = process.env.CHECK_EMAIL; - if (!nem.checkRange(name, MIN, MAX)) alert = process.env.CHECK_NAME; - - if (alert !== "") return res.status(403).json({ message: alert }); + const { CHECK_EMAIL, CHECK_NAME, CHECK_ROLE, STRING_MAX, STRING_MIN } = process.env; + + if ( + !nem.checkRange(role, STRING_MIN, STRING_MAX) || + !nem.checkEmail(email) || + !nem.checkRange(name, STRING_MIN, STRING_MAX) + ) { + return res.status(403).json({ message: CHECK_ROLE || CHECK_EMAIL || CHECK_NAME }); + } } /** * ? CHECK USER PASSWORD * * Checks if the user password is valid. - * * @param {string} pass - The user password to be checked. * @param {object} res - The response object. * @return {object} - The response object with an error message if the password is invalid. */ exports.checkUserPass = (pass, res) => { - if (!nem.checkPass(pass)) return res.status(403).json({ message: process.env.CHECK_PASS }); + const { CHECK_PASS } = process.env; + + if (!nem.checkPass(pass)) return res.status(403).json({ message: CHECK_PASS }); } /** * ? CHECK USER UNIQUE * * Checks if the given user's name & email are unique. - * * @param {string} name - The name to check against the user's name. * @param {string} email - The email to check against the user's email. * @param {object} user - The user object to compare against. @@ -62,8 +62,10 @@ exports.checkUserPass = (pass, res) => { * @return {object} The JSON response containing the error message if the name or email is not unique. */ exports.checkUserUnique = (name, email, user, res) => { - if (user.name === name) return res.status(403).json({ message: process.env.DISPO_NAME }); - if (user.email === email) return res.status(403).json({ message: process.env.DISPO_EMAIL }); + const { DISPO_EMAIL, DISPO_NAME } = process.env; + + if (user.name === name) return res.status(403).json({ message: DISPO_NAME }); + if (user.email === email) return res.status(403).json({ message: DISPO_EMAIL }); } //! ******************** PUBLIC ******************** @@ -71,7 +73,6 @@ exports.checkUserUnique = (name, email, user, res) => { /** * ? CREATE USER * * Creates a new user. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {Function} next - The next middleware function. @@ -79,68 +80,63 @@ exports.checkUserUnique = (name, email, user, res) => { * @throws {Error} If the user is not created. */ exports.createUser = (req, res, next) => { + const { USER_CREATED, USER_NOT_CREATED } = process.env; + form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkUserData(fields.name, fields.email, fields.role, res); - this.checkUserPass(fields.pass, res); + const { name, email, role, pass } = fields; + const { image } = files; - User - .findAll() - .then((users) => { - for (let user of users) { this.checkUserUnique(fields.name, fields.email, user, res) } + const IMG = nem.getName(name) + "." + IMG_EXT; + + this.checkUserData(name, email, role, res); + this.checkUserPass(pass, res); - let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; - nem.setThumbnail("users/" + files.image.newFilename, USERS_THUMB + image); + User.findAll() + .then((users) => { + for (const user of users) this.checkUserUnique(name, email, user, res); + if (image && image.newFilename) nem.setThumbnail("users/" + image.newFilename, USERS_THUMB + IMG); - bcrypt - .hash(fields.pass, 10) + bcrypt.hash(pass, 10) .then((hash) => { - let user = { - name: fields.name, - email: fields.email, - image: image, - pass: hash, - role: fields.role - } - - User - .create(user) + const user = { ...fields, image: IMG, pass: hash }; + + User.create(user) .then(() => { - fs.unlink(USERS_IMG + files.image.newFilename, () => { res.status(201).json({ message: process.env.USER_CREATED }) }) + if (image && image.newFilename) { + fs.unlink(USERS_IMG + image.newFilename, () => { res.status(201).json({ message: USER_CREATED })}); + } }) - .catch(() => res.status(400).json({ message: process.env.USER_NOT_CREATED })); - + .catch(() => res.status(400).json({ message: USER_NOT_CREATED })); }) - .catch(() => res.status(400).json({ message: process.env.USER_NOT_PASS })); + .catch(() => res.status(400).json({ message: USER_NOT_PASS })); }) - .catch(() => { res.status(404).json({ message: process.env.USERS_NOT_FOUND }) }); + .catch(() => { res.status(404).json({ message: USERS_NOT_FOUND })}); }); } /** * ? SEND USER MESSAGE * * Sends a message. - * * @param {Object} req - the request object * @param {Object} res - the response object * @param {Function} next - the next middleware function */ exports.sendMessage = (req, res, next) => { + const { USER_MESSAGE } = process.env; + const mailer = nem.getMailer(); + form.parse(req, (err, fields) => { if (err) { next(err); return } - const mailer = nem.getMailer(); - fields.html = `

${fields.html}

`; + const mail = nem.getMessage(fields); + fields.html = `

${fields.html}

`; (async function () { try { - let mail = nem.getMessage(fields); - - await mailer.sendMail(mail, function () { - res.status(202).json({ message: process.env.USER_MESSAGE }); - }); - } catch (e) { console.error(e); } + await mailer.sendMail(mail, function () { res.status(202).json({ message: USER_MESSAGE })}); + } catch (e) { console.error(e) } })(); }) } @@ -150,54 +146,48 @@ exports.sendMessage = (req, res, next) => { /** * ? LIST ALL USERS WITHOUT PASSWORD * * Retrieves the list of users. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} The list of users in JSON format. * @throws {Error} If the users are not found in the database. */ exports.listUsers = (req, res) => { - User - .findAll() - .then((users) => { - let usersList = []; + const usersList = []; - for (let user of users) { - let userSafe = { + User.findAll() + .then((users) => { + for (const user of users) { + const userSafe = { id: user.id, name: user.name, email: user.email, image: user.image, role: user.role }; - usersList.push(userSafe); } res.status(200).json(usersList); }) - .catch(() => res.status(404).json({ message: process.env.USERS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: USERS_NOT_FOUND })); } /** * ? READ A USER * * Retrieves a user by their ID & sends a JSON response. - * * @param {object} req - The request object. * @param {object} res - The response object. * @return {object} The user data in JSON format. * @throws {Error} If the user is not found in the database. */ exports.readUser = (req, res) => { - User - .findByPk(parseInt(req.params.id)) + User.findByPk(parseInt(req.params.id)) .then((user) => res.status(200).json(user)) - .catch(() => res.status(404).json({ message: process.env.USER_NOT_FOUND })); + .catch(() => res.status(404).json({ message: USER_NOT_FOUND })); } /** * ? UPDATE USER * * Updates a user based on the provided request data. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {Function} next - The next middleware function. @@ -205,90 +195,67 @@ exports.readUser = (req, res) => { * @throws {Error} If the user is not updated in the database. */ exports.updateUser = (req, res, next) => { - const id = parseInt(req.params.id); + const { USER_NOT_UPDATED, USER_UPDATED } = process.env; form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkUserData(fields.name, fields.email, fields.role, res); + const { name, email, role, pass } = fields; + const { image } = files; + + const ID = parseInt(req.params.id); + const IMG = nem.getName(name) + "." + IMG_EXT; - User - .findAll() + let user; + this.checkUserData(name, email, role, res); + + User.findAll() .then((users) => { - for (let user of users) { - if (user.id !== id) this.checkUserUnique(fields.name, fields.email, user, res); - } + users.filter(user => user.id !== ID).forEach(user => this.checkUserUnique(name, email, user, res)); + if (image && image.newFilename) nem.setThumbnail("users/" + image.newFilename, USERS_THUMB + IMG); + + if (pass) { + this.checkUserPass(pass, res); - let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; - if (files.image) nem.setThumbnail("users/" + files.image.newFilename, USERS_THUMB + image); - - if (fields.pass) { - this.checkUserPass(fields.pass, res); - - bcrypt - .hash(fields.pass, 10) - .then((hash) => { - let user = { - name: fields.name, - email: fields.email, - image: image, - pass: hash, - role: fields.role - } - - User - .update(user, { where: { id: id }}) - .then(() => { - if (files.image) fs.unlink(USERS_IMG + files.image.newFilename, () => { }); - res.status(200).json({ message: process.env.USER_UPDATED }); - }) - .catch(() => res.status(400).json({ message: process.env.USER_NOT_UPDATED })); - }) - .catch(() => res.status(400).json({ message: process.env.USER_NOT_PASS })); - - } else { - let user = { - name: fields.name, - email: fields.email, - image: image, - role: fields.role - } - - User - .update(user, { where: { id: id }}) - .then(() => { - if (files.image) fs.unlink(USERS_IMG + files.image.newFilename, () => { }); - res.status(200).json({ message: process.env.USER_UPDATED }); - }) - .catch(() => res.status(400).json({ message: process.env.USER_NOT_UPDATED })); + bcrypt.hash(pass, 10) + .then((hash) => { user = { ...fields, image: IMG, pass: hash }}) + .catch(() => res.status(400).json({ message: USER_NOT_PASS })); + + } else { + user = { ...fields, image: IMG } } + + User.update(user, { where: { id: ID }}) + .then(() => { + if (image && image.newFilename) fs.unlink(USERS_IMG + image.newFilename, () => {}); + res.status(200).json({ message: USER_UPDATED }); + }) + .catch(() => res.status(400).json({ message: USER_NOT_UPDATED })); }) - .catch(() => res.status(404).json({ message: process.env.USERS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: USERS_NOT_FOUND })); }) } /** * ? DELETE USER - * * Deletes a user and associated comments & reviews from the database. - * + * * Deletes a user, associated comments & reviews from the database. * @param {Object} req - The request object containing the user id in the params. * @param {Object} res - The response object to send the result. * @return {Object} The response object with a status & JSON message indicating success or failure. * @throws {Error} If the user is not deleted from the database. */ exports.deleteUser = (req, res) => { - const id = parseInt(req.params.id); + const { USER_DELETED, USER_NOT_DELETED } = process.env; + const ID = parseInt(req.params.id); - User - .findByPk(id) + User.findByPk(ID) .then(user => { fs.unlink(USERS_THUMB + user.image, () => { - User - .destroy({ where: { id: id }}) - .then(() => res.status(204).json({ message: process.env.USER_DELETED })) - .catch(() => res.status(400).json({ message: process.env.USER_NOT_DELETED })) + User.destroy({ where: { id: ID }}) + .then(() => res.status(204).json({ message: USER_DELETED })) + .catch(() => res.status(400).json({ message: USER_NOT_DELETED })) }) }) - .catch(() => res.status(404).json({ message: process.env.USER_NOT_FOUND })); + .catch(() => res.status(404).json({ message: USER_NOT_FOUND })); } From f60db53db28a9baf00db57322a574e33291da555 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 02:19:34 +0400 Subject: [PATCH 13/21] Complete refactoring of AuthCtrl --- controller/AuthCtrl.js | 80 ++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/controller/AuthCtrl.js b/controller/AuthCtrl.js index ff2a7fe..2197428 100644 --- a/controller/AuthCtrl.js +++ b/controller/AuthCtrl.js @@ -8,6 +8,8 @@ const Recaptcha = require("google-recaptcha"); require("dotenv").config(); +const { USER_NOT_FOUND } = process.env; + const form = formidable(); const recaptcha = new Recaptcha({ secret: process.env.RECAPTCHA_SECRET }); const User = db.user; @@ -15,31 +17,27 @@ const User = db.user; /** * ? READ AVATAR * * Retrieves the avatar information for a specific user. - * * @param {object} req - The request object. * @param {object} res - The response object. * @return {object} The avatar information for the user. * @throws {Error} If the user is not found in the database. */ exports.readAvatar = (req, res) => { - User - .findByPk(parseInt(req.params.id)) + User.findByPk(parseInt(req.params.id)) .then((user) => { - let avatar = {}; - - avatar.name = user.name; - avatar.image = user.image; - avatar.role = user.role; - + const avatar = { + name: user.name, + image: user.image, + role: user.role + }; res.status(200).json(avatar) }) - .catch(() => res.status(404).json({ message: process.env.USER_NOT_FOUND })); + .catch(() => res.status(404).json({ message: USER_NOT_FOUND })); } /** * ? CHECK RECAPTCHA * * Checks the validity of a recaptcha response. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {Function} next - The next middleware function. @@ -54,12 +52,8 @@ exports.checkRecaptcha = (req, res, next) => { const remoteIp = req.connection.remoteAddress; recaptcha.verify({ response, remoteIp }, (err, data) => { - - if (err) { - res.status(500).send(err); - } else { - res.send(data); - } + if (!err) res.send(data); + else res.status(500).send(err); }); }) } @@ -67,27 +61,28 @@ exports.checkRecaptcha = (req, res, next) => { /** * ? LOGIN USER * * Login a user. - * * @param {Object} req - the request object * @param {Object} res - the response object * @param {Function} next - the next middleware function * @throws {Error} If the user is not found in the database. */ exports.loginUser = (req, res, next) => { + const { AUTH_LOGIN } = process.env; + form.parse(req, (err, fields) => { if (err) { next(err); return } + const { email, pass } = fields; User - .findOne({ where: { email: fields.email }}) - .then((user) => { nem.setAuth(fields.pass, user, res) }) - .catch(() => res.status(401).json({ message: process.env.AUTH_LOGIN })); + .findOne({ where: { email: email }}) + .then((user) => { nem.setAuth(pass, user, res) }) + .catch(() => res.status(401).json({ message: AUTH_LOGIN })); }) } /** * ? FORGOT PASSWORD * * Handles the forgot password functionality. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {Function} next - The next middleware function. @@ -95,50 +90,45 @@ exports.loginUser = (req, res, next) => { * @throws {Error} If the user is not found in the database. */ exports.forgotPass = (req, res, next) => { + const { AUTH_MESSAGE, CHECK_EMAIL, DISPO_EMAIL_REF, USER_NOT_PASS, USER_NOT_UPDATED } = process.env; + form.parse(req, (err, fields) => { if (err) { next(err); return } - if (!nem.checkEmail(fields.email)) return res.status(403).json({ message: process.env.CHECK_EMAIL }); + const { email, html } = fields; + const pass = nem.getPassword(); + fields.html = `

${html}

${pass}`; + + if (!nem.checkEmail(email)) return res.status(403).json({ message: CHECK_EMAIL }); + + const mailer = nem.getMailer(); + const mail = nem.getMessage(fields); User - .findOne({ where: { email: fields.email }}) + .findOne({ where: { email: email }}) .then((user) => { if (user !== null) { - let pass = nem.getPassword(); - fields.html = `

${fields.html}

${pass}`; - bcrypt .hash(pass, 10) .then((hash) => { - let newUser = { - name: user.name, - email: user.email, - image: user.image, - pass: hash, - role: user.role - } + const newUser = { ...user, pass: hash }; User .update(newUser, { where: { id: user.id }}) .then(() => { - const mailer = nem.getMailer(); (async function(){ try { - let mail = nem.getMessage(fields); - await mailer.sendMail(mail, function() { - res.status(202).json({ message: process.env.AUTH_MESSAGE }); - }); - } catch(e){ console.error(e); } + await mailer.sendMail(mail, function() {res.status(202).json({ message: AUTH_MESSAGE })}); + } catch(e){ console.error(e) } })(); }) - .catch(() => res.status(400).json({ message: process.env.USER_NOT_UPDATED })); + .catch(() => res.status(400).json({ message: USER_NOT_UPDATED })); }) - .catch(() => res.status(400).json({ message: process.env.USER_NOT_PASS })); - + .catch(() => res.status(400).json({ message: USER_NOT_PASS })); } else { - return res.status(403).json({ message: process.env.DISPO_EMAIL_REF }); + return res.status(403).json({ message: DISPO_EMAIL_REF }); } }) - .catch(() => res.status(404).json({ message: process.env.USER_NOT_FOUND })); + .catch(() => res.status(404).json({ message: USER_NOT_FOUND })); }) } From 3434307d3fc1c972e6756eb9db5ec5683aabeaa6 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 02:32:03 +0400 Subject: [PATCH 14/21] Complete refactoring of LinkCtrl --- controller/LinkCtrl.js | 92 ++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/controller/LinkCtrl.js b/controller/LinkCtrl.js index c1965d3..b831e6e 100644 --- a/controller/LinkCtrl.js +++ b/controller/LinkCtrl.js @@ -6,6 +6,8 @@ const nem = require("nemjs"); require("dotenv").config(); +const { LINKS_NOT_FOUND } = process.env; + const form = formidable(); const Link = db.link; @@ -14,7 +16,6 @@ const Link = db.link; /** * ? CHECK LINK DATA * * Validates the link data provided and returns an error message if any validation fails. - * * @param {string} name - The name of the link. * @param {string} url - The URL of the link. * @param {string} cat - The category of the link. @@ -22,20 +23,20 @@ const Link = db.link; * @return {object} The error message if any validation fails. */ exports.checkLinkData = (name, url, cat, res) => { - const MAX = process.env.STRING_MAX; - const MIN = process.env.STRING_MIN; - let alert = ""; - - if (!nem.checkRange(cat, MIN, MAX)) alert = process.env.CHECK_CAT; - if (!nem.checkUrl("https://" + url)) alert = process.env.CHECK_URL; - if (!nem.checkRange(name, MIN, MAX)) alert = process.env.CHECK_NAME; - if (alert !== "") return res.status(403).json({ message: alert }); + const { CHECK_CAT, CHECK_NAME, CHECK_URL, STRING_MAX, STRING_MIN } = process.env; + + if ( + !nem.checkRange(cat, STRING_MIN, STRING_MAX) || + !nem.checkUrl("https://" + url) || + !nem.checkRange(name, STRING_MIN, STRING_MAX) + ) { + return res.status(403).json({ message: CHECK_CAT || CHECK_URL || CHECK_NAME }); + } } /** * ? CHECK LINK UNIQUE * * Checks if the given link name & URL are unique. - * * @param {string} name - The name of the link to check uniqueness for. * @param {string} url - The URL of the link to check uniqueness for. * @param {object} link - The link object to compare against. @@ -43,8 +44,10 @@ exports.checkLinkData = (name, url, cat, res) => { * @return {object} - The response object with the appropriate status & message. */ exports.checkLinkUnique = (name, url, link, res) => { - if (link.name === name) return res.status(403).json({ message: process.env.DISPO_NAME }); - if (link.url === url) return res.status(403).json({ message: process.env.DISPO_URL }); + const { DISPO_NAME, DISPO_URL } = process.env; + + if (link.name === name) return res.status(403).json({ message: DISPO_NAME }); + if (link.url === url) return res.status(403).json({ message: DISPO_URL }); } //! ******************** PUBLIC ******************** @@ -52,17 +55,15 @@ exports.checkLinkUnique = (name, url, link, res) => { /** * ? LIST LINKS * * Retrieves a list of links. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} A JSON object containing the list of links. * @throws {Error} If the links are not found in the database. */ exports.listLinks = (req, res) => { - Link - .findAll() + Link.findAll() .then((links) => res.status(200).json(links)) - .catch(() => res.status(404).json({ message: process.env.LINKS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: LINKS_NOT_FOUND })); }; //! ******************** PRIVATE ******************** @@ -70,7 +71,6 @@ exports.listLinks = (req, res) => { /** * ? CREATE LINK * * Creates a link based on the request data. - * * @param {Object} req - the request object * @param {Object} res - the response object * @param {Function} next - the next middleware function @@ -78,27 +78,29 @@ exports.listLinks = (req, res) => { * @throws {Error} If the link is not created. */ exports.createLink = (req, res, next) => { + const { LINK_CREATED, LINK_NOT_CREATED } = process.env; + form.parse(req, (err, fields) => { if (err) { next(err); return } - this.checkLinkData(fields.name, fields.url, fields.cat, res); - Link - .findAll() + const { name, url, cat } = fields; + this.checkLinkData(name, url, cat, res); + + Link.findAll() .then((links) => { - for (let link of links) this.checkLinkUnique(fields.name, fields.url, link, res); - Link - .create(fields) - .then(() => res.status(201).json({ message: process.env.LINK_CREATED })) - .catch(() => res.status(400).json({ message: process.env.LINK_NOT_CREATED })); + for (let link of links) this.checkLinkUnique(name, url, link, res); + + Link.create(fields) + .then(() => res.status(201).json({ message: LINK_CREATED })) + .catch(() => res.status(400).json({ message: LINK_NOT_CREATED })); }) - .catch(() => res.status(404).json({ message: process.env.LINKS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: LINKS_NOT_FOUND })); }) }; /** * ? UPDATE LINK * * Updates a link in the database. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {Function} next - The next middleware function. @@ -106,38 +108,40 @@ exports.createLink = (req, res, next) => { * @throws {Error} If the link is not updated. */ exports.updateLink = (req, res, next) => { - const id = parseInt(req.params.id); + const { LINK_NOT_UPDATED, LINK_UPDATED } = process.env; + const ID = parseInt(req.params.id); + form.parse(req, (err, fields) => { if (err) { next(err); return } - this.checkLinkData(fields.name, fields.url, fields.cat, res); - Link - .findAll() + const { name, url, cat } = fields; + this.checkLinkData(name, url, cat, res); + + Link.findAll() .then((links) => { - for (let link of links) { - if (link.id !== id) this.checkLinkUnique(fields.name, fields.url, link, res); - } - Link - .update(fields, { where: { id: id }}) - .then(() => res.status(200).json({ message: process.env.LINK_UPDATED })) - .catch(() => res.status(400).json({ message: process.env.LINK_NOT_UPDATED })); + links.filter(link => link.id !== ID).forEach(link => this.checkLinkUnique(name, url, link, res)); + + Link.update(fields, { where: { id: ID }}) + .then(() => res.status(200).json({ message: LINK_UPDATED })) + .catch(() => res.status(400).json({ message: LINK_NOT_UPDATED })); }) - .catch(() => res.status(404).json({ message: process.env.LINKS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: LINKS_NOT_FOUND })); }) }; /** * ? DELETE LINK * * Deletes a link. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} - A message indicating that the link was deleted. * @throws {Error} If the link is not deleted. */ exports.deleteLink = (req, res) => { - Link - .destroy({ where: { id: parseInt(req.params.id) }}) - .then(() => res.status(204).json({ message: process.env.LINK_DELETED })) - .catch(() => res.status(400).json({ message: process.env.LINK_NOT_DELETED })) + const { LINK_DELETED, LINK_NOT_DELETED } = process.env; + const ID = parseInt(req.params.id); + + Link.destroy({ where: { id: ID }}) + .then(() => res.status(204).json({ message: LINK_DELETED })) + .catch(() => res.status(400).json({ message: LINK_NOT_DELETED })) }; From a5097ee22fe36daf307b1181440fef750d3cf87a Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 02:32:45 +0400 Subject: [PATCH 15/21] Save lines to AuthCtrl --- controller/AuthCtrl.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/controller/AuthCtrl.js b/controller/AuthCtrl.js index 2197428..ebe7f5f 100644 --- a/controller/AuthCtrl.js +++ b/controller/AuthCtrl.js @@ -73,8 +73,7 @@ exports.loginUser = (req, res, next) => { if (err) { next(err); return } const { email, pass } = fields; - User - .findOne({ where: { email: email }}) + User.findOne({ where: { email: email }}) .then((user) => { nem.setAuth(pass, user, res) }) .catch(() => res.status(401).json({ message: AUTH_LOGIN })); }) @@ -104,8 +103,7 @@ exports.forgotPass = (req, res, next) => { const mailer = nem.getMailer(); const mail = nem.getMessage(fields); - User - .findOne({ where: { email: email }}) + User.findOne({ where: { email: email }}) .then((user) => { if (user !== null) { bcrypt @@ -113,8 +111,7 @@ exports.forgotPass = (req, res, next) => { .then((hash) => { const newUser = { ...user, pass: hash }; - User - .update(newUser, { where: { id: user.id }}) + User.update(newUser, { where: { id: user.id }}) .then(() => { (async function(){ try { From 54c038ad517ad05a57e1a73a17b564a318de4297 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 11:26:38 +0400 Subject: [PATCH 16/21] Complete refactoring of GalleryCtrl --- controller/GalleryCtrl.js | 131 +++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 71 deletions(-) diff --git a/controller/GalleryCtrl.js b/controller/GalleryCtrl.js index 76c3737..9c38ee7 100644 --- a/controller/GalleryCtrl.js +++ b/controller/GalleryCtrl.js @@ -7,6 +7,8 @@ const nem = require("nemjs"); require("dotenv").config(); +const { GALLERIES_NOT_FOUND } = process.env; + const GALLERIES_IMG = process.env.IMG_URL + "galleries/"; const GALLERIES_THUMB = process.env.THUMB_URL + "galleries/"; @@ -19,24 +21,25 @@ const Image = db.image; /** * ? CHECK GALLERY DATA * * Checks the gallery data for valid name and author. - * * @param {string} name - The name of the gallery. * @param {string} author - The author of the gallery. * @param {object} res - The response object. * @return {object} A message indicating that the gallery data is invalid. */ exports.checkGalleryData = (name, author, res) => { - const MAX = process.env.STRING_MAX; - const MIN = process.env.STRING_MIN; - - if (!nem.checkRange(author, MIN, MAX)) return res.status(403).json({ message: process.env.CHECK_NAME }); - if (!nem.checkRange(name, MIN, MAX)) return res.status(403).json({ message: process.env.CHECK_NAME }); + const { CHECK_NAME, STRING_MAX, STRING_MIN } = process.env; + + if ( + !nem.checkRange(author, STRING_MIN, STRING_MAX) || + !nem.checkRange(name, STRING_MIN, STRING_MAX) + ) { + return res.status(403).json({ message: CHECK_NAME }); + } } /** * ? CHECK GALLERY UNIQUE * * Checks if the given name is unique in the gallery. - * * @param {string} name - The name to be checked. * @param {object} gallery - The gallery object. * @param {object} res - The response object. @@ -44,7 +47,9 @@ exports.checkGalleryData = (name, author, res) => { * @throws {Error} If the name is not unique. */ exports.checkGalleryUnique = (name, gallery, res) => { - if (gallery.name === name) return res.status(403).json({ message: process.env.DISPO_NAME }); + const { DISPO_NAME } = process.env; + + if (gallery.name === name) return res.status(403).json({ message: DISPO_NAME }); } //! ******************** PUBLIC ******************** @@ -52,33 +57,32 @@ exports.checkGalleryUnique = (name, gallery, res) => { /** * ? LIST GALLERIES * * Retrieves a list of all galleries. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} The list of galleries in JSON format. * @throws {Error} If the galleries are not found in the database. */ exports.listGalleries = (req, res) => { - Gallery - .findAll() + Gallery.findAll() .then((galleries) => { res.status(200).json(galleries) }) - .catch(() => res.status(404).json({ message: process.env.GALLERIES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: GALLERIES_NOT_FOUND })); } /** * ? READ GALLERY * * Retrieves a gallery by its ID and sends it as a JSON response. - * * @param {object} req - The request object. * @param {object} res - The response object. * @return {object} The retrieved gallery as a JSON response. * @throws {Error} If the gallery is not found in the database. */ exports.readGallery = (req, res) => { - Gallery - .findByPk(parseInt(req.params.id)) - .then((gallery) => { res.status(200).json(gallery) }) - .catch(() => res.status(404).json({ message: process.env.GALLERY_NOT_FOUND })); + const { GALLERY_NOT_FOUND } = process.env; + const ID = parseInt(req.params.id); + + Gallery.findByPk(ID) + .then((gallery) => { res.status(200).json(gallery) }) + .catch(() => res.status(404).json({ message: GALLERY_NOT_FOUND })); } //! ******************** PRIVATE ******************** @@ -86,7 +90,6 @@ exports.readGallery = (req, res) => { /** * ? CREATE GALLERY * * Creates a new gallery. - * * @param {Object} req - the request object * @param {Object} res - the response object * @param {Function} next - the next middleware function @@ -94,38 +97,32 @@ exports.readGallery = (req, res) => { * @throws {Error} If the gallery was not created. */ exports.createGallery = (req, res, next) => { + const { GALLERY_CREATED, GALLERY_NOT_CREATED } = process.env; + form.parse(req, (err, fields) => { if (err) { next(err); return } - this.checkGalleryData(fields.name, fields.author, res); + const { author, name } = fields; + this.checkGalleryData(name, author, res); - Gallery - .findAll() + Gallery.findAll() .then((galleries) => { - for (let gallery of galleries) { - this.checkGalleryUnique(fields.name, gallery, res) - } - - let cover = nem.getPosterName(fields.name); - let gallery = { - name: fields.name, - author: fields.author, - cover: cover - }; - - Gallery - .create(gallery) - .then(() => res.status(201).json({ message: process.env.GALLERY_CREATED })) - .catch(() => res.status(400).json({ message: process.env.GALLERY_NOT_CREATED })); + for (let gallery of galleries) this.checkGalleryUnique(name, gallery, res); + + const cover = nem.getPosterName(name); + const gallery = { ...fields, cover: cover }; + + Gallery.create(gallery) + .then(() => res.status(201).json({ message: GALLERY_CREATED })) + .catch(() => res.status(400).json({ message: GALLERY_NOT_CREATED })); }) - .catch(() => res.status(404).json({ message: process.env.GALLERIES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: GALLERIES_NOT_FOUND })); }) } /** * ? UPDATE GALLERY * * Update the gallery with the given request data. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {Function} next - The next middleware function. @@ -133,64 +130,56 @@ exports.createGallery = (req, res, next) => { * @throws {Error} If the gallery is not updated. */ exports.updateGallery = (req, res, next) => { - const id = parseInt(req.params.id); + const { GALLERY_NOT_UPDATED, GALLERY_UPDATED } = process.env; + const ID = parseInt(req.params.id); form.parse(req, (err, fields) => { if (err) { next(err); return } - this.checkGalleryData(fields.name, fields.author, res); + const { author, name } = fields; + this.checkGalleryData(name, author, res); - Gallery - .findAll() + Gallery.findAll() .then((galleries) => { - for (let gallery of galleries) { - if (gallery.id !== id) this.checkGalleryUnique(fields.name, gallery, res); - } - - let gallery = { - name: fields.name, - author: fields.author - }; - - Gallery - .update(gallery, { where: { id: id }}) - .then(() => res.status(200).json({ message: process.env.GALLERY_UPDATED })) - .catch(() => res.status(400).json({ message: process.env.GALLERY_NOT_UPDATED })); + galleries.filter(gallery => gallery.id !== ID).forEach(gallery => + this.checkGalleryUnique(name, gallery, res)); + + const gallery = { ...fields }; + + Gallery.update(gallery, { where: { id: ID }}) + .then(() => res.status(200).json({ message: GALLERY_UPDATED })) + .catch(() => res.status(400).json({ message: GALLERY_NOT_UPDATED })); }) - .catch(() => res.status(404).json({ message: process.env.GALLERIES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: GALLERIES_NOT_FOUND })); }) } /** * ? DELETE GALLERY * * Deletes a gallery and its associated images. - * * @param {Object} req - the request object * @param {Object} res - the response object * @return {Object} A message indicating that the gallery was deleted. * @throws {Error} If the gallery is not deleted. */ exports.deleteGallery = (req, res) => { - const id = parseInt(req.params.id); + const { GALLERY_DELETED, GALLERY_NOT_DELETED, IMAGE_DELETE_MANY, IMAGES_NOT_FOUND } = process.env; + const ID = parseInt(req.params.id); - Image - .findAll({ where: { galleryId: id }}) + Image.findAll({ where: { galleryId: ID }}) .then(images => { for (let image of images) { - fs.unlink(GALLERIES_THUMB + image.name, () => { - fs.unlink(GALLERIES_IMG + image.name, () => {}); + fs.unlink(GALLERIES_THUMB + image.name, () => { + fs.unlink(GALLERIES_IMG + image.name, () => {}) }); } - Image - .destroy({ where: { galleryId: id }}) + Image.destroy({ where: { galleryId: ID }}) .then(() => - - Gallery - .destroy({ where: { id: id }}) - .then(() => res.status(204).json({ message: process.env.GALLERY_DELETED })) - .catch(() => res.status(400).json({ message: process.env.GALLERY_NOT_DELETED })) + Gallery.destroy({ where: { id: ID }}) + .then(() => res.status(204).json({ message: GALLERY_DELETED })) + .catch(() => res.status(400).json({ message: GALLERY_NOT_DELETED })) ) - .catch(() => res.status(400).json({ message: process.env.IMAGE_DELETE_MANY })); + .catch(() => res.status(400).json({ message: IMAGE_DELETE_MANY })); }) - .catch(() => res.status(404).json({ message: process.env.IMAGES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: IMAGES_NOT_FOUND })); } From 7b67eedc0150f1dc89e19e6a7bd89a5d13121964 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 11:26:46 +0400 Subject: [PATCH 17/21] Complete refactoring of ImageCtrl --- controller/ImageCtrl.js | 131 ++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 72 deletions(-) diff --git a/controller/ImageCtrl.js b/controller/ImageCtrl.js index feeb02c..1a29787 100644 --- a/controller/ImageCtrl.js +++ b/controller/ImageCtrl.js @@ -7,8 +7,10 @@ const nem = require("nemjs"); require("dotenv").config(); -const GALLERIES_IMG = process.env.IMG_URL + "galleries/"; -const GALLERIES_THUMB = process.env.THUMB_URL + "galleries/"; +const { IMAGES_NOT_FOUND, IMG_URL, THUMB_URL } = process.env; + +const GALLERIES_IMG = IMG_URL + "galleries/"; +const GALLERIES_THUMB = THUMB_URL + "galleries/"; const form = formidable({ uploadDir: GALLERIES_IMG, keepExtensions: true }); const Gallery = db.gallery; @@ -19,47 +21,30 @@ const Image = db.image; /** * ? CHECK IMAGE DATA * * Checks the image data. - * * @param {string} description - The description of the image data. * @param {object} res - The response object. * @return {object} The JSON response. */ exports.checkImageData = (description, res) => { - if (!nem.checkRange(description, process.env.STRING_MIN, process.env.TEXT_MAX)) { - return res.status(403).json({ message: process.env.CHECK_NAME }); + const { CHECK_NAME, STRING_MIN, TEXT_MAX } = process.env; + + if (!nem.checkRange(description, STRING_MIN, TEXT_MAX)) { + return res.status(403).json({ message: CHECK_NAME }) } } /** * ? SET IMAGE * * Sets the image & thumbnail for a gallery. - * * @param {string} image - The filename of the image to set. * @param {string} newFilename - The new filename to use for the image. */ exports.setImage = (image, newFilename) => { - let input = "galleries/" + newFilename; - let output = "galleries/" + image; - - nem.setImage(input, process.env.IMG_URL + output); - nem.setThumbnail(input, process.env.THUMB_URL + output); -} + const INPUT = "galleries/" + newFilename; + const OUTPUT = "galleries/" + image; -/** - * ? GET IMAGE - * * Retrieves an image with the given name, description & gallery ID. - * - * @param {string} name - The name of the image. - * @param {string} description - The description of the image. - * @param {number} galleryId - The ID of the gallery the image belongs to. - * @return {object} - An object containing the name, description & gallery ID of the image. - */ -exports.getImage = (name, description, galleryId) => { - return { - name: name, - description: description, - galleryId: galleryId - } + nem.setImage(INPUT, IMG_URL + OUTPUT); + nem.setThumbnail(INPUT, THUMB_URL + OUTPUT); } //! ******************** PUBLIC ******************** @@ -67,7 +52,6 @@ exports.getImage = (name, description, galleryId) => { /** * ? LIST IMAGES * * Retrieves a list of gallery images based on the provided gallery ID. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Promise} A promise that resolves to a response containing the list of gallery images. @@ -75,17 +59,14 @@ exports.getImage = (name, description, galleryId) => { */ exports.listImages = (req, res) => { Image.belongsTo(Gallery, { foreignKey: "galleryId" }); - Image - .findAll({ + + Image.findAll({ where: { galleryId: req.params.id }, attributes: ["id", "name", "description", "galleryId"], - include: { - model: Gallery, - attributes: ["name"], - } + include: { model: Gallery, attributes: ["name"] } }) .then((images) => { res.status(200).json(images) }) - .catch(() => res.status(404).json({ message: process.env.IMAGES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: IMAGES_NOT_FOUND })); }; //! ******************** PRIVATE ******************** @@ -93,7 +74,6 @@ exports.listImages = (req, res) => { /** * ? CREATE IMAGE * * Creates an image based on the request data. - * * @param {Object} req - the request object * @param {Object} res - the response object * @param {Function} next - the next middleware function @@ -101,44 +81,48 @@ exports.listImages = (req, res) => { * @throws {Error} If the image is not created in the database. */ exports.createImage = (req, res, next) => { + const { GALLERY_NOT_FOUND, IMAGE_CREATED, IMAGE_NOT_CREATED, IMAGES_NOT_FOUND, IMG_EXT } = process.env; + form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkImageData(fields.description, res); + const { description, galleryId } = fields; + const { image } = files; - Gallery - .findOne({ where: { id: fields.galleryId }}) + this.checkImageData(description, res); + + Gallery.findOne({ where: { id: galleryId }}) .then((gallery) => { - Image - .findAll({ where: { galleryId: fields.galleryId }}) + Image.findAll({ where: { galleryId: galleryId }}) .then((images) => { let index = images.length + 1; - if (index < 10) { index = "0" + index } + if (index < 10) index = "0" + index; + + const name = nem.getName(gallery.name) + "-" + index + "." + IMG_EXT; + const img = { ...fields, name: name }; - let name = nem.getName(gallery.name) + "-" + index + "." + process.env.IMG_EXT; - this.setImage(name, files.image.newFilename); - let image = this.getImage(name, fields.description, fields.galleryId); + if (image && image.newFilename) this.setImage(name, image.newFilename); - Image - .create(image) + Image.create(img) .then(() => { - fs.unlink(GALLERIES_IMG + files.image.newFilename, () => { - res.status(201).json({ message: process.env.IMAGE_CREATED }); - }) + if (image && image.newFilename) { + fs.unlink(GALLERIES_IMG + image.newFilename, () => { + res.status(201).json({ message: IMAGE_CREATED }) + }) + } }) - .catch(() => res.status(400).json({ message: process.env.IMAGE_NOT_CREATED })); + .catch(() => res.status(400).json({ message: IMAGE_NOT_CREATED })); }) - .catch(() => res.status(404).json({ message: process.env.IMAGES_NOT_FOUND })); + .catch(() => res.status(404).json({ message: IMAGES_NOT_FOUND })); }) - .catch(() => res.status(404).json({ message: process.env.GALLERY_NOT_FOUND })); + .catch(() => res.status(404).json({ message: GALLERY_NOT_FOUND })); }) }; /** * ? UPDATE IMAGE * * Updates an image. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {Function} next - The next middleware function. @@ -146,49 +130,52 @@ exports.createImage = (req, res, next) => { * @throws {Error} If the image is not updated in the database. */ exports.updateImage = (req, res, next) => { + const { IMAGE_NOT_UPDATED, IMAGE_UPDATED } = process.env; + const ID = parseInt(req.params.id); + form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkImageData(fields.description, res); - let name = fields.name; + const { name, description } = fields; + const { image } = files; + const img = { ...fields }; - if (files.image) this.setImage(name, files.image.newFilename); - let image = this.getImage(name, fields.description, fields.galleryId); + this.checkImageData(description, res); + if (image && image.newFilename) this.setImage(name, image.newFilename); - Image - .update(image, { where: { id: parseInt(req.params.id) }}) + Image.update(img, { where: { id: ID }}) .then(() => { - if (files.image) fs.unlink(GALLERIES_IMG + files.image.newFilename, () => {}); - res.status(200).json({ message: process.env.IMAGE_UPDATED }); + if (image && image.newFilename) { + fs.unlink(GALLERIES_IMG + image.newFilename, () => {}) + } + res.status(200).json({ message: IMAGE_UPDATED }); }) - .catch(() => res.status(400).json({ message: process.env.IMAGE_NOT_UPDATED })); + .catch(() => res.status(400).json({ message: IMAGE_NOT_UPDATED })); }) }; /** * ? DELETE IMAGE * * Deletes an image from the server and database. - * * @param {Object} req - The HTTP request object. * @param {Object} res - The HTTP response object. * @return {Object} A message indicating that the image was deleted. * @throws {Error} If the image is not deleted in the database. */ exports.deleteImage = (req, res) => { - const id = parseInt(req.params.id); + const { IMAGE_DELETED, IMAGE_NOT_DELETED, IMAGE_NOT_FOUND } = process.env; + const ID = parseInt(req.params.id); - Image - .findByPk(id) + Image.findByPk(ID) .then((image) => { fs.unlink(GALLERIES_THUMB + image.name, () => { fs.unlink(GALLERIES_IMG + image.name, () => { - Image - .destroy({ where: { id: id }}) - .then(() => res.status(204).json({ message: process.env.IMAGE_DELETED })) - .catch(() => res.status(400).json({ message: process.env.IMAGE_NOT_DELETED })); + Image.destroy({ where: { id: ID }}) + .then(() => res.status(204).json({ message: IMAGE_DELETED })) + .catch(() => res.status(400).json({ message: IMAGE_NOT_DELETED })); }) }) }) - .catch(() => res.status(400).json({ message: process.env.IMAGE_NOT_FOUND })); + .catch(() => res.status(400).json({ message: IMAGE_NOT_FOUND })); }; From 4abeb871d2b948429bf2f2af86b1d4a18b2f7c4f Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 11:27:00 +0400 Subject: [PATCH 18/21] Complete refactoring of OrderCtrl --- controller/OrderCtrl.js | 93 ++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/controller/OrderCtrl.js b/controller/OrderCtrl.js index f2c6fe5..ee91439 100644 --- a/controller/OrderCtrl.js +++ b/controller/OrderCtrl.js @@ -6,6 +6,8 @@ const nem = require("nemjs"); require("dotenv").config(); +const { ORDERS_NOT_FOUND } = process.env; + const form = formidable(); const Order = db.order; const User = db.user; @@ -15,34 +17,37 @@ const User = db.user; /** * ? SET MESSAGE * * Sets the message content for an order. - * * @param {number} total - The total amount of the order. * @param {string} paymentId - The ID of the payment. * @param {Array} products - An array of products in the order. - * @return {Object} message - The message object containing the subject, text, and html properties. + * @return {Object} message - The message object containing subject, text & html. */ exports.setMessage = (total, paymentId, products) => { + const { CURRENCY_SYMBOL, ORDER_LIST, ORDER_NAME, ORDER_PAYMENT, ORDER_PRICE, ORDER_QUANTITY, ORDER_SUBJECT, ORDER_TITLE, ORDER_TOTAL } = process.env; + let message = {}; - message.subject = process.env.ORDER_SUBJECT; + message.subject = ORDER_SUBJECT; message.text = ` -

${process.env.ORDER_TITLE}

+

${ORDER_TITLE}

- ${process.env.ORDER_TOTAL} - ${total} ${process.env.CURRENCY_SYMBOL}, - ${process.env.ORDER_PAYMENT} + ${ORDER_TOTAL} + ${total} ${CURRENCY_SYMBOL}, + ${ORDER_PAYMENT} #${paymentId} !

-

${process.env.ORDER_LIST}

`; +

${ORDER_LIST}

`; for (let product of products) { + const { id, name, option, quantity, price } = product; + message.products += `
    -
  • id : ${product.id}
  • -
  • ${process.env.ORDER_NAME} : ${product.name}
  • -
  • option : ${product.option}
  • -
  • ${process.env.ORDER_QUANTITY} : ${product.quantity}
  • -
  • ${process.env.ORDER_PRICE} : ${product.price} ${process.env.CURRENCY_SYMBOL}
  • +
  • id : ${id}
  • +
  • ${ORDER_NAME} : ${name}
  • +
  • option : ${option}
  • +
  • ${ORDER_QUANTITY} : ${quantity}
  • +
  • ${ORDER_PRICE} : ${price} ${CURRENCY_SYMBOL}
`; } @@ -57,39 +62,36 @@ exports.setMessage = (total, paymentId, products) => { /** * ? LIST ORDERS * * Retrieves a list of orders. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} The list of orders. * @throws {Error} If the orders are not found in the database. */ exports.listOrders = (req, res) => { - Order - .findAll() + Order.findAll() .then((orders) => { res.status(200).json(orders) }) - .catch(() => res.status(404).json({ message: process.env.ORDERS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: ORDERS_NOT_FOUND })); }; /** * ? LIST USER ORDERS * * Retrieves a list of orders for a specific user. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} The list of user orders. * @throws {Error} If the orders are not found in the database. */ exports.listUserOrders = (req, res) => { - Order - .findAll({ where: { userId: parseInt(req.params.id) }}) + const ID = parseInt(req.params.id); + + Order.findAll({ where: { userId: ID }}) .then((orders) => res.status(200).json(orders)) - .catch(() => res.status(404).json({ message: process.env.ORDERS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: ORDERS_NOT_FOUND })); }; /** * ? CREATE ORDER * * Creates an order based on the request data. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {Function} next - The next middleware function. @@ -97,39 +99,41 @@ exports.listUserOrders = (req, res) => { * @throws {Error} If an error occurs while creating the order. */ exports.createOrder = (req, res, next) => { + const { ORDER_CREATED, ORDER_MESSAGE, ORDER_NOT_CREATED, USER_NOT_FOUND } = process.env; + form.parse(req, (err, fields) => { if (err) { next(err); return } - let message = this.setMessage(fields.total, fields.paymentId, fields.products); - Order - .create(fields) + const { paymentId, products, total } = fields; + let message = this.setMessage(total, paymentId, products); + + Order.create(fields) .then(() => { - User - .findByPk(fields.userId) + + User.findByPk(fields.userId) .then((user) => { message.email = user.email; const mailer = nem.getMailer(); + const mail = nem.getMessage(message); (async function(){ try { - let mail = nem.getMessage(fields); - await mailer.sendMail(mail, function() { - res.status(202).json({ message: process.env.ORDER_MESSAGE }); + await mailer.sendMail(mail, function() { + res.status(202).json({ message: ORDER_MESSAGE }) }); } catch(e){ console.error(e); } })(); }) - .catch(() => res.status(404).json({ message: process.env.USER_NOT_FOUND })); + .catch(() => res.status(404).json({ message: USER_NOT_FOUND })); }) - .then(() => res.status(201).json({ message: process.env.ORDER_CREATED })) - .catch(() => res.status(400).json({ message: process.env.ORDER_NOT_CREATED })); + .then(() => res.status(201).json({ message: ORDER_CREATED })) + .catch(() => res.status(400).json({ message: ORDER_NOT_CREATED })); }) }; /** * ? UPDATE ORDER * * Updates an order. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @param {function} next - The next middleware function. @@ -137,28 +141,31 @@ exports.createOrder = (req, res, next) => { * @throws {Error} If the order is not updated. */ exports.updateOrder = (req, res, next) => { + const { ORDER_NOT_UPDATED, ORDER_UPDATED } = process.env; + const ID = parseInt(req.params.id); + form.parse(req, (err, fields) => { if (err) { next(err); return } - Order - .update(fields, { where: { id: parseInt(req.params.id) }}) - .then(() => res.status(200).json({ message: process.env.ORDER_UPDATED })) - .catch(() => res.status(400).json({ message: process.env.ORDER_NOT_UPDATED })); + Order.update(fields, { where: { id: ID }}) + .then(() => res.status(200).json({ message: ORDER_UPDATED })) + .catch(() => res.status(400).json({ message: ORDER_NOT_UPDATED })); }) }; /** * ? DELETE ORDER * * Deletes an order. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} A message indicating that the order was deleted. * @throws {Error} If the order is not deleted. */ exports.deleteOrder = (req, res) => { - Order - .destroy({ where: { id: parseInt(req.params.id) }}) - .then(() => res.status(204).json({ message: process.env.ORDER_DELETED })) - .catch(() => res.status(400).json({ message: process.env.ORDER_NOT_DELETED })) + const { ORDER_DELETED, ORDER_NOT_DELETED } = process.env; + const ID = parseInt(req.params.id); + + Order.destroy({ where: { id: ID }}) + .then(() => res.status(204).json({ message: ORDER_DELETED })) + .catch(() => res.status(400).json({ message: ORDER_NOT_DELETED })) }; From 840ce4f7143830c531c556b502739020b2f13e4e Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 11:27:23 +0400 Subject: [PATCH 19/21] Complete refactoring of ProductCtrl --- controller/ProductCtrl.js | 186 +++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 104 deletions(-) diff --git a/controller/ProductCtrl.js b/controller/ProductCtrl.js index 6b0500a..c6aceb6 100644 --- a/controller/ProductCtrl.js +++ b/controller/ProductCtrl.js @@ -7,8 +7,10 @@ const nem = require("nemjs"); require("dotenv").config(); -const PRODUCTS_IMG = process.env.IMG_URL + "products/"; -const PRODUCTS_THUMB = process.env.THUMB_URL + "products/"; +const {IMG_EXT, IMG_URL, PRODUCT_NOT_FOUND, PRODUCTS_NOT_FOUND, THUMB_URL } = process.env; + +const PRODUCTS_IMG = IMG_URL + "products/"; +const PRODUCTS_THUMB = THUMB_URL + "products/"; const form = formidable({ uploadDir: PRODUCTS_IMG, keepExtensions: true }); const Product = db.product; @@ -18,38 +20,33 @@ const Product = db.product; /** * ? CHECK PRODUCT DATA * * Validates and checks the product data before processing it. - * * @param {string} name - The name of the product. * @param {string} description - The description of the product. * @param {string} alt - The alternative name of the product. * @param {number} price - The price of the product. * @param {string} cat - The category of the product. * @param {object} res - The response object. - * @return {object} The response object with a JSON message if there are any validation errors. + * @return {object} The response object with a JSON message if there are errors. */ exports.checkProductData = (name, description, alt, price, cat, res) => { - const PRICE_MAX = process.env.PRICE_MAX; - const PRICE_MIN = process.env.PRICE_MIN; - const STR_MAX = process.env.STRING_MAX; - const STR_MIN = process.env.STRING_MIN; - const TXT_MAX = process.env.TEXT_MAX; - const TXT_MIN = process.env.TEXT_MIN; - - let alert = ""; - - if (!nem.checkRange(cat, STR_MIN, STR_MAX)) alert = process.env.CHECK_CAT; - if (!nem.checkRange(price, PRICE_MIN, PRICE_MAX)) alert = process.env.CHECK_PRICE; - if (!nem.checkRange(alt, STR_MIN, STR_MAX)) alert = process.env.CHECK_NAME; - if (!nem.checkRange(description, TXT_MIN, TXT_MAX)) alert = process.env.CHECK_TEXT; - if (!nem.checkRange(name, STR_MIN, STR_MAX)) alert = process.env.CHECK_NAME; - - if (alert !== "") return res.status(403).json({ message: alert }); + const { CHECK_CAT, CHECK_NAME, CHECK_PRICE, CHECK_TEXT, PRICE_MAX, PRICE_MIN, STRING_MAX, STRING_MIN, TEXT_MAX, TEXT_MIN } = process.env; + + if ( + !nem.checkRange(cat, STRING_MIN, STRING_MAX) || + !nem.checkRange(price, PRICE_MIN, PRICE_MAX) || + !nem.checkRange(alt, STRING_MIN, STRING_MAX) || + !nem.checkRange(description, TEXT_MIN, TEXT_MAX) || + !nem.checkRange(name, STRING_MIN, STRING_MAX) + ) { + return res.status(403).json({ + message: CHECK_CAT || CHECK_PRICE || CHECK_NAME || CHECK_TEXT || CHECK_NAME + }); + } } /** * ? CHECK PRODUCT UNIQUE * * Checks if the given product name and description are unique. - * * @param {string} name - The name of the product. * @param {string} description - The description of the product. * @param {object} product - The product object to compare with. @@ -57,48 +54,27 @@ exports.checkProductData = (name, description, alt, price, cat, res) => { * @return {object} The JSON response object with the appropriate message and status code. */ exports.checkProductUnique = (name, description, product, res) => { - if (product.name === name) return res.status(403).json({ message: process.env.DISPO_NAME }); - if (product.description === description) return res.status(403).json({ message: process.env.DISPO_DESCRIPTION }); -} + const { DISPO_DESCRIPTION, DISPO_NAME } = process.env; -/** - * ? GET PRODUCT - * * Returns a product object with the given properties. - * - * @param {string} name - The name of the product. - * @param {string} description - The description of the product. - * @param {string} image - The image URL of the product. - * @param {string} alt - The alternative text for the product image. - * @param {number} price - The price of the product. - * @param {object} options - The options for the product. - * @param {string} cat - The category of the product. - * @return {object} The product object with the given properties. - */ -exports.getProduct = (name, description, image, alt, price, options, cat) => { - return { - name: name, - description: description, - image: image, - alt: alt, - price: price, - options: options, - cat: cat + if (product.name === name || product.description === description) { + return res.status(403).json({ message: DISPO_NAME || DISPO_DESCRIPTION }); } } /** * ? SET IMAGE * * Sets the image for a product. - * * @param {string} name - The name of the product. * @param {string} newFilename - The new filename of the image. */ exports.setImage = (name, newFilename) => { - let input = "products/" + newFilename; - let output = "products/" + name; + const { IMG_HEIGHT, IMG_WIDTH } = process.env; + + const INPUT = "products/" + newFilename; + const OUTPUT = "products/" + name; - nem.setThumbnail(input, process.env.THUMB_URL + output); - nem.setThumbnail(input, process.env.IMG_URL + output, process.env.IMG_WIDTH, process.env.IMG_HEIGHT); + nem.setThumbnail(INPUT, THUMB_URL + OUTPUT); + nem.setThumbnail(INPUT, IMG_URL + OUTPUT, IMG_WIDTH, IMG_HEIGHT); } //! ******************** PUBLIC ******************** @@ -106,33 +82,31 @@ exports.setImage = (name, newFilename) => { /** * ? LIST PRODUCTS * * Retrieves a list of all products. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} The list of products in JSON format. * @throws {Error} If the products are not found in the database. */ exports.listProducts = (req, res) => { - Product - .findAll() + Product.findAll() .then((products) => { res.status(200).json(products) }) - .catch(() => res.status(404).json({ message: process.env.PRODUCTS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: PRODUCTS_NOT_FOUND })); }; /** * ? READ PRODUCT * * Reads a product by its ID. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} The product in JSON format. * @throws {Error} If the product is not found in the database. */ exports.readProduct = (req, res) => { - Product - .findByPk(parseInt(req.params.id)) + const ID = parseInt(req.params.id); + + Product.findByPk(ID) .then((product) => { res.status(200).json(product) }) - .catch(() => res.status(404).json({ message: process.env.PRODUCT_NOT_FOUND })); + .catch(() => res.status(404).json({ message: PRODUCT_NOT_FOUND })); } //! ******************** PRIVATE ******************** @@ -140,7 +114,6 @@ exports.readProduct = (req, res) => { /** * ? CREATE PRODUCT * * Creates a new product. - * * @param {Object} req - the request object * @param {Object} res - the response object * @param {Function} next - the next middleware function @@ -148,41 +121,44 @@ exports.readProduct = (req, res) => { * @throws {Error} If the product is not created. */ exports.createProduct = (req, res, next) => { + const { PRODUCT_CREATED, PRODUCT_NOT_CREATED } = process.env; + form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkProductData(fields.name, fields.description, fields.alt, fields.price, fields.cat, res); + const { alt, cat, description, name, price } = fields; + const { image } = files; + + this.checkProductData(name, description, alt, price, cat, res); - Product - .findAll() + Product.findAll() .then((products) => { - for (let product of products) { this.checkProductUnique(fields.name, fields.description, product, res) } + for (let product of products) { + this.checkProductUnique(name, description, product, res) + } - let options = nem.getArrayFromString(fields.options); - let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; - this.setImage(image, files.image.newFilename); + const IMG = nem.getName(fields.name) + "." + IMG_EXT; + const product = { ...fields, image: IMG }; - let product = this.getProduct( - fields.name, fields.description, image, fields.alt, fields.price, options, fields.cat - ); + if (image && image.newFilename) this.setImage(IMG, image.newFilename); - Product - .create(product) + Product.create(product) .then(() => { - fs.unlink(PRODUCTS_IMG + files.image.newFilename, () => { - res.status(201).json({ message: process.env.PRODUCT_CREATED }) - }) + if (image && image.newFilename) { + fs.unlink(PRODUCTS_IMG + image.newFilename, () => { + res.status(201).json({ message: PRODUCT_CREATED }) + }) + } }) - .catch(() => res.status(400).json({ message: process.env.PRODUCT_NOT_CREATED })); + .catch(() => res.status(400).json({ message: PRODUCT_NOT_CREATED })); }) - .catch(() => res.status(404).json({ message: process.env.PRODUCTS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: PRODUCTS_NOT_FOUND })); }) }; /** * ? UPDATE PRODUCT * * Updates a product. - * * @param {Object} req - the request object * @param {Object} res - the response object * @param {Function} next - the next middleware function @@ -190,60 +166,62 @@ exports.createProduct = (req, res, next) => { * @throws {Error} If the product is not updated. */ exports.updateProduct = (req, res, next) => { - const id = parseInt(req.params.id); + const { PRODUCT_NOT_UPDATED, PRODUCT_UPDATED } = process.env; + const ID = parseInt(req.params.id); form.parse(req, (err, fields, files) => { if (err) { next(err); return } - this.checkProductData(fields.name, fields.description, fields.alt, fields.price, fields.cat, res); - Product - .findAll() + const { name, description, alt, price, cat } = fields; + const { image } = files; + + this.checkProductData(name, description, alt, price, cat, res); + + Product.findAll() .then((products) => { - for (let product of products) { - if (product.id !== id) this.checkProductUnique(fields.name, fields.description, product, res); - } + products.filter(product => product.id !== ID).forEach(product => + this.checkProductUnique(name, description, product, res)); - let image = nem.getName(fields.name) + "." + process.env.IMG_EXT; - if (files.image) this.setImage(image, files.image.newFilename); + const IMG = nem.getName(name) + "." + IMG_EXT; + const product = { ...fields, image: IMG }; - let options = nem.getArrayFromString(fields.options); - let product = this.getProduct(fields.name, fields.description, image, fields.alt, fields.price, options, fields.cat); + if (image && image.newFilename) this.setImage(IMG, image.newFilename); - Product - .update(product, { where: { id: id }}) + Product.update(product, { where: { id: ID }}) .then(() => { - if (files.image) fs.unlink(PRODUCTS_IMG + files.image.newFilename, () => {}); - res.status(200).json({ message: process.env.PRODUCT_UPDATED }); + if (image && image.newFilename) { + fs.unlink(PRODUCTS_IMG + image.newFilename, () => {}) + } + res.status(200).json({ message: PRODUCT_UPDATED }); }) - .catch(() => res.status(400).json({ message: process.env.PRODUCT_NOT_UPDATED })); + .catch(() => res.status(400).json({ message: PRODUCT_NOT_UPDATED })); }) - .catch(() => res.status(404).json({ message: process.env.PRODUCTS_NOT_FOUND })); + .catch(() => res.status(404).json({ message: PRODUCTS_NOT_FOUND })); }) }; /** * ? DELETE PRODUCT * * Deletes a product from the database. - * * @param {Object} req - The request object. * @param {Object} res - The response object. * @return {Object} A message indicating that the product was deleted. * @throws {Error} If the product is not found in the database. */ exports.deleteProduct = (req, res) => { - const id = parseInt(req.params.id); + const { PRODUCT_DELETED, PRODUCT_NOT_DELETED } = process.env; + const ID = parseInt(req.params.id); - Product - .findByPk(id) + Product.findByPk(ID) .then(product => { fs.unlink(PRODUCTS_THUMB + product.image, () => { fs.unlink(PRODUCTS_IMG + product.image, () => { - Product - .destroy({ where: { id: id }}) - .then(() => res.status(204).json({ message: process.env.PRODUCT_DELETED })) - .catch(() => res.status(400).json({ message: process.env.PRODUCT_NOT_DELETED })) + + Product.destroy({ where: { id: ID }}) + .then(() => res.status(204).json({ message: PRODUCT_DELETED })) + .catch(() => res.status(400).json({ message: PRODUCT_NOT_DELETED })) }) }) }) - .catch(() => res.status(404).json({ message: process.env.PRODUCT_NOT_FOUND })); + .catch(() => res.status(404).json({ message: PRODUCT_NOT_FOUND })); } From bb2bc68f8db7afdeef2be0a9c593c529f99b3757 Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 11:28:25 +0400 Subject: [PATCH 20/21] Review some controllers optimizations --- controller/ArticleCtrl.js | 24 +++++++++++++++++------- controller/AuthCtrl.js | 19 ++++++++++--------- controller/LinkCtrl.js | 8 +++++--- controller/UserCtrl.js | 33 +++++++++++++++++++++++---------- 4 files changed, 55 insertions(+), 29 deletions(-) diff --git a/controller/ArticleCtrl.js b/controller/ArticleCtrl.js index e35e937..2fcac65 100644 --- a/controller/ArticleCtrl.js +++ b/controller/ArticleCtrl.js @@ -36,7 +36,9 @@ exports.checkArticleData = (name, text, alt, cat, res) => { !nem.checkRange(text, TEXT_MIN, TEXT_MAX) || !nem.checkRange(name, STRING_MIN, STRING_MAX) ) { - return res.status(403).json({ message: CHECK_CAT || CHECK_NAME || CHECK_TEXT || CHECK_NAME }); + return res.status(403).json({ + message: CHECK_CAT || CHECK_NAME || CHECK_TEXT || CHECK_NAME + }); } } @@ -52,8 +54,9 @@ exports.checkArticleData = (name, text, alt, cat, res) => { exports.checkArticleUnique = (name, text, article, res) => { const { DISPO_NAME, DISPO_TEXT } = process.env; - if (article.name === name) return res.status(403).json({ message: DISPO_NAME }); - if (article.text === text) return res.status(403).json({ message: DISPO_TEXT }); + if (article.name === name || article.text === text) { + return res.status(403).json({ message: DISPO_NAME || DISPO_TEXT }) + } } /** @@ -99,7 +102,9 @@ exports.listArticles = (req, res) => { * @throws {Error} If the article is not found in the database. */ exports.readArticle = (req, res) => { - Article.findByPk(parseInt(req.params.id)) + const ID = parseInt(req.params.id); + + Article.findByPk(ID) .then((article) => { res.status(200).json(article) }) .catch(() => res.status(404).json({ message: ARTICLE_NOT_FOUND })); } @@ -139,7 +144,9 @@ exports.createArticle = (req, res, next) => { Article.create(article) .then(() => { if (image && image.newFilename) { - fs.unlink(ARTICLES_IMG + image.newFilename, () => { res.status(201).json({ message: ARTICLE_CREATED })}) + fs.unlink(ARTICLES_IMG + image.newFilename, () => { + res.status(201).json({ message: ARTICLE_CREATED }) + }) } }) .catch(() => res.status(400).json({ message: ARTICLE_NOT_CREATED })); @@ -174,14 +181,17 @@ exports.updateArticle = (req, res, next) => { Article.findAll() .then((articles) => { - articles.filter(article => article.id !== ID).forEach(article => this.checkArticleUnique(name, text, article, res)); + articles.filter(article => article.id !== ID) + .forEach(article => this.checkArticleUnique(name, text, article, res)); if (image && image.newFilename) this.setImage(IMG, image.newFilename); const article = { ...fields, image: IMG }; Article.update(article, { where: { id: ID }}) .then(() => { - if (image && image.newFilename) fs.unlink(ARTICLES_IMG + image.newFilename, () => {}); + if (image && image.newFilename) { + fs.unlink(ARTICLES_IMG + image.newFilename, () => {}) + } res.status(200).json({ message: ARTICLE_UPDATED }); }) .catch(() => res.status(400).json({ message: ARTICLE_NOT_UPDATED })); diff --git a/controller/AuthCtrl.js b/controller/AuthCtrl.js index ebe7f5f..5bbe5bc 100644 --- a/controller/AuthCtrl.js +++ b/controller/AuthCtrl.js @@ -23,14 +23,13 @@ const User = db.user; * @throws {Error} If the user is not found in the database. */ exports.readAvatar = (req, res) => { - User.findByPk(parseInt(req.params.id)) - .then((user) => { - const avatar = { - name: user.name, - image: user.image, - role: user.role - }; - res.status(200).json(avatar) + const ID = parseInt(req.params.id); + + User.findByPk(ID) + .then((user) => { + const { name, image, role } = user; + const avatar = { name: name, image: image, role: role }; + res.status(200).json(avatar); }) .catch(() => res.status(404).json({ message: USER_NOT_FOUND })); } @@ -115,7 +114,9 @@ exports.forgotPass = (req, res, next) => { .then(() => { (async function(){ try { - await mailer.sendMail(mail, function() {res.status(202).json({ message: AUTH_MESSAGE })}); + await mailer.sendMail(mail, function() { + res.status(202).json({ message: AUTH_MESSAGE }) + }); } catch(e){ console.error(e) } })(); }) diff --git a/controller/LinkCtrl.js b/controller/LinkCtrl.js index b831e6e..ba29b3b 100644 --- a/controller/LinkCtrl.js +++ b/controller/LinkCtrl.js @@ -46,8 +46,9 @@ exports.checkLinkData = (name, url, cat, res) => { exports.checkLinkUnique = (name, url, link, res) => { const { DISPO_NAME, DISPO_URL } = process.env; - if (link.name === name) return res.status(403).json({ message: DISPO_NAME }); - if (link.url === url) return res.status(403).json({ message: DISPO_URL }); + if (link.name === name || link.url === url) { + return res.status(403).json({ message: DISPO_NAME || DISPO_URL }); + } } //! ******************** PUBLIC ******************** @@ -119,7 +120,8 @@ exports.updateLink = (req, res, next) => { Link.findAll() .then((links) => { - links.filter(link => link.id !== ID).forEach(link => this.checkLinkUnique(name, url, link, res)); + links.filter(link => link.id !== ID).forEach(link => + this.checkLinkUnique(name, url, link, res)); Link.update(fields, { where: { id: ID }}) .then(() => res.status(200).json({ message: LINK_UPDATED })) diff --git a/controller/UserCtrl.js b/controller/UserCtrl.js index 7b9b6c6..e635a14 100644 --- a/controller/UserCtrl.js +++ b/controller/UserCtrl.js @@ -20,7 +20,7 @@ const User = db.user; /** * ? CHECK USER DATA - * * Validates user data & returns a JSON response with an error message if any validation fails. + * * Validates user data & returns a JSON response with an error message if it fails. * @param {string} name - The user's name. * @param {string} email - The user's email. * @param {string} role - The user's role. @@ -64,8 +64,9 @@ exports.checkUserPass = (pass, res) => { exports.checkUserUnique = (name, email, user, res) => { const { DISPO_EMAIL, DISPO_NAME } = process.env; - if (user.name === name) return res.status(403).json({ message: DISPO_NAME }); - if (user.email === email) return res.status(403).json({ message: DISPO_EMAIL }); + if (user.name === name || user.email === email) { + return res.status(403).json({ message: DISPO_NAME || DISPO_EMAIL }) + } } //! ******************** PUBLIC ******************** @@ -96,7 +97,9 @@ exports.createUser = (req, res, next) => { User.findAll() .then((users) => { for (const user of users) this.checkUserUnique(name, email, user, res); - if (image && image.newFilename) nem.setThumbnail("users/" + image.newFilename, USERS_THUMB + IMG); + if (image && image.newFilename) { + nem.setThumbnail("users/" + image.newFilename, USERS_THUMB + IMG); + } bcrypt.hash(pass, 10) .then((hash) => { @@ -105,7 +108,9 @@ exports.createUser = (req, res, next) => { User.create(user) .then(() => { if (image && image.newFilename) { - fs.unlink(USERS_IMG + image.newFilename, () => { res.status(201).json({ message: USER_CREATED })}); + fs.unlink(USERS_IMG + image.newFilename, () => { + res.status(201).json({ message: USER_CREATED }) + }) } }) .catch(() => res.status(400).json({ message: USER_NOT_CREATED })); @@ -135,7 +140,9 @@ exports.sendMessage = (req, res, next) => { (async function () { try { - await mailer.sendMail(mail, function () { res.status(202).json({ message: USER_MESSAGE })}); + await mailer.sendMail(mail, function () { + res.status(202).json({ message: USER_MESSAGE }) + }); } catch (e) { console.error(e) } })(); }) @@ -211,8 +218,12 @@ exports.updateUser = (req, res, next) => { User.findAll() .then((users) => { - users.filter(user => user.id !== ID).forEach(user => this.checkUserUnique(name, email, user, res)); - if (image && image.newFilename) nem.setThumbnail("users/" + image.newFilename, USERS_THUMB + IMG); + users.filter(user => user.id !== ID).forEach(user => + this.checkUserUnique(name, email, user, res)); + + if (image && image.newFilename) { + nem.setThumbnail("users/" + image.newFilename, USERS_THUMB + IMG) + } if (pass) { this.checkUserPass(pass, res); @@ -227,7 +238,9 @@ exports.updateUser = (req, res, next) => { User.update(user, { where: { id: ID }}) .then(() => { - if (image && image.newFilename) fs.unlink(USERS_IMG + image.newFilename, () => {}); + if (image && image.newFilename) { + fs.unlink(USERS_IMG + image.newFilename, () => {}) + } res.status(200).json({ message: USER_UPDATED }); }) .catch(() => res.status(400).json({ message: USER_NOT_UPDATED })); @@ -241,7 +254,7 @@ exports.updateUser = (req, res, next) => { * * Deletes a user, associated comments & reviews from the database. * @param {Object} req - The request object containing the user id in the params. * @param {Object} res - The response object to send the result. - * @return {Object} The response object with a status & JSON message indicating success or failure. + * @return {Object} The response object with a status & JSON message. * @throws {Error} If the user is not deleted from the database. */ exports.deleteUser = (req, res) => { From 782ea279cc9ce402dfd8da3b9fc66999c6334a9a Mon Sep 17 00:00:00 2001 From: Philippe Beck Date: Sun, 17 Dec 2023 11:28:35 +0400 Subject: [PATCH 21/21] Release 0.2.1-alpha --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8ed8dd..3025d1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nens", - "version": "0.2.0-alpha", + "version": "0.2.1-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nens", - "version": "0.2.0-alpha", + "version": "0.2.1-alpha", "license": "Apache-2.0 License", "dependencies": { "bcrypt": "^5.1.0", diff --git a/package.json b/package.json index 990d9ba..763226e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nens", - "version": "0.2.0-alpha", + "version": "0.2.1-alpha", "description": "API with Node, Express, NemJS & SQL", "keywords": [ "api",