171 lines
5.1 KiB
JavaScript
171 lines
5.1 KiB
JavaScript
const express = require('express');
|
|
const cors = require('cors');
|
|
const mysql = require('mysql2/promise');
|
|
|
|
const app = express();
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
const dbConfig = {
|
|
host: process.env.DB_HOST || 'db',
|
|
user: process.env.DB_USER || 'root',
|
|
password: process.env.DB_PASSWORD || 'password',
|
|
database: process.env.DB_NAME || 'nutrition',
|
|
waitForConnections: true,
|
|
connectionLimit: 10,
|
|
queueLimit: 0
|
|
};
|
|
|
|
let pool;
|
|
// Wait for DB to be ready
|
|
const connectDB = async () => {
|
|
let retries = 5;
|
|
while (retries) {
|
|
try {
|
|
pool = mysql.createPool(dbConfig);
|
|
await pool.query('SELECT 1');
|
|
console.log('Connected to MariaDB');
|
|
break;
|
|
} catch (err) {
|
|
console.error('Failed to connect to MariaDB, retrying...', err);
|
|
retries -= 1;
|
|
await new Promise(res => setTimeout(res, 5000));
|
|
}
|
|
}
|
|
};
|
|
connectDB();
|
|
|
|
// Get Profile
|
|
app.get('/api/profile/:userId', async (req, res) => {
|
|
try {
|
|
const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [req.params.userId]);
|
|
if (rows.length > 0) {
|
|
res.json(rows[0]);
|
|
} else {
|
|
res.status(404).json({ error: 'Profile not found' });
|
|
}
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Save Profile
|
|
app.post('/api/profile', async (req, res) => {
|
|
const p = req.body;
|
|
const userId = p.id || 'default_user';
|
|
try {
|
|
await pool.query(`
|
|
INSERT INTO users (id, height, weight, age, gender, activityLevel, goal, bmi, tdee, targetCalories, targetProtein, targetFat, targetCarbs, targetWater)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE
|
|
height=?, weight=?, age=?, gender=?, activityLevel=?, goal=?, bmi=?, tdee=?, targetCalories=?, targetProtein=?, targetFat=?, targetCarbs=?, targetWater=?
|
|
`, [
|
|
userId, p.height, p.weight, p.age, p.gender, p.activityLevel, p.goal, p.bmi, p.tdee, p.targetCalories, p.targetProtein, p.targetFat, p.targetCarbs, p.targetWater,
|
|
p.height, p.weight, p.age, p.gender, p.activityLevel, p.goal, p.bmi, p.tdee, p.targetCalories, p.targetProtein, p.targetFat, p.targetCarbs, p.targetWater
|
|
]);
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Get Logs (returns a mapped object { "YYYY-MM-DD": DailyLog })
|
|
app.get('/api/logs/:userId', async (req, res) => {
|
|
try {
|
|
const [logRows] = await pool.query('SELECT * FROM daily_logs WHERE user_id = ?', [req.params.userId]);
|
|
const [mealRows] = await pool.query('SELECT * FROM meals WHERE user_id = ?', [req.params.userId]);
|
|
|
|
const logs = {};
|
|
|
|
logRows.forEach(row => {
|
|
// row.date is Date object, format to YYYY-MM-DD
|
|
const dateStr = new Date(row.date).toISOString().split('T')[0];
|
|
logs[dateStr] = {
|
|
date: dateStr,
|
|
waterIntake: row.waterIntake,
|
|
weight: row.weight,
|
|
meals: []
|
|
};
|
|
});
|
|
|
|
mealRows.forEach(row => {
|
|
const dateStr = new Date(row.date).toISOString().split('T')[0];
|
|
if (!logs[dateStr]) {
|
|
logs[dateStr] = { date: dateStr, waterIntake: 0, meals: [] };
|
|
}
|
|
logs[dateStr].meals.push({
|
|
id: row.id,
|
|
name: row.name,
|
|
time: row.time,
|
|
calories: row.calories,
|
|
protein: row.protein,
|
|
fat: row.fat,
|
|
carbs: row.carbs
|
|
});
|
|
});
|
|
|
|
res.json(logs);
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Add Meal
|
|
app.post('/api/logs/meal', async (req, res) => {
|
|
const { userId, date, meal } = req.body;
|
|
try {
|
|
await pool.query(`
|
|
INSERT INTO meals (id, user_id, date, name, time, calories, protein, fat, carbs)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`, [meal.id, userId, date, meal.name, meal.time, meal.calories, meal.protein, meal.fat, meal.carbs]);
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Add Water
|
|
app.post('/api/logs/water', async (req, res) => {
|
|
const { userId, date, amount } = req.body;
|
|
try {
|
|
await pool.query(`
|
|
INSERT INTO daily_logs (date, user_id, waterIntake)
|
|
VALUES (?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE waterIntake = waterIntake + ?
|
|
`, [date, userId, amount, amount]);
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Log Weight
|
|
app.post('/api/logs/weight', async (req, res) => {
|
|
const { userId, date, weight } = req.body;
|
|
try {
|
|
await pool.query(`
|
|
INSERT INTO daily_logs (date, user_id, weight)
|
|
VALUES (?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE weight = ?
|
|
`, [date, userId, weight, weight]);
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Clear Data
|
|
app.delete('/api/data/:userId', async (req, res) => {
|
|
try {
|
|
await pool.query('DELETE FROM users WHERE id = ?', [req.params.userId]);
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
const PORT = process.env.PORT || 3000;
|
|
app.listen(PORT, () => {
|
|
console.log(`API server running on port ${PORT}`);
|
|
});
|