- Campo universal de ubicación (Google Maps/Waze/OSM/coordenadas/dirección) sobre proveedores extensibles (src/utils/ubicacion) con resolver e inferencia inversa Nominatim (nombre/provincia pre-rellenados, alias cooficiales) - FAB flotante abajo a la derecha que abre la pasarela en un modal accesible (Escape, foco contenido, responsive); sin descripción ni puntuación; avisos de duplicado y filtro de palabras dentro del modal - Aviso PWA reposicionado: tarjeta abajo a la izquierda en móvil, botón compacto arriba a la izquierda en PC (no tapa el FAB) - Suite de pruebas: 88 unitarias/componente (vitest + RTL, offline) y 10 de integración (supertest + SQLite :memory: y Nominatim real opt-in) - CI: workflow de Gitea Actions con npm test + build en push/PR e integración manual
90 lines
2.7 KiB
JavaScript
90 lines
2.7 KiB
JavaScript
import Database from "better-sqlite3";
|
|
import { fileURLToPath } from "url";
|
|
import { dirname, join } from "path";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
// Ruta de la BD sobreescribible para pruebas (admite ":memory:"); en
|
|
// producción se usa el archivo del repo.
|
|
const dbPath = process.env.LOCALESP_DB || join(__dirname, "../localesp.db");
|
|
const db = new Database(dbPath);
|
|
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS locales (
|
|
id TEXT PRIMARY KEY,
|
|
nombre TEXT NOT NULL,
|
|
descripcion TEXT,
|
|
provincia TEXT,
|
|
subcategoria TEXT,
|
|
direccion TEXT,
|
|
enlaceGoogleMaps TEXT,
|
|
puntuacion INTEGER DEFAULT 0,
|
|
categoria TEXT,
|
|
fecha TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
lat REAL,
|
|
lng REAL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS pendientes (
|
|
id TEXT PRIMARY KEY,
|
|
nombre TEXT NOT NULL,
|
|
descripcion TEXT,
|
|
provincia TEXT,
|
|
subcategoria TEXT,
|
|
direccion TEXT,
|
|
enlaceGoogleMaps TEXT,
|
|
puntuacion INTEGER DEFAULT 0,
|
|
categoria TEXT,
|
|
estado TEXT DEFAULT 'pendiente',
|
|
fechaPropuesta TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
lat REAL,
|
|
lng REAL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS config (
|
|
id TEXT PRIMARY KEY,
|
|
datos TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS reportes (
|
|
id TEXT PRIMARY KEY,
|
|
localId TEXT NOT NULL,
|
|
motivo TEXT,
|
|
comentario TEXT,
|
|
fecha TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
estado TEXT DEFAULT 'pendiente'
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id TEXT PRIMARY KEY,
|
|
email TEXT UNIQUE NOT NULL,
|
|
password TEXT NOT NULL,
|
|
created TEXT DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
`);
|
|
|
|
// Migración suave: si la base de datos ya existía con el esquema antiguo
|
|
// (sin provincia/subcategoria/direccion/enlaceGoogleMaps/puntuacion),
|
|
// añadimos las columnas que falten sin borrar nada, porque
|
|
// CREATE TABLE IF NOT EXISTS no modifica tablas ya creadas.
|
|
function ensureColumn(table, column, definition) {
|
|
const cols = db.prepare(`PRAGMA table_info(${table})`).all().map(c => c.name);
|
|
if (!cols.includes(column)) {
|
|
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
|
|
}
|
|
}
|
|
|
|
for (const table of ["locales", "pendientes"]) {
|
|
ensureColumn(table, "provincia", "TEXT");
|
|
ensureColumn(table, "subcategoria", "TEXT");
|
|
ensureColumn(table, "direccion", "TEXT");
|
|
ensureColumn(table, "enlaceGoogleMaps", "TEXT");
|
|
ensureColumn(table, "puntuacion", "INTEGER DEFAULT 0");
|
|
}
|
|
// fechaConfirmacion: última vez que alguien confirmó que el local sigue activo.
|
|
// Al aprobarse por primera vez se inicializa igual a "fecha"; luego se actualiza
|
|
// con /api/locales/:id/confirmar cada vez que un usuario pulsa "Sigue aquí".
|
|
ensureColumn("locales", "fechaConfirmacion", "TEXT");
|
|
db.prepare("UPDATE locales SET fechaConfirmacion = fecha WHERE fechaConfirmacion IS NULL").run();
|
|
|
|
export default db;
|