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.status(404).json({ error: 'Not found' }); }); // 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.status(500).json({ error: 'Internal server error', fullError: err.stack }); } 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.status(404).json({ error: 'Short URL not found' }); } }); }); 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.status(500).json({ error: 'Internal server error', fullError: err.stack }); } rows.forEach((row, i) => { db.all('SELECT * FROM refs WHERE shortUrl = ?', [row.shortUrl], (err, refs) => { if (err) { console.error(err); return res.status(500).json({ error: 'Internal server error', fullError: err.stack }); } 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.status(500).json({ error: 'Internal server error', fullError: err.stack }); } if (row) { db.all('SELECT * FROM refs WHERE shortUrl = ?', [shortUrl], (err, rows) => { if (err) { console.error(err); return res.status(500).json({ error: 'Internal server error', fullError: err.stack }); } res.json({ url: row.url, shortUrl: row.shortUrl, visits: row.visits, refs: rows }); }); } else { res.status(404).json({ error: 'Short URL not found' }); } }); } }); 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.status(500).json({ error: 'Internal server error', fullError: err.stack }); } 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.status(500).json({ error: 'Internal server error', fullError: err.stack }); } 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}`); });