From 84d7fbd7352c9d539bf4d031f3e88f25c3085891 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Fri, 26 Jun 2015 14:19:06 -0400 Subject: [PATCH] Delete report/s implemented. Misc bugs fixed --- .../autopsy/casemodule/Bundle.properties | 4 +- .../sleuthkit/autopsy/casemodule/Case.java | 41 ++++++++++++++++- .../autopsy/datamodel/Bundle.properties | 3 ++ .../sleuthkit/autopsy/datamodel/Reports.java | 45 ++++++++++++++++++- .../directorytree/DataResultFilterNode.java | 5 ++- .../sleuthkit/autopsy/report/ReportKML.java | 1 + 6 files changed, 95 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 0d42366b0b..ec12ed5a4d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -220,4 +220,6 @@ XMLCaseManagement.open.msgDlg.notAutCase.msg=Error\: This is not an Autopsy conf Detail\: \n\ Cannot open a non-Autopsy config file (at {1}). XMLCaseManagement.open.msgDlg.notAutCase.title=Error -AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel \ No newline at end of file +AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel +Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk. +Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 298435eeb0..ff8b522e69 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -29,6 +29,7 @@ import java.nio.file.InvalidPathException; import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.Collection; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; @@ -39,6 +40,7 @@ import java.util.TimeZone; import java.util.logging.Level; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; +import org.apache.commons.io.FileUtils; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; @@ -128,7 +130,13 @@ public class Case implements SleuthkitCase.ErrorObserver { * case. The old value supplied by the event object is null and the new * value is a reference to a Report object representing the new report. */ - REPORT_ADDED; + REPORT_ADDED, + /** + * Name for the property change event when a report/s is/are deleted + * from the case. Both the old value and the new value supplied by the + * event object are null. + */ + REPORTS_DELETED; }; private String name; @@ -1185,6 +1193,37 @@ public class Case implements SleuthkitCase.ErrorObserver { return this.db.getAllReports(); } + public void deleteReports(Collection reports) throws TskCoreException { + + String pathToReportsFolder = Paths.get(this.db.getDbDirPath(), "Reports").normalize().toString(); + for (Report report : reports) { + // traverse to the root directory of Report report. + String reportPath = report.getPath(); + while (!Paths.get(reportPath, "..").normalize().toString().equals(pathToReportsFolder)) { + reportPath = Paths.get(reportPath, "..").normalize().toString(); + } + + // delete from the disk. + try { + FileUtils.deleteDirectory(new File(reportPath)); + } catch (IOException | SecurityException ex) { + logger.log(Level.WARNING, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.log.msg"), ex); + JOptionPane.showMessageDialog(null, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.msg", report.getReportName(), reportPath)); + } + + // delete from the database. + this.db.deleteReport(report); + + // fire property change event. + try { + Case.pcs.firePropertyChange(Events.REPORTS_DELETED.toString(), null, null); + } catch (Exception ex) { + String errorMessage = String.format("A Case %s listener threw an exception", Events.REPORTS_DELETED.toString()); //NON-NLS + logger.log(Level.SEVERE, errorMessage, ex); + } + } + } + /** * Returns if the case has data in it yet. * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index bc28375e08..fa16107ea7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -280,3 +280,6 @@ VolumeNode.createSheet.flags.displayName=Flags VolumeNode.createSheet.flags.desc=no description AbstractAbstractFileNode.objectId=Object ID ArtifactStringContent.getStr.artifactId.text=Artifact ID +DeleteReportAction.actionDisplayName=Delete Report(s) +DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion +DeleteReportAction.actionPerformed.showConfirmDialog.msg=Delete {0} reports.\nClick OK to proceed. \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java index 9822227d7a..8237aa1e32 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.logging.Level; import javax.swing.AbstractAction; @@ -37,8 +38,10 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.TskCoreException; @@ -97,7 +100,7 @@ public final class Reports implements AutopsyVisitableItem { @Override public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); - if (eventType.equals(Case.Events.REPORT_ADDED.toString())) { + if (eventType.equals(Case.Events.REPORT_ADDED.toString()) || eventType.equals(Case.Events.REPORTS_DELETED.toString())) { ReportNodeFactory.this.refresh(true); } } @@ -183,6 +186,7 @@ public final class Reports implements AutopsyVisitableItem { List actions = new ArrayList<>(); actions.addAll(Arrays.asList(super.getActions(true))); actions.add(new OpenReportAction()); + actions.add(DeleteReportAction.getInstance()); return actions.toArray(new Action[actions.size()]); } @@ -191,6 +195,45 @@ public final class Reports implements AutopsyVisitableItem { return new OpenReportAction(); } + private static class DeleteReportAction extends AbstractAction { + + private static DeleteReportAction instance; + + // This class is a singleton to support multi-selection of nodes, + // since org.openide.nodes.NodeOp.findActions(Node[] nodes) will + // only pick up an Action if every node in the array returns a + // reference to the same action object from Node.getActions(boolean). + private static DeleteReportAction getInstance() { + if (instance == null) { + instance = new DeleteReportAction(); + } + return instance; + } + + /** + * Do not instantiate directly. Use + * DeleteReportAction.getInstance(), instead. + */ + private DeleteReportAction() { + super(NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionDisplayName")); + } + + @Override + public void actionPerformed(ActionEvent e) { + Collection selectedReportsCollection = Utilities.actionsGlobalContext().lookupAll(Report.class); + if (JOptionPane.showConfirmDialog(null, + NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionPerformed.showConfirmDialog.title"), + NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionPerformed.showConfirmDialog.msg", selectedReportsCollection.size()), + JOptionPane.OK_CANCEL_OPTION) == 0) { + try { + Case.getCurrentCase().deleteReports(selectedReportsCollection); + DataContentTopComponent.findInstance().repaint(); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DeleteReportAction.class.getName()).log(Level.INFO, "Error deleting the reports. ", ex); // NON-NLS - Provide solution to the user? + } + } + } + } private final class OpenReportAction extends AbstractAction { private OpenReportAction() { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index f6fed23038..c620ba01b9 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -118,7 +118,10 @@ public class DataResultFilterNode extends FilterNode { List actions = new ArrayList<>(); final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); - actions.addAll(originalNode.accept(getActionsDIV)); + List accept = originalNode.accept(getActionsDIV); + if(accept != null) { + actions.addAll(accept); + } //actions.add(new IndexContentFilesAction(nodeContent, "Index")); return actions.toArray(new Action[actions.size()]); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index 061329bf4a..74784e2136 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -321,6 +321,7 @@ class ReportKML implements GeneralReportModule { // read the next line line = reader.readLine(); } + reader.close(); progressPanel.increment(); /* * Step 4: write the XML file