Ongoing workout session data is persistent now
This commit is contained in:
@@ -18,7 +18,7 @@ const app = express();
|
||||
// -------------------------------------------------------------------
|
||||
async function ensureAdminUser() {
|
||||
const adminEmail = process.env.ADMIN_EMAIL || 'admin@gymflow.ai';
|
||||
const adminPassword = process.env.ADMIN_PASSWORD || 'admin123';
|
||||
const adminPassword = process.env.ADMIN_PASSWORD || 'admin1234';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
|
||||
@@ -62,6 +62,47 @@ router.post('/login', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Register
|
||||
router.post('/register', async (req, res) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
|
||||
// Check if user already exists
|
||||
const existingUser = await prisma.user.findUnique({ where: { email } });
|
||||
if (existingUser) {
|
||||
return res.status(400).json({ error: 'User already exists' });
|
||||
}
|
||||
|
||||
if (!password || password.length < 4) {
|
||||
return res.status(400).json({ error: 'Password too short' });
|
||||
}
|
||||
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
email,
|
||||
password: hashedPassword,
|
||||
role: 'USER',
|
||||
profile: {
|
||||
create: {
|
||||
weight: 70
|
||||
}
|
||||
}
|
||||
},
|
||||
include: { profile: true }
|
||||
});
|
||||
|
||||
const token = jwt.sign({ userId: user.id, role: user.role }, JWT_SECRET);
|
||||
const { password: _, ...userSafe } = user;
|
||||
|
||||
res.json({ success: true, user: userSafe, token });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Change Password
|
||||
router.post('/change-password', async (req, res) => {
|
||||
|
||||
@@ -138,4 +179,92 @@ router.patch('/profile', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Admin: Get All Users
|
||||
router.get('/users', async (req, res) => {
|
||||
try {
|
||||
const token = req.headers.authorization?.split(' ')[1];
|
||||
if (!token) return res.status(401).json({ error: 'Unauthorized' });
|
||||
|
||||
const decoded = jwt.verify(token, JWT_SECRET) as any;
|
||||
if (decoded.role !== 'ADMIN') {
|
||||
return res.status(403).json({ error: 'Admin access required' });
|
||||
}
|
||||
|
||||
const users = await prisma.user.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
role: true,
|
||||
isBlocked: true,
|
||||
isFirstLogin: true,
|
||||
profile: true
|
||||
}
|
||||
});
|
||||
|
||||
res.json({ success: true, users });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Admin: Delete User
|
||||
router.delete('/users/:id', async (req, res) => {
|
||||
try {
|
||||
const token = req.headers.authorization?.split(' ')[1];
|
||||
if (!token) return res.status(401).json({ error: 'Unauthorized' });
|
||||
|
||||
const decoded = jwt.verify(token, JWT_SECRET) as any;
|
||||
if (decoded.role !== 'ADMIN') {
|
||||
return res.status(403).json({ error: 'Admin access required' });
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
|
||||
// Prevent deleting self
|
||||
if (id === decoded.userId) {
|
||||
return res.status(400).json({ error: 'Cannot delete yourself' });
|
||||
}
|
||||
|
||||
await prisma.user.delete({ where: { id } });
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Admin: Toggle Block User
|
||||
router.patch('/users/:id/block', async (req, res) => {
|
||||
try {
|
||||
const token = req.headers.authorization?.split(' ')[1];
|
||||
if (!token) return res.status(401).json({ error: 'Unauthorized' });
|
||||
|
||||
const decoded = jwt.verify(token, JWT_SECRET) as any;
|
||||
if (decoded.role !== 'ADMIN') {
|
||||
return res.status(403).json({ error: 'Admin access required' });
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { block } = req.body;
|
||||
|
||||
// Prevent blocking self
|
||||
if (id === decoded.userId) {
|
||||
return res.status(400).json({ error: 'Cannot block yourself' });
|
||||
}
|
||||
|
||||
await prisma.user.update({
|
||||
where: { id },
|
||||
data: { isBlocked: block }
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -133,6 +133,121 @@ router.post('/', async (req: any, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Get active session (session without endTime)
|
||||
router.get('/active', async (req: any, res) => {
|
||||
try {
|
||||
const userId = req.user.userId;
|
||||
const activeSession = await prisma.workoutSession.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
endTime: null
|
||||
},
|
||||
include: { sets: { include: { exercise: true }, orderBy: { order: 'asc' } } }
|
||||
});
|
||||
|
||||
if (!activeSession) {
|
||||
return res.json({ success: true, session: null });
|
||||
}
|
||||
|
||||
res.json({ success: true, session: activeSession });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Update active session (for real-time set updates)
|
||||
router.put('/active', async (req: any, res) => {
|
||||
try {
|
||||
const userId = req.user.userId;
|
||||
const { id, startTime, endTime, userBodyWeight, note, planId, planName, sets } = req.body;
|
||||
|
||||
// Convert timestamps to Date objects if they are numbers
|
||||
const start = new Date(startTime);
|
||||
const end = endTime ? new Date(endTime) : null;
|
||||
const weight = userBodyWeight ? parseFloat(userBodyWeight) : null;
|
||||
|
||||
// Check if session exists and belongs to user
|
||||
const existing = await prisma.workoutSession.findFirst({
|
||||
where: { id, userId }
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
return res.status(404).json({ error: 'Session not found' });
|
||||
}
|
||||
|
||||
// Delete existing sets to replace them
|
||||
await prisma.workoutSet.deleteMany({ where: { sessionId: id } });
|
||||
|
||||
const updated = await prisma.workoutSession.update({
|
||||
where: { id },
|
||||
data: {
|
||||
startTime: start,
|
||||
endTime: end,
|
||||
userBodyWeight: weight,
|
||||
note,
|
||||
planId,
|
||||
planName,
|
||||
sets: {
|
||||
create: sets.map((s: any, idx: number) => ({
|
||||
exerciseId: s.exerciseId,
|
||||
order: idx,
|
||||
weight: s.weight,
|
||||
reps: s.reps,
|
||||
distanceMeters: s.distanceMeters,
|
||||
durationSeconds: s.durationSeconds,
|
||||
completed: s.completed !== undefined ? s.completed : true
|
||||
}))
|
||||
}
|
||||
},
|
||||
include: { sets: { include: { exercise: true } } }
|
||||
});
|
||||
|
||||
// Update user profile weight if session has weight and is finished
|
||||
if (weight && end) {
|
||||
await prisma.userProfile.upsert({
|
||||
where: { userId },
|
||||
create: { userId, weight },
|
||||
update: { weight }
|
||||
});
|
||||
}
|
||||
|
||||
res.json({ success: true, session: updated });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Delete active session (quit without saving)
|
||||
router.delete('/active', async (req: any, res) => {
|
||||
try {
|
||||
const userId = req.user.userId;
|
||||
|
||||
// Find active session
|
||||
const activeSession = await prisma.workoutSession.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
endTime: null
|
||||
}
|
||||
});
|
||||
|
||||
if (!activeSession) {
|
||||
return res.json({ success: true, message: 'No active session found' });
|
||||
}
|
||||
|
||||
// Delete the session (cascade will delete sets)
|
||||
await prisma.workoutSession.delete({
|
||||
where: { id: activeSession.id }
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Delete session
|
||||
router.delete('/:id', async (req: any, res) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user