Files
kentekengen/server/db.js
2026-03-01 13:23:49 +00:00

125 lines
3.7 KiB
JavaScript

import Database from 'better-sqlite3';
import bcrypt from 'bcrypt';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { readFileSync } from 'fs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const DB_PATH = join(__dirname, 'kenteken.db');
let db;
export function initDb() {
db = new Database(DB_PATH);
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');
db.exec(`
CREATE TABLE IF NOT EXISTS cars (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
width REAL NOT NULL,
height REAL NOT NULL,
rearWidth REAL,
rearHeight REAL
)
`);
db.exec(`
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
`);
// Seed the database with default cars if empty
const count = db.prepare('SELECT COUNT(*) as cnt FROM cars').get();
if (count.cnt === 0) {
seedDefaultCars();
}
// Set default admin password if not set
const pwd = db.prepare("SELECT value FROM settings WHERE key = 'admin_password'").get();
if (!pwd) {
const hash = bcrypt.hashSync('Rotterdam-010', 10);
db.prepare("INSERT INTO settings (key, value) VALUES ('admin_password', ?)").run(hash);
}
}
function seedDefaultCars() {
const defaultCarsPath = join(__dirname, '..', 'Kenteken-Gen-1-main', 'src', 'frontend', 'carOptions.json');
let defaultCars;
try {
defaultCars = JSON.parse(readFileSync(defaultCarsPath, 'utf-8'));
} catch {
// Fallback: try from shared-cars.json
try {
const sharedPath = join(__dirname, '..', 'Kenteken-Gen-1-main', 'shared-cars.json');
defaultCars = JSON.parse(readFileSync(sharedPath, 'utf-8'));
} catch {
defaultCars = [];
}
}
const insert = db.prepare(
'INSERT INTO cars (name, width, height, rearWidth, rearHeight) VALUES (?, ?, ?, ?, ?)'
);
const insertMany = db.transaction((cars) => {
for (const car of cars) {
insert.run(car.name, car.width, car.height, car.rearWidth || null, car.rearHeight || null);
}
});
insertMany(defaultCars);
}
export function getAllCars() {
return db.prepare('SELECT * FROM cars ORDER BY name COLLATE NOCASE').all();
}
export function addCar({ name, width, height, rearWidth, rearHeight }) {
const result = db.prepare(
'INSERT INTO cars (name, width, height, rearWidth, rearHeight) VALUES (?, ?, ?, ?, ?)'
).run(name, width, height, rearWidth, rearHeight);
return db.prepare('SELECT * FROM cars WHERE id = ?').get(result.lastInsertRowid);
}
export function updateCar(id, { name, width, height, rearWidth, rearHeight }) {
const result = db.prepare(
'UPDATE cars SET name = ?, width = ?, height = ?, rearWidth = ?, rearHeight = ? WHERE id = ?'
).run(name, width, height, rearWidth, rearHeight, id);
if (result.changes === 0) return null;
return db.prepare('SELECT * FROM cars WHERE id = ?').get(id);
}
export function deleteCar(id) {
const result = db.prepare('DELETE FROM cars WHERE id = ?').run(id);
return result.changes > 0;
}
export function replaceAllCars(cars) {
const tx = db.transaction(() => {
db.prepare('DELETE FROM cars').run();
const insert = db.prepare(
'INSERT INTO cars (name, width, height, rearWidth, rearHeight) VALUES (?, ?, ?, ?, ?)'
);
for (const car of cars) {
insert.run(
String(car.name || '').trim(),
Number(car.width) || 0,
Number(car.height) || 0,
car.rearWidth ? Number(car.rearWidth) : null,
car.rearHeight ? Number(car.rearHeight) : null
);
}
});
tx();
}
export function verifyPassword(password) {
const row = db.prepare("SELECT value FROM settings WHERE key = 'admin_password'").get();
if (!row) return false;
return bcrypt.compareSync(password, row.value);
}