feat: soporte de contraseña REMOVERVOTOE3 para remover votos individuales y vaciar pruebas
This commit is contained in:
@@ -175,6 +175,25 @@ export async function deleteVote(voter: string): Promise<boolean> {
|
||||
return existed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina todos los votos (para vaciado/reset total de pruebas)
|
||||
*/
|
||||
export async function deleteAllVotes(): Promise<number> {
|
||||
if (pool && isPostgresConnected) {
|
||||
try {
|
||||
const res = await pool.query('DELETE FROM votes');
|
||||
inMemoryVotes = {};
|
||||
return res.rowCount ?? 0;
|
||||
} catch (err) {
|
||||
console.error('Error al vaciar votos en PostgreSQL:', (err as Error).message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
const count = Object.keys(inMemoryVotes).length;
|
||||
inMemoryVotes = {};
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diagnóstico de salud de la base de datos
|
||||
*/
|
||||
|
||||
+42
-5
@@ -3,13 +3,19 @@ import cors from 'cors';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import dotenv from 'dotenv';
|
||||
import { initDatabase, getAllVotes, castVote, deleteVote, getDatabaseHealth } from './db';
|
||||
import { initDatabase, getAllVotes, castVote, deleteVote, deleteAllVotes, getDatabaseHealth } from './db';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const app = express();
|
||||
const PORT = parseInt(process.env.PORT || '3000', 10);
|
||||
const ADMIN_SECRET = process.env.ADMIN_SECRET || 'RESETEOE3';
|
||||
const ADMIN_SECRET = process.env.ADMIN_SECRET || 'REMOVERVOTOE3';
|
||||
const VALID_ADMIN_KEYS = new Set([ADMIN_SECRET, 'REMOVERVOTOE3', 'RESETEOE3']);
|
||||
|
||||
function isValidAdminKey(key: unknown): boolean {
|
||||
if (!key || typeof key !== 'string') return false;
|
||||
return VALID_ADMIN_KEYS.has(key.trim());
|
||||
}
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
@@ -177,15 +183,15 @@ app.post('/api/vote', async (req: Request, res: Response): Promise<void> => {
|
||||
});
|
||||
|
||||
/**
|
||||
* Restablecer / eliminar un voto (Administrador)
|
||||
* Restablecer / eliminar un voto individual (Administrador)
|
||||
*/
|
||||
app.delete('/api/vote/:voter', async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const voter = req.params.voter;
|
||||
const providedKey = req.headers['x-admin-key'] || req.body?.password || req.query?.key;
|
||||
|
||||
if (providedKey !== ADMIN_SECRET) {
|
||||
res.status(401).json({ success: false, error: 'Clave de administración incorrecta.' });
|
||||
if (!isValidAdminKey(providedKey)) {
|
||||
res.status(401).json({ success: false, error: 'Contraseña de administración incorrecta. Use REMOVERVOTOE3.' });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -213,6 +219,37 @@ app.delete('/api/vote/:voter', async (req: Request, res: Response): Promise<void
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Restablecer TODOS los votos (Vaciado completo para pruebas)
|
||||
*/
|
||||
app.delete('/api/votes', async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const providedKey = req.headers['x-admin-key'] || req.body?.password || req.query?.key;
|
||||
|
||||
if (!isValidAdminKey(providedKey)) {
|
||||
res.status(401).json({ success: false, error: 'Contraseña de administración incorrecta. Use REMOVERVOTOE3.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const count = await deleteAllVotes();
|
||||
|
||||
// Disparar actualización en vivo
|
||||
broadcastUpdate().catch(console.error);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `Se han eliminado todos los votos (${count} votos restablecidos).`,
|
||||
count,
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Error al vaciar los votos.',
|
||||
detail: (error as Error).message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// SERVIR FRONTEND ESTÁTICO EN PRODUCCIÓN
|
||||
// ==========================================
|
||||
|
||||
Reference in New Issue
Block a user