Skip to content

Commit 167bc46

Browse files
committed
feat: controllo integrità files allegati
1 parent 73859eb commit 167bc46

3 files changed

Lines changed: 627 additions & 13 deletions

File tree

modules/aggiornamenti/actions.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Modules\Aggiornamenti\Controlli\ColonneDuplicateViste;
2525
use Modules\Aggiornamenti\Controlli\Controllo;
2626
use Modules\Aggiornamenti\Controlli\DatiFattureElettroniche;
27+
use Modules\Aggiornamenti\Controlli\IntegritaFile;
2728
use Modules\Aggiornamenti\Controlli\PianoConti;
2829
use Modules\Aggiornamenti\Controlli\PianoContiRagioneSociale;
2930
use Modules\Aggiornamenti\Controlli\PluginDuplicati;
@@ -154,6 +155,7 @@
154155
PluginDuplicati::class,
155156
ReaValidi::class,
156157
TabelleLanguage::class,
158+
IntegritaFile::class,
157159
];
158160

159161
$results = [];

modules/aggiornamenti/controlli.php

Lines changed: 173 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,23 @@ function setPercentage(percent) {
188188
$("#progress .progress-bar span").text(percent + "%");
189189
}
190190
191+
/**
192+
* Formatta i bytes in formato leggibile
193+
* @param bytes
194+
* @param decimals
195+
*/
196+
function formatBytes(bytes, decimals = 2) {
197+
if (bytes === 0) return "0 Bytes";
198+
199+
const k = 1024;
200+
const dm = decimals < 0 ? 0 : decimals;
201+
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
202+
203+
const i = Math.floor(Math.log(bytes) / Math.log(k));
204+
205+
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
206+
}
207+
191208
/**
192209
*
193210
* @param controllo
@@ -205,15 +222,53 @@ function initcard(controllo, success, records) {
205222
206223
let card = `<div class="card ` + cssClass + `" id="controllo-` + controllo["id"] + `">
207224
<div class="card-header with-border">
208-
<h3 class="card-title">` + controllo["name"] + `</h3>
225+
<h3 class="card-title">` + controllo["name"];
226+
227+
// Aggiungi badge inline per il controllo IntegritaFile
228+
if (controllo["class"] === "Modules\\\\Aggiornamenti\\\\Controlli\\\\IntegritaFile" && !success && records.length > 0) {
229+
let orphanFiles = records.filter(r => r.tipo === "file_orfano");
230+
let orphanRecords = records.filter(r => r.tipo === "file_mancante");
231+
232+
if (orphanFiles.length > 0 || orphanRecords.length > 0) {
233+
if (orphanFiles.length > 0) {
234+
let totalSize = 0;
235+
orphanFiles.forEach(function(file) {
236+
if (file.dimensione_bytes) {
237+
totalSize += parseInt(file.dimensione_bytes);
238+
}
239+
});
240+
let sizeFormatted = totalSize > 0 ? formatBytes(totalSize) : "";
241+
card += ` <span class="badge badge-danger ml-2">
242+
<i class="fa fa-trash mr-1"></i>${orphanFiles.length} file${sizeFormatted ? " - " + sizeFormatted : ""}
243+
</span>`;
244+
}
245+
246+
if (orphanRecords.length > 0) {
247+
card += ` <span class="badge badge-warning ml-2">
248+
<i class="fa fa-database mr-1"></i>${orphanRecords.length} record
249+
</span>`;
250+
}
251+
}
252+
}
253+
254+
card += `</h3>
209255
<div class="card-tools pull-right">`;
210256
211-
// Aggiungi pulsante azione globale se il controllo lo supporta e ci sono record
257+
// Aggiungi pulsanti azione globale se il controllo lo supporta e ci sono record
212258
if (!success && records.length > 0 && hasGlobalActions(controllo)) {
213-
card += `
214-
<button type="button" class="btn btn-success btn-sm" data-controllo-id="` + controllo["id"] + `" data-controllo-class="` + controllo["class"] + `" onclick="eseguiAzioneGlobale(this)">
215-
<i class="fa fa-check-circle"></i> '.tr('Risolvi tutti i conflitti').'
216-
</button>`;
259+
// Pulsante specifico per IntegritaFile che esegue entrambe le operazioni
260+
if (controllo["class"] === "Modules\\\\Aggiornamenti\\\\Controlli\\\\IntegritaFile") {
261+
card += `
262+
<button type="button" class="btn btn-success btn-sm" data-controllo-id="` + controllo["id"] + `" data-controllo-class="` + controllo["class"] + `" data-action="remove_all_both" onclick="eseguiAzioneGlobaleConParametri(this)">
263+
<i class="fa fa-check-circle"></i> '.tr('Risolvi tutti i conflitti').'
264+
</button>`;
265+
} else {
266+
// Pulsante generico per altri controlli
267+
card += `
268+
<button type="button" class="btn btn-success btn-sm" data-controllo-id="` + controllo["id"] + `" data-controllo-class="` + controllo["class"] + `" onclick="eseguiAzioneGlobale(this)">
269+
<i class="fa fa-check-circle"></i> '.tr('Risolvi tutti i conflitti').'
270+
</button>`;
271+
}
217272
}
218273
219274
card += `
@@ -233,11 +288,11 @@ function initcard(controllo, success, records) {
233288
<table class="table table-striped table-hover table-sm table-bordered">
234289
<thead>
235290
<tr>
236-
<th width="15%">'.tr('Record').'</th>
291+
<th width="30%">'.tr('Record').'</th>
237292
<th>'.tr('Descrizione').'</th>`;
238293
239294
if (hasRowOptions) {
240-
card += `<th class="text-center" width="15%">'.tr('Opzioni').'</th>`;
295+
card += `<th class="text-center" width="12%">'.tr('Opzioni').'</th>`;
241296
}
242297
243298
card += `
@@ -271,7 +326,7 @@ function addRiga(controllo, card, record) {
271326
<td>` + record.descrizione + `</td>`;
272327
273328
if (hasOptions) {
274-
riga += `<td></td>`;
329+
riga += `<td class="text-center"></td>`;
275330
}
276331
277332
riga += `</tr>`;
@@ -281,7 +336,7 @@ function addRiga(controllo, card, record) {
281336
if (hasOptions) {
282337
const options_columns = riga.find("td").last();
283338
record.options.forEach(function (option, id){
284-
let button = `<button type="button" class="btn btn-` + option.color + `">
339+
let button = `<button type="button" class="btn btn-` + option.color + ` btn-sm ">
285340
<i class="` + option.icon + `"></i> ` + option.name + `
286341
</buttton>`;
287342
button = $(button);
@@ -310,7 +365,8 @@ function hasGlobalActions(controllo) {
310365
"Modules\\\\Aggiornamenti\\\\Controlli\\\\ReaValidi",
311366
"Modules\\\\Aggiornamenti\\\\Controlli\\\\ColonneDuplicateViste",
312367
"Modules\\\\Aggiornamenti\\\\Controlli\\\\PluginDuplicati",
313-
"Modules\\\\Aggiornamenti\\\\Controlli\\\\TabelleLanguage"
368+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\TabelleLanguage",
369+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\IntegritaFile"
314370
];
315371
316372
return controlliConAzioniGlobali.includes(controllo["class"]);
@@ -375,6 +431,17 @@ function getMessaggioConferma(controlloClass) {
375431
"'.tr('Migliorerà la coerenza del database multilingua').'",
376432
"'.tr('Operazione sicura e reversibile').'"
377433
]
434+
},
435+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\IntegritaFile": {
436+
titolo: "'.tr('Conferma operazioni di pulizia').'",
437+
descrizione: "'.tr('Sei sicuro di voler procedere con le operazioni di pulizia selezionate?').'",
438+
operazioni: [
439+
"'.tr('RIMOZIONE FILE ORFANI: Rimuoverà definitivamente tutti i file presenti nel filesystem ma non registrati nel database').'",
440+
"'.tr('RIMOZIONE RECORD ORFANI: Rimuoverà dal database tutti i record che puntano a file fisici inesistenti').'",
441+
"'.tr('I file e record eliminati non potranno essere recuperati').'",
442+
"'.tr('Libererà spazio su disco e pulirà il database da riferimenti non validi').'",
443+
"'.tr('Non può essere annullata').'"
444+
]
378445
}
379446
};
380447
@@ -474,10 +541,103 @@ function eseguiAzioneGlobale(buttonElement) {
474541
});
475542
}
476543
544+
/**
545+
* Esegue un azione globale con parametri specifici
546+
*/
547+
function eseguiAzioneGlobaleConParametri(button) {
548+
let controlloId = $(button).data("controllo-id");
549+
let controlloClass = $(button).data("controllo-class");
550+
let action = $(button).data("action");
551+
552+
// Usa la stessa logica della funzione esistente ma con parametri
553+
let messaggio = getMessaggioConferma(controlloClass);
554+
555+
// Genera la lista delle operazioni
556+
let operazioniHtml = "";
557+
messaggio.operazioni.forEach(function(operazione) {
558+
operazioniHtml += `<li>${operazione}</li>`;
559+
});
560+
561+
// Crea modal di conferma con lo stile del gestionale
562+
let modalHtml = `
563+
<div class="modal fade" id="modal-conferma-risoluzione" tabindex="-1" role="dialog">
564+
<div class="modal-dialog modal-lg" role="document">
565+
<div class="modal-content">
566+
<div class="modal-header">
567+
<h4 class="modal-title">
568+
<i class="fa fa-exclamation-triangle text-warning"></i>
569+
${messaggio.titolo}
570+
</h4>
571+
<button type="button" class="close" data-dismiss="modal">
572+
<span>&times;</span>
573+
</button>
574+
</div>
575+
<div class="modal-body">
576+
<p>${messaggio.descrizione}</p>
577+
<div class="alert alert-warning">
578+
<i class="fa fa-info-circle"></i>
579+
'.tr('Questa operazione:').'
580+
<ul class="mb-0 mt-2">
581+
${operazioniHtml}
582+
</ul>
583+
</div>
584+
</div>
585+
<div class="modal-footer">
586+
<button type="button" class="btn btn-default" data-dismiss="modal" style="float: left;">
587+
<i class="fa fa-times"></i> '.tr('Annulla').'
588+
</button>
589+
<button type="button" class="btn btn-warning" id="conferma-risoluzione" style="float: right;">
590+
<i class="fa fa-check"></i> '.tr('Procedi').'
591+
</button>
592+
<div style="clear: both;"></div>
593+
</div>
594+
</div>
595+
</div>
596+
</div>
597+
`;
598+
599+
// Rimuovi modal esistente se presente
600+
$("#modal-conferma-risoluzione").remove();
601+
602+
// Aggiungi modal al DOM
603+
$("body").append(modalHtml);
604+
605+
// Mostra modal con configurazione per evitare chiusura accidentale
606+
$("#modal-conferma-risoluzione").modal({
607+
backdrop: "static",
608+
keyboard: false,
609+
show: true
610+
});
611+
612+
// Gestisci click su conferma
613+
$("#conferma-risoluzione").on("click", function(e) {
614+
e.preventDefault();
615+
e.stopPropagation();
616+
617+
let confirmButton = $(this);
618+
let restoreConfirm = buttonLoading(confirmButton);
619+
620+
// Disabilita il pulsante di annulla durante l operazione
621+
$("#modal-conferma-risoluzione .btn-default").prop("disabled", true);
622+
623+
eseguiRisoluzioneGlobale(button, controlloId, controlloClass, function() {
624+
// Callback di successo: chiudi modal
625+
$("#modal-conferma-risoluzione").modal("hide");
626+
loadControllo(controlloId);
627+
}, function() {
628+
// Callback di errore: ripristina pulsanti
629+
buttonRestore(confirmButton, restoreConfirm);
630+
$("#modal-conferma-risoluzione .btn-default").prop("disabled", false);
631+
}, {action: action});
632+
633+
return false;
634+
});
635+
}
636+
477637
/**
478638
* Esegue effettivamente la risoluzione globale
479639
*/
480-
function eseguiRisoluzioneGlobale(button, controlloId, controlloClass, successCallback, errorCallback) {
640+
function eseguiRisoluzioneGlobale(button, controlloId, controlloClass, successCallback, errorCallback, params = {}) {
481641
let restore = buttonLoading(button);
482642
483643
$.ajax({
@@ -488,7 +648,7 @@ function eseguiRisoluzioneGlobale(button, controlloId, controlloClass, successCa
488648
id_module: globals.id_module,
489649
op: "controlli-action-global",
490650
controllo: controlloClass,
491-
params: {},
651+
params: params,
492652
},
493653
success: function(results) {
494654
// Rimuovi tutte le righe del controllo

0 commit comments

Comments
 (0)