-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
176 lines (148 loc) · 6 KB
/
server.js
File metadata and controls
176 lines (148 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import express from 'express';
import dotenv from 'dotenv';
import { MongoClient } from 'mongodb';
import cookieParser from 'cookie-parser';
import path from 'path';
import { fileURLToPath } from 'url';
// Load environment variables
dotenv.config();
const { MONGO_URI, API_BASE_URL } = process.env;
const PORT = process.env.PORT || 3000;
const AUTH_COOKIE_NAME = 'auth_token';
const API_PREFIX = API_BASE_URL || '/api';
// ES Module equivalent of __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
let db;
// --- Database Connection ---
async function connectToDb() {
try {
const client = new MongoClient(MONGO_URI,{
serverSelectionTimeoutMS: 5000,
heartbeatFrequencyMS: 1000,
connectTimeoutMS: 30000,
socketTimeoutMS: 360000,
retryWrites: true,
retryReads: true,
});
await client.connect();
db = client.db('chat_ldata'); // Use the specific db from the URI
console.log('Connected to MongoDB');
} catch (error) {
console.error('Failed to connect to MongoDB', error);
process.exit(1);
}
}
// --- Authentication Middleware ---
const authMiddleware = (req, res, next) => {
const authToken = req.cookies[AUTH_COOKIE_NAME];
if (authToken && authToken.startsWith('user_')) {
// 从cookie中提取用户名
req.currentUser = authToken.replace('user_', '');
next();
} else {
res.status(401).json({ message: 'Unauthorized' });
}
};
// --- API Routes ---
app.post('/login', async (req, res) => {
const { username, password } = req.body;
// 检查密码格式:用户名 + "123321"
const expectedPassword = username + '123321';
if (password === expectedPassword) {
// 验证用户是否存在于数据库中
try {
const user = await db.collection('users').findOne({ username: username });
if (user) {
// 设置包含用户名的cookie
res.cookie(AUTH_COOKIE_NAME, `user_${username}`, { httpOnly: true, maxAge: 3600 * 1000 }); // 1 hour cookie
res.status(200).json({ message: 'Login successful' });
} else {
res.status(401).json({ message: '用户不存在' });
}
} catch (error) {
console.error('Login error:', error);
res.status(500).json({ message: '登录过程中发生错误' });
}
} else {
res.status(401).json({ message: '用户名或密码错误' });
}
});
app.post('/logout', (req, res) => {
res.clearCookie(AUTH_COOKIE_NAME);
res.status(200).json({ message: 'Logged out' });
});
// GET all users (except admin) and their linkMappings
app.get(`${API_PREFIX}/users`, authMiddleware, async (req, res) => {
try {
const currentUser = req.currentUser;
// 构建查询条件:只返回当前登录用户的数据
const query = { username: currentUser };
const users = await db.collection('users').find(query).project({
username: 1,
'preferences.linkMappings': 1
}).toArray();
res.json(users);
} catch (error) {
console.error('Error fetching users:', error);
res.status(500).json({ message: 'Error fetching data from database.' });
}
});
// Update a user's linkMappings
app.post(`${API_PREFIX}/users/:username`, authMiddleware, async (req, res) => {
const { username } = req.params;
const { linkMappings: updatedMappingsFromClient } = req.body;
if (!Array.isArray(updatedMappingsFromClient)) {
return res.status(400).json({ message: 'linkMappings must be an array.' });
}
try {
// Step 1: Read the user's full, original document from the database.
const user = await db.collection('users').findOne({ username: username });
if (!user) {
return res.status(404).json({ message: 'User not found.' });
}
// Get the original mappings, ensuring it's an array.
const originalMappings = user.preferences?.linkMappings || [];
// Step 2: Modify the original data with the updates from the client.
const newMappings = originalMappings.map((originalMapping, index) => {
// If the client sent a corresponding mapping, update its 'links' property.
if (updatedMappingsFromClient[index]) {
return {
...originalMapping,
links: updatedMappingsFromClient[index].links
};
}
// Otherwise, return the original mapping untouched.
return originalMapping;
});
// Step 3: Write the safely merged, complete data back to the database.
const result = await db.collection('users').updateOne(
{ username: username },
{ $set: { 'preferences.linkMappings': newMappings } }
);
res.status(200).json({ message: 'User updated successfully.' });
} catch (error) {
console.error(`Error updating user ${username}:`, error);
res.status(500).json({ message: 'Error updating data in database.' });
}
});
// --- Serve Frontend ---
// For any other GET request, send the dashboard (if logged in) or login page
app.get('*', (req, res) => {
const authToken = req.cookies[AUTH_COOKIE_NAME];
if (authToken && authToken.startsWith('user_')) {
res.sendFile(path.join(__dirname, 'public', 'dashboard.html'));
} else {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
}
});
// --- Start Server ---
connectToDb().then(() => {
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
});