Explorar el Código

Refactor: extract app factory, fix SQLite memory path and multer error handling

k4be hace 8 horas
padre
commit
bd81bd6487

+ 2 - 25
gpx-vis-backend/index.js

@@ -1,8 +1,3 @@
-const express = require('express');
-const compression = require('compression');
-const cors = require('cors');
-const path = require('path');
-
 let config;
 try {
   config = require('./config');
@@ -12,27 +7,9 @@ try {
 }
 
 const { initDatabase } = require('./src/database');
-const authRoutes = require('./src/routes/auth');
-const dirRoutes = require('./src/routes/directories');
-const trackRoutes = require('./src/routes/tracks');
-const shareRoutes = require('./src/routes/share');
-const adminRoutes = require('./src/routes/admin');
-const statsRoutes = require('./src/routes/stats');
-
-const app = express();
-
-app.use(compression());
-app.use(cors({ origin: config.cors.origin, credentials: true }));
-app.use(express.json());
-
-app.use('/api/auth', authRoutes);
-app.use('/api/directories', dirRoutes);
-app.use('/api/tracks', trackRoutes);
-app.use('/api/share', shareRoutes);
-app.use('/api/admin', adminRoutes);
-app.use('/api/stats', statsRoutes);
+const { createApp } = require('./src/app');
 
-app.get('/health', (req, res) => res.json({ ok: true }));
+const app = createApp(config);
 
 async function start() {
   await initDatabase();

+ 13 - 8
gpx-vis-backend/package.json

@@ -5,18 +5,23 @@
   "main": "index.js",
   "scripts": {
     "start": "node index.js",
-    "dev": "node --watch index.js"
+    "dev": "node --watch index.js",
+    "test": "mocha --require test/setup.js 'test/**/*.test.js' --timeout 10000"
   },
   "dependencies": {
-    "express": "^4.18.2",
-    "sequelize": "^6.35.2",
-    "sqlite3": "^5.1.7",
-    "mysql2": "^3.7.1",
     "bcryptjs": "^2.4.3",
+    "compression": "^1.7.4",
+    "cors": "^2.8.5",
+    "express": "^4.18.2",
     "jsonwebtoken": "^9.0.2",
     "multer": "^1.4.5-lts.1",
-    "xml2js": "^0.6.2",
-    "compression": "^1.7.4",
-    "cors": "^2.8.5"
+    "mysql2": "^3.7.1",
+    "sequelize": "^6.35.2",
+    "sqlite3": "^5.1.7",
+    "xml2js": "^0.6.2"
+  },
+  "devDependencies": {
+    "mocha": "^11.7.5",
+    "supertest": "^7.2.2"
   }
 }

+ 24 - 0
gpx-vis-backend/src/app.js

@@ -0,0 +1,24 @@
+const express = require('express');
+const compression = require('compression');
+const cors = require('cors');
+
+function createApp(config) {
+  const app = express();
+
+  app.use(compression());
+  app.use(cors({ origin: config.cors?.origin || '*', credentials: true }));
+  app.use(express.json());
+
+  app.use('/api/auth', require('./routes/auth'));
+  app.use('/api/directories', require('./routes/directories'));
+  app.use('/api/tracks', require('./routes/tracks'));
+  app.use('/api/share', require('./routes/share'));
+  app.use('/api/admin', require('./routes/admin'));
+  app.use('/api/stats', require('./routes/stats'));
+
+  app.get('/health', (req, res) => res.json({ ok: true }));
+
+  return app;
+}
+
+module.exports = { createApp };

+ 5 - 3
gpx-vis-backend/src/database.js

@@ -11,8 +11,9 @@ function getSequelize() {
   if (sequelize) return sequelize;
   const db = config.database || {};
   if (db.type === 'sqlite' || !db.type) {
-    const storage = path.resolve(db.storage || './data/gpx-vis.db');
-    fs.mkdirSync(path.dirname(storage), { recursive: true });
+    const rawStorage = db.storage || './data/gpx-vis.db';
+    const storage = rawStorage === ':memory:' ? ':memory:' : path.resolve(rawStorage);
+    if (storage !== ':memory:') fs.mkdirSync(path.dirname(storage), { recursive: true });
     sequelize = new Sequelize({ dialect: 'sqlite', storage, logging: false });
   } else {
     sequelize = new Sequelize(db.database, db.username, db.password, {
@@ -29,7 +30,8 @@ async function initDatabase() {
   const sq = getSequelize();
   // Import models to register them
   require('./models');
-  await sq.sync({ alter: true });
+  const isMemory = (config.database?.storage === ':memory:');
+  await sq.sync(isMemory ? {} : { alter: true });
   console.log('Database initialized');
 }
 

+ 6 - 1
gpx-vis-backend/src/routes/tracks.js

@@ -77,7 +77,12 @@ router.get('/:id/points', requireAuth, async (req, res) => {
   }
 });
 
-router.post('/upload', requireAuth, upload.single('file'), async (req, res) => {
+router.post('/upload', requireAuth, (req, res, next) => {
+  upload.single('file')(req, res, (err) => {
+    if (err) return res.status(400).json({ error: err.message || 'File upload error' });
+    next();
+  });
+}, async (req, res) => {
   try {
     if (!req.file) return res.status(400).json({ error: 'No file uploaded' });