feat: rediseño UI completo + infra email + stats
This commit is contained in:
parent
93d75ddafe
commit
24401c0ee5
37 changed files with 2162 additions and 412 deletions
|
|
@ -84,12 +84,14 @@ ${today}`;
|
|||
exports.PROVIDER_DATA = PROVIDER_DATA;
|
||||
|
||||
exports.sendErasureMail = async ({ provider, email, nickname, phone, address, extra }) => {
|
||||
const providerInfo = PROVIDER_DATA[provider] || {
|
||||
name: provider,
|
||||
email: `privacy@${provider}.com`,
|
||||
company: provider,
|
||||
address: '',
|
||||
};
|
||||
const providerInfo = PROVIDER_DATA[provider];
|
||||
|
||||
/* Sin fallback: el provider ya fue validado en erase.js contra ALLOWED_PROVIDERS.
|
||||
Si llegara algo desconocido aquí sería un bug, no un caso legítimo.
|
||||
No construir email destino dinámico — eso sería un open relay. */
|
||||
if (!providerInfo) {
|
||||
throw new Error(`Proveedor desconocido: ${provider}`);
|
||||
}
|
||||
|
||||
// Si el proveedor no tiene email directo, no enviamos (devolvemos aviso)
|
||||
if (!providerInfo.email) {
|
||||
|
|
|
|||
55
api/services/stats.js
Normal file
55
api/services/stats.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const DATA_FILE = path.join(__dirname, '..', 'data', 'stats.json');
|
||||
|
||||
const EMPTY = () => ({
|
||||
total_sent: 0,
|
||||
total_redirected: 0,
|
||||
total_errors: 0,
|
||||
total_searches: 0,
|
||||
by_provider: Object.create(null), // null prototype — previene prototype pollution
|
||||
updated: null,
|
||||
});
|
||||
|
||||
function load() {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
|
||||
} catch {
|
||||
return EMPTY();
|
||||
}
|
||||
}
|
||||
|
||||
function save(data) {
|
||||
const dir = path.dirname(DATA_FILE);
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
const tmp = DATA_FILE + '.tmp';
|
||||
fs.writeFileSync(tmp, JSON.stringify(data, null, 2), 'utf8');
|
||||
fs.renameSync(tmp, DATA_FILE); // atómico en mismo filesystem
|
||||
}
|
||||
|
||||
function record({ type, provider }) {
|
||||
const s = load();
|
||||
|
||||
if (type === 'sent') s.total_sent++;
|
||||
else if (type === 'redirected') s.total_redirected++;
|
||||
else if (type === 'error') s.total_errors++;
|
||||
else if (type === 'search') s.total_searches++;
|
||||
|
||||
if (provider && (type === 'sent' || type === 'redirected')) {
|
||||
if (!s.by_provider[provider]) s.by_provider[provider] = { sent: 0, redirected: 0 };
|
||||
if (type === 'sent') s.by_provider[provider].sent++;
|
||||
if (type === 'redirected') s.by_provider[provider].redirected++;
|
||||
}
|
||||
|
||||
s.updated = new Date().toISOString().slice(0, 10);
|
||||
save(s);
|
||||
}
|
||||
|
||||
function get() {
|
||||
return load();
|
||||
}
|
||||
|
||||
module.exports = { record, get };
|
||||
Loading…
Add table
Add a link
Reference in a new issue