-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
101 lines (83 loc) · 2.43 KB
/
server.js
File metadata and controls
101 lines (83 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const express = require("express");
const path = require("path");
const shortid = require("shortid");
const validator = require("validator");
require("dotenv").config();
const connectDB = require("./lib/db");
const URL = require("./models/url");
const app = express();
app.use(express.json());
app.use(express.static(path.join(__dirname)));
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "index.html"));
});
connectDB()
.then(() => console.log("MongoDB Connected"))
.catch(() => {
console.error(
"MongoDB auth failed. Check MONGO_URI username/password and Atlas IP access list."
);
process.exit(1);
});
// ✅ Create Short URL
app.post("/shorten", async (req, res) => {
const { url, customCode } = req.body || {};
if (!url) {
return res.status(400).json({ error: "URL is required" });
}
if (!validator.isURL(url, { require_protocol: true })) {
return res.status(400).json({
error: "Invalid URL. Include protocol, e.g. https://example.com",
});
}
const codePattern = /^[a-zA-Z0-9_-]{4,20}$/;
if (customCode && !codePattern.test(customCode)) {
return res.status(400).json({
error:
"Custom code must be 4-20 chars and use only letters, numbers, - or _",
});
}
let shortCode = customCode || shortid.generate();
if (customCode) {
const existingCustom = await URL.findOne({ shortCode: customCode });
if (existingCustom) {
return res.status(409).json({
error: "Custom code already taken. Try another one.",
});
}
} else {
let retries = 3;
while (retries > 0) {
const exists = await URL.findOne({ shortCode });
if (!exists) break;
shortCode = shortid.generate();
retries -= 1;
}
}
await URL.create({
originalUrl: url,
shortCode,
});
const shortUrl = `${req.protocol}://${req.get("host")}/${shortCode}`;
const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=240x240&data=${encodeURIComponent(
shortUrl
)}`;
res.status(201).json({
shortUrl,
shortCode,
qrCodeUrl,
});
});
// ✅ Redirect
app.get("/:code", async (req, res) => {
const url = await URL.findOne({ shortCode: req.params.code });
if (url) {
return res.redirect(url.originalUrl);
}
return res.status(404).send("URL not found");
});
// ✅ PORT (IMPORTANT FOR DEPLOYMENT)
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});