From eba7858caf583195629f4545739a7e7ddcb81011 Mon Sep 17 00:00:00 2001 From: divlo Date: Mon, 3 Aug 2020 18:39:35 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20API:=20ShortLinks=20-=20GET/POST/PU?= =?UTF-8?q?T/DELETE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app.js | 6 + api/assets/functions/functionObject.js | 2 - api/assets/functions/main/linkShortener.js | 72 -------- api/controllers/links_shortener.js | 191 +++++++++++++++++++++ api/routes/links_shortener.js | 23 +++ 5 files changed, 220 insertions(+), 74 deletions(-) delete mode 100644 api/assets/functions/main/linkShortener.js create mode 100644 api/controllers/links_shortener.js create mode 100644 api/routes/links_shortener.js diff --git a/api/app.js b/api/app.js index a83c0d8..bae5bcd 100644 --- a/api/app.js +++ b/api/app.js @@ -32,6 +32,7 @@ app.use('/favorites', require('./routes/favorites')) app.use('/comments', require('./routes/comments')) app.use('/quotes', require('./routes/quotes')) app.use('/tasks', require('./routes/tasks')) +app.use('/links', require('./routes/links_shortener')) /* Errors Handling */ app.use((_req, _res, next) => @@ -51,6 +52,7 @@ const Favorites = require('./models/favorites') const Comments = require('./models/comments') const Quotes = require('./models/quotes') const Tasks = require('./models/tasks') +const ShortLinks = require('./models/short_links') // A function has a category Categories.hasOne(Functions, { constraints: true, onDelete: 'CASCADE' }) @@ -76,6 +78,10 @@ Quotes.belongsTo(Users, { constraints: false }) Users.hasMany(Tasks) Tasks.belongsTo(Users, { constraints: false }) +// Users can have links +Users.hasMany(ShortLinks) +ShortLinks.belongsTo(Users, { constraints: false }) + /* Server */ // sequelize.sync({ force: true }) sequelize diff --git a/api/assets/functions/functionObject.js b/api/assets/functions/functionObject.js index 69a4bef..aa80188 100644 --- a/api/assets/functions/functionObject.js +++ b/api/assets/functions/functionObject.js @@ -9,7 +9,6 @@ const calculateAgeOutput = require('./main/calculateAge') const heapAlgorithmOutput = require('./main/heapAlgorithm') const convertEncodingOutput = require('./main/convertEncoding') const randomQuote = require('./main/randomQuote') -const linkShortener = require('./main/linkShortener') const rightPriceOutput = require('./main/rightPrice') const isPalindromeOutput = require('./main/isPalindrome') const findLongestWordOutput = require('./main/findLongestWord') @@ -28,7 +27,6 @@ const functionObject = { heapAlgorithm: heapAlgorithmOutput, convertEncoding: convertEncodingOutput, randomQuote: randomQuote, - linkShortener: linkShortener, rightPrice: rightPriceOutput, isPalindrome: isPalindromeOutput, findLongestWord: findLongestWordOutput, diff --git a/api/assets/functions/main/linkShortener.js b/api/assets/functions/main/linkShortener.js deleted file mode 100644 index 6f424d3..0000000 --- a/api/assets/functions/main/linkShortener.js +++ /dev/null @@ -1,72 +0,0 @@ -const validator = require('validator') -const errorHandling = require('../../utils/errorHandling') -const { requiredFields, serverError } = require('../../config/errors') -const shortLinks = require('../../../models/short_links') - -const shortLinkBaseURL = 'https://s.divlo.fr' - -module.exports = async ({ res, next }, argsObject) => { - let { url, shortcutName } = argsObject - - // S'il n'y a pas les champs obligatoire - if (!(url && shortcutName)) { - return errorHandling(next, requiredFields) - } - - // Si ce n'est pas une url - if (!validator.isURL(url)) { - return errorHandling(next, { - message: 'Veuillez entré une URL valide.', - statusCode: 400 - }) - } - - // Si ce n'est pas de type slug - if (!validator.isSlug(shortcutName)) { - return errorHandling(next, { - message: - "Le nom de votre raccourci doit être de type slug (ne pas contenir d'espaces, ni de caractères spéciaux).", - statusCode: 400 - }) - } - - // Sanitize shortcutName - shortcutName = validator.escape(shortcutName) - shortcutName = validator.trim(shortcutName) - shortcutName = validator.blacklist(shortcutName, ' ') - - try { - // Si l'url a déjà été raccourcie - const urlInDatabase = await shortLinks.findOne({ where: { url } }) - if (urlInDatabase) { - const urlShort = `${shortLinkBaseURL}/${urlInDatabase.shortcut}` - return errorHandling(next, { - message: `L'url a déjà été raccourcie...

${urlShort}`, - statusCode: 400 - }) - } - - // Si le nom du raccourci existe déjà - const shortcutInDatabase = await shortLinks.findOne({ - where: { shortcut: shortcutName } - }) - if (shortcutInDatabase) { - const urlShort = `${shortLinkBaseURL}/${shortcutInDatabase.shortcut}` - return errorHandling(next, { - message: `Le nom du raccourci a déjà été utilisé...

${urlShort}`, - statusCode: 400 - }) - } - - // Ajout du lien raccourci - const result = await shortLinks.create({ url, shortcut: shortcutName }) - const shortcutLinkResult = `${shortLinkBaseURL}/${result.shortcut}` - return res.status(200).json({ - resultHTML: `URL Raccourcie :

${shortcutLinkResult}`, - result: shortcutLinkResult - }) - } catch (error) { - console.log(error) - return errorHandling(next, serverError) - } -} diff --git a/api/controllers/links_shortener.js b/api/controllers/links_shortener.js new file mode 100644 index 0000000..eac7749 --- /dev/null +++ b/api/controllers/links_shortener.js @@ -0,0 +1,191 @@ +const validator = require('validator') +const errorHandling = require('../assets/utils/errorHandling') +const { requiredFields, serverError } = require('../assets/config/errors') +const ShortLinks = require('../models/short_links') +const getPagesHelper = require('../assets/utils/getPagesHelper') +const Sequelize = require('sequelize') + +const shortLinkBaseURL = 'https://s.divlo.fr' + +exports.getLinks = async (req, res, next) => { + const { userId } = req + const options = { + where: { userId }, + order: [['createdAt', 'DESC']] + } + return await getPagesHelper({ req, res, next }, ShortLinks, options) +} + +exports.postLink = async (req, res, next) => { + const { userId } = req + let { url, shortcutName } = req.body + + // S'il n'y a pas les champs obligatoire + if (!(url && shortcutName)) { + return errorHandling(next, requiredFields) + } + + // Si ce n'est pas une url + if (!validator.isURL(url)) { + return errorHandling(next, { + message: 'Veuillez entré une URL valide.', + statusCode: 400 + }) + } + + // Si ce n'est pas de type slug + if (!validator.isSlug(shortcutName)) { + return errorHandling(next, { + message: + "Le nom de votre raccourci doit être de type slug (ne pas contenir d'espaces, ni de caractères spéciaux).", + statusCode: 400 + }) + } + + // Sanitize shortcutName + shortcutName = validator.escape(shortcutName) + shortcutName = validator.trim(shortcutName) + shortcutName = validator.blacklist(shortcutName, ' ') + + try { + // Si l'url a déjà été raccourcie + const urlInDatabase = await ShortLinks.findOne({ where: { url } }) + if (urlInDatabase) { + const urlShort = `${shortLinkBaseURL}/${urlInDatabase.shortcut}` + return errorHandling(next, { + message: `L'url a déjà été raccourcie...

${urlShort}`, + statusCode: 400 + }) + } + + // Si le nom du raccourci existe déjà + const shortcutInDatabase = await ShortLinks.findOne({ + where: { shortcut: shortcutName } + }) + if (shortcutInDatabase) { + const urlShort = `${shortLinkBaseURL}/${shortcutInDatabase.shortcut}` + return errorHandling(next, { + message: `Le nom du raccourci a déjà été utilisé...

${urlShort}`, + statusCode: 400 + }) + } + + // Ajout du lien raccourci + const result = await ShortLinks.create({ + url, + shortcut: shortcutName, + userId + }) + const shortcutLinkResult = `${shortLinkBaseURL}/${result.shortcut}` + return res.status(200).json({ + resultHTML: `URL Raccourcie :

${shortcutLinkResult}`, + result: shortcutLinkResult + }) + } catch (error) { + console.log(error) + return errorHandling(next, serverError) + } +} + +exports.putLink = async (req, res, next) => { + const { id } = req.params + const { userId } = req + let { url, shortcutName } = req.body + + // S'il n'y a pas les champs obligatoire + if (!(url && shortcutName)) { + return errorHandling(next, requiredFields) + } + + // Si ce n'est pas une url + if (!validator.isURL(url)) { + return errorHandling(next, { + message: 'Veuillez entré une URL valide.', + statusCode: 400 + }) + } + + // Si ce n'est pas de type slug + if (!validator.isSlug(shortcutName)) { + return errorHandling(next, { + message: + "Le nom de votre raccourci doit être de type slug (ne pas contenir d'espaces, ni de caractères spéciaux).", + statusCode: 400 + }) + } + + // Sanitize shortcutName + shortcutName = validator.escape(shortcutName) + shortcutName = validator.trim(shortcutName) + shortcutName = validator.blacklist(shortcutName, ' ') + + try { + // Si l'url a déjà été raccourcie par quelqu'un d'autre + const urlInDatabase = await ShortLinks.findOne({ + where: { url, [Sequelize.Op.not]: { userId } } + }) + if (urlInDatabase) { + const urlShort = `${shortLinkBaseURL}/${urlInDatabase.shortcut}` + return errorHandling(next, { + message: `L'url a déjà été raccourcie...

${urlShort}`, + statusCode: 400 + }) + } + + // Si le nom du raccourci existe déjà par quelqu'un d'autre + const shortcutInDatabase = await ShortLinks.findOne({ + where: { shortcut: shortcutName, [Sequelize.Op.not]: { userId } } + }) + if (shortcutInDatabase) { + const urlShort = `${shortLinkBaseURL}/${shortcutInDatabase.shortcut}` + return errorHandling(next, { + message: `Le nom du raccourci a déjà été utilisé...

${urlShort}`, + statusCode: 400 + }) + } + + // Modification du lien raccourci + const result = await ShortLinks.findOne({ + where: { id, userId } + }) + console.log(result) + if (!result) { + return errorHandling(next, { + statusCode: 404, + message: "Le raccourci n'existe pas..." + }) + } + result.url = url + result.shortcut = shortcutName + const { shortcut } = await result.save() + const shortcutLinkResult = `${shortLinkBaseURL}/${shortcut}` + return res.status(200).json({ + resultHTML: `URL Raccourcie :

${shortcutLinkResult}`, + result: shortcutLinkResult + }) + } catch (error) { + console.log(error) + return errorHandling(next, serverError) + } +} + +exports.deleteLink = async (req, res, next) => { + const { id } = req.params + const { userId } = req + try { + const linkResult = await ShortLinks.findOne({ + where: { id, userId } + }) + if (!linkResult) { + return errorHandling(next, { + message: "Le lien raccourci n'existe pas.", + statusCode: 404 + }) + } + await linkResult.destroy() + return res.status(200).json({ message: 'La lien a bien été supprimé!' }) + } catch (error) { + console.log(error) + return errorHandling(next, serverError) + } +} diff --git a/api/routes/links_shortener.js b/api/routes/links_shortener.js new file mode 100644 index 0000000..5a7e9a1 --- /dev/null +++ b/api/routes/links_shortener.js @@ -0,0 +1,23 @@ +const { Router } = require('express') +const linksShortenerController = require('../controllers/links_shortener') +const isAuth = require('../middlewares/isAuth') + +const LinksShortenerRouter = Router() + +LinksShortenerRouter.route('/') + + // Récupère les liens d'un utilisateur + .get(isAuth, linksShortenerController.getLinks) + + // Ajouter un lien à raccourcir d'un utilisateur + .post(isAuth, linksShortenerController.postLink) + +LinksShortenerRouter.route('/:id') + + // Permet de modifier le lien raccourci d'un utilisateur + .put(isAuth, linksShortenerController.putLink) + + // Supprimer un lien d'un utilisateur + .delete(isAuth, linksShortenerController.deleteLink) + +module.exports = LinksShortenerRouter