121 lines
4.0 KiB
JavaScript
121 lines
4.0 KiB
JavaScript
const express = require('express');
|
|
const sqlite3 = require('sqlite3').verbose();
|
|
const cors = require('cors');
|
|
const path = require('path');
|
|
const multer = require('multer');
|
|
const fs = require('fs');
|
|
|
|
const app = express();
|
|
|
|
// Use DATA_DIR env var if set, otherwise use local "data" folder
|
|
const DATA_DIR = process.env.DATA_DIR || path.join(__dirname, 'data');
|
|
|
|
const dbPath = path.join(DATA_DIR, 'db.sqlite');
|
|
const db = new sqlite3.Database(dbPath);
|
|
const upload = multer({ dest: path.join(DATA_DIR, 'uploads/') });
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
app.use('/uploads', express.static(path.join(DATA_DIR, 'uploads')));
|
|
|
|
// Create uploads directory if it doesn't exist
|
|
fs.mkdirSync(path.join(DATA_DIR, 'uploads'), { recursive: true });
|
|
|
|
// Initialize database and ensure counters table exists
|
|
db.serialize(() => {
|
|
db.run(`CREATE TABLE IF NOT EXISTS counters (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
value INTEGER NOT NULL DEFAULT 0,
|
|
name TEXT NOT NULL DEFAULT 'Counter',
|
|
image TEXT
|
|
)`);
|
|
});
|
|
|
|
// Get all counters
|
|
app.get('/api/counters', (req, res) => {
|
|
db.all('SELECT * FROM counters', (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
// Ensure id and value are numbers
|
|
const counters = rows.map(row => ({
|
|
...row,
|
|
id: Number(row.id),
|
|
value: Number(row.value)
|
|
}));
|
|
res.json(counters);
|
|
});
|
|
});
|
|
|
|
// Create a new counter with image
|
|
app.post('/api/counters', upload.single('image'), (req, res) => {
|
|
const { name = 'Counter', value = 0 } = req.body;
|
|
const image = req.file ? `/uploads/${req.file.filename}` : null;
|
|
db.run('INSERT INTO counters (name, value, image) VALUES (?, ?, ?)', [name, value, image], function (err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ id: Number(this.lastID), name, value: Number(value), image });
|
|
});
|
|
});
|
|
|
|
// Update a counter (now supports image upload)
|
|
app.put('/api/counters/:id', upload.single('image'), (req, res) => {
|
|
const { name, value } = req.body;
|
|
const id = req.params.id;
|
|
let image = null;
|
|
|
|
// If a new image is uploaded, get its path
|
|
if (req.file) {
|
|
image = `/uploads/${req.file.filename}`;
|
|
// Optionally, delete the old image file
|
|
db.get('SELECT image FROM counters WHERE id = ?', [id], (err, row) => {
|
|
if (row && row.image) {
|
|
const oldImagePath = path.join(__dirname, '..', row.image);
|
|
fs.unlink(oldImagePath, () => { }); // Ignore errors
|
|
}
|
|
});
|
|
}
|
|
|
|
// Build dynamic SQL and params
|
|
let fields = [];
|
|
let params = [];
|
|
if (name !== undefined) { fields.push('name = ?'); params.push(name); }
|
|
if (value !== undefined) { fields.push('value = ?'); params.push(value); }
|
|
if (image !== null) { fields.push('image = ?'); params.push(image); }
|
|
if (fields.length === 0) return res.status(400).json({ error: 'No valid fields to update.' });
|
|
|
|
params.push(id);
|
|
const sql = `UPDATE counters SET ${fields.join(', ')} WHERE id = ?`;
|
|
|
|
db.run(sql, params, function (err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ updated: this.changes });
|
|
});
|
|
});
|
|
|
|
// Delete a counter
|
|
app.delete('/api/counters/:id', (req, res) => {
|
|
db.run('DELETE FROM counters WHERE id = ?', [req.params.id], function (err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ deleted: this.changes });
|
|
});
|
|
});
|
|
|
|
// Serve static frontend files
|
|
const clientBuildPath = path.join(__dirname, '..', 'frontend', 'dist');
|
|
app.use(express.static(clientBuildPath));
|
|
|
|
// For SPA: serve index.html for any unknown route (after API and uploads)
|
|
app.get('/*path', (req, res) => {
|
|
if (req.path.startsWith('/api') || req.path.startsWith('/uploads')) return res.status(404).end();
|
|
res.sendFile(path.join(clientBuildPath, 'index.html'));
|
|
});
|
|
|
|
const PORT = 3000;
|
|
app.listen(PORT, () => {
|
|
console.log(`API server running on http://localhost:${PORT}`);
|
|
});
|
|
|
|
process.on('SIGTERM', () => {
|
|
console.log('SIGTERM received, shutting down gracefully...');
|
|
db.close(() => {
|
|
console.log('Database connection closed.');
|
|
process.exit(0);
|
|
});
|
|
}); |