Spaces:
Sleeping
Sleeping
| 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; |