Actualizar server.js
This commit is contained in:
54
server.js
54
server.js
@@ -237,6 +237,8 @@ async function autoUpdateDB() {
|
|||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='plan_tier') THEN ALTER TABLE users ADD COLUMN plan_tier TEXT DEFAULT 'free'; END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='plan_tier') THEN ALTER TABLE users ADD COLUMN plan_tier TEXT DEFAULT 'free'; END IF;
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='company_slug') THEN ALTER TABLE users ADD COLUMN company_slug TEXT UNIQUE; END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='company_slug') THEN ALTER TABLE users ADD COLUMN company_slug TEXT UNIQUE; END IF;
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='zones') THEN ALTER TABLE users ADD COLUMN zones JSONB DEFAULT '[]'; END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='zones') THEN ALTER TABLE users ADD COLUMN zones JSONB DEFAULT '[]'; END IF;
|
||||||
|
-- NUEVO: Columna de estado para Baja Temporal
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='status') THEN ALTER TABLE users ADD COLUMN status TEXT DEFAULT 'active'; END IF;
|
||||||
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='provider_data') THEN ALTER TABLE services ADD COLUMN provider_data JSONB DEFAULT '{}'; END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='provider_data') THEN ALTER TABLE services ADD COLUMN provider_data JSONB DEFAULT '{}'; END IF;
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='import_source') THEN ALTER TABLE services ADD COLUMN import_source TEXT; END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='import_source') THEN ALTER TABLE services ADD COLUMN import_source TEXT; END IF;
|
||||||
@@ -653,28 +655,40 @@ app.delete("/guilds/:id", authMiddleware, async (req, res) => { try { await pool
|
|||||||
// BUSCADOR GEOGRÁFICO: Consulta la tabla que poblaste en Adminer
|
// BUSCADOR GEOGRÁFICO: Consulta la tabla que poblaste en Adminer
|
||||||
// BUSCADOR GEOGRÁFICO MEJORADO (Ignora tildes automáticamente)
|
// BUSCADOR GEOGRÁFICO MEJORADO (Ignora tildes automáticamente)
|
||||||
app.get("/api/geo/municipios/:provincia", authMiddleware, async (req, res) => {
|
app.get("/api/geo/municipios/:provincia", authMiddleware, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let { provincia } = req.params;
|
let { provincia } = req.params;
|
||||||
|
|
||||||
// Normalizamos la entrada: quitamos tildes y ponemos en mayúsculas
|
// Normalizamos la entrada: quitamos tildes y ponemos en mayúsculas
|
||||||
// Ejemplo: "CÁDIZ" -> "CADIZ"
|
// Ejemplo: "CÁDIZ" -> "CADIZ"
|
||||||
const provClean = provincia.toUpperCase()
|
const provClean = provincia.toUpperCase()
|
||||||
.normalize("NFD")
|
.normalize("NFD")
|
||||||
.replace(/[\u0300-\u036f]/g, "");
|
.replace(/[\u0300-\u036f]/g, "");
|
||||||
|
|
||||||
const q = await pool.query(
|
const q = await pool.query(
|
||||||
"SELECT municipio, codigo_postal FROM master_geo_es WHERE provincia = $1 ORDER BY municipio ASC",
|
"SELECT municipio, codigo_postal FROM master_geo_es WHERE provincia = $1 ORDER BY municipio ASC",
|
||||||
[provClean]
|
[provClean]
|
||||||
);
|
);
|
||||||
res.json({ ok: true, municipios: q.rows });
|
res.json({ ok: true, municipios: q.rows });
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error al leer master_geo_es:", e.message);
|
||||||
|
res.status(500).json({ ok: false });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// NUEVO: Endpoint para activar/desactivar operario (Baja Temporal)
|
||||||
|
app.patch("/admin/users/:id/status", authMiddleware, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { status } = req.body; // 'active' o 'inactive'
|
||||||
|
await pool.query("UPDATE users SET status = $1 WHERE id = $2 AND owner_id = $3",
|
||||||
|
[status, req.params.id, req.user.accountId]);
|
||||||
|
res.json({ ok: true });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error al leer master_geo_es:", e.message);
|
|
||||||
res.status(500).json({ ok: false });
|
res.status(500).json({ ok: false });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/admin/users", authMiddleware, async (req, res) => { try { const q = await pool.query(`SELECT u.id, u.full_name, u.email, u.phone, u.role, u.zones, COALESCE(json_agg(g.id) FILTER (WHERE g.id IS NOT NULL), '[]') as guilds FROM users u LEFT JOIN user_guilds ug ON u.id=ug.user_id LEFT JOIN guilds g ON ug.guild_id=g.id WHERE u.owner_id=$1 GROUP BY u.id ORDER BY u.id DESC`, [req.user.accountId]); res.json({ ok: true, users: q.rows }); } catch (e) { res.status(500).json({ ok: false }); } });
|
app.get("/admin/users", authMiddleware, async (req, res) => { try { const q = await pool.query(`SELECT u.id, u.full_name, u.email, u.phone, u.role, u.zones, u.status, COALESCE(json_agg(g.id) FILTER (WHERE g.id IS NOT NULL), '[]') as guilds FROM users u LEFT JOIN user_guilds ug ON u.id=ug.user_id LEFT JOIN guilds g ON ug.guild_id=g.id WHERE u.owner_id=$1 GROUP BY u.id ORDER BY u.id DESC`, [req.user.accountId]); res.json({ ok: true, users: q.rows }); } catch (e) { res.status(500).json({ ok: false }); } });
|
||||||
app.post("/admin/users", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const { fullName, email, password, role, guilds, phone, zones } = req.body; if (!email || !password || !fullName || !phone) return res.status(400).json({ ok: false }); const p = normalizePhone(phone); const hash = await bcrypt.hash(password, 10); const check = await client.query("SELECT id FROM users WHERE (phone=$1 OR email=$2) AND owner_id=$3", [p, email, req.user.accountId]); if (check.rowCount > 0) return res.status(400).json({ ok: false, error: "Duplicado" }); await client.query('BEGIN'); const insert = await client.query("INSERT INTO users (full_name, email, password_hash, role, phone, is_verified, owner_id, zones) VALUES ($1, $2, $3, $4, $5, TRUE, $6, $7) RETURNING id", [fullName, email, hash, role || 'operario', p, req.user.accountId, JSON.stringify(zones || [])]); const uid = insert.rows[0].id; if (guilds) for (const gid of guilds) await client.query("INSERT INTO user_guilds (user_id, guild_id) VALUES ($1, $2)", [uid, gid]); await client.query('COMMIT'); res.json({ ok: true }); } catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); } });
|
app.post("/admin/users", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const { fullName, email, password, role, guilds, phone, zones } = req.body; if (!email || !password || !fullName || !phone) return res.status(400).json({ ok: false }); const p = normalizePhone(phone); const hash = await bcrypt.hash(password, 10); const check = await client.query("SELECT id FROM users WHERE (phone=$1 OR email=$2) AND owner_id=$3", [p, email, req.user.accountId]); if (check.rowCount > 0) return res.status(400).json({ ok: false, error: "Duplicado" }); await client.query('BEGIN'); const insert = await client.query("INSERT INTO users (full_name, email, password_hash, role, phone, is_verified, owner_id, zones, status) VALUES ($1, $2, $3, $4, $5, TRUE, $6, $7, 'active') RETURNING id", [fullName, email, hash, role || 'operario', p, req.user.accountId, JSON.stringify(zones || [])]); const uid = insert.rows[0].id; if (guilds) for (const gid of guilds) await client.query("INSERT INTO user_guilds (user_id, guild_id) VALUES ($1, $2)", [uid, gid]); await client.query('COMMIT'); res.json({ ok: true }); } catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); } });
|
||||||
app.put("/admin/users/:id", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const userId = req.params.id; const { fullName, email, phone, role, guilds, password, zones } = req.body; const p = normalizePhone(phone); await client.query('BEGIN'); if(password) { const hash = await bcrypt.hash(password, 10); await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, password_hash=$5, zones=$6 WHERE id=$7", [fullName, email, p, role, hash, JSON.stringify(zones || []), userId]); } else { await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, zones=$5 WHERE id=$6", [fullName, email, p, role, JSON.stringify(zones || []), userId]); } if (guilds && Array.isArray(guilds)) { await client.query("DELETE FROM user_guilds WHERE user_id=$1", [userId]); for (const gid of guilds) await client.query("INSERT INTO user_guilds (user_id, guild_id) VALUES ($1, $2)", [userId, gid]); } await client.query('COMMIT'); res.json({ ok: true }); } catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); } });
|
app.put("/admin/users/:id", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const userId = req.params.id; const { fullName, email, phone, role, guilds, password, zones } = req.body; const p = normalizePhone(phone); await client.query('BEGIN'); if(password) { const hash = await bcrypt.hash(password, 10); await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, password_hash=$5, zones=$6 WHERE id=$7", [fullName, email, p, role, hash, JSON.stringify(zones || []), userId]); } else { await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, zones=$5 WHERE id=$6", [fullName, email, p, role, JSON.stringify(zones || []), userId]); } if (guilds && Array.isArray(guilds)) { await client.query("DELETE FROM user_guilds WHERE user_id=$1", [userId]); for (const gid of guilds) await client.query("INSERT INTO user_guilds (user_id, guild_id) VALUES ($1, $2)", [userId, gid]); } await client.query('COMMIT'); res.json({ ok: true }); } catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); } });
|
||||||
app.delete("/admin/users/:id", authMiddleware, async (req, res) => { try { await pool.query("DELETE FROM users WHERE id=$1 AND owner_id=$2", [req.params.id, req.user.accountId]); res.json({ ok: true }); } catch (e) { res.status(500).json({ ok: false }); } });
|
app.delete("/admin/users/:id", authMiddleware, async (req, res) => { try { await pool.query("DELETE FROM users WHERE id=$1 AND owner_id=$2", [req.params.id, req.user.accountId]); res.json({ ok: true }); } catch (e) { res.status(500).json({ ok: false }); } });
|
||||||
|
|
||||||
@@ -683,4 +697,10 @@ app.get("/config/company", authMiddleware, async (req, res) => { try { const q =
|
|||||||
app.post("/config/company", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const { slug } = req.body; if (!slug || slug.length < 3) return res.status(400).json({ ok: false, error: "Mínimo 3 caracteres" }); const cleanSlug = slug.toLowerCase().replace(/[^a-z0-9-]/g, ""); if (cleanSlug !== slug) return res.status(400).json({ ok: false, error: "Carácteres inválidos" }); const check = await client.query("SELECT id FROM users WHERE company_slug=$1 AND id != $2", [cleanSlug, req.user.accountId]); if (check.rowCount > 0) return res.status(400).json({ ok: false, error: "Nombre en uso" }); await client.query("UPDATE users SET company_slug=$1 WHERE id=$2", [cleanSlug, req.user.accountId]); res.json({ ok: true, fullUrl: `https://${cleanSlug}.integrarepara.es` }); } catch (e) { res.status(500).json({ ok: false }); } finally { client.release(); } });
|
app.post("/config/company", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const { slug } = req.body; if (!slug || slug.length < 3) return res.status(400).json({ ok: false, error: "Mínimo 3 caracteres" }); const cleanSlug = slug.toLowerCase().replace(/[^a-z0-9-]/g, ""); if (cleanSlug !== slug) return res.status(400).json({ ok: false, error: "Carácteres inválidos" }); const check = await client.query("SELECT id FROM users WHERE company_slug=$1 AND id != $2", [cleanSlug, req.user.accountId]); if (check.rowCount > 0) return res.status(400).json({ ok: false, error: "Nombre en uso" }); await client.query("UPDATE users SET company_slug=$1 WHERE id=$2", [cleanSlug, req.user.accountId]); res.json({ ok: true, fullUrl: `https://${cleanSlug}.integrarepara.es` }); } catch (e) { res.status(500).json({ ok: false }); } finally { client.release(); } });
|
||||||
|
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
autoUpdateDB().then(() => { app.listen(port, "0.0.0.0", () => console.log(`🚀 Server OK en puerto ${port}`)); });
|
autoUpdateDB().then(() => { app.listen(port, "0.0.0.0", () => console.log(`🚀 Server OK en puerto ${port}`)); });
|
||||||
|
|
||||||
|
como seria para asignar por codigo postal el operario al traspasar de proveedores el expediente??
|
||||||
|
|
||||||
|
si el codigo postal del expediente de proveedores concuerda con algun operario activo que se asigne a el solo si tiene activo ese codigo postal.
|
||||||
|
|
||||||
|
modifica solo lo necesario, NO TOQUES EL RESTO.
|
||||||
Reference in New Issue
Block a user