const express = require('express'); const jwt = require('jsonwebtoken'); const SourceText = require('../models/SourceText'); const router = express.Router(); // Middleware to verify token (simplified - matches auth.js) const authenticateToken = (req, res, next) => { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; if (!token) { return res.status(401).json({ error: 'Access token required' }); } // For our simplified system, just check if token exists and has the right format if (token.startsWith('user_') || token.startsWith('visitor_')) { req.user = { token }; // We'll get user details from localStorage on frontend next(); } else { return res.status(403).json({ error: 'Invalid token' }); } }; // Get all source texts with filters router.get('/', authenticateToken, async (req, res) => { try { const { sourceLanguage, sourceCulture, targetCulture, difficulty, sourceType, tags, page = 1, limit = 10 } = req.query; const filter = { isActive: true }; if (sourceLanguage) filter.sourceLanguage = sourceLanguage; if (sourceCulture) filter.sourceCulture = sourceCulture; if (targetCulture) filter.targetCultures = targetCulture; if (difficulty) filter.difficulty = difficulty; if (sourceType) filter.sourceType = sourceType; if (tags) filter.tags = { $in: tags.split(',') }; const skip = (page - 1) * limit; const texts = await SourceText.find(filter) .sort({ createdAt: -1 }) .skip(skip) .limit(parseInt(limit)) .populate('createdBy', 'username'); const total = await SourceText.countDocuments(filter); res.json({ texts, pagination: { page: parseInt(page), limit: parseInt(limit), total, pages: Math.ceil(total / limit) } }); } catch (error) { console.error('Get source texts error:', error); res.status(500).json({ error: 'Failed to get source texts' }); } }); // Get a specific source text by ID router.get('/:id', authenticateToken, async (req, res) => { try { const text = await SourceText.findById(req.params.id) .populate('createdBy', 'username'); if (!text) { return res.status(404).json({ error: 'Source text not found' }); } // Increment usage count text.usageCount += 1; await text.save(); res.json(text); } catch (error) { console.error('Get source text error:', error); res.status(500).json({ error: 'Failed to get source text' }); } }); // Create a new source text router.post('/', authenticateToken, async (req, res) => { try { const { title, content, sourceLanguage, sourceCulture, sourceUrl, sourceType, culturalElements, difficulty, tags, context, targetCultures, imageUrl, imageAlt, translationBrief, weekNumber, category } = req.body; // Validate required fields if (!title || !content || !sourceLanguage || !sourceCulture) { return res.status(400).json({ error: 'Title, content, source language, and source culture are required' }); } const sourceText = new SourceText({ title, content, sourceLanguage, sourceCulture, sourceUrl, sourceType, culturalElements: culturalElements || [], difficulty: difficulty || 'intermediate', tags: tags || [], context, targetCultures: targetCultures || [], imageUrl, imageAlt, translationBrief, weekNumber, category, createdBy: req.user.userId }); await sourceText.save(); res.status(201).json({ message: 'Source text created successfully', sourceText }); } catch (error) { console.error('Create source text error:', error); res.status(500).json({ error: 'Failed to create source text' }); } }); // Update a source text router.put('/:id', authenticateToken, async (req, res) => { try { const sourceText = await SourceText.findById(req.params.id); if (!sourceText) { return res.status(404).json({ error: 'Source text not found' }); } // Only allow creators or admins to update if (sourceText.createdBy.toString() !== req.user.userId && req.user.role !== 'admin') { return res.status(403).json({ error: 'Not authorized to update this source text' }); } const updatedText = await SourceText.findByIdAndUpdate( req.params.id, req.body, { new: true, runValidators: true } ); res.json({ message: 'Source text updated successfully', sourceText: updatedText }); } catch (error) { console.error('Update source text error:', error); res.status(500).json({ error: 'Failed to update source text' }); } }); // Delete a source text (soft delete) router.delete('/:id', authenticateToken, async (req, res) => { try { const sourceText = await SourceText.findById(req.params.id); if (!sourceText) { return res.status(404).json({ error: 'Source text not found' }); } // Only allow creators or admins to delete if (sourceText.createdBy.toString() !== req.user.userId && req.user.role !== 'admin') { return res.status(403).json({ error: 'Not authorized to delete this source text' }); } sourceText.isActive = false; await sourceText.save(); res.json({ message: 'Source text deleted successfully' }); } catch (error) { console.error('Delete source text error:', error); res.status(500).json({ error: 'Failed to delete source text' }); } }); // Rate a source text router.post('/:id/rate', authenticateToken, async (req, res) => { try { const { rating } = req.body; if (!rating || rating < 1 || rating > 5) { return res.status(400).json({ error: 'Rating must be between 1 and 5' }); } const sourceText = await SourceText.findById(req.params.id); if (!sourceText) { return res.status(404).json({ error: 'Source text not found' }); } // Update average rating const newTotal = (sourceText.averageRating * sourceText.ratingCount) + rating; sourceText.ratingCount += 1; sourceText.averageRating = newTotal / sourceText.ratingCount; await sourceText.save(); res.json({ message: 'Rating submitted successfully', averageRating: sourceText.averageRating, ratingCount: sourceText.ratingCount }); } catch (error) { console.error('Rate source text error:', error); res.status(500).json({ error: 'Failed to submit rating' }); } }); // Get weekly practice data by week number (temporarily public for testing) router.get('/weekly-practice/week/:weekNumber', async (req, res) => { try { const weekNumber = parseInt(req.params.weekNumber); if (isNaN(weekNumber) || weekNumber < 1 || weekNumber > 6) { return res.status(400).json({ error: 'Invalid week number. Must be between 1 and 6.' }); } // Debug: Log what we're searching for console.log(`Searching for weekly practice week ${weekNumber}`); const practices = await SourceText.find({ category: 'weekly-practice', weekNumber: weekNumber, isActive: true }).sort({ createdAt: 1 }); console.log(`Found ${practices.length} practices for week ${weekNumber}`); if (practices.length === 0) { // Debug: Check what's actually in the database const allTexts = await SourceText.find({}); console.log(`Total texts in database: ${allTexts.length}`); console.log('Sample texts:', allTexts.slice(0, 3).map(t => ({ title: t.title, category: t.category, weekNumber: t.weekNumber }))); return res.status(404).json({ error: `No weekly practice found for week ${weekNumber}`, practices: [], weekNumber: weekNumber, debug: { totalTexts: allTexts.length, sampleTexts: allTexts.slice(0, 3).map(t => ({ title: t.title, category: t.category, weekNumber: t.weekNumber })) } }); } res.json({ weekNumber: weekNumber, practices: practices, total: practices.length }); } catch (error) { console.error('Get weekly practice error:', error); res.status(500).json({ error: 'Failed to get weekly practice data' }); } }); // Get cultural elements for a source text router.get('/:id/cultural-elements', authenticateToken, async (req, res) => { try { const sourceText = await SourceText.findById(req.params.id); if (!sourceText) { return res.status(404).json({ error: 'Source text not found' }); } res.json({ culturalElements: sourceText.culturalElements, content: sourceText.content }); } catch (error) { console.error('Get cultural elements error:', error); res.status(500).json({ error: 'Failed to get cultural elements' }); } }); // Highlight cultural elements in text router.post('/:id/highlight', authenticateToken, async (req, res) => { try { const { culturalElements } = req.body; const sourceText = await SourceText.findById(req.params.id); if (!sourceText) { return res.status(404).json({ error: 'Source text not found' }); } // Only allow creators or admins to update cultural elements if (sourceText.createdBy.toString() !== req.user.userId && req.user.role !== 'admin') { return res.status(403).json({ error: 'Not authorized to update this source text' }); } sourceText.culturalElements = culturalElements; await sourceText.save(); res.json({ message: 'Cultural elements updated successfully', culturalElements: sourceText.culturalElements }); } catch (error) { console.error('Highlight cultural elements error:', error); res.status(500).json({ error: 'Failed to update cultural elements' }); } }); module.exports = router;