UrlShortener/index.js
Christopher Cookman 43c0becdb9
New Features
- Add /stats/all to get ALL urls
2024-08-16 01:11:53 -06:00

130 lines
3.8 KiB
JavaScript

require("dotenv").config();
const express = require('express');
const app = express();
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('url.db');
db.on('open', () => {
db.run('CREATE TABLE IF NOT EXISTS urls (shortUrl TEXT, url TEXT, visits INTEGER DEFAULT 0)');
db.run('CREATE TABLE IF NOT EXISTS refs (shortUrl TEXT, referrer TEXT UNIQUE, visits INTEGER DEFAULT 0)');
})
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.get("/", (req, res) => {
res.sendStatus(404);
});
// Add your routes and middleware here
app.get('/:shortUrl', (req, res) => { // Shortened URL
const shortUrl = req.params.shortUrl;
db.get('SELECT url FROM urls WHERE shortUrl = ?', [shortUrl], (err, row) => {
if (err) {
console.error(err);
return res.sendStatus(500);
}
if (row) {
res.redirect(row.url);
// If the UA isn't a bot, increment the view count
if (!req.headers['user-agent'].includes('bot')) {
db.run('UPDATE urls SET visits = visits + 1 WHERE shortUrl = ?', [shortUrl]);
// If req.params.ref exists, increment the referrer count, if the row doesn't exist, insert it
if (req.query.ref) {
db.run('INSERT OR IGNORE INTO refs (shortUrl, referrer) VALUES (?, ?)', [shortUrl, req.query.ref]);
db.run('UPDATE refs SET visits = visits + 1 WHERE shortUrl = ? AND referrer = ?', [shortUrl, req.query.ref]);
}
}
}
else {
res.sendStatus(404);
}
});
});
app.get('/stats/:shortUrl', (req, res) => { // Stats
if (req.query.passcode !== passcode) {
return res.status(403).json({ error: 'Invalid passcode' });
}
const shortUrl = req.params.shortUrl;
if (shortUrl === 'all') {
// Get all URLs and refs. nest refs inside urls
db.all('SELECT * FROM urls', (err, rows) => {
if (err) {
console.error(err);
return res.sendStatus(500);
}
rows.forEach((row, i) => {
db.all('SELECT * FROM refs WHERE shortUrl = ?', [row.shortUrl], (err, refs) => {
if (err) {
console.error(err);
return res.sendStatus(500);
}
rows[i].refs = refs;
if (i === rows.length - 1) {
res.json(rows);
}
});
});
});
} else {
db.get('SELECT * FROM urls WHERE shortUrl = ?', [shortUrl], (err, row) => {
if (err) {
console.error(err);
return res.sendStatus(500);
}
if (row) {
db.all('SELECT * FROM refs WHERE shortUrl = ?', [shortUrl], (err, rows) => {
if (err) {
console.error(err);
return res.sendStatus(500);
}
res.json({ url: row.url, shortUrl: row.shortUrl, visits: row.visits, refs: rows });
});
}
else {
res.send("Code not found").status(404);
}
});
}
});
app.post('/shorten', (req, res) => { // Shorten URL
// Check that { url} exists
if (!req.body.url) {
return res.status(400).json({ error: 'Please provide a URL' });
}
if (req.body.passcode !== passcode) {
return res.status(403).json({ error: 'Invalid passcode' });
}
// Generate a 8 character long string, only if { shortUrl } doesnt exist in body
const shortUrl = req.body.shortUrl || Math.random().toString(36).substr(2, 8);
// Check if shortUrl is already in use
db.get('SELECT shortUrl FROM urls WHERE shortUrl = ?', [shortUrl], (err, row) => {
if (err) {
console.error(err);
return res.sendStatus(500);
}
if (row) {
return res.status(400).json({ error: 'Short URL already in use' });
}
// Insert the URL into the database
db.run('INSERT INTO urls (shortUrl, url) VALUES (?, ?)', [shortUrl, req.body.url], (err) => {
if (err) {
console.error(err);
return res.sendStatus(500);
}
res.json({ shortUrl });
});
});
});
port = process.env.SERVER_PORT || 3000;
passcode = process.env.API_KEY;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
console.log(`API Passcode is ${passcode}`);
});