Fixes on docker compose & notify
Run Tests on Branches / Backend Tests (push) Successful in 3m28s
Run Tests on Branches / Frontend Tests (push) Successful in 3m27s

This commit is contained in:
Antoni Nuñez Romeu
2026-07-02 17:09:15 +02:00
parent 15e136f3d5
commit 1bc34b1134
3 changed files with 170 additions and 64 deletions
+77 -21
View File
@@ -139,6 +139,14 @@ async function userDbRun(sql, params = []) {
return dbRun(sql.replace(/\s+RETURNING\s+\w+\s*$/i, ''), params);
}
async function userDbAll(sql, params = []) {
if (pgPool) {
const res = await pgPool.query(toPositional(sql), params);
return res.rows;
}
return dbAll(sql, params);
}
// Accept opening_hours as either an object or a JSON string from the client
// and return a TEXT value (or null) safe to persist.
function serializeOpeningHours(value) {
@@ -376,6 +384,75 @@ app.get('/api/medicines/:medicineId', async (req, res) => {
}
});
// ========== AUTHENTICATION MIDDLEWARE ==========
// Middleware to check if user is authenticated
const requireAuth = (req, res, next) => {
if (req.session && req.session.userId) {
return next();
}
return res.status(401).json({ error: 'Authentication required' });
};
// Middleware to check if user is an admin
const requireAdmin = (req, res, next) => {
if (req.session && req.session.userId && req.session.isAdmin) {
return next();
}
if (req.session && req.session.userId) {
return res.status(403).json({ error: 'Admin access required' });
}
return res.status(401).json({ error: 'Authentication required' });
};
// ========== RECENT SEARCHES (session-based) ==========
const MAX_RECENT = 10;
// Get recent searches for the logged-in user
app.get('/api/search/recent', requireAuth, (req, res) => {
res.json(req.session.recentSearches || []);
});
// Save a medicine to recent searches
app.post('/api/search/recent', requireAuth, (req, res) => {
try {
const { medicine } = req.body;
if (!medicine || !medicine.id) {
return res.status(400).json({ error: 'Medicine data required' });
}
if (!req.session.recentSearches) {
req.session.recentSearches = [];
}
// Remove duplicate if exists (by id)
req.session.recentSearches = req.session.recentSearches.filter(
(m) => m.id !== medicine.id
);
// Add to front with timestamp
req.session.recentSearches.unshift({
id: medicine.id,
name: medicine.name,
active_ingredient: medicine.active_ingredient,
dosage: medicine.dosage,
form: medicine.form,
timestamp: Date.now(),
});
// Keep only last MAX_RECENT
if (req.session.recentSearches.length > MAX_RECENT) {
req.session.recentSearches = req.session.recentSearches.slice(0, MAX_RECENT);
}
res.json({ ok: true });
} catch (error) {
console.error('Error saving recent search:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Get all pharmacies (for admin/debugging)
app.get('/api/pharmacies', async (req, res) => {
try {
@@ -438,27 +515,6 @@ app.get('/api/tsi/:cip/prescriptions', async (req, res) => {
}
});
// ========== AUTHENTICATION MIDDLEWARE ==========
// Middleware to check if user is authenticated
const requireAuth = (req, res, next) => {
if (req.session && req.session.userId) {
return next();
}
return res.status(401).json({ error: 'Authentication required' });
};
// Middleware to check if user is an admin
const requireAdmin = (req, res, next) => {
if (req.session && req.session.userId && req.session.isAdmin) {
return next();
}
if (req.session && req.session.userId) {
return res.status(403).json({ error: 'Admin access required' });
}
return res.status(401).json({ error: 'Authentication required' });
};
// ========== AUTHENTICATION ROUTES ==========
// Login endpoint