const path = require('path'); const fsp = require('fs/promises'); const scanCartella = require('./scanCartella'); const processFile = require('./processFile'); const { sha256 } = require('./utils'); const createCleanupFunctions = require('./orphanCleanup'); const { WEB_ROOT } = require('../config'); const { log } = require('./logger'); // --------------------------------------------------------- // NORMALIZZAZIONE PATH (toglie /app/...) // --------------------------------------------------------- function normalizeRelPath(user, dirPath, fileName) { if (!dirPath) return ""; let rel = dirPath.replace(/\\/g, "/"); // Rimuove tutto fino a /photos/ rel = rel.replace(/^.*\/photos\//, ""); // Ora rel = "Fabio/original/2017Irlanda/.../" const prefix = `${user}/original/`; if (rel.startsWith(prefix)) { rel = rel.slice(prefix.length); } if (rel.startsWith("/")) rel = rel.slice(1); // Aggiunge il file if (fileName) { rel = `${rel}/${fileName}`.replace(/\/+/g, "/"); } return rel; // es: "2017Irlanda19-29ago/IMG_0120.JPG" } // --------------------------------------------------------- // CALCOLO ID IDENTICO AL VECCHIO SCAN // --------------------------------------------------------- function computeId(user, relPath) { const parts = relPath.split('/').filter(Boolean); const cartella = parts[0]; const fileRelPath = parts.slice(1).join('/'); const id = sha256(`${user}/${cartella}/${fileRelPath}`); return { id, cartella, fileRelPath }; } // --------------------------------------------------------- // 1) ADD FILE // --------------------------------------------------------- async function handleAddFile(user, dirPath, fileName, db) { const relPath = normalizeRelPath(user, dirPath, fileName); log(`🟦 [ADD] user=${user} file=${relPath}`); // 🔥 Ricostruzione identica al vecchio scanPhoto const parts = relPath.split('/'); const cartella = parts[0]; // es: "2017Irlanda19-29ago" const fileRelPath = parts.slice(1).join('/'); // es: "IMG_0116.JPG" const photosRoot = path.resolve(__dirname, '..', '..', WEB_ROOT, 'photos'); const absPath = path.join(photosRoot, user, 'original', cartella, fileRelPath); const ext = path.extname(fileName).toLowerCase(); const st = await fsp.stat(absPath); // 🔥 FIX: processFile deve ricevere fileRelPath completo di "original/" const meta = await processFile( user, cartella, path.posix.join('original', cartella, fileRelPath), absPath, ext, st ); // Inserimento identico al vecchio scanPhoto const row = { id: meta.id, user, cartella, name: meta.name, path: meta.path, thub1: meta.thub1, thub2: meta.thub2, mime_type: meta.mime_type, width: meta.width, height: meta.height, rotation: meta.rotation, size_bytes: meta.size_bytes, mtimeMs: meta.mtimeMs, duration_ms: meta.duration_ms ?? null, taken_at: meta.taken_at ?? null, data: meta.data ?? null, lat: meta.gps?.lat ?? null, lon: meta.gps?.lng ?? null, alt: meta.gps?.alt ?? null, location: meta.location ? JSON.stringify(meta.location) : null }; await db('photos') .insert(row) .onConflict('id') .merge(); log(`🟢 [ADD] Inserito/aggiornato id=${meta.id}`); return row; } // --------------------------------------------------------- // 2) DELETE FILE // --------------------------------------------------------- async function handleDeleteFile(user, dirPath, fileName, db) { const relPath = normalizeRelPath(user, dirPath, fileName); log(`🟥 [DEL] user=${user} file=${relPath}`); const { id } = computeId(user, relPath); const { deleteThumbsById, deleteFromDB } = createCleanupFunctions(db); await deleteThumbsById(id); await deleteFromDB(id, user); log(`🔴 [DEL] File eliminato id=${id}`); return { deleted: id }; } // --------------------------------------------------------- // 3) ADD DIRECTORY // --------------------------------------------------------- async function handleAddDir(user, dir, db) { log(`🟦 [ADD_DIR] user=${user} dir=${dir}`); const photosRoot = path.resolve(__dirname, '..', '..', WEB_ROOT, 'photos'); const absDir = path.join(photosRoot, user, 'original', dir); log(`📁 [ADD_DIR] absDir=${absDir}`); let results = []; for await (const f of scanCartella(user, dir, absDir, db)) { log(`📄 [ADD_DIR] File trovato: ${f.relPath}`); const meta = await processFile( user, dir, f.relPath, f.absPath, f.ext, f.stat ); await db('photos').insert(meta).onConflict('id').merge(); log(`🟢 [ADD_DIR] Inserito/aggiornato id=${meta.id} name=${meta.name}`); results.push(meta); } log(`🟣 [ADD_DIR] Completato. Files=${results.length}`); return results; } // --------------------------------------------------------- // 4) DELETE DIRECTORY // --------------------------------------------------------- async function handleDeleteDir(user, dir, db) { log(`🟥 [DEL_DIR] user=${user} dir=${dir}`); const rows = await db('photos') .where({ user, cartella: dir }) .select('id'); const { deleteThumbsById, deleteFromDB } = createCleanupFunctions(db); log(`📁 [DEL_DIR] Trovati ${rows.length} file da eliminare`); for (const r of rows) { log(`🗑️ [DEL_DIR] Eliminazione id=${r.id}`); await deleteThumbsById(r.id); await deleteFromDB(r.id, user); } log(`🔴 [DEL_DIR] Cartella eliminata. Totale file=${rows.length}`); return { deleted: rows.length }; } module.exports = { handleAddFile, handleDeleteFile, handleAddDir, handleDeleteDir };