const express = require('express'); const sqlite3 = require('sqlite3').verbose(); const path = require('path'); const app = express(); // Middleware app.use(express.json()); app.use(express.static('public')); // Initialize SQLite database const db = new sqlite3.Database('./products.db', (err) => { if (err) console.error(err.message); console.log('Connected to products database.'); }); // Create products table db.run(`CREATE TABLE IF NOT EXISTS products ( id INTEGER PRIMARY KEY AUTOINCREMENT, mpn TEXT NOT NULL, sn TEXT NOT NULL, createdAt DATETIME DEFAULT CURRENT_TIMESTAMP, createdBy TEXT NOT NULL )`); // API Routes // Create products (batch insert) app.post('/api/product/create', (req, res) => { const products = req.body; if (!Array.isArray(products) || products.length === 0) { return res.status(400).json({ error: 'Expected an array of products' }); } const stmt = db.prepare('INSERT INTO products (mpn, sn, createdBy) VALUES (?, ?, ?)'); let inserted = 0; let errors = []; products.forEach((product, index) => { if (!product.mpn || !product.sn || !product.createdBy) { errors.push(`Product at index ${index} is missing required fields`); return; } stmt.run(product.mpn, product.sn, product.createdBy, (err) => { if (err) errors.push(`Error inserting product at index ${index}: ${err.message}`); else inserted++; }); }); stmt.finalize(() => { res.json({ success: true, inserted, errors: errors.length > 0 ? errors : undefined }); }); }); // Get products with pagination, search, and sort app.get('/api/product/get', (req, res) => { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 50; const search = req.query.search || ''; const sortBy = req.query.sortBy || 'id'; const sortOrder = req.query.sortOrder || 'DESC'; const offset = (page - 1) * limit; // Validate sortBy to prevent SQL injection const validColumns = ['id', 'mpn', 'sn', 'createdAt', 'createdBy']; const column = validColumns.includes(sortBy) ? sortBy : 'id'; const order = sortOrder.toUpperCase() === 'ASC' ? 'ASC' : 'DESC'; let query = 'SELECT * FROM products'; let countQuery = 'SELECT COUNT(*) as total FROM products'; let params = []; if (search) { const searchCondition = ` WHERE mpn LIKE ? OR sn LIKE ? OR createdBy LIKE ? OR id LIKE ?`; query += searchCondition; countQuery += searchCondition; const searchParam = `%${search}%`; params = [searchParam, searchParam, searchParam, searchParam]; } query += ` ORDER BY ${column} ${order} LIMIT ? OFFSET ?`; params.push(limit, offset); db.get(countQuery, search ? params.slice(0, 4) : [], (err, countRow) => { if (err) { return res.status(500).json({ error: err.message }); } db.all(query, params, (err, rows) => { if (err) { return res.status(500).json({ error: err.message }); } res.json({ products: rows, total: countRow.total, page, limit, totalPages: Math.ceil(countRow.total / limit) }); }); }); }); // Delete product app.delete('/api/product/delete/:id', (req, res) => { const id = req.params.id; db.run('DELETE FROM products WHERE id = ?', id, function(err) { if (err) { return res.status(500).json({ error: err.message }); } if (this.changes === 0) { return res.status(404).json({ error: 'Product not found' }); } res.json({ success: true, deleted: this.changes }); }); }); // Serve HTML UI app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); const PORT = process.env.PORT || 4444; app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); });