From 51297724fe804eafed95fa26952154d536a9f0c9 Mon Sep 17 00:00:00 2001 From: Oluwaseyi Ogunjuyigbe Date: Thu, 2 Apr 2020 19:37:40 +0100 Subject: [PATCH 1/4] Refactored domain name variable --- src/controllers/urlController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/urlController.js b/src/controllers/urlController.js index bbe8ed3..46fd580 100644 --- a/src/controllers/urlController.js +++ b/src/controllers/urlController.js @@ -1,6 +1,6 @@ import UrlShorten from "../models/UrlShorten"; import nanoid from "nanoid"; -import { DOMAIN_NAME } from "../config/constants"; +// import { DOMAIN_NAME } from "../config/constants"; import { respondWithWarning } from '../helpers/responseHandler'; import { getMetric } from '../middlewares/getMetrics'; @@ -18,7 +18,7 @@ export const trimUrl = async (req, res) => { // this line is there because production server fails to detect our // DOMAIN_NAME config variable - const domain_name = DOMAIN_NAME ? DOMAIN_NAME : 'trim.ng' + const domain_name = "https://"+req.headers.host //If the user submitted a custom url, use it. This has been validated by an earlier middleware. if (custom_url) newUrlCode = encodeURIComponent(custom_url); //Sanitize the string as a valid uri comp. first. From a53de6235a98c0adcd81d138d33d69bdd8c1e858 Mon Sep 17 00:00:00 2001 From: Oluwaseyi Ogunjuyigbe Date: Fri, 3 Apr 2020 00:48:02 +0100 Subject: [PATCH 2/4] refactors done --- CONTRIBUTING.md | 17 ++++++++++++++++- README.md | 23 +++-------------------- package.json | 1 + src/controllers/urlController.js | 8 +------- src/middlewares/validate.js | 9 +++++++++ src/middlewares/validateUrl.js | 19 +++++++++---------- src/routes/routes.js | 8 +++++--- 7 files changed, 44 insertions(+), 41 deletions(-) create mode 100644 src/middlewares/validate.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b2e0603..f80cc0b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,21 @@ If you've created a new branch to work on rather than working directly on `Devel 7. Finally, push your newly merged feature branch to the remote github server for backup.
git push origin your-feature-branch
-## Code Structrure & Readability + +##### This will be the file and folder structure + + src + ├── config + ├── constants.js + ├── controllers + ├── database + ├── helpers + ├── middlewares + ├── models + ├── routes + ├── services + ├── tests + └── views +
diff --git a/README.md b/README.md index 3ff6b9c..0b266e8 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,10 @@ Not just a link shortener but branded and can track engagements. ### Getting Started Below are instructions to kick start AutoMart in your local server. - **First off, you must have node/npm installed. Install the latest node version [here](https://nodejs.org/en/download/). Not to worry, the npm package comes along with the node package** ### Installation - 1. Clone this repository by running this on your terminal: `git clone https://github.com/hngi/node-url-shortener.git` 2. Navigate to the project's directory with: `cd node-url-shortener` 3. Run `npm install` to install dependencies @@ -36,30 +34,15 @@ Not just a link shortener but branded and can track engagements. ##### Test Driven Tests are written with mocha, chai-http and chai. -##### This will be the file and folder structure - - src - ├── config - ├── constants.js - ├── controllers - ├── database - ├── helpers - ├── middlewares - ├── models - ├── routes - ├── services - ├── tests - └── views -
- #### Stack: * Bootstrap * Node * Mongodb - #### License ISC License - +### API + 1. Trim a long URL + \ No newline at end of file diff --git a/package.json b/package.json index b61359d..f7e0f5d 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "express": "^4.17.1", "express-device": "^0.4.2", "express-session": "1.16.2", + "express-validator": "^6.4.0", "geoip-lite": "^1.3.8", "mongoose": "^5.7.5", "morgan": "^1.9.1", diff --git a/src/controllers/urlController.js b/src/controllers/urlController.js index 46fd580..c19d786 100644 --- a/src/controllers/urlController.js +++ b/src/controllers/urlController.js @@ -1,6 +1,5 @@ import UrlShorten from "../models/UrlShorten"; import nanoid from "nanoid"; -// import { DOMAIN_NAME } from "../config/constants"; import { respondWithWarning } from '../helpers/responseHandler'; import { getMetric } from '../middlewares/getMetrics'; @@ -13,22 +12,17 @@ import { getMetric } from '../middlewares/getMetrics'; export const trimUrl = async (req, res) => { try { let {expiry_date, custom_url} = req.body; - let newUrlCode; - - // this line is there because production server fails to detect our - // DOMAIN_NAME config variable const domain_name = "https://"+req.headers.host //If the user submitted a custom url, use it. This has been validated by an earlier middleware. if (custom_url) newUrlCode = encodeURIComponent(custom_url); //Sanitize the string as a valid uri comp. first. else newUrlCode = nanoid(5); //If no custom url is provided, generate a random one. - const newTrim = new UrlShorten({ long_url: req.url, clipped_url: `${domain_name}/${newUrlCode}`, urlCode: newUrlCode, - created_by: req.cookies.userID + created_by: req.cookies.userID || req.cookies['connect.sid'] }); // Date validation has been done already diff --git a/src/middlewares/validate.js b/src/middlewares/validate.js new file mode 100644 index 0000000..0383ff3 --- /dev/null +++ b/src/middlewares/validate.js @@ -0,0 +1,9 @@ +const {validationResult} = require('express-validator'); +module.exports = (req, res, next) => { +const errors = validationResult(req); +if (!errors.isEmpty()) { +let error = {}; errors.array().map((err) => error[err.param] = err.msg); +return res.status(400).json({error}); +} +next(); +}; \ No newline at end of file diff --git a/src/middlewares/validateUrl.js b/src/middlewares/validateUrl.js index 48c08f8..37dbd3b 100644 --- a/src/middlewares/validateUrl.js +++ b/src/middlewares/validateUrl.js @@ -11,12 +11,11 @@ import { respondWithWarning } from '../helpers/responseHandler'; */ export const stripUrl = async (req, res, next) => { const { long_url, expiry_date, custom_url } = req.body; - + if(new Date(long_url).getTime() < new Date().getTime()) return respondWithWarning(res,400,'Expiry date must be in the future') const schema = Joi.object({ url: Joi.string().regex( /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/ ).error(new Error('Enter a valid URL')), - expiry: Joi.date().iso().greater(new Date()).allow('').error(new Error('Expiry date must be in the future')), custom_url: Joi.string().regex(/^[A-Za-z0-9_.\-~]{0,}$/).error(new Error('custom URL must contain only alphanumeric, period(.), hyphen(-), underscore(_) and tilde(~) characters')), }); const validationOptions = { @@ -24,7 +23,7 @@ export const stripUrl = async (req, res, next) => { stripUnknown: true, // remove unknown keys from the validated data }; - const { error } = await schema.validate({ url: long_url, expiry: expiry_date, custom_url }, validationOptions); + const { error } = await schema.validate({ url: long_url, expiry: new Date(expiry_date), custom_url }, validationOptions); if (error) { const result = respondWithWarning(res, 400, error.message); return result; @@ -40,12 +39,12 @@ export const stripUrl = async (req, res, next) => { * @param {*} next */ export const validateOwnDomain = (req, res, next) => { - // The strippedUrl already contains the hostname, so match it against our own... + // The strippedUrl already contains the hostname, so match it against our own... if ( - req.url.startsWith(DOMAIN_NAME) || - req.url.startsWith(`https://${DOMAIN_NAME}`) || - req.url.startsWith(`http://${DOMAIN_NAME}`) || - req.url.startsWith(`www.${DOMAIN_NAME}`) + req.body.long_url.startsWith(req.headers.host) || + req.body.long_url.startsWith(`https://${req.headers.host}`) || + req.body.long_url.startsWith(`http://${req.headers.host}`) || + req.body.long_url.startsWith(`www.${req.headers.host}`) ) { const result = respondWithWarning(res, 400, "Cannot trim an already generated URL"); return result; @@ -61,8 +60,8 @@ export const validateOwnDomain = (req, res, next) => { */ export const urlAlreadyTrimmedByUser = (req, res, next) => { const searchParams = { - long_url: req.url, - created_by: req.cookies.userID + long_url: req.url || req.body.long_url, + created_by: req.cookies.userID || req.cookies['connect.sid'] }; UrlShorten.findOne(searchParams, (error, retrievedClip) => { diff --git a/src/routes/routes.js b/src/routes/routes.js index ccb6852..05a24d9 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -1,3 +1,5 @@ +const validate = require('../middlewares/validate'); +const { check } = require('express-validator'); import { aboutPage, renderLandingPage, @@ -18,11 +20,11 @@ import { getUrlClickMetrics } from '../controllers/metricsController'; export const initRoutes = app => { app.get("/", validateCookie, renderLandingPage); app.get("/about", (req, res) => res.status(200).render("about")); - app.post("/", stripUrl, validateOwnDomain, urlAlreadyTrimmedByUser, customUrlExists, trimUrl); + app.post("/", [check('long_url').isString().not().isEmpty().withMessage('Long url cannot be empty'), + check('expiry_date').optional().matches(/([12]\d{3}[-\/](0[1-9]|1[0-2])[-\/](0[1-9]|[12]\d|3[01]))/).withMessage('Date format has to be yyyy-mm-dd or yyyy/mm/dd')] + ,validate, validateOwnDomain, stripUrl, urlAlreadyTrimmedByUser, customUrlExists, trimUrl); app.get("/about", aboutPage); - app.get("/:id", getUrlAndUpdateCount); - app.get('/metrics/:urlShortenId', getUrlClickMetrics); app.all("*", (req, res) => res.status(404).render("error")); }; From 6b4738af05a4b42e95e05ecdd9777eb7fa4d2085 Mon Sep 17 00:00:00 2001 From: Oluwaseyi Ogunjuyigbe Date: Fri, 3 Apr 2020 12:06:42 +0100 Subject: [PATCH 3/4] title tags refactored --- src/views/about.ejs | 8 ++++++++ src/views/error.ejs | 7 +++++++ src/views/index.ejs | 8 ++++++++ src/views/partials/header.ejs | 8 +------- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/views/about.ejs b/src/views/about.ejs index 6eaf08f..a5fa19f 100644 --- a/src/views/about.ejs +++ b/src/views/about.ejs @@ -1,4 +1,12 @@ <% include partials/header %> + + About Trim + + + + + +