Missing files from commit
This commit is contained in:
+149
-78
@@ -175,42 +175,68 @@ function serializeOpeningHours(value) {
|
||||
// Initialize database tables
|
||||
async function initDatabase() {
|
||||
try {
|
||||
// Create pharmacies table
|
||||
await dbRun(`
|
||||
CREATE TABLE IF NOT EXISTS pharmacies (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
address TEXT NOT NULL,
|
||||
phone TEXT,
|
||||
latitude REAL,
|
||||
longitude REAL,
|
||||
opening_hours TEXT
|
||||
)
|
||||
`);
|
||||
|
||||
// Add opening_hours to pre-existing pharmacies tables (no-op if already present)
|
||||
try {
|
||||
await dbRun(`ALTER TABLE pharmacies ADD COLUMN opening_hours TEXT`);
|
||||
} catch (e) {
|
||||
if (!/duplicate column/i.test(e.message)) throw e;
|
||||
// Create pharmacies table — PG when available, SQLite fallback
|
||||
if (pgPool) {
|
||||
await pgPool.query(`
|
||||
CREATE TABLE IF NOT EXISTS pharmacies (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
address TEXT NOT NULL,
|
||||
phone TEXT,
|
||||
latitude DOUBLE PRECISION,
|
||||
longitude DOUBLE PRECISION,
|
||||
opening_hours TEXT
|
||||
)
|
||||
`);
|
||||
} else {
|
||||
await dbRun(`
|
||||
CREATE TABLE IF NOT EXISTS pharmacies (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
address TEXT NOT NULL,
|
||||
phone TEXT,
|
||||
latitude REAL,
|
||||
longitude REAL,
|
||||
opening_hours TEXT
|
||||
)
|
||||
`);
|
||||
// Add opening_hours to pre-existing pharmacies tables (no-op if already present)
|
||||
try {
|
||||
await dbRun(`ALTER TABLE pharmacies ADD COLUMN opening_hours TEXT`);
|
||||
} catch (e) {
|
||||
if (!/duplicate column/i.test(e.message)) throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Create junction table for pharmacy-medicine relationships
|
||||
// Ahora usa nregistro (número de registro de CIMA) en lugar de medicine_id local
|
||||
await dbRun(`
|
||||
CREATE TABLE IF NOT EXISTS pharmacy_medicines (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
pharmacy_id INTEGER NOT NULL,
|
||||
medicine_nregistro TEXT NOT NULL,
|
||||
medicine_name TEXT,
|
||||
price REAL,
|
||||
stock INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (pharmacy_id) REFERENCES pharmacies(id),
|
||||
UNIQUE(pharmacy_id, medicine_nregistro)
|
||||
)
|
||||
`);
|
||||
|
||||
await dbRun(`CREATE INDEX IF NOT EXISTS idx_pharmacy_medicine ON pharmacy_medicines(medicine_nregistro)`);
|
||||
if (pgPool) {
|
||||
await pgPool.query(`
|
||||
CREATE TABLE IF NOT EXISTS pharmacy_medicines (
|
||||
id SERIAL PRIMARY KEY,
|
||||
pharmacy_id INTEGER NOT NULL REFERENCES pharmacies(id),
|
||||
medicine_nregistro TEXT NOT NULL,
|
||||
medicine_name TEXT,
|
||||
price REAL,
|
||||
stock INTEGER DEFAULT 0,
|
||||
UNIQUE(pharmacy_id, medicine_nregistro)
|
||||
)
|
||||
`);
|
||||
await pgPool.query(`CREATE INDEX IF NOT EXISTS idx_pharmacy_medicine ON pharmacy_medicines(medicine_nregistro)`);
|
||||
} else {
|
||||
await dbRun(`
|
||||
CREATE TABLE IF NOT EXISTS pharmacy_medicines (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
pharmacy_id INTEGER NOT NULL,
|
||||
medicine_nregistro TEXT NOT NULL,
|
||||
medicine_name TEXT,
|
||||
price REAL,
|
||||
stock INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (pharmacy_id) REFERENCES pharmacies(id),
|
||||
UNIQUE(pharmacy_id, medicine_nregistro)
|
||||
)
|
||||
`);
|
||||
await dbRun(`CREATE INDEX IF NOT EXISTS idx_pharmacy_medicine ON pharmacy_medicines(medicine_nregistro)`);
|
||||
}
|
||||
|
||||
// Create users table — PG when available, SQLite fallback
|
||||
if (pgPool) {
|
||||
@@ -395,6 +421,36 @@ if (!pgPool) {
|
||||
`);
|
||||
}
|
||||
|
||||
// Recent searches table
|
||||
if (pgPool) {
|
||||
await pgPool.query(`
|
||||
CREATE TABLE IF NOT EXISTS recent_searches (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
medicine_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
active_ingredient TEXT,
|
||||
dosage TEXT,
|
||||
form TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
)
|
||||
`);
|
||||
} else {
|
||||
await dbRun(`
|
||||
CREATE TABLE IF NOT EXISTS recent_searches (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
medicine_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
active_ingredient TEXT,
|
||||
dosage TEXT,
|
||||
form TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
)
|
||||
`);
|
||||
}
|
||||
|
||||
// User addresses table
|
||||
if (pgPool) {
|
||||
await pgPool.query(`
|
||||
@@ -456,7 +512,7 @@ app.get('/api/medicines/:medicineId/pharmacies', async (req, res) => {
|
||||
try {
|
||||
const nregistro = req.params.medicineId; // Ahora es el nregistro de CIMA
|
||||
|
||||
const pharmacies = await dbAll(`
|
||||
const pharmacies = await userDbAll(`
|
||||
SELECT
|
||||
p.id,
|
||||
p.name,
|
||||
@@ -519,46 +575,61 @@ const requireAdmin = (req, res, next) => {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
};
|
||||
|
||||
// ========== RECENT SEARCHES (session-based) ==========
|
||||
// ========== RECENT SEARCHES (database-based) ==========
|
||||
|
||||
const MAX_RECENT = 10;
|
||||
const MAX_RECENT = 5;
|
||||
|
||||
// Get recent searches for the logged-in user
|
||||
app.get('/api/search/recent', requireAuth, (req, res) => {
|
||||
res.json(req.session.recentSearches || []);
|
||||
app.get('/api/search/recent', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const userId = req.session.userId;
|
||||
const rows = await userDbAll(
|
||||
'SELECT id, medicine_id, name, active_ingredient, dosage, form, created_at FROM recent_searches WHERE user_id = ? ORDER BY created_at DESC LIMIT ?',
|
||||
[userId, MAX_RECENT]
|
||||
);
|
||||
res.json(rows.map(r => ({
|
||||
id: r.medicine_id,
|
||||
name: r.name,
|
||||
active_ingredient: r.active_ingredient,
|
||||
dosage: r.dosage,
|
||||
form: r.form,
|
||||
timestamp: r.created_at,
|
||||
})));
|
||||
} catch (error) {
|
||||
console.error('Error fetching recent searches:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Save a medicine to recent searches
|
||||
app.post('/api/search/recent', requireAuth, (req, res) => {
|
||||
app.post('/api/search/recent', requireAuth, async (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 = [];
|
||||
}
|
||||
const userId = req.session.userId;
|
||||
|
||||
// Remove duplicate if exists (by id)
|
||||
req.session.recentSearches = req.session.recentSearches.filter(
|
||||
(m) => m.id !== medicine.id
|
||||
// Remove duplicate if exists (by medicine_id)
|
||||
await userDbRun(
|
||||
'DELETE FROM recent_searches WHERE user_id = ? AND medicine_id = ?',
|
||||
[userId, 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(),
|
||||
});
|
||||
// Insert new entry
|
||||
await userDbRun(
|
||||
'INSERT INTO recent_searches (user_id, medicine_id, name, active_ingredient, dosage, form) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[userId, medicine.id, medicine.name, medicine.active_ingredient || null, medicine.dosage || null, medicine.form || null]
|
||||
);
|
||||
|
||||
// Keep only last MAX_RECENT
|
||||
if (req.session.recentSearches.length > MAX_RECENT) {
|
||||
req.session.recentSearches = req.session.recentSearches.slice(0, MAX_RECENT);
|
||||
}
|
||||
// Trim to MAX_RECENT — delete oldest beyond limit
|
||||
await userDbRun(
|
||||
`DELETE FROM recent_searches WHERE user_id = ? AND id NOT IN (
|
||||
SELECT id FROM recent_searches WHERE user_id = ? ORDER BY created_at DESC LIMIT ?
|
||||
)`,
|
||||
[userId, userId, MAX_RECENT]
|
||||
);
|
||||
|
||||
res.json({ ok: true });
|
||||
} catch (error) {
|
||||
@@ -570,7 +641,7 @@ app.post('/api/search/recent', requireAuth, (req, res) => {
|
||||
// Get all pharmacies (for admin/debugging)
|
||||
app.get('/api/pharmacies', async (req, res) => {
|
||||
try {
|
||||
const pharmacies = await dbAll(`
|
||||
const pharmacies = await userDbAll(`
|
||||
SELECT * FROM pharmacies ORDER BY name
|
||||
`);
|
||||
res.json(pharmacies);
|
||||
@@ -1447,7 +1518,7 @@ app.post('/api/admin/pharmacies', requireAdmin, async (req, res) => {
|
||||
}
|
||||
|
||||
// Check for duplicate (same name and address)
|
||||
const existing = await dbGet(
|
||||
const existing = await userDbGet(
|
||||
'SELECT * FROM pharmacies WHERE name = ? AND address = ?',
|
||||
[name.trim(), address.trim()]
|
||||
);
|
||||
@@ -1458,7 +1529,7 @@ app.post('/api/admin/pharmacies', requireAdmin, async (req, res) => {
|
||||
|
||||
const openingHoursValue = serializeOpeningHours(opening_hours);
|
||||
|
||||
const result = await dbRun(
|
||||
const result = await userDbRun(
|
||||
'INSERT INTO pharmacies (name, address, phone, latitude, longitude, opening_hours) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[name.trim(), address.trim(), phone ? phone.trim() : null, latitude || null, longitude || null, openingHoursValue]
|
||||
);
|
||||
@@ -1467,7 +1538,7 @@ app.post('/api/admin/pharmacies', requireAdmin, async (req, res) => {
|
||||
throw new Error('Failed to get lastID from database insert');
|
||||
}
|
||||
|
||||
const newPharmacy = await dbGet(
|
||||
const newPharmacy = await userDbGet(
|
||||
'SELECT * FROM pharmacies WHERE id = ?',
|
||||
[result.lastID]
|
||||
);
|
||||
@@ -1499,12 +1570,12 @@ app.put('/api/admin/pharmacies/:id', requireAdmin, async (req, res) => {
|
||||
|
||||
const openingHoursValue = serializeOpeningHours(opening_hours);
|
||||
|
||||
await dbRun(
|
||||
await userDbRun(
|
||||
'UPDATE pharmacies SET name = ?, address = ?, phone = ?, latitude = ?, longitude = ?, opening_hours = ? WHERE id = ?',
|
||||
[name, address, phone || null, latitude || null, longitude || null, openingHoursValue, pharmacyId]
|
||||
);
|
||||
|
||||
const updatedPharmacy = await dbGet(
|
||||
const updatedPharmacy = await userDbGet(
|
||||
'SELECT * FROM pharmacies WHERE id = ?',
|
||||
[pharmacyId]
|
||||
);
|
||||
@@ -1526,10 +1597,10 @@ app.delete('/api/admin/pharmacies/:id', requireAdmin, async (req, res) => {
|
||||
const pharmacyId = parseInt(req.params.id);
|
||||
|
||||
// Delete related pharmacy_medicines first
|
||||
await dbRun('DELETE FROM pharmacy_medicines WHERE pharmacy_id = ?', [pharmacyId]);
|
||||
await userDbRun('DELETE FROM pharmacy_medicines WHERE pharmacy_id = ?', [pharmacyId]);
|
||||
|
||||
// Delete the pharmacy
|
||||
await dbRun('DELETE FROM pharmacies WHERE id = ?', [pharmacyId]);
|
||||
await userDbRun('DELETE FROM pharmacies WHERE id = ?', [pharmacyId]);
|
||||
|
||||
res.json({ message: 'Pharmacy deleted successfully' });
|
||||
} catch (error) {
|
||||
@@ -1555,8 +1626,8 @@ app.post('/api/admin/pharmacies/import-webhook', requireAdmin, async (req, res)
|
||||
const hasRegion =
|
||||
region.lat != null || region.lon != null || region.radio != null;
|
||||
const result = await runFarmaciaWebhookImport(
|
||||
dbGet,
|
||||
dbRun,
|
||||
userDbGet,
|
||||
userDbRun,
|
||||
url.trim(),
|
||||
hasRegion ? region : null
|
||||
);
|
||||
@@ -1604,7 +1675,7 @@ app.post('/api/admin/pharmacies/import-external', requireAdmin, async (req, res)
|
||||
});
|
||||
}
|
||||
|
||||
const stats = await importPharmaciesFromRows(dbGet, dbRun, rows);
|
||||
const stats = await importPharmaciesFromRows(userDbGet, userDbRun, rows);
|
||||
res.json({ ...stats, totalReceived: rows.length, source });
|
||||
} catch (error) {
|
||||
console.error('External pharmacy import:', error);
|
||||
@@ -1636,7 +1707,7 @@ app.get('/api/admin/pharmacies/:pharmacyId/medicines', requireAdmin, async (req,
|
||||
try {
|
||||
const pharmacyId = parseInt(req.params.pharmacyId);
|
||||
|
||||
const medicines = await dbAll(`
|
||||
const medicines = await userDbAll(`
|
||||
SELECT
|
||||
pm.id,
|
||||
pm.pharmacy_id,
|
||||
@@ -1666,33 +1737,33 @@ app.post('/api/admin/pharmacy-medicines', requireAdmin, async (req, res) => {
|
||||
}
|
||||
|
||||
// Check if relationship already exists
|
||||
const existing = await dbGet(
|
||||
const existing = await userDbGet(
|
||||
'SELECT * FROM pharmacy_medicines WHERE pharmacy_id = ? AND medicine_nregistro = ?',
|
||||
[pharmacy_id, medicine_nregistro]
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
// Update existing relationship
|
||||
await dbRun(
|
||||
await userDbRun(
|
||||
'UPDATE pharmacy_medicines SET medicine_name = ?, price = ?, stock = ? WHERE pharmacy_id = ? AND medicine_nregistro = ?',
|
||||
[medicine_name, price || null, stock || 0, pharmacy_id, medicine_nregistro]
|
||||
);
|
||||
} else {
|
||||
// Insert new relationship
|
||||
await dbRun(
|
||||
await userDbRun(
|
||||
'INSERT INTO pharmacy_medicines (pharmacy_id, medicine_nregistro, medicine_name, price, stock) VALUES (?, ?, ?, ?, ?)',
|
||||
[pharmacy_id, medicine_nregistro, medicine_name, price || null, stock || 0]
|
||||
);
|
||||
}
|
||||
|
||||
const relationship = await dbGet(
|
||||
const relationship = await userDbGet(
|
||||
`SELECT * FROM pharmacy_medicines
|
||||
WHERE pharmacy_id = ? AND medicine_nregistro = ?`,
|
||||
[pharmacy_id, medicine_nregistro]
|
||||
);
|
||||
|
||||
if (!existing) {
|
||||
const pharmacy = await dbGet('SELECT id, name FROM pharmacies WHERE id = ?', [pharmacy_id]);
|
||||
const pharmacy = await userDbGet('SELECT id, name FROM pharmacies WHERE id = ?', [pharmacy_id]);
|
||||
sendPushForMedicine({
|
||||
medicine_nregistro,
|
||||
medicine_name: medicine_name || relationship?.medicine_name || null,
|
||||
@@ -1713,12 +1784,12 @@ app.put('/api/admin/pharmacy-medicines/:id', requireAdmin, async (req, res) => {
|
||||
const id = parseInt(req.params.id);
|
||||
const { price, stock } = req.body;
|
||||
|
||||
await dbRun(
|
||||
await userDbRun(
|
||||
'UPDATE pharmacy_medicines SET price = ?, stock = ? WHERE id = ?',
|
||||
[price || null, stock || 0, id]
|
||||
);
|
||||
|
||||
const updated = await dbGet(
|
||||
const updated = await userDbGet(
|
||||
'SELECT * FROM pharmacy_medicines WHERE id = ?',
|
||||
[id]
|
||||
);
|
||||
@@ -1738,7 +1809,7 @@ app.put('/api/admin/pharmacy-medicines/:id', requireAdmin, async (req, res) => {
|
||||
app.delete('/api/admin/pharmacy-medicines/:id', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const id = parseInt(req.params.id);
|
||||
await dbRun('DELETE FROM pharmacy_medicines WHERE id = ?', [id]);
|
||||
await userDbRun('DELETE FROM pharmacy_medicines WHERE id = ?', [id]);
|
||||
res.json({ message: 'Medicine removed from pharmacy successfully' });
|
||||
} catch (error) {
|
||||
console.error('Error deleting pharmacy-medicine:', error);
|
||||
|
||||
Reference in New Issue
Block a user