TKK_E32231242/backend/server.js

266 lines
8.1 KiB
JavaScript

const express = require('express');
const http = require('http');
const { Server } = require("socket.io");
const cors = require('cors');
const db = require('./database');
const app = express();
app.use(cors());
app.use(express.json());
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
let currentTestSession = {
athleteId: null,
attempts: []
};
// Helper for Promisified DB queries
const dbAll = (sql, params = []) => {
return new Promise((resolve, reject) => {
db.all(sql, params, (err, rows) => {
if (err) reject(err);
else resolve(rows);
});
});
};
const dbGet = (sql, params = []) => {
return new Promise((resolve, reject) => {
db.get(sql, params, (err, row) => {
if (err) reject(err);
else resolve(row);
});
});
};
const dbRun = (sql, params = []) => {
return new Promise((resolve, reject) => {
db.run(sql, params, function (err) {
if (err) reject(err);
else resolve({ id: this.lastID, changes: this.changes });
});
});
};
// API Routes
app.get('/api/athletes', async (req, res) => {
try {
const athletes = await dbAll('SELECT * FROM athletes ORDER BY id DESC');
res.json(athletes);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.get('/api/athletes/:id', async (req, res) => {
try {
const athlete = await dbGet('SELECT * FROM athletes WHERE id = ?', [req.params.id]);
if (athlete) res.json(athlete);
else res.status(404).json({ error: 'Athlete not found' });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.post('/api/athletes', async (req, res) => {
const { name, age, height, weight, category, rfid_tag } = req.body;
try {
const result = await dbRun(
'INSERT INTO athletes (name, age, height, weight, category, rfid_tag) VALUES (?, ?, ?, ?, ?, ?)',
[name, age, height, weight, category, rfid_tag]
);
res.json({ id: result.id, success: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: err.message });
}
});
app.delete('/api/athletes/:id', async (req, res) => {
try {
await dbRun('DELETE FROM attempts WHERE athlete_id = ?', [req.params.id]);
await dbRun('DELETE FROM athletes WHERE id = ?', [req.params.id]);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.get('/api/leaderboard', async (req, res) => {
try {
const query = `
SELECT a.name, a.category, MAX(at.force) as best_score
FROM athletes a
JOIN attempts at ON a.id = at.athlete_id
GROUP BY a.id, a.name, a.category
ORDER BY best_score DESC
`;
const leaderboard = await dbAll(query);
res.json(leaderboard);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.get('/api/attempts/:athleteId', async (req, res) => {
try {
const attempts = await dbAll(
'SELECT * FROM attempts WHERE athlete_id = ? ORDER BY timestamp ASC',
[req.params.athleteId]
);
res.json(attempts);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Get History for Chart (Option 3)
app.get('/api/history/:athleteId', async (req, res) => {
try {
const history = await dbAll(`
SELECT
strftime('%Y-%m-%d %H:%M', timestamp) as date,
force
FROM attempts
WHERE athlete_id = ?
ORDER BY timestamp ASC
`, [req.params.athleteId]);
res.json(history);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Start/Stop Test Session logic
app.post('/api/start-test', (req, res) => {
const { athleteId } = req.body;
// Reset session for this athlete
currentTestSession = { athleteId: parseInt(athleteId), attempts: [] };
io.emit('session_started', { athleteId: currentTestSession.athleteId });
console.log(`Session started for athlete ${athleteId}`);
res.json({ success: true });
});
app.post('/api/stop-test', (req, res) => {
currentTestSession = { athleteId: null, attempts: [] };
io.emit('session_ended');
console.log(`Session ended`);
res.json({ success: true });
});
app.post('/api/admin/login', async (req, res) => {
const { username, password } = req.body;
try {
const admin = await dbGet('SELECT * FROM admins WHERE username = ?', [username]);
if (admin && password === admin.password) {
res.json({ success: true, token: 'mock-admin-token', username: admin.username });
} else {
res.status(401).json({ success: false, message: 'Username atau Password salah' });
}
} catch (err) {
res.status(500).json({ error: 'Database error' });
}
});
// Admin Management APIs
app.get('/api/admin/users', async (req, res) => {
try {
const admins = await dbAll('SELECT id, username FROM admins');
res.json(admins);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.post('/api/admin/users', async (req, res) => {
const { username, password } = req.body;
try {
await dbRun('INSERT INTO admins (username, password) VALUES (?, ?)', [username, password]);
res.json({ success: true, message: 'Admin baru ditambahkan' });
} catch (err) {
res.status(500).json({ error: 'Username sudah digunakan atau gagal simpan' });
}
});
app.delete('/api/admin/users/:id', async (req, res) => {
try {
await dbRun('DELETE FROM admins WHERE id = ?', [req.params.id]);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.post('/api/admin/update-password', async (req, res) => {
const { username, oldPassword, newPassword } = req.body;
try {
const admin = await dbGet('SELECT * FROM admins WHERE username = ?', [username]);
if (!admin || oldPassword !== admin.password) {
return res.status(400).json({ success: false, message: 'Password lama salah' });
}
await dbRun('UPDATE admins SET password = ? WHERE username = ?', [newPassword, username]);
res.json({ success: true, message: 'Password berhasil diubah' });
} catch (err) {
res.status(500).json({ error: 'Gagal mengubah password' });
}
});
// Socket.io
io.on('connection', (socket) => {
console.log('Client connected', socket.id);
// Received from RFID reader (simulation)
socket.on('rfid_scan', (tagId) => {
console.log('RFID Scanned:', tagId);
io.emit('rfid_scanned', tagId);
});
// Received from Impact Sensor (simulation)
// Stream for graph visualization
socket.on('sensor_stream', (value) => {
io.emit('sensor_live_data', value);
});
// Impact detected (Peak value or significant hit)
socket.on('impact_detected', async (forceValue) => {
console.log('Impact detected:', forceValue);
if (currentTestSession.athleteId) {
const athleteId = currentTestSession.athleteId;
// Save to DB
try {
await dbRun('INSERT INTO attempts (athlete_id, force) VALUES (?, ?)', [athleteId, forceValue]);
currentTestSession.attempts.push(forceValue);
const attemptCount = currentTestSession.attempts.length;
io.emit('new_attempt_result', {
force: forceValue,
attemptNumber: attemptCount,
athleteId
});
if (attemptCount >= 3) {
io.emit('test_milestone_reached', { athleteId, count: 3 });
}
} catch (err) {
console.error("Error saving attempt:", err);
}
}
});
});
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});