saifurl/server.js

147 lines
4 KiB
JavaScript

import express from "express";
import mongoose from "mongoose";
import dotenv from "dotenv";
import ShortUrl from "./modules/shortUrl.js";
import { nanoid } from "nanoid";
import methodOverride from "method-override";
dotenv.config({ path: ".env.local" });
const MONGODB_URI = process.env.MONGODB_URI;
const PORT = process.env.PORT || 3000;
const accessToken = process.env.ACCESS_TOKEN;
const app = express();
app.use(express.json());
app.use(methodOverride("_method"));
app.use(express.urlencoded({ extended: false }));
// View engine and body parsing
app.set("view engine", "ejs");
// Database connection
mongoose
.connect(MONGODB_URI)
.then(() => console.log("Connected to MongoDB"))
.catch((err) => console.error("Failed to connect to MongoDB", err));
app.get("/", async (req, res) => {
try {
const token = req.query.token;
const shortUrls = await ShortUrl.find();
if (token === accessToken) {
return res.render("admin", { shortUrls: shortUrls, token: token });
}
res.render("viewer", { shortUrls: shortUrls });
} catch (error) {
console.error("Error fetching short URLs:", error);
res.status(500).send("Internal Server Error");
}
});
// CREATE A NEW SHORT URL
app.post("/shorturls", async (req, res) => {
try {
const { fullUrl, token, customShortUrl } = req.body;
const domain = `${req.protocol}://${req.headers.host}`;
if (token !== accessToken) {
return res.status(403).send("Forbidden: Invalid access token");
}
if (!fullUrl) {
return res.status(400).send("Full URL is required.");
}
const short = customShortUrl || nanoid(7);
const existingShort = await ShortUrl.findOne({ short });
if (existingShort) {
return res.status(400).send("Custom short URL already exists.");
}
const existingFull = await ShortUrl.findOne({ full: fullUrl });
if (existingFull) {
return res
.status(400)
.send(
`Full URL already exists at <a href="${domain}/${existingFull.short}">${domain}/${existingFull.short}</a>`
);
}
await ShortUrl.create({ full: fullUrl, short });
res.redirect("/?token=" + token);
} catch (error) {
console.error("Error creating short URL:", error);
res.status(500).send("Internal Server Error");
}
});
// REDIRECT TO THE FULL URL
app.get("/:shorturl", async (req, res) => {
try {
const shortUrl = await ShortUrl.findOne({ short: req.params.shorturl });
if (!shortUrl) return res.sendStatus(404);
shortUrl.clicks++;
await shortUrl.save();
res.redirect(shortUrl.full);
} catch (error) {
console.error("Error fetching short URL:", error);
res.status(500).send("Internal Server Error");
}
});
// UPDATE AN EXISTING SHORT URL
app.patch("/shorturls/:id", async (req, res) => {
const { fullUrl, customShortUrl } = req.body;
const token = req.query.token;
const id = req.params.id;
if (token !== accessToken) {
return res.status(401).json({ success: false, message: "Invalid token" });
}
try {
const updated = await ShortUrl.findByIdAndUpdate(
id,
{ full: fullUrl, short: customShortUrl },
{ new: true }
);
if (!updated) {
return res
.status(404)
.json({ success: false, message: "Short URL not found" });
}
res.json({ success: true, updated });
} catch (err) {
console.error(err);
res.status(500).json({ success: false, message: "Server error" });
}
});
// DELETE A SHORT URL
app.delete("/shorturls/:id", async (req, res) => {
try {
const { id } = req.params;
const { token } = req.query;
if (token !== accessToken) {
return res.status(403).send("Forbidden: Invalid access token");
}
await ShortUrl.findByIdAndDelete(id);
res.redirect("/?token=" + token);
} catch (error) {
console.error("Error deleting short URL:", error);
res.status(500).send("Internal Server Error");
}
});
// START THE SERVER
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});