From a0a339aa3f974056ecfcaed87b9eb0072b960397 Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Thu, 8 Oct 2020 10:33:57 +0530 Subject: [PATCH 01/11] Hello Universe Simple index view with ejs --- README.md | 1 + Views/index.ejs | 1 + package.json | 2 +- server.js | 16 ++++++++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Views/index.ejs create mode 100644 server.js diff --git a/README.md b/README.md index 606c476..c31c5bb 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,5 @@ ejs- templating language to create views ### dev dependencies `npm i --save-dev nodemon` +//npm install -g nodemon For refreshing server for every new change diff --git a/Views/index.ejs b/Views/index.ejs new file mode 100644 index 0000000..a17dcb5 --- /dev/null +++ b/Views/index.ejs @@ -0,0 +1 @@ +Hello Universe diff --git a/package.json b/package.json index ed37085..9c9fbeb 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "A url shortner", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "devStart": "nodemon server.js" }, "repository": { "type": "git", diff --git a/server.js b/server.js new file mode 100644 index 0000000..31d6655 --- /dev/null +++ b/server.js @@ -0,0 +1,16 @@ +const express = require("express"); + +//make basic app + +const app = express(); + +//setting ejs as view engine +app.set("view engine", "ejs"); + +// index page with request and response parameters +app.get("/", (req, res) => { + res.render("index"); +}); + +// start listening on specified port +app.listen(process.env.PORT || 4567); From 2dc434103c269633f97bd7b4177cd608a3f44a7c Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Thu, 8 Oct 2020 11:04:07 +0530 Subject: [PATCH 02/11] Form Table generated from form data --- Views/index.ejs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Views/index.ejs b/Views/index.ejs index a17dcb5..76de5c8 100644 --- a/Views/index.ejs +++ b/Views/index.ejs @@ -1 +1,35 @@ -Hello Universe + + + + + + YouRL-Hello Universe + + +

URL Shortner

+
+ + + +
+ + + + + + + + + + + + + + + + +
Full URLShortened URLTotal Clicks
+ https://sunn-e.github.io + 4201
+ + From b198e531f2dc4572b318b03901870e6b82235001 Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Thu, 8 Oct 2020 11:23:52 +0530 Subject: [PATCH 03/11] Added Bootstrap CSS --- Views/index.ejs | 66 +++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/Views/index.ejs b/Views/index.ejs index 76de5c8..52c389a 100644 --- a/Views/index.ejs +++ b/Views/index.ejs @@ -3,33 +3,51 @@ + YouRL-Hello Universe -

URL Shortner

-
- - - -
+
+

URL Shortner

+
+ + + +
- - - - - - - - - - - - - - - -
Full URLShortened URLTotal Clicks
- https://sunn-e.github.io - 4201
+ + + + + + + + + + + + + + + + +
+ List of URLs and click counts +
Full URLShortened URLTotal Clicks
+ https://sunn-e.github.io + 4201
+
From 6f36ae86807dff9254b3ce07deea96a49f18e024 Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Thu, 8 Oct 2020 11:49:58 +0530 Subject: [PATCH 04/11] connection to mongodb using mongoose, no schema yet. --- Views/index.ejs | 2 +- models/README.md | 1 + server.js | 13 +++++++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 models/README.md diff --git a/Views/index.ejs b/Views/index.ejs index 52c389a..2410678 100644 --- a/Views/index.ejs +++ b/Views/index.ejs @@ -14,7 +14,7 @@

URL Shortner

-
+ { res.render("index"); }); +//post +app.post("/shortUrls", (req, res) => {}); // start listening on specified port app.listen(process.env.PORT || 4567); From 3869894394ee66de7c8c32337798a03d7263e9d0 Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Thu, 8 Oct 2020 11:51:08 +0530 Subject: [PATCH 05/11] Adding data model/ Schema | fullurl | shorturl | clicks | + shortid-library to shorten url/get id from url --- models/shortUrl.js | 29 +++++++++++++++++++++++++++++ package-lock.json | 13 +++++++++++++ package.json | 3 ++- 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 models/shortUrl.js diff --git a/models/shortUrl.js b/models/shortUrl.js new file mode 100644 index 0000000..359e33c --- /dev/null +++ b/models/shortUrl.js @@ -0,0 +1,29 @@ +//to connect to mongodb +const mongoose = require("mongoose"); + +// to create short identifier +//has .generate() function that we will pass to shorturl as default +const shortId = require("shortid"); + +//db schema +// | fullurl | shorturl | clicks | +const shortUrlSchema = new mongoose.Schema({ + fullurl: { + type: String, + required: true, + }, + shorturl: { + type: String, + required: true, + default: shortId.generate, + }, + clicks: { + type: Number, + required: true, + default: 0, + }, +}); + +//now exporting this to hook model with database +// model name, schema name +modules.exports = mongoose.model("shortUrl", shortUrlSchema); diff --git a/package-lock.json b/package-lock.json index 7ad2ab2..77c026d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -991,6 +991,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "nanoid": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", + "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -1342,6 +1347,14 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, + "shortid": { + "version": "2.2.15", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.15.tgz", + "integrity": "sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==", + "requires": { + "nanoid": "^2.1.0" + } + }, "sift": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", diff --git a/package.json b/package.json index 9c9fbeb..72dd23d 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "dependencies": { "ejs": "^3.1.5", "express": "^4.17.1", - "mongoose": "^5.10.8" + "mongoose": "^5.10.8", + "shortid": "^2.2.15" }, "devDependencies": { "nodemon": "^2.0.4" From eeb195793c9985c7dd04cc6a09cc82d48740df85 Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Thu, 8 Oct 2020 13:52:48 +0530 Subject: [PATCH 06/11] Working prototype. --- README.md | 12 ++++++++++++ Views/index.ejs | 15 +++++++++------ models/shortUrl.js | 6 +++--- server.js | 23 ++++++++++++++++++----- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c31c5bb..1f38071 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,15 @@ ejs- templating language to create views `npm i --save-dev nodemon` //npm install -g nodemon For refreshing server for every new change + +### mongodb on windows + +make sure admin access + +- to access db + +"C:\Program Files\MongoDB\Server\4.4\bin\mongod.exe" --dbpath="c:\data\db" + +- to start server + +"C:\Program Files\MongoDB\Server\4.4\bin\mongo.exe" diff --git a/Views/index.ejs b/Views/index.ejs index 2410678..99c1e32 100644 --- a/Views/index.ejs +++ b/Views/index.ejs @@ -15,13 +15,13 @@

URL Shortner

- + @@ -39,13 +39,16 @@ + <% shortUrls.forEach(shortUrl => { %> + - https://sunn-e.github.io + <%= shortUrl.full %> - 420 - 1 + <%= shortUrl.short %> + <%= shortUrl.clicks %> + <% }) %> });
diff --git a/models/shortUrl.js b/models/shortUrl.js index 359e33c..b519976 100644 --- a/models/shortUrl.js +++ b/models/shortUrl.js @@ -8,11 +8,11 @@ const shortId = require("shortid"); //db schema // | fullurl | shorturl | clicks | const shortUrlSchema = new mongoose.Schema({ - fullurl: { + full: { type: String, required: true, }, - shorturl: { + short: { type: String, required: true, default: shortId.generate, @@ -26,4 +26,4 @@ const shortUrlSchema = new mongoose.Schema({ //now exporting this to hook model with database // model name, schema name -modules.exports = mongoose.model("shortUrl", shortUrlSchema); +module.exports = mongoose.model("shortUrl", shortUrlSchema); diff --git a/server.js b/server.js index f5c72fe..c72c6fc 100644 --- a/server.js +++ b/server.js @@ -7,19 +7,32 @@ const app = express(); //setting ejs as view engine app.set("view engine", "ejs"); +// tell express, app is using url parameters +app.use(express.urlencoded({ extended: false })); + // to connect to database const mongoose = require("mongoose"); -mongoose.connect("mongodb://localhost/urlShortner", { +mongoose.connect("mongodb://localhost/db", { useNewUrlParser: true, useUnifiedTopology: true, }); + +// import data model/ schema +const ShortUrl = require("./models/shortUrl"); + //get // index page with request and response parameters -app.get("/", (req, res) => { - res.render("index"); +// show all url in index page +app.get("/", async (req, res) => { + const shortUrls = await ShortUrl.find(); + res.render("index", { shortUrls: shortUrls }); }); //post -app.post("/shortUrls", (req, res) => {}); -// start listening on specified port +app.post("/shortUrls", async (req, res) => { + ShortUrl.create({ full: req.body.fullUrl }); + res.redirect("/"); +}); +// start listening on specified port 4567 +//can set as environment var app.listen(process.env.PORT || 4567); From dee251b52429b35c2f8fb720649678ae742d4afd Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Fri, 9 Oct 2020 10:32:01 +0530 Subject: [PATCH 07/11] typo --- Views/index.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Views/index.ejs b/Views/index.ejs index 99c1e32..681493f 100644 --- a/Views/index.ejs +++ b/Views/index.ejs @@ -48,7 +48,7 @@ <%= shortUrl.short %> <%= shortUrl.clicks %> - <% }) %> }); + <% }) %>
From 83bafe3f7f3764237d462327e140973eb239151f Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Fri, 9 Oct 2020 10:33:57 +0530 Subject: [PATCH 08/11] Added clicks abd ability to redirect to full url You can click on short or full url. Increments the count and updates in db. Sends 404 if null url. --- server.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index c72c6fc..d64dce4 100644 --- a/server.js +++ b/server.js @@ -22,7 +22,7 @@ const ShortUrl = require("./models/shortUrl"); //get // index page with request and response parameters -// show all url in index page +// show all url from table "ShortUrl" in index page app.get("/", async (req, res) => { const shortUrls = await ShortUrl.find(); res.render("index", { shortUrls: shortUrls }); @@ -33,6 +33,25 @@ app.post("/shortUrls", async (req, res) => { ShortUrl.create({ full: req.body.fullUrl }); res.redirect("/"); }); + +//for clicking on short url after slash +//parameter ":shortUrl" +app.get("/:shortUrl", async (req, res) => { + //find the one where in "short", a "shortUrl" is found + const shortUrl = await ShortUrl.findOne({ short: req.params.shortUrl }); + + //if user sends empty shorturl,send 404 + if (shortUrl == null) return res.sendStatus(404); + + //otherwise increase the click + shortUrl.clicks++; + //save the changes in table + shortUrl.save(); + + //redirect the full link corresponding the short url we found + res.redirect(shortUrl.full); +}); + // start listening on specified port 4567 //can set as environment var app.listen(process.env.PORT || 4567); From a2acc098a7321d76a049090cee462fe136094410 Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Fri, 9 Oct 2020 16:56:26 +0530 Subject: [PATCH 09/11] Added timestamp feature `.createdAt`; gives the moment the link was submitted --- Views/index.ejs | 2 ++ models/shortUrl.js | 35 ++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Views/index.ejs b/Views/index.ejs index 681493f..a80c05a 100644 --- a/Views/index.ejs +++ b/Views/index.ejs @@ -36,6 +36,7 @@ Full URL Shortened URL Total Clicks + Timestamp @@ -47,6 +48,7 @@ <%= shortUrl.short %> <%= shortUrl.clicks %> + <%= shortUrl.createdAt;%> <% }) %> diff --git a/models/shortUrl.js b/models/shortUrl.js index b519976..6ebf986 100644 --- a/models/shortUrl.js +++ b/models/shortUrl.js @@ -7,22 +7,27 @@ const shortId = require("shortid"); //db schema // | fullurl | shorturl | clicks | -const shortUrlSchema = new mongoose.Schema({ - full: { - type: String, - required: true, +const shortUrlSchema = new mongoose.Schema( + { + full: { + type: String, + required: true, + }, + short: { + type: String, + required: true, + default: shortId.generate, + }, + clicks: { + type: Number, + required: true, + default: 0, + }, }, - short: { - type: String, - required: true, - default: shortId.generate, - }, - clicks: { - type: Number, - required: true, - default: 0, - }, -}); + { timestamps: true } +); + +//var mySchema = new mongoose.Schema( {name: String}, {timestamps: true} ); //now exporting this to hook model with database // model name, schema name From 5453470e43a3e4547c1a237808e65b36624da526 Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Fri, 9 Oct 2020 16:59:37 +0530 Subject: [PATCH 10/11] Added ability to deploy on Heroku --- README.md | 13 +++++++++++++ package.json | 1 + server.js | 7 +++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1f38071..d974f3b 100644 --- a/README.md +++ b/README.md @@ -33,3 +33,16 @@ make sure admin access - to start server "C:\Program Files\MongoDB\Server\4.4\bin\mongo.exe" + +## Deploy + +### Heroku + +1. Fork this repository +1. Create a free Heroku Account +1. Create free heroku app with your github fork + +## Roadmap + +- A login Screen +- protected routes with JWT diff --git a/package.json b/package.json index 72dd23d..ef6fb0f 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "A url shortner", "main": "index.js", "scripts": { + "start": "node ./server.js", "devStart": "nodemon server.js" }, "repository": { diff --git a/server.js b/server.js index d64dce4..193a2b4 100644 --- a/server.js +++ b/server.js @@ -12,7 +12,9 @@ app.use(express.urlencoded({ extended: false })); // to connect to database const mongoose = require("mongoose"); -mongoose.connect("mongodb://localhost/db", { + +//App deploy or localhost mode connection to MongoDB +mongoose.connect(process.env.MONGO_URL || "mongodb://localhost/db", { useNewUrlParser: true, useUnifiedTopology: true, }); @@ -46,7 +48,8 @@ app.get("/:shortUrl", async (req, res) => { //otherwise increase the click shortUrl.clicks++; //save the changes in table - shortUrl.save(); + //can use `await` here but speed of redirect is more important + await shortUrl.save(); //redirect the full link corresponding the short url we found res.redirect(shortUrl.full); From 1af4324869fd4c2e78340f1d4fc43c500720dda1 Mon Sep 17 00:00:00 2001 From: Sunny Dhoke Date: Fri, 9 Oct 2020 17:18:15 +0530 Subject: [PATCH 11/11] Adding CI --- .github/workflows/node.js.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/node.js.yml diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000..a391700 --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,29 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [10.x, 12.x, 14.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build --if-present + - run: npm test