dvc890 commited on
Commit
3c8b5da
·
verified ·
1 Parent(s): 65c1cc4

Upload 54 files

Browse files
Files changed (2) hide show
  1. server.js +7 -7
  2. services/api.ts +15 -6
server.js CHANGED
@@ -3,7 +3,7 @@ const {
3
  School, User, Student, Course, Score, ClassModel, SubjectModel, ExamModel, ScheduleModel,
4
  ConfigModel, NotificationModel, GameSessionModel, StudentRewardModel, LuckyDrawConfigModel, GameMonsterConfigModel, GameZenConfigModel,
5
  AchievementConfigModel, TeacherExchangeConfigModel, StudentAchievementModel, AttendanceModel, LeaveRequestModel, SchoolCalendarModel,
6
- WishModel, FeedbackModel, TodoModel
7
  } = require('./models');
8
 
9
  // Import AI Routes
@@ -113,8 +113,6 @@ const generateStudentNo = async () => {
113
  // MOUNT AI ROUTES
114
  app.use('/api/ai', aiRoutes);
115
 
116
- // ... (Rest of Existing Routes) ...
117
-
118
  // --- TODO LIST ENDPOINTS ---
119
  app.get('/api/todos', async (req, res) => {
120
  const username = req.headers['x-user-username'];
@@ -201,7 +199,6 @@ app.put('/api/users/:id/menu-order', async (req, res) => {
201
  res.json({ success: true });
202
  });
203
 
204
- // ... (Rest of existing routes unchanged) ...
205
  app.get('/api/classes/:className/teachers', async (req, res) => {
206
  const { className } = req.params;
207
  const schoolId = req.headers['x-school-id'];
@@ -384,10 +381,13 @@ app.get('/api/auth/me', async (req, res) => {
384
  const token = authHeader.split(' ')[1]; // Bearer <token>
385
  if (token && token.startsWith('mock-token-')) {
386
  const userId = token.replace('mock-token-', '');
387
- // Validate ID format (Mongodb ObjectId is 24 hex chars)
388
- if (/^[0-9a-fA-F]{24}$/.test(userId)) {
389
  const user = await User.findById(userId);
390
  if (user) return res.json(user);
 
 
 
391
  }
392
  }
393
  }
@@ -531,7 +531,7 @@ app.post('/api/auth/login', async (req, res) => {
531
  const user = await User.findOne({ username, password });
532
  if (!user) return res.status(401).json({ message: 'Error' });
533
  if (user.status !== 'active') return res.status(403).json({ error: 'PENDING_APPROVAL' });
534
- res.json({ token: 'mock-token-' + user._id, user });
535
  });
536
 
537
  app.get('/api/schools', async (req, res) => { res.json(await School.find()); });
 
3
  School, User, Student, Course, Score, ClassModel, SubjectModel, ExamModel, ScheduleModel,
4
  ConfigModel, NotificationModel, GameSessionModel, StudentRewardModel, LuckyDrawConfigModel, GameMonsterConfigModel, GameZenConfigModel,
5
  AchievementConfigModel, TeacherExchangeConfigModel, StudentAchievementModel, AttendanceModel, LeaveRequestModel, SchoolCalendarModel,
6
+ WishModel, FeedbackModel, TodoModel, AIUsageModel
7
  } = require('./models');
8
 
9
  // Import AI Routes
 
113
  // MOUNT AI ROUTES
114
  app.use('/api/ai', aiRoutes);
115
 
 
 
116
  // --- TODO LIST ENDPOINTS ---
117
  app.get('/api/todos', async (req, res) => {
118
  const username = req.headers['x-user-username'];
 
199
  res.json({ success: true });
200
  });
201
 
 
202
  app.get('/api/classes/:className/teachers', async (req, res) => {
203
  const { className } = req.params;
204
  const schoolId = req.headers['x-school-id'];
 
381
  const token = authHeader.split(' ')[1]; // Bearer <token>
382
  if (token && token.startsWith('mock-token-')) {
383
  const userId = token.replace('mock-token-', '');
384
+ try {
385
+ // Simplified lookup without strict regex to support migrated/mock data
386
  const user = await User.findById(userId);
387
  if (user) return res.json(user);
388
+ } catch (e) {
389
+ // Ignore cast errors or invalid ID formats
390
+ console.log('Session lookup error:', e.message);
391
  }
392
  }
393
  }
 
531
  const user = await User.findOne({ username, password });
532
  if (!user) return res.status(401).json({ message: 'Error' });
533
  if (user.status !== 'active') return res.status(403).json({ error: 'PENDING_APPROVAL' });
534
+ res.json({ token: 'mock-token-' + user._id.toString(), user });
535
  });
536
 
537
  app.get('/api/schools', async (req, res) => { res.json(await School.find()); });
services/api.ts CHANGED
@@ -3,7 +3,7 @@ import { User } from '../types';
3
 
4
  const API_BASE = '/api';
5
 
6
- const request = async (endpoint: string, options?: RequestInit) => {
7
  const token = localStorage.getItem('token');
8
  const headers = {
9
  'Content-Type': 'application/json',
@@ -24,9 +24,11 @@ const request = async (endpoint: string, options?: RequestInit) => {
24
  });
25
 
26
  if (response.status === 401) {
27
- localStorage.removeItem('token');
28
- localStorage.removeItem('user');
29
- window.location.href = '/';
 
 
30
  throw new Error('Unauthorized');
31
  }
32
 
@@ -77,10 +79,17 @@ export const api = {
77
  },
78
  refreshSession: async () => {
79
  try {
80
- const user = await request('/auth/me');
 
 
81
  localStorage.setItem('user', JSON.stringify(user));
82
  return user;
83
- } catch (e) { return null; }
 
 
 
 
 
84
  },
85
  updateProfile: (data: any) => request('/auth/profile', { method: 'PUT', body: JSON.stringify(data) }),
86
  },
 
3
 
4
  const API_BASE = '/api';
5
 
6
+ const request = async (endpoint: string, options?: RequestInit & { skipRedirect?: boolean }) => {
7
  const token = localStorage.getItem('token');
8
  const headers = {
9
  'Content-Type': 'application/json',
 
24
  });
25
 
26
  if (response.status === 401) {
27
+ if (!options?.skipRedirect) {
28
+ localStorage.removeItem('token');
29
+ localStorage.removeItem('user');
30
+ window.location.href = '/';
31
+ }
32
  throw new Error('Unauthorized');
33
  }
34
 
 
79
  },
80
  refreshSession: async () => {
81
  try {
82
+ // Pass skipRedirect: true to prevent infinite reload loop if server returns 401
83
+ // @ts-ignore
84
+ const user = await request('/auth/me', { skipRedirect: true });
85
  localStorage.setItem('user', JSON.stringify(user));
86
  return user;
87
+ } catch (e) {
88
+ // If refresh fails (e.g. 401), clear local user to force re-login on next check, but don't hard reload
89
+ localStorage.removeItem('user');
90
+ localStorage.removeItem('token');
91
+ return null;
92
+ }
93
  },
94
  updateProfile: (data: any) => request('/auth/profile', { method: 'PUT', body: JSON.stringify(data) }),
95
  },