Skip to content

Commit f2bff53

Browse files
committed
Server Added
0 parents  commit f2bff53

File tree

10 files changed

+436
-0
lines changed

10 files changed

+436
-0
lines changed

.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
**/.git
8+
9+
# testing
10+
/coverage
11+
12+
# production
13+
/build
14+
15+
# misc
16+
.DS_Store
17+
.env
18+
.env.local
19+
.env.development.local
20+
.env.test.local
21+
.env.production.local
22+
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
yarn.lock

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: node app.js

app.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
const express = require("express");
2+
const mongoose = require("mongoose");
3+
const bodyParser = require("body-parser");
4+
const cors = require("cors");
5+
6+
const url = require("./routes/api/url");
7+
const users = require("./routes/api/users");
8+
const auth = require("./routes/api/auth");
9+
10+
const Url = require("./models/url");
11+
12+
const app = express();
13+
14+
app.use(bodyParser.urlencoded({ extended: false }));
15+
app.use(bodyParser.json());
16+
app.use(cors());
17+
18+
mongoose
19+
.connect(
20+
`mongodb+srv://${process.env.MONGO_USER}:${process.env.MONGO_PASSWORD}@cluster0-jwfcs.mongodb.net/${process.env.MONGO_DB}?retryWrites=true&w=majority`,
21+
{
22+
useNewUrlParser: true,
23+
useUnifiedTopology: true,
24+
useCreateIndex: true,
25+
}
26+
)
27+
.then(() => {
28+
console.log("MongoDb connected.....");
29+
})
30+
.catch((err) => {
31+
console.log("Cannot connect to db due to " + err);
32+
});
33+
34+
app.use("/api/urls", url);
35+
app.use("/api/register", users);
36+
app.use("/api/login", auth);
37+
38+
app.get("/:code", async (req, res) => {
39+
try {
40+
const url = await Url.findOne({ code: req.params.code });
41+
42+
if (url) {
43+
if (
44+
url.lastDate &&
45+
url.lastDate.toISOString() < new Date().toISOString()
46+
) {
47+
const user = await User.findById(url.creator);
48+
49+
for (let i = 0; i < user.shortenedUrl.length; i++) {
50+
if (user.shortenedUrl[i].toString() === id) {
51+
user.shortenedUrl.splice(i, 1);
52+
break;
53+
}
54+
}
55+
await user.save();
56+
await url.deleteOne();
57+
return res
58+
.status(404)
59+
.json({ msg: "This Compress URL does not exist any more!" });
60+
}
61+
if (!url.status) {
62+
return res
63+
.status(200)
64+
.json({ msg: "This url is temporarily out of service!" });
65+
}
66+
67+
url.clicks = url.clicks + 1;
68+
url.save();
69+
return res.redirect(url.longUrl);
70+
} else {
71+
return res.status(404).json({ msg: "No Compressed URL Found" });
72+
}
73+
} catch (err) {
74+
console.log(err);
75+
res.status(500).json({ msg: "Internal Server Error" });
76+
}
77+
});
78+
79+
const port = process.env.PORT || 5000;
80+
81+
app.listen(port, () => console.log(`Server Started on port ${port}`));

middleware/auth.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const jwt = require("jsonwebtoken");
2+
3+
module.exports = async (req, res, next) => {
4+
const token = req.header("x-auth-token");
5+
6+
//Check for token
7+
if (!token)
8+
return res
9+
.status(401)
10+
.send({ msg: "Authorization denied, Login / SignUp again" });
11+
try {
12+
//Verify token
13+
const decoded = await jwt.verify(token, process.env.JWT_SECRET);
14+
//Add user from payload
15+
req.user = decoded;
16+
next();
17+
} catch (e) {
18+
return res.status(401).send({ msg: "Timeout!, Login / SignUp again" });
19+
}
20+
};

models/url.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const mongoose = require("mongoose");
2+
const Schema = mongoose.Schema;
3+
4+
const urlSchema = new Schema(
5+
{
6+
status: {
7+
type: Boolean,
8+
default: 1,
9+
},
10+
code: String,
11+
longUrl: {
12+
type: String,
13+
required: true,
14+
},
15+
shortUrl: String,
16+
clicks: {
17+
type: Number,
18+
default: 0,
19+
},
20+
creator: {
21+
type: Schema.Types.ObjectId,
22+
ref: "User",
23+
},
24+
lastDate: {
25+
type: Date,
26+
default: null,
27+
},
28+
},
29+
{
30+
timestamps: true,
31+
}
32+
);
33+
34+
module.exports = mongoose.model("Url", urlSchema);

models/user.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const mongoose = require("mongoose");
2+
3+
const Schema = mongoose.Schema;
4+
5+
const userSchema = new Schema(
6+
{
7+
name: {
8+
type: String,
9+
required: true,
10+
},
11+
email: {
12+
type: String,
13+
required: true,
14+
},
15+
password: {
16+
type: String,
17+
required: true,
18+
},
19+
shortenedUrl: [
20+
{
21+
type: Schema.Types.ObjectId,
22+
ref: "Url",
23+
},
24+
],
25+
},
26+
{ timestamps: true }
27+
);
28+
29+
module.exports = mongoose.model("User", userSchema);

package.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "hackstack-task",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "app.js",
6+
"scripts": {
7+
"start": "node app.js",
8+
"server": "nodemon app.js",
9+
"client": "npm start --prefix client"
10+
},
11+
"author": "Himanshu",
12+
"license": "ISC",
13+
"dependencies": {
14+
"bcryptjs": "^2.4.3",
15+
"body-parser": "^1.19.0",
16+
"cors": "^2.8.5",
17+
"express": "^4.17.1",
18+
"jsonwebtoken": "^8.5.1",
19+
"mongoose": "^5.9.15",
20+
"shortid": "^2.2.15",
21+
"valid-url": "^1.0.9"
22+
},
23+
"devDependencies": {
24+
"nodemon": "^2.0.4"
25+
}
26+
}

routes/api/auth.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const express = require("express");
2+
const router = express.Router();
3+
const bcrypt = require("bcryptjs");
4+
const jwt = require("jsonwebtoken");
5+
const auth = require("../../middleware/auth");
6+
7+
const User = require("../../models/user");
8+
9+
router.post("/", async (req, res) => {
10+
const { name, email, password } = req.body;
11+
12+
if (!email || !password) {
13+
return res.status(400).send({ msg: "Please enter all fields" });
14+
}
15+
16+
const user = await User.findOne({ email });
17+
if (!user) return res.status(400).send({ msg: "User Does not Exist" });
18+
19+
bcrypt.compare(password, user.password).then((isMatch) => {
20+
if (!isMatch) return res.status(403).send({ msg: "Invalid Credentials" });
21+
22+
jwt.sign(
23+
{ id: user.id },
24+
process.env.JWT_SECRET,
25+
{ expiresIn: 3600 },
26+
(err, token) => {
27+
if (err) throw err;
28+
return res.json({
29+
token,
30+
user,
31+
});
32+
}
33+
);
34+
});
35+
});
36+
37+
router.get("/user", auth, (req, res) => {
38+
User.findById(req.user.id)
39+
.select("-password")
40+
.then((user) => res.status(200).json(user));
41+
});
42+
43+
module.exports = router;

routes/api/url.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
const express = require("express");
2+
const router = express.Router();
3+
const validUrl = require("valid-url");
4+
const shortId = require("shortid");
5+
6+
const middleAuth = require("../../middleware/auth");
7+
8+
const Url = require("../../models/url");
9+
const User = require("../../models/user");
10+
11+
router.get("/", middleAuth, async (req, res) => {
12+
try {
13+
const user = await User.findById(req.user.id)
14+
.populate("shortenedUrl")
15+
.exec();
16+
if (!user) {
17+
return res.status(400).json({ msg: "User does not exist" });
18+
} else {
19+
return res
20+
.status(200)
21+
.json({ msg: "User found", url: user.shortenedUrl });
22+
}
23+
} catch (err) {
24+
console.log(err);
25+
res.status(500).send({ msg: "Internal Server Error" });
26+
}
27+
});
28+
29+
router.post("/compress", middleAuth, async (req, res) => {
30+
const { longUrl, lastDate } = req.body;
31+
32+
// const baseUrl = "http://localhost:5000";
33+
const baseUrl = process.env.BASE_URL;
34+
if (!validUrl.isUri(baseUrl)) {
35+
return res.status(400).send({ msg: "Invalid Base Url" });
36+
}
37+
38+
const urlCode = shortId.generate();
39+
40+
if (validUrl.isUri(longUrl)) {
41+
try {
42+
let url = await Url.findOne({ longUrl: longUrl });
43+
44+
if (url) {
45+
res
46+
.status(400)
47+
.send({ msg: "Compressed URL already exists", url: url.shortUrl });
48+
} else {
49+
const shortUrl = baseUrl + "/" + urlCode;
50+
51+
url = new Url({
52+
longUrl,
53+
shortUrl,
54+
urlCode,
55+
lastDate: lastDate,
56+
code: urlCode,
57+
creator: req.user.id,
58+
});
59+
const newUrl = await url.save();
60+
61+
const user = await User.findById(req.user.id);
62+
await user.shortenedUrl.push(newUrl._id);
63+
await user.save();
64+
65+
res
66+
.status(200)
67+
.json({ msg: "URL Compressed Successfully", url: newUrl });
68+
}
69+
} catch (err) {
70+
console.log(err);
71+
res.status(500).send({ msg: "Internal Server Error" });
72+
}
73+
} else {
74+
res.status(401).send({ msg: "Invalid Long URL" });
75+
}
76+
});
77+
78+
router.delete("/:id", middleAuth, async (req, res) => {
79+
const id = req.params.id;
80+
81+
try {
82+
const url = await Url.findById(id);
83+
84+
if (req.user.id !== url.creator.toString()) {
85+
return res.status(401).json({ msg: "Unauthorized User" });
86+
}
87+
88+
const user = await User.findById(req.user.id);
89+
90+
for (let i = 0; i < user.shortenedUrl.length; i++) {
91+
if (user.shortenedUrl[i].toString() === id) {
92+
user.shortenedUrl.splice(i, 1);
93+
break;
94+
}
95+
}
96+
await user.save();
97+
await url.deleteOne();
98+
99+
res.status(200).json({ msg: "Short Url Deleted Successfully" });
100+
} catch (err) {
101+
console.log(err);
102+
res.status(500).json({ msg: "Internal Server Error" });
103+
}
104+
});
105+
106+
router.patch("/:id", middleAuth, async (req, res) => {
107+
const id = req.params.id;
108+
109+
try {
110+
const url = await Url.findById(id);
111+
112+
if (req.user.id !== url.creator.toString()) {
113+
return res.status(401).json({ msg: "Unauthorized User" });
114+
}
115+
116+
const { lastDate, status } = req.body;
117+
118+
url.lastDate = lastDate;
119+
url.status = status;
120+
const newUrl = await url.save();
121+
res.status(200).json({ msg: "URL updated successfully", url: newUrl });
122+
} catch (err) {
123+
console.log(err);
124+
res.status(500).json({ msg: "Internal Server Error" });
125+
}
126+
});
127+
128+
module.exports = router;

0 commit comments

Comments
 (0)