// scanner/scanPhoto.js const path = require('path'); const fs = require('fs'); const fsp = require('fs/promises'); const { loadPreviousIndex, saveIndex } = require('./indexStore'); const scanCartella = require('./scanCartella'); const postWithAuth = require('./postWithAuth'); const { WEB_ROOT, SEND_PHOTOS, BASE_URL, WRITE_INDEX } = require('../config'); const createCleanupFunctions = require('./orphanCleanup'); async function scanPhoto(dir, userName, db) { console.log(`[SCAN] Avvio scanPhoto per user=${userName}`); // Log di configurazione (utile per diagnosi) console.log('[SCAN] Config:', { WEB_ROOT, SEND_PHOTOS, BASE_URL, WRITE_INDEX }); // 1) Carico l’indice precedente (fonte unica durante la run) const previousIndexTree = await loadPreviousIndex(); // <— RAM source // 2) Clono l’indice per costruire il nuovo const nextIndexTree = JSON.parse(JSON.stringify(previousIndexTree || {})); // Funzioni di cleanup (solo thumbs + DB) // NOTA: con Opzione A NON leggiamo più l'indice da file e NON aggiorniamo index.json "in itinere" const { // buildIdsListForFolder, // <— NON usato in Opzione A removeIdFromList, deleteThumbsById, deleteFromDB // deleteFromIndexById // <— NON usato in Opzione A } = createCleanupFunctions(db); // [1](https://electrolux-my.sharepoint.com/personal/fabio_micheluz_electrolux_com/Documents/File%20di%20Microsoft%20Copilot%20Chat/orphanCleanup.js.txt) const photosRoot = path.resolve(__dirname, '..', '..', WEB_ROOT, 'photos'); const userDir = path.join(photosRoot, userName, 'original'); let changes = []; // --------------------------------------------------------- // SCAN DI UNA SINGOLA CARTELLA // --------------------------------------------------------- async function scanSingleFolder(user, cartella, absCartella) { console.log(`\n==============================================`); console.log(`[SCAN] CARTELLA → ${user}/${cartella}`); console.log("=============================================="); // Costruisci idsIndex dall'indice in RAM (previousIndexTree) // Fonte unica di verità per questa run → evita drift con il file su disco. let idsIndex = Object.keys(previousIndexTree?.[user]?.[cartella] || {}) .filter(k => k !== '_folderHash'); // <— niente metadati console.log(`[ORPHAN] ID iniziali in RAM (${idsIndex.length}):`); idsIndex.forEach(id => console.log(" -", id)); // File reali trovati nella cartella const folderFiles = await scanCartella( user, cartella, absCartella, previousIndexTree ); // [2](https://electrolux-my.sharepoint.com/personal/fabio_micheluz_electrolux_com/Documents/File%20di%20Microsoft%20Copilot%20Chat/scanCartella.js.txt) for (const m of folderFiles) { const prev = previousIndexTree?.[m.user]?.[m.cartella]?.[m.id]; // 🔥 FILE INVARIATO if (prev && prev.hash === m._indexHash) { console.log(`[SCAN] SKIP (unchanged) → ${m.path}`); // Rimuovo SOLO dalla lista orfani (dalla RAM) idsIndex = removeIdFromList(idsIndex, m.id); // [1](https://electrolux-my.sharepoint.com/personal/fabio_micheluz_electrolux_com/Documents/File%20di%20Microsoft%20Copilot%20Chat/orphanCleanup.js.txt) continue; } // 🔥 FILE NUOVO O MODIFICATO → aggiorno nextIndexTree nextIndexTree[m.user] ??= {}; nextIndexTree[m.user][m.cartella] ??= {}; nextIndexTree[m.user][m.cartella][m.id] = { id: m.id, user: m.user, cartella: m.cartella, path: m.path, hash: m._indexHash }; // Rimuovo dalla lista orfani (in RAM) idsIndex = removeIdFromList(idsIndex, m.id); // [1](https://electrolux-my.sharepoint.com/personal/fabio_micheluz_electrolux_com/Documents/File%20di%20Microsoft%20Copilot%20Chat/orphanCleanup.js.txt) changes.push(m); } // --------------------------------------------------------- // ORFANI → rimuovo SOLO da nextIndexTree + thumbs + DB // --------------------------------------------------------- if (idsIndex.length > 0) { console.log(`[ORPHAN] ID orfani trovati nella cartella ${cartella}:`); idsIndex.forEach(id => console.log(" -", id)); } else { console.log(`[ORPHAN] Nessun ID orfano nella cartella ${cartella}`); } for (const orphanId of idsIndex) { console.log(`\n[ORPHAN] Eliminazione ID → ${orphanId}`); // 1) Cancello thumbs const thumbsDeleted = await deleteThumbsById(orphanId); // [1](https://electrolux-my.sharepoint.com/personal/fabio_micheluz_electrolux_com/Documents/File%20di%20Microsoft%20Copilot%20Chat/orphanCleanup.js.txt) console.log(` → thumbsDeleted = ${thumbsDeleted}`); // 2) Cancello dal DB const dbDeleted = deleteFromDB(orphanId); // [1](https://electrolux-my.sharepoint.com/personal/fabio_micheluz_electrolux_com/Documents/File%20di%20Microsoft%20Copilot%20Chat/orphanCleanup.js.txt) console.log(` → dbDeleted = ${dbDeleted}`); // 3) Cancello SOLO da nextIndexTree (in RAM) const userTree = nextIndexTree[user]; if (userTree && userTree[cartella] && userTree[cartella][orphanId]) { delete userTree[cartella][orphanId]; console.log(` → nextIndexTree updated (removed ${orphanId})`); } console.log(`[ORPHAN] COMPLETATO → ${orphanId}`); } console.log(`==============================================\n`); } // --------------------------------------------------------- // SCAN SOLO SOTTOCARTELLE — niente _root // --------------------------------------------------------- let entries = []; try { entries = await fsp.readdir(userDir, { withFileTypes: true }); } catch { console.log(`[SCAN] Nessuna directory per utente ${userName}`); return []; } for (const e of entries) { if (!e.isDirectory()) continue; const cartella = e.name; const absCartella = path.join(userDir, cartella); await scanSingleFolder(userName, cartella, absCartella); } // --------------------------------------------------------- // SALVO SOLO nextIndexTree (scrittura unica a fine run) // --------------------------------------------------------- if (WRITE_INDEX) { await saveIndex(nextIndexTree); // [1](https://electrolux-my.sharepoint.com/personal/fabio_micheluz_electrolux_com/Documents/File%20di%20Microsoft%20Copilot%20Chat/orphanCleanup.js.txt) } // --------------------------------------------------------- // INVIO AL SERVER // --------------------------------------------------------- if (SEND_PHOTOS && BASE_URL && changes.length) { for (const p of changes) { try { await postWithAuth(`${BASE_URL}/photos`, p); } catch (err) { console.error('Errore invio:', err.message); } } } console.log(`SCAN COMPLETATA: ${changes.length} file aggiornati`); return changes; } module.exports = scanPhoto;