fsn-pstgr-pbi / backend /server.js
StringFellow's picture
Update backend/server.js
61b5f02 verified
Raw
History Blame Contribute Delete
4.99 kB
const express = require('express');
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const { Pool } = require('pg');
const path = require('path');
const app = express();
app.use(express.json());
app.use(cookieParser());
const PORT = 7860;
const SECRET_KEY = process.env.JWT_SECRET || 'fallback_secret';
// Connect to PostgreSQL (Vela)
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: { rejectUnauthorized: false }
});
const authenticateToken = (req, res, next) => {
const token = req.cookies.token;
if (!token) return res.status(401).json({ error: "Unauthorized" });
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return res.status(403).json({ error: "Forbidden" });
req.user = user;
next();
});
};
// --- AUTH ROUTES ---
app.post('/api/login', async (req, res) => {
const { username, password } = req.body;
try {
const result = await pool.query('SELECT * FROM portal_users WHERE username = $1 AND password = $2', [username, password]);
if (result.rows.length === 0) return res.status(401).json({ error: "Invalid credentials" });
const user = result.rows[0];
// Token expires in 8 hours
const token = jwt.sign({ id: user.id, username: user.username, role: user.role }, SECRET_KEY, { expiresIn: '8h' });
// Cookie explicitly expires in 8 hours
res.cookie('token', token, {
httpOnly: true,
secure: true,
sameSite: 'Strict',
maxAge: 8 * 60 * 60 * 1000
});
res.json({ role: user.role, id: user.id });
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
app.post('/api/logout', (req, res) => {
res.clearCookie('token');
res.json({ success: true });
});
// --- ADMIN ROUTES ---
app.get('/api/admin/users', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
const result = await pool.query("SELECT id, username, password, pages FROM portal_users WHERE role = 'user' ORDER BY id ASC");
res.json(result.rows);
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
app.post('/api/admin/users', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
const pagesJson = JSON.stringify(req.body.pages || []);
const result = await pool.query(
'INSERT INTO portal_users (username, password, role, pages) VALUES ($1, $2, $3, $4) RETURNING id, username, password, pages',
[req.body.username, req.body.password, 'user', pagesJson]
);
res.json(result.rows[0]);
} catch (err) {
res.status(500).json({ error: "Database error. Username might already exist." });
}
});
app.delete('/api/admin/users/:id', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
await pool.query('DELETE FROM portal_users WHERE id = $1', [req.params.id]);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
app.put('/api/admin/users/:id/pages', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
const pagesJson = JSON.stringify(req.body.pages || []);
await pool.query('UPDATE portal_users SET pages = $1 WHERE id = $2', [pagesJson, req.params.id]);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
app.put('/api/admin/users/:id/password', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
await pool.query('UPDATE portal_users SET password = $1 WHERE id = $2', [req.body.password, req.params.id]);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
// --- USER ROUTES ---
app.get('/api/user/pages', authenticateToken, async (req, res) => {
try {
const result = await pool.query('SELECT pages FROM portal_users WHERE id = $1', [req.user.id]);
if (result.rows.length === 0) return res.status(404).json({ error: "User not found" });
const userPages = result.rows[0].pages || [];
res.json(userPages);
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
// Serve React App
app.use(express.static(path.join(__dirname, 'public')));
app.get('*', (req, res) => res.sendFile(path.join(__dirname, 'public', 'index.html')));
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));