dvc890 commited on
Commit
38b645f
·
verified ·
1 Parent(s): 41ae5ab

Update routes/features.js

Browse files
Files changed (1) hide show
  1. routes/features.js +52 -2
routes/features.js CHANGED
@@ -122,7 +122,57 @@ router.post('/games/monster-config', async (req, res) => { const data = injectSc
122
  router.get('/games/zen-config', async (req, res) => { const filter = getQueryFilter(req); const ownerFilter = await getGameOwnerFilter(req); if (req.query.className) filter.className = req.query.className; Object.assign(filter, ownerFilter); const config = await GameZenConfigModel.findOne(filter); res.json(config || {}); });
123
  router.post('/games/zen-config', async (req, res) => { const data = injectSchoolId(req, req.body); if (req.headers['x-user-role'] === 'TEACHER') { const user = await User.findOne({ username: req.headers['x-user-username'] }); data.ownerId = user ? user._id.toString() : null; } await GameZenConfigModel.findOneAndUpdate({ className: data.className, ...getQueryFilter(req), ownerId: data.ownerId }, data, { upsert: true }); res.json({ success: true }); });
124
  router.get('/games/mountain', async (req, res) => { res.json(await GameSessionModel.findOne({...getQueryFilter(req), className: req.query.className})); });
125
- router.post('/games/mountain', async (req, res) => { const { className } = req.body; const sId = req.headers['x-school-id']; const role = req.headers['x-user-role']; const username = req.headers['x-user-username']; if (role === 'TEACHER') { const user = await User.findOne({ username }); const cls = await ClassModel.findOne({ schoolId: sId, $expr: { $eq: [{ $concat: ["$grade", "$className"] }, className] } }); if (!cls) return res.status(404).json({ error: 'Class not found' }); const allowedIds = cls.homeroomTeacherIds || []; if (!allowedIds.includes(user._id.toString())) return res.status(403).json({ error: 'PERMISSION_DENIED', message: '只有班主任可以操作登峰游戏' }); } await GameSessionModel.findOneAndUpdate({ className, ...getQueryFilter(req) }, injectSchoolId(req, req.body), {upsert:true}); res.json({}); });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  router.get('/rewards', async (req, res) => { const filter = getQueryFilter(req); if (req.headers['x-user-role'] === 'TEACHER') { const user = await User.findOne({ username: req.headers['x-user-username'] }); if (user) filter.ownerId = user._id.toString(); } if(req.query.studentId) filter.studentId = req.query.studentId; if (req.query.className) { const classStudents = await Student.find({ className: req.query.className, ...getQueryFilter(req) }, '_id'); filter.studentId = { $in: classStudents.map(s => s._id.toString()) }; } if (req.query.excludeType) filter.rewardType = { $ne: req.query.excludeType }; const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 20; const skip = (page - 1) * limit; const total = await StudentRewardModel.countDocuments(filter); const list = await StudentRewardModel.find(filter).sort({createTime:-1}).skip(skip).limit(limit); res.json({ list, total }); });
127
  router.post('/rewards', async (req, res) => { const data = injectSchoolId(req, req.body); if (!data.count) data.count = 1; if (req.headers['x-user-role'] === 'TEACHER') { const user = await User.findOne({ username: req.headers['x-user-username'] }); data.ownerId = user ? user._id.toString() : null; } if(data.rewardType==='DRAW_COUNT') { data.status='REDEEMED'; await Student.findByIdAndUpdate(data.studentId, {$inc:{drawAttempts:data.count}}); } await StudentRewardModel.create(data); res.json({}); });
128
  router.put('/rewards/:id', async (req, res) => { await StudentRewardModel.findByIdAndUpdate(req.params.id, req.body); res.json({}); });
@@ -204,4 +254,4 @@ router.delete('/achievements/record/:id', async (req, res) => {
204
  });
205
  router.post('/achievements/exchange', async (req, res) => { const { studentId, ruleId, teacherId } = req.body; const sId = req.headers['x-school-id']; const student = await Student.findById(studentId); if (!student) return res.status(404).json({ error: 'Student not found' }); let rule = null; let ownerId = null; if (teacherId) { const tConfig = await TeacherExchangeConfigModel.findOne({ teacherId, schoolId: sId }); rule = tConfig?.rules.find(r => r.id === ruleId); ownerId = teacherId; } else { const config = await AchievementConfigModel.findOne({ className: student.className, schoolId: sId }); rule = config?.exchangeRules?.find(r => r.id === ruleId); } if (!rule) return res.status(404).json({ error: 'Rule not found' }); if (student.flowerBalance < rule.cost) { return res.status(400).json({ error: 'INSUFFICIENT_FUNDS', message: '小红花余额不足' }); } await Student.findByIdAndUpdate(studentId, { $inc: { flowerBalance: -rule.cost } }); await StudentRewardModel.create({ schoolId: sId, studentId, studentName: student.name, rewardType: rule.rewardType, name: rule.rewardName, count: rule.rewardValue, status: rule.rewardType === 'DRAW_COUNT' ? 'REDEEMED' : 'PENDING', source: '积分兑换', ownerId, createTime: new Date() }); if (rule.rewardType === 'DRAW_COUNT') { await Student.findByIdAndUpdate(studentId, { $inc: { drawAttempts: rule.rewardValue } }); } res.json({ success: true }); });
206
 
207
- module.exports = router;
 
122
  router.get('/games/zen-config', async (req, res) => { const filter = getQueryFilter(req); const ownerFilter = await getGameOwnerFilter(req); if (req.query.className) filter.className = req.query.className; Object.assign(filter, ownerFilter); const config = await GameZenConfigModel.findOne(filter); res.json(config || {}); });
123
  router.post('/games/zen-config', async (req, res) => { const data = injectSchoolId(req, req.body); if (req.headers['x-user-role'] === 'TEACHER') { const user = await User.findOne({ username: req.headers['x-user-username'] }); data.ownerId = user ? user._id.toString() : null; } await GameZenConfigModel.findOneAndUpdate({ className: data.className, ...getQueryFilter(req), ownerId: data.ownerId }, data, { upsert: true }); res.json({ success: true }); });
124
  router.get('/games/mountain', async (req, res) => { res.json(await GameSessionModel.findOne({...getQueryFilter(req), className: req.query.className})); });
125
+
126
+ // Updated mountain game handler with robust permission check
127
+ router.post('/games/mountain', async (req, res) => {
128
+ const { className } = req.body;
129
+ const sId = req.headers['x-school-id'];
130
+ const role = req.headers['x-user-role'];
131
+ const username = req.headers['x-user-username'];
132
+
133
+ if (role === 'TEACHER') {
134
+ const user = await User.findOne({ username });
135
+
136
+ let isAuthorized = false;
137
+
138
+ // 1. Check User Profile (Primary authority)
139
+ if (user && user.homeroomClass === className) {
140
+ isAuthorized = true;
141
+ }
142
+
143
+ // 2. Check Class Database (Fallback for legacy/ID-linked)
144
+ if (!isAuthorized) {
145
+ const cls = await ClassModel.findOne({
146
+ schoolId: sId,
147
+ $or: [
148
+ { $expr: { $eq: [{ $concat: ["$grade", "$className"] }, className] } },
149
+ { className: className }
150
+ ]
151
+ });
152
+
153
+ if (cls) {
154
+ const allowedIds = cls.homeroomTeacherIds || [];
155
+ if (allowedIds.includes(user._id.toString())) {
156
+ isAuthorized = true;
157
+ } else if (cls.teacherName && (cls.teacherName.includes(user.trueName) || cls.teacherName.includes(user.username))) {
158
+ // Legacy Name Match
159
+ isAuthorized = true;
160
+ }
161
+ } else {
162
+ // If class not found in DB but user has it in profile, we allow (user is creator/authority)
163
+ // But typically class should exist. We'll stick to logic above.
164
+ }
165
+ }
166
+
167
+ if (!isAuthorized) {
168
+ return res.status(403).json({ error: 'PERMISSION_DENIED', message: '只有班主任可以操作登峰游戏' });
169
+ }
170
+ }
171
+
172
+ await GameSessionModel.findOneAndUpdate({ className, ...getQueryFilter(req) }, injectSchoolId(req, req.body), {upsert:true});
173
+ res.json({});
174
+ });
175
+
176
  router.get('/rewards', async (req, res) => { const filter = getQueryFilter(req); if (req.headers['x-user-role'] === 'TEACHER') { const user = await User.findOne({ username: req.headers['x-user-username'] }); if (user) filter.ownerId = user._id.toString(); } if(req.query.studentId) filter.studentId = req.query.studentId; if (req.query.className) { const classStudents = await Student.find({ className: req.query.className, ...getQueryFilter(req) }, '_id'); filter.studentId = { $in: classStudents.map(s => s._id.toString()) }; } if (req.query.excludeType) filter.rewardType = { $ne: req.query.excludeType }; const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 20; const skip = (page - 1) * limit; const total = await StudentRewardModel.countDocuments(filter); const list = await StudentRewardModel.find(filter).sort({createTime:-1}).skip(skip).limit(limit); res.json({ list, total }); });
177
  router.post('/rewards', async (req, res) => { const data = injectSchoolId(req, req.body); if (!data.count) data.count = 1; if (req.headers['x-user-role'] === 'TEACHER') { const user = await User.findOne({ username: req.headers['x-user-username'] }); data.ownerId = user ? user._id.toString() : null; } if(data.rewardType==='DRAW_COUNT') { data.status='REDEEMED'; await Student.findByIdAndUpdate(data.studentId, {$inc:{drawAttempts:data.count}}); } await StudentRewardModel.create(data); res.json({}); });
178
  router.put('/rewards/:id', async (req, res) => { await StudentRewardModel.findByIdAndUpdate(req.params.id, req.body); res.json({}); });
 
254
  });
255
  router.post('/achievements/exchange', async (req, res) => { const { studentId, ruleId, teacherId } = req.body; const sId = req.headers['x-school-id']; const student = await Student.findById(studentId); if (!student) return res.status(404).json({ error: 'Student not found' }); let rule = null; let ownerId = null; if (teacherId) { const tConfig = await TeacherExchangeConfigModel.findOne({ teacherId, schoolId: sId }); rule = tConfig?.rules.find(r => r.id === ruleId); ownerId = teacherId; } else { const config = await AchievementConfigModel.findOne({ className: student.className, schoolId: sId }); rule = config?.exchangeRules?.find(r => r.id === ruleId); } if (!rule) return res.status(404).json({ error: 'Rule not found' }); if (student.flowerBalance < rule.cost) { return res.status(400).json({ error: 'INSUFFICIENT_FUNDS', message: '小红花余额不足' }); } await Student.findByIdAndUpdate(studentId, { $inc: { flowerBalance: -rule.cost } }); await StudentRewardModel.create({ schoolId: sId, studentId, studentName: student.name, rewardType: rule.rewardType, name: rule.rewardName, count: rule.rewardValue, status: rule.rewardType === 'DRAW_COUNT' ? 'REDEEMED' : 'PENDING', source: '积分兑换', ownerId, createTime: new Date() }); if (rule.rewardType === 'DRAW_COUNT') { await Student.findByIdAndUpdate(studentId, { $inc: { drawAttempts: rule.rewardValue } }); } res.json({ success: true }); });
256
 
257
+ module.exports = router;