fix(sync): ranking dedup + copy logs over HTTP

- ranking.js: déduplique par (gencod, site) avant batchUpsert pour éviter
  "ON CONFLICT DO UPDATE command cannot affect row a second time"
- server.js: bouton "Copier les logs" utilise execCommand fallback quand
  navigator.clipboard indisponible (accès HTTP sans HTTPS)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 4.6 committed 2026-03-19 12:06:27 +01:00
1 parent 5ce480ade3
commit e189cc3045
2 files changed
+21 -11

No files matched your search

+15 -10
View File
@@ -280,17 +280,22 @@ async function refresh(){
function copyLogs(){ function copyLogs(){
const box = document.getElementById('logBox'); const box = document.getElementById('logBox');
const text = Array.from(box.querySelectorAll('.log-line')).map(l => l.textContent).join('\\n'); const text = Array.from(box.querySelectorAll('.log-line')).map(l => l.textContent).join('\\n');
navigator.clipboard.writeText(text).then(() => {
const btn = document.getElementById('btnCopyLogs'); const btn = document.getElementById('btnCopyLogs');
btn.textContent = 'Copié !'; function onSuccess(){ btn.textContent = 'Copié !'; setTimeout(() => { btn.textContent = 'Copier les logs'; }, 2000); }
setTimeout(() => { btn.textContent = 'Copier les logs'; }, 2000); if(navigator.clipboard && window.isSecureContext){
}).catch(() => { navigator.clipboard.writeText(text).then(onSuccess).catch(fallback);
const sel = window.getSelection(); } else {
const range = document.createRange(); fallback();
range.selectNodeContents(box); }
sel.removeAllRanges(); function fallback(){
sel.addRange(range); const ta = document.createElement('textarea');
}); ta.value = text;
ta.style.cssText = 'position:fixed;top:-9999px;left:-9999px;opacity:0';
document.body.appendChild(ta);
ta.focus(); ta.select();
try{ document.execCommand('copy'); onSuccess(); } catch(e){ alert('Copie manuelle : sélectionnez les logs et Ctrl+C'); }
document.body.removeChild(ta);
}
} }
async function runSync(){ async function runSync(){
+6 -1
View File
@@ -46,7 +46,12 @@ async function syncRanking(force) {
date_calcul_mag: r.DATE_CALCUL_MAG || null, date_calcul_mag: r.DATE_CALCUL_MAG || null,
})); }));
const count = await batchUpsert(pg, 'ranking', rows, ['gencod', 'site'], COLS); // Dédupliquer par (gencod, site) — garder la dernière occurrence
const seen = new Map();
for (const r of rows) seen.set(`${r.gencod}|${r.site}`, r);
const deduped = Array.from(seen.values());
const count = await batchUpsert(pg, 'ranking', deduped, ['gencod', 'site'], COLS);
await logSync(pg, 'ranking', count, 'ok'); await logSync(pg, 'ranking', count, 'ok');
console.log(`[ranking] ${count} lignes upsert`); console.log(`[ranking] ${count} lignes upsert`);
} catch (err) { } catch (err) {