138 lines
5.1 KiB
JavaScript
138 lines
5.1 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const QRCode = require('qrcode');
|
|
const shortid = require('shortid');
|
|
const { verifyToken } = require('../middleware/auth');
|
|
const { Pool } = require('pg');
|
|
|
|
const pgPool = new Pool({
|
|
host: process.env.PGHOST || 'postgres',
|
|
port: process.env.PGPORT || 5432,
|
|
user: process.env.PGUSER || 'postgres',
|
|
password: process.env.PGPASSWORD || 'postgres',
|
|
database: process.env.PGDATABASE || 'ckqr',
|
|
});
|
|
|
|
// Get all QRs for user
|
|
router.get('/', verifyToken, async (req, res) => {
|
|
try {
|
|
const result = await pgPool.query(
|
|
`SELECT q.*,
|
|
COALESCE((SELECT COUNT(*) FROM qr_scans s WHERE s.qr_code_id = q.id), 0) as scans
|
|
FROM qr_codes q
|
|
WHERE q.user_id = $1
|
|
ORDER BY q.created_at DESC`,
|
|
[req.user.id]
|
|
);
|
|
res.json({ qr_codes: result.rows });
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Server error fetching QR codes' });
|
|
}
|
|
});
|
|
|
|
// Generate QR Code
|
|
router.post('/generate', verifyToken, async (req, res) => {
|
|
const { name, type, dataType, destinationUrl, designData, customSlug } = req.body;
|
|
const userId = req.user.id;
|
|
|
|
if (!type || !dataType) {
|
|
return res.status(400).json({ error: 'Missing type or dataType' });
|
|
}
|
|
|
|
try {
|
|
let shortUrlId = null;
|
|
let finalQrContent = destinationUrl;
|
|
|
|
if (type === 'dynamic') {
|
|
if (!destinationUrl) return res.status(400).json({ error: 'Destination URL is required for dynamic QR' });
|
|
|
|
// Allow custom slug or generate random
|
|
shortUrlId = customSlug ? customSlug.trim() : shortid.generate();
|
|
|
|
// Enforce uniqueness for custom slug
|
|
if (customSlug) {
|
|
const existing = await pgPool.query('SELECT id FROM qr_codes WHERE short_url_id = $1', [shortUrlId]);
|
|
if (existing.rows.length > 0) {
|
|
return res.status(409).json({ error: 'That custom link is already taken. Please choose another.' });
|
|
}
|
|
}
|
|
|
|
// In production, this would use the real domain (e.g. https://ck-qr.com/l/)
|
|
finalQrContent = `${process.env.BASE_URL || 'http://localhost:4001'}/l/${shortUrlId}`;
|
|
}
|
|
|
|
const result = await pgPool.query(
|
|
`INSERT INTO qr_codes (user_id, name, type, data_type, destination_url, short_url_id, design_data)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *`,
|
|
[userId, name || 'Untitled QR', type, dataType, destinationUrl, shortUrlId, designData || {}]
|
|
);
|
|
|
|
// Generate Image (Data URI for simple response, could be saved to S3 later)
|
|
const qrImage = await QRCode.toDataURL(finalQrContent);
|
|
|
|
res.json({
|
|
message: 'QR Code generated',
|
|
qrRecord: result.rows[0],
|
|
qrImage: qrImage
|
|
});
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Server error generating QR code' });
|
|
}
|
|
});
|
|
|
|
// Update QR Code (Editable Link)
|
|
router.put('/:id', verifyToken, async (req, res) => {
|
|
const { name, destinationUrl, shortUrlId } = req.body;
|
|
const qrId = req.params.id;
|
|
const userId = req.user.id;
|
|
|
|
try {
|
|
// Verify ownership
|
|
const qrCheck = await pgPool.query('SELECT * FROM qr_codes WHERE id = $1 AND user_id = $2', [qrId, userId]);
|
|
if (qrCheck.rows.length === 0) {
|
|
return res.status(404).json({ error: 'QR Code not found or unauthorized' });
|
|
}
|
|
|
|
const qr = qrCheck.rows[0];
|
|
let newShortUrlId = shortUrlId ? shortUrlId.trim() : qr.short_url_id;
|
|
|
|
// Check if slug changed and enforce uniqueness
|
|
if (newShortUrlId !== qr.short_url_id) {
|
|
const existing = await pgPool.query('SELECT id FROM qr_codes WHERE short_url_id = $1', [newShortUrlId]);
|
|
if (existing.rows.length > 0) {
|
|
return res.status(409).json({ error: 'That custom link is already taken. Please choose another.' });
|
|
}
|
|
}
|
|
|
|
// Update DB
|
|
const updated = await pgPool.query(
|
|
`UPDATE qr_codes
|
|
SET name = COALESCE($1, name),
|
|
destination_url = COALESCE($2, destination_url),
|
|
short_url_id = COALESCE($3, short_url_id)
|
|
WHERE id = $4 RETURNING *`,
|
|
[name, destinationUrl, newShortUrlId, qrId]
|
|
);
|
|
|
|
res.json({ message: 'QR Code updated', qrRecord: updated.rows[0] });
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Server error updating QR code' });
|
|
}
|
|
});
|
|
|
|
// Delete QR Code
|
|
router.delete('/:id', verifyToken, async (req, res) => {
|
|
try {
|
|
const result = await pgPool.query('DELETE FROM qr_codes WHERE id = $1 AND user_id = $2 RETURNING id', [req.params.id, req.user.id]);
|
|
if (result.rows.length === 0) return res.status(404).json({ error: 'Not found' });
|
|
res.json({ message: 'QR Code deleted' });
|
|
} catch (err) {
|
|
res.status(500).json({ error: 'Error deleting QR code' });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|