Reality123b commited on
Commit
1b0fc70
·
verified ·
1 Parent(s): 3b29350

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +15 -101
server.js CHANGED
@@ -1,3 +1,11 @@
 
 
 
 
 
 
 
 
1
  const express = require('express');
2
  const sqlite3 = require('sqlite3').verbose();
3
  const bcrypt = require('bcryptjs');
@@ -6,30 +14,21 @@ const multer = require('multer');
6
  const cors = require('cors');
7
  const helmet = require('helmet');
8
  const rateLimit = require('express-rate-limit');
9
- const fs = require('fs');
10
- const path = require('path');
11
  const archiver = require('archiver');
12
  const { parse } = require('csv-parse');
13
-
14
  const app = express();
15
  const PORT = process.env.PORT || 3000;
16
  const JWT_SECRET = process.env.JWT_SECRET || 'your-super-secret-jwt-key-change-this-in-production';
17
  const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'DataMaster2024!';
18
-
19
- // Middleware
20
  app.use(helmet());
21
  app.use(cors());
22
  app.use(express.json({ limit: '50mb' }));
23
  app.use(express.urlencoded({ extended: true, limit: '50mb' }));
24
-
25
- // Rate limiting
26
  const limiter = rateLimit({
27
- windowMs: 15 * 60 * 1000, // 15 minutes
28
- max: 100 // limit each IP to 100 requests per windowMs
29
  });
30
  app.use(limiter);
31
-
32
- // File upload configuration
33
  const storage = multer.diskStorage({
34
  destination: (req, file, cb) => {
35
  const uploadPath = path.join(__dirname, 'datasets');
@@ -42,17 +41,12 @@ const storage = multer.diskStorage({
42
  cb(null, `${Date.now()}-${file.originalname}`);
43
  }
44
  });
45
-
46
- const upload = multer({
47
  storage: storage,
48
- limits: { fileSize: 100 * 1024 * 1024 } // 100MB limit
49
  });
50
-
51
- // Initialize databases
52
  const userDb = new sqlite3.Database('./data/users.db');
53
  const datasetDb = new sqlite3.Database('./data/datasets.db');
54
-
55
- // Create tables
56
  userDb.serialize(() => {
57
  userDb.run(`CREATE TABLE IF NOT EXISTS users (
58
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -62,7 +56,6 @@ userDb.serialize(() => {
62
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
63
  )`);
64
  });
65
-
66
  datasetDb.serialize(() => {
67
  datasetDb.run(`CREATE TABLE IF NOT EXISTS datasets (
68
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -76,16 +69,12 @@ datasetDb.serialize(() => {
76
  download_count INTEGER DEFAULT 0
77
  )`);
78
  });
79
-
80
- // Authentication middleware
81
  const authenticateToken = (req, res, next) => {
82
  const authHeader = req.headers['authorization'];
83
  const token = authHeader && authHeader.split(' ')[1];
84
-
85
  if (!token) {
86
  return res.status(401).json({ error: 'Access token required' });
87
  }
88
-
89
  jwt.verify(token, JWT_SECRET, (err, user) => {
90
  if (err) {
91
  return res.status(403).json({ error: 'Invalid token' });
@@ -94,25 +83,16 @@ const authenticateToken = (req, res, next) => {
94
  next();
95
  });
96
  };
97
-
98
- // Routes
99
-
100
- // Health check
101
  app.get('/health', (req, res) => {
102
  res.json({ status: 'OK', timestamp: new Date().toISOString() });
103
  });
104
-
105
- // User registration
106
  app.post('/api/register', async (req, res) => {
107
  try {
108
  const { username, password } = req.body;
109
-
110
  if (!username || !password) {
111
  return res.status(400).json({ error: 'Username and password required' });
112
  }
113
-
114
  const hashedPassword = await bcrypt.hash(password, 10);
115
-
116
  userDb.run(
117
  'INSERT INTO users (username, password) VALUES (?, ?)',
118
  [username, hashedPassword],
@@ -123,9 +103,8 @@ app.post('/api/register', async (req, res) => {
123
  }
124
  return res.status(500).json({ error: 'Database error' });
125
  }
126
-
127
  const token = jwt.sign({ id: this.lastID, username }, JWT_SECRET, { expiresIn: '24h' });
128
- res.status(201).json({
129
  message: 'User created successfully',
130
  token,
131
  user: { id: this.lastID, username }
@@ -136,15 +115,11 @@ app.post('/api/register', async (req, res) => {
136
  res.status(500).json({ error: 'Server error' });
137
  }
138
  });
139
-
140
- // User login
141
  app.post('/api/login', (req, res) => {
142
  const { username, password } = req.body;
143
-
144
  if (!username || !password) {
145
  return res.status(400).json({ error: 'Username and password required' });
146
  }
147
-
148
  userDb.get(
149
  'SELECT * FROM users WHERE username = ?',
150
  [username],
@@ -152,22 +127,18 @@ app.post('/api/login', (req, res) => {
152
  if (err) {
153
  return res.status(500).json({ error: 'Database error' });
154
  }
155
-
156
  if (!user) {
157
  return res.status(401).json({ error: 'Invalid credentials' });
158
  }
159
-
160
  const validPassword = await bcrypt.compare(password, user.password);
161
  if (!validPassword) {
162
  return res.status(401).json({ error: 'Invalid credentials' });
163
  }
164
-
165
  const token = jwt.sign(
166
  { id: user.id, username: user.username, role: user.role },
167
  JWT_SECRET,
168
  { expiresIn: '24h' }
169
  );
170
-
171
  res.json({
172
  message: 'Login successful',
173
  token,
@@ -176,8 +147,6 @@ app.post('/api/login', (req, res) => {
176
  }
177
  );
178
  });
179
-
180
- // Get all datasets
181
  app.get('/api/datasets', authenticateToken, (req, res) => {
182
  datasetDb.all(
183
  'SELECT id, name, description, file_type, size, created_by, created_at, download_count FROM datasets ORDER BY created_at DESC',
@@ -189,18 +158,14 @@ app.get('/api/datasets', authenticateToken, (req, res) => {
189
  }
190
  );
191
  });
192
-
193
- // Upload dataset
194
  app.post('/api/datasets/upload', authenticateToken, upload.single('file'), (req, res) => {
195
  if (!req.file) {
196
  return res.status(400).json({ error: 'No file uploaded' });
197
  }
198
-
199
  const { name, description } = req.body;
200
  if (!name) {
201
  return res.status(400).json({ error: 'Dataset name required' });
202
  }
203
-
204
  datasetDb.run(
205
  'INSERT INTO datasets (name, description, file_path, file_type, size, created_by) VALUES (?, ?, ?, ?, ?, ?)',
206
  [name, description || '', req.file.path, req.file.mimetype, req.file.size, req.user.username],
@@ -211,7 +176,6 @@ app.post('/api/datasets/upload', authenticateToken, upload.single('file'), (req,
211
  }
212
  return res.status(500).json({ error: 'Database error' });
213
  }
214
-
215
  res.status(201).json({
216
  id: this.lastID,
217
  name,
@@ -223,11 +187,8 @@ app.post('/api/datasets/upload', authenticateToken, upload.single('file'), (req,
223
  }
224
  );
225
  });
226
-
227
- // Download dataset
228
  app.get('/api/datasets/:id/download', authenticateToken, (req, res) => {
229
  const datasetId = req.params.id;
230
-
231
  datasetDb.get(
232
  'SELECT * FROM datasets WHERE id = ?',
233
  [datasetId],
@@ -235,56 +196,43 @@ app.get('/api/datasets/:id/download', authenticateToken, (req, res) => {
235
  if (err) {
236
  return res.status(500).json({ error: 'Database error' });
237
  }
238
-
239
  if (!dataset) {
240
  return res.status(404).json({ error: 'Dataset not found' });
241
  }
242
-
243
  if (!fs.existsSync(dataset.file_path)) {
244
  return res.status(404).json({ error: 'File not found on server' });
245
  }
246
-
247
- // Update download count
248
  datasetDb.run(
249
  'UPDATE datasets SET download_count = download_count + 1 WHERE id = ?',
250
  [datasetId]
251
  );
252
-
253
  res.download(dataset.file_path, dataset.name);
254
  }
255
  );
256
  });
257
-
258
- // Create custom dataset from JSON
259
  app.post('/api/datasets/create', authenticateToken, (req, res) => {
260
  const { name, description, data } = req.body;
261
-
262
  if (!name || !data) {
263
  return res.status(400).json({ error: 'Name and data required' });
264
  }
265
-
266
  const fileName = `${Date.now()}-${name.replace(/[^a-zA-Z0-9]/g, '_')}.json`;
267
  const filePath = path.join(__dirname, 'datasets', fileName);
268
-
269
  fs.writeFile(filePath, JSON.stringify(data, null, 2), (err) => {
270
  if (err) {
271
  return res.status(500).json({ error: 'Failed to create file' });
272
  }
273
-
274
  const fileSize = fs.statSync(filePath).size;
275
-
276
  datasetDb.run(
277
  'INSERT INTO datasets (name, description, file_path, file_type, size, created_by) VALUES (?, ?, ?, ?, ?, ?)',
278
  [name, description || '', filePath, 'application/json', fileSize, req.user.username],
279
  function(err) {
280
  if (err) {
281
- fs.unlinkSync(filePath); // Clean up file if database insert fails
282
  if (err.message.includes('UNIQUE constraint failed')) {
283
  return res.status(409).json({ error: 'Dataset name already exists' });
284
  }
285
  return res.status(500).json({ error: 'Database error' });
286
  }
287
-
288
  res.status(201).json({
289
  id: this.lastID,
290
  name,
@@ -297,11 +245,8 @@ app.post('/api/datasets/create', authenticateToken, (req, res) => {
297
  );
298
  });
299
  });
300
-
301
- // Delete dataset
302
  app.delete('/api/datasets/:id', authenticateToken, (req, res) => {
303
  const datasetId = req.params.id;
304
-
305
  datasetDb.get(
306
  'SELECT * FROM datasets WHERE id = ?',
307
  [datasetId],
@@ -309,22 +254,15 @@ app.delete('/api/datasets/:id', authenticateToken, (req, res) => {
309
  if (err) {
310
  return res.status(500).json({ error: 'Database error' });
311
  }
312
-
313
  if (!dataset) {
314
  return res.status(404).json({ error: 'Dataset not found' });
315
  }
316
-
317
- // Check if user owns the dataset or is admin
318
  if (dataset.created_by !== req.user.username && req.user.role !== 'admin') {
319
  return res.status(403).json({ error: 'Not authorized to delete this dataset' });
320
  }
321
-
322
- // Delete file
323
  if (fs.existsSync(dataset.file_path)) {
324
  fs.unlinkSync(dataset.file_path);
325
  }
326
-
327
- // Delete from database
328
  datasetDb.run(
329
  'DELETE FROM datasets WHERE id = ?',
330
  [datasetId],
@@ -338,11 +276,8 @@ app.delete('/api/datasets/:id', authenticateToken, (req, res) => {
338
  }
339
  );
340
  });
341
-
342
- // Get dataset info
343
  app.get('/api/datasets/:id', authenticateToken, (req, res) => {
344
  const datasetId = req.params.id;
345
-
346
  datasetDb.get(
347
  'SELECT * FROM datasets WHERE id = ?',
348
  [datasetId],
@@ -350,26 +285,19 @@ app.get('/api/datasets/:id', authenticateToken, (req, res) => {
350
  if (err) {
351
  return res.status(500).json({ error: 'Database error' });
352
  }
353
-
354
  if (!dataset) {
355
  return res.status(404).json({ error: 'Dataset not found' });
356
  }
357
-
358
  res.json(dataset);
359
  }
360
  );
361
  });
362
-
363
- // Bulk download (zip multiple datasets)
364
  app.post('/api/datasets/bulk-download', authenticateToken, (req, res) => {
365
  const { datasetIds } = req.body;
366
-
367
  if (!datasetIds || !Array.isArray(datasetIds)) {
368
  return res.status(400).json({ error: 'Dataset IDs array required' });
369
  }
370
-
371
  const placeholders = datasetIds.map(() => '?').join(',');
372
-
373
  datasetDb.all(
374
  `SELECT * FROM datasets WHERE id IN (${placeholders})`,
375
  datasetIds,
@@ -377,36 +305,22 @@ app.post('/api/datasets/bulk-download', authenticateToken, (req, res) => {
377
  if (err) {
378
  return res.status(500).json({ error: 'Database error' });
379
  }
380
-
381
  if (datasets.length === 0) {
382
  return res.status(404).json({ error: 'No datasets found' });
383
  }
384
-
385
  const archive = archiver('zip', { zlib: { level: 9 } });
386
-
387
  res.attachment('datasets.zip');
388
  archive.pipe(res);
389
-
390
  datasets.forEach(dataset => {
391
  if (fs.existsSync(dataset.file_path)) {
392
  archive.file(dataset.file_path, { name: dataset.name });
393
  }
394
  });
395
-
396
  archive.finalize();
397
  }
398
  );
399
  });
400
-
401
- // Error handling middleware
402
  app.use((err, req, res, next) => {
403
- console.error(err.stack);
404
  res.status(500).json({ error: 'Something went wrong!' });
405
  });
406
-
407
- // Start server
408
- app.listen(PORT, () => {
409
- console.log(`Server running on port ${PORT}`);
410
- console.log(`Admin password: ${ADMIN_PASSWORD}`);
411
- console.log(`JWT Secret: ${JWT_SECRET}`);
412
- });
 
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ ['data', 'datasets'].forEach(dir => {
4
+ const fullPath = path.join(__dirname, dir);
5
+ if (!fs.existsSync(fullPath)) {
6
+ fs.mkdirSync(fullPath, { recursive: true });
7
+ }
8
+ });
9
  const express = require('express');
10
  const sqlite3 = require('sqlite3').verbose();
11
  const bcrypt = require('bcryptjs');
 
14
  const cors = require('cors');
15
  const helmet = require('helmet');
16
  const rateLimit = require('express-rate-limit');
 
 
17
  const archiver = require('archiver');
18
  const { parse } = require('csv-parse');
 
19
  const app = express();
20
  const PORT = process.env.PORT || 3000;
21
  const JWT_SECRET = process.env.JWT_SECRET || 'your-super-secret-jwt-key-change-this-in-production';
22
  const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'DataMaster2024!';
 
 
23
  app.use(helmet());
24
  app.use(cors());
25
  app.use(express.json({ limit: '50mb' }));
26
  app.use(express.urlencoded({ extended: true, limit: '50mb' }));
 
 
27
  const limiter = rateLimit({
28
+ windowMs: 15 * 60 * 1000,
29
+ max: 100
30
  });
31
  app.use(limiter);
 
 
32
  const storage = multer.diskStorage({
33
  destination: (req, file, cb) => {
34
  const uploadPath = path.join(__dirname, 'datasets');
 
41
  cb(null, `${Date.now()}-${file.originalname}`);
42
  }
43
  });
44
+ const upload = multer({
 
45
  storage: storage,
46
+ limits: { fileSize: 100 * 1024 * 1024 }
47
  });
 
 
48
  const userDb = new sqlite3.Database('./data/users.db');
49
  const datasetDb = new sqlite3.Database('./data/datasets.db');
 
 
50
  userDb.serialize(() => {
51
  userDb.run(`CREATE TABLE IF NOT EXISTS users (
52
  id INTEGER PRIMARY KEY AUTOINCREMENT,
 
56
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
57
  )`);
58
  });
 
59
  datasetDb.serialize(() => {
60
  datasetDb.run(`CREATE TABLE IF NOT EXISTS datasets (
61
  id INTEGER PRIMARY KEY AUTOINCREMENT,
 
69
  download_count INTEGER DEFAULT 0
70
  )`);
71
  });
 
 
72
  const authenticateToken = (req, res, next) => {
73
  const authHeader = req.headers['authorization'];
74
  const token = authHeader && authHeader.split(' ')[1];
 
75
  if (!token) {
76
  return res.status(401).json({ error: 'Access token required' });
77
  }
 
78
  jwt.verify(token, JWT_SECRET, (err, user) => {
79
  if (err) {
80
  return res.status(403).json({ error: 'Invalid token' });
 
83
  next();
84
  });
85
  };
 
 
 
 
86
  app.get('/health', (req, res) => {
87
  res.json({ status: 'OK', timestamp: new Date().toISOString() });
88
  });
 
 
89
  app.post('/api/register', async (req, res) => {
90
  try {
91
  const { username, password } = req.body;
 
92
  if (!username || !password) {
93
  return res.status(400).json({ error: 'Username and password required' });
94
  }
 
95
  const hashedPassword = await bcrypt.hash(password, 10);
 
96
  userDb.run(
97
  'INSERT INTO users (username, password) VALUES (?, ?)',
98
  [username, hashedPassword],
 
103
  }
104
  return res.status(500).json({ error: 'Database error' });
105
  }
 
106
  const token = jwt.sign({ id: this.lastID, username }, JWT_SECRET, { expiresIn: '24h' });
107
+ res.status(201).json({
108
  message: 'User created successfully',
109
  token,
110
  user: { id: this.lastID, username }
 
115
  res.status(500).json({ error: 'Server error' });
116
  }
117
  });
 
 
118
  app.post('/api/login', (req, res) => {
119
  const { username, password } = req.body;
 
120
  if (!username || !password) {
121
  return res.status(400).json({ error: 'Username and password required' });
122
  }
 
123
  userDb.get(
124
  'SELECT * FROM users WHERE username = ?',
125
  [username],
 
127
  if (err) {
128
  return res.status(500).json({ error: 'Database error' });
129
  }
 
130
  if (!user) {
131
  return res.status(401).json({ error: 'Invalid credentials' });
132
  }
 
133
  const validPassword = await bcrypt.compare(password, user.password);
134
  if (!validPassword) {
135
  return res.status(401).json({ error: 'Invalid credentials' });
136
  }
 
137
  const token = jwt.sign(
138
  { id: user.id, username: user.username, role: user.role },
139
  JWT_SECRET,
140
  { expiresIn: '24h' }
141
  );
 
142
  res.json({
143
  message: 'Login successful',
144
  token,
 
147
  }
148
  );
149
  });
 
 
150
  app.get('/api/datasets', authenticateToken, (req, res) => {
151
  datasetDb.all(
152
  'SELECT id, name, description, file_type, size, created_by, created_at, download_count FROM datasets ORDER BY created_at DESC',
 
158
  }
159
  );
160
  });
 
 
161
  app.post('/api/datasets/upload', authenticateToken, upload.single('file'), (req, res) => {
162
  if (!req.file) {
163
  return res.status(400).json({ error: 'No file uploaded' });
164
  }
 
165
  const { name, description } = req.body;
166
  if (!name) {
167
  return res.status(400).json({ error: 'Dataset name required' });
168
  }
 
169
  datasetDb.run(
170
  'INSERT INTO datasets (name, description, file_path, file_type, size, created_by) VALUES (?, ?, ?, ?, ?, ?)',
171
  [name, description || '', req.file.path, req.file.mimetype, req.file.size, req.user.username],
 
176
  }
177
  return res.status(500).json({ error: 'Database error' });
178
  }
 
179
  res.status(201).json({
180
  id: this.lastID,
181
  name,
 
187
  }
188
  );
189
  });
 
 
190
  app.get('/api/datasets/:id/download', authenticateToken, (req, res) => {
191
  const datasetId = req.params.id;
 
192
  datasetDb.get(
193
  'SELECT * FROM datasets WHERE id = ?',
194
  [datasetId],
 
196
  if (err) {
197
  return res.status(500).json({ error: 'Database error' });
198
  }
 
199
  if (!dataset) {
200
  return res.status(404).json({ error: 'Dataset not found' });
201
  }
 
202
  if (!fs.existsSync(dataset.file_path)) {
203
  return res.status(404).json({ error: 'File not found on server' });
204
  }
 
 
205
  datasetDb.run(
206
  'UPDATE datasets SET download_count = download_count + 1 WHERE id = ?',
207
  [datasetId]
208
  );
 
209
  res.download(dataset.file_path, dataset.name);
210
  }
211
  );
212
  });
 
 
213
  app.post('/api/datasets/create', authenticateToken, (req, res) => {
214
  const { name, description, data } = req.body;
 
215
  if (!name || !data) {
216
  return res.status(400).json({ error: 'Name and data required' });
217
  }
 
218
  const fileName = `${Date.now()}-${name.replace(/[^a-zA-Z0-9]/g, '_')}.json`;
219
  const filePath = path.join(__dirname, 'datasets', fileName);
 
220
  fs.writeFile(filePath, JSON.stringify(data, null, 2), (err) => {
221
  if (err) {
222
  return res.status(500).json({ error: 'Failed to create file' });
223
  }
 
224
  const fileSize = fs.statSync(filePath).size;
 
225
  datasetDb.run(
226
  'INSERT INTO datasets (name, description, file_path, file_type, size, created_by) VALUES (?, ?, ?, ?, ?, ?)',
227
  [name, description || '', filePath, 'application/json', fileSize, req.user.username],
228
  function(err) {
229
  if (err) {
230
+ fs.unlinkSync(filePath);
231
  if (err.message.includes('UNIQUE constraint failed')) {
232
  return res.status(409).json({ error: 'Dataset name already exists' });
233
  }
234
  return res.status(500).json({ error: 'Database error' });
235
  }
 
236
  res.status(201).json({
237
  id: this.lastID,
238
  name,
 
245
  );
246
  });
247
  });
 
 
248
  app.delete('/api/datasets/:id', authenticateToken, (req, res) => {
249
  const datasetId = req.params.id;
 
250
  datasetDb.get(
251
  'SELECT * FROM datasets WHERE id = ?',
252
  [datasetId],
 
254
  if (err) {
255
  return res.status(500).json({ error: 'Database error' });
256
  }
 
257
  if (!dataset) {
258
  return res.status(404).json({ error: 'Dataset not found' });
259
  }
 
 
260
  if (dataset.created_by !== req.user.username && req.user.role !== 'admin') {
261
  return res.status(403).json({ error: 'Not authorized to delete this dataset' });
262
  }
 
 
263
  if (fs.existsSync(dataset.file_path)) {
264
  fs.unlinkSync(dataset.file_path);
265
  }
 
 
266
  datasetDb.run(
267
  'DELETE FROM datasets WHERE id = ?',
268
  [datasetId],
 
276
  }
277
  );
278
  });
 
 
279
  app.get('/api/datasets/:id', authenticateToken, (req, res) => {
280
  const datasetId = req.params.id;
 
281
  datasetDb.get(
282
  'SELECT * FROM datasets WHERE id = ?',
283
  [datasetId],
 
285
  if (err) {
286
  return res.status(500).json({ error: 'Database error' });
287
  }
 
288
  if (!dataset) {
289
  return res.status(404).json({ error: 'Dataset not found' });
290
  }
 
291
  res.json(dataset);
292
  }
293
  );
294
  });
 
 
295
  app.post('/api/datasets/bulk-download', authenticateToken, (req, res) => {
296
  const { datasetIds } = req.body;
 
297
  if (!datasetIds || !Array.isArray(datasetIds)) {
298
  return res.status(400).json({ error: 'Dataset IDs array required' });
299
  }
 
300
  const placeholders = datasetIds.map(() => '?').join(',');
 
301
  datasetDb.all(
302
  `SELECT * FROM datasets WHERE id IN (${placeholders})`,
303
  datasetIds,
 
305
  if (err) {
306
  return res.status(500).json({ error: 'Database error' });
307
  }
 
308
  if (datasets.length === 0) {
309
  return res.status(404).json({ error: 'No datasets found' });
310
  }
 
311
  const archive = archiver('zip', { zlib: { level: 9 } });
 
312
  res.attachment('datasets.zip');
313
  archive.pipe(res);
 
314
  datasets.forEach(dataset => {
315
  if (fs.existsSync(dataset.file_path)) {
316
  archive.file(dataset.file_path, { name: dataset.name });
317
  }
318
  });
 
319
  archive.finalize();
320
  }
321
  );
322
  });
 
 
323
  app.use((err, req, res, next) => {
 
324
  res.status(500).json({ error: 'Something went wrong!' });
325
  });
326
+ app.listen(PORT, () => {});