144 lines
4.1 KiB
JavaScript
144 lines
4.1 KiB
JavaScript
import express from 'express';
|
|
import { query } from '../db/index.js';
|
|
import { authMiddleware } from '../middleware/auth.js';
|
|
import { asyncHandler, AppError } from '../middleware/errorHandler.js';
|
|
import { socketEvents } from '../sockets/index.js';
|
|
|
|
const router = express.Router();
|
|
|
|
// Get all predictions for a challenge
|
|
router.get('/challenge/:challengeId', authMiddleware, asyncHandler(async (req, res) => {
|
|
const { challengeId } = req.params;
|
|
|
|
// Verify access
|
|
const access = await query(
|
|
`SELECT * FROM challenges WHERE id = ? AND (created_by = ? OR id IN (
|
|
SELECT challenge_id FROM challenge_participants WHERE user_id = ? AND status = 'accepted'
|
|
))`,
|
|
[challengeId, req.user.userId, req.user.userId]
|
|
);
|
|
|
|
if (access.length === 0) {
|
|
throw new AppError('Access denied', 403);
|
|
}
|
|
|
|
// Get predictions
|
|
const predictions = await query(
|
|
`SELECT
|
|
p.*,
|
|
u.username,
|
|
v.username as validated_by_username
|
|
FROM predictions p
|
|
INNER JOIN users u ON p.user_id = u.id
|
|
LEFT JOIN users v ON p.validated_by = v.id
|
|
WHERE p.challenge_id = ?
|
|
ORDER BY p.created_at DESC`,
|
|
[challengeId]
|
|
);
|
|
|
|
res.json({ predictions });
|
|
}));
|
|
|
|
// Create a new prediction
|
|
router.post('/', authMiddleware, asyncHandler(async (req, res) => {
|
|
const { challenge_id, content } = req.body;
|
|
|
|
if (!challenge_id || !content || !content.trim()) {
|
|
throw new AppError('Challenge ID and content are required', 400);
|
|
}
|
|
|
|
// Verify access
|
|
const access = await query(
|
|
`SELECT * FROM challenges WHERE id = ? AND (created_by = ? OR id IN (
|
|
SELECT challenge_id FROM challenge_participants WHERE user_id = ? AND status = 'accepted'
|
|
))`,
|
|
[challenge_id, req.user.userId, req.user.userId]
|
|
);
|
|
|
|
if (access.length === 0) {
|
|
throw new AppError('Access denied', 403);
|
|
}
|
|
|
|
const result = await query(
|
|
'INSERT INTO predictions (challenge_id, user_id, content) VALUES (?, ?, ?)',
|
|
[challenge_id, req.user.userId, content.trim()]
|
|
);
|
|
|
|
const prediction = {
|
|
id: result.insertId,
|
|
challenge_id,
|
|
user_id: req.user.userId,
|
|
username: req.user.username,
|
|
content: content.trim(),
|
|
status: 'pending',
|
|
created_at: new Date()
|
|
};
|
|
|
|
// Emit real-time event to all users in the challenge
|
|
socketEvents.predictionCreated(challenge_id, prediction);
|
|
|
|
res.json({ prediction });
|
|
}));
|
|
|
|
// Validate/invalidate a prediction (approve someone else's)
|
|
router.post('/:id/validate', authMiddleware, asyncHandler(async (req, res) => {
|
|
const predictionId = req.params.id;
|
|
const { status } = req.body; // 'validated' or 'invalidated'
|
|
|
|
if (!['validated', 'invalidated'].includes(status)) {
|
|
throw new AppError('Invalid status', 400);
|
|
}
|
|
|
|
// Get the prediction
|
|
const predictions = await query(
|
|
'SELECT * FROM predictions WHERE id = ?',
|
|
[predictionId]
|
|
);
|
|
|
|
if (predictions.length === 0) {
|
|
throw new AppError('Prediction not found', 404);
|
|
}
|
|
|
|
const prediction = predictions[0];
|
|
|
|
// Cannot validate own prediction
|
|
if (prediction.user_id === req.user.userId) {
|
|
throw new AppError('Cannot validate your own prediction', 403);
|
|
}
|
|
|
|
// Verify access to the challenge
|
|
const access = await query(
|
|
`SELECT * FROM challenges WHERE id = ? AND (created_by = ? OR id IN (
|
|
SELECT challenge_id FROM challenge_participants WHERE user_id = ? AND status = 'accepted'
|
|
))`,
|
|
[prediction.challenge_id, req.user.userId, req.user.userId]
|
|
);
|
|
|
|
if (access.length === 0) {
|
|
throw new AppError('Access denied', 403);
|
|
}
|
|
|
|
// Update prediction
|
|
await query(
|
|
'UPDATE predictions SET status = ?, validated_by = ?, validated_at = NOW() WHERE id = ?',
|
|
[status, req.user.userId, predictionId]
|
|
);
|
|
|
|
// Get updated prediction with usernames
|
|
const updatedPrediction = await query(
|
|
`SELECT p.*, u.username, v.username as validated_by_username
|
|
FROM predictions p
|
|
INNER JOIN users u ON p.user_id = u.id
|
|
LEFT JOIN users v ON p.validated_by = v.id
|
|
WHERE p.id = ?`,
|
|
[predictionId]
|
|
);
|
|
|
|
// Emit real-time event to all users in the challenge
|
|
socketEvents.predictionValidated(prediction.challenge_id, updatedPrediction[0]);
|
|
|
|
res.json({ status });
|
|
}));
|
|
|
|
export default router;
|