mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-20 03:24:55 +00:00
Merge pull request #1721 from mhmdfy/column-arrangement
add column arrangement storage
This commit is contained in:
commit
ae3ba27e19
@ -105,7 +105,7 @@ public class DataResultTopComponent extends TopComponent implements DataResult,
|
||||
setTitle(title); // set the title
|
||||
setName(title);
|
||||
|
||||
putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.valueOf(isMain)); // set option to close compoment in GUI
|
||||
putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isMain); // set option to close compoment in GUI
|
||||
putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, true);
|
||||
putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, true);
|
||||
|
||||
@ -249,7 +249,6 @@ public class DataResultTopComponent extends TopComponent implements DataResult,
|
||||
|
||||
private void setCustomMode() {
|
||||
if (customModeName != null) {
|
||||
//putClientProperty("TopComponentAllowDockAnywhere", Boolean.TRUE);
|
||||
Mode mode = WindowManager.getDefault().findMode(customModeName);
|
||||
if (mode != null) {
|
||||
StringBuilder message = new StringBuilder("Found custom mode, setting: "); //NON-NLS
|
||||
|
@ -30,10 +30,15 @@ import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.TableColumnModelEvent;
|
||||
import javax.swing.event.TableColumnModelListener;
|
||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.view.OutlineView;
|
||||
@ -48,7 +53,11 @@ import org.openide.nodes.NodeMemberEvent;
|
||||
import org.openide.nodes.NodeReorderEvent;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbPreferences;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.ItemType;
|
||||
|
||||
/**
|
||||
* DataResult sortable table viewer
|
||||
@ -63,6 +72,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
private Set<Property<?>> propertiesAcc = new LinkedHashSet<>();
|
||||
private final DummyNodeListener dummyNodeListener = new DummyNodeListener();
|
||||
private static final String DUMMY_NODE_DISPLAY_NAME = NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.dummyNodeDisplayName");
|
||||
private Node currentRoot;
|
||||
|
||||
/**
|
||||
* Creates a DataResultViewerTable object that is compatible with node
|
||||
@ -86,7 +96,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
OutlineView ov = ((OutlineView) this.tableScrollPanel);
|
||||
ov.setAllowedDragActions(DnDConstants.ACTION_NONE);
|
||||
ov.setAllowedDropActions(DnDConstants.ACTION_NONE);
|
||||
|
||||
ov.getOutline().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
|
||||
@ -94,6 +103,29 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
ov.getOutline().setRootVisible(false);
|
||||
ov.getOutline().setDragEnabled(false);
|
||||
|
||||
ov.getOutline().getColumnModel().addColumnModelListener(new TableColumnModelListener() {
|
||||
@Override
|
||||
public void columnAdded(TableColumnModelEvent e) {}
|
||||
@Override
|
||||
public void columnRemoved(TableColumnModelEvent e) {}
|
||||
@Override
|
||||
public void columnMarginChanged(ChangeEvent e) {}
|
||||
@Override
|
||||
public void columnSelectionChanged(ListSelectionEvent e) {}
|
||||
|
||||
@Override
|
||||
public void columnMoved(TableColumnModelEvent e) {
|
||||
// change the order of the column in the array/hashset
|
||||
List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
Node.Property<?> prop = props.remove(e.getFromIndex());
|
||||
props.add(e.getToIndex(), prop);
|
||||
|
||||
propertiesAcc.clear();
|
||||
for (int j = 0; j < props.size(); ++j) {
|
||||
propertiesAcc.add(props.get(j));
|
||||
}
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Add mouse listener to perform action on double-click
|
||||
* A somewhat hacky way to perform action even if the column clicked
|
||||
@ -217,23 +249,19 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
throw new IllegalArgumentException(
|
||||
NbBundle.getMessage(this.getClass(), "DataResultViewerTable.illegalArgExc.noChildFromParent"));
|
||||
} else {
|
||||
Set<Property> allProperties = new LinkedHashSet<Property>();
|
||||
Set<Property> allProperties = new LinkedHashSet<>();
|
||||
while (firstChild != null) {
|
||||
for (PropertySet ps : firstChild.getPropertySets()) {
|
||||
//if (ps.getName().equals(Sheet.PROPERTIES)) {
|
||||
//return ps.getProperties();
|
||||
final Property[] props = ps.getProperties();
|
||||
final int propsNum = props.length;
|
||||
for (int i = 0; i < propsNum; ++i) {
|
||||
allProperties.add(props[i]);
|
||||
}
|
||||
//}
|
||||
}
|
||||
firstChild = firstChild.getChildren().getNodeAt(0);
|
||||
}
|
||||
|
||||
properties = allProperties.toArray(new Property[0]);
|
||||
//throw new IllegalArgumentException("Child Node doesn't have the regular PropertySet.");
|
||||
properties = allProperties.toArray(new Property<?>[0]);
|
||||
}
|
||||
return properties;
|
||||
|
||||
@ -253,7 +281,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
int childCount = 0;
|
||||
for (Node child : children.getNodes()) {
|
||||
if (++childCount > rows) {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
for (PropertySet ps : child.getPropertySets()) {
|
||||
final Property<?>[] props = ps.getProperties();
|
||||
@ -319,25 +347,20 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
* @param root The parent Node of the ContentNodes
|
||||
*/
|
||||
private void setupTable(final Node root) {
|
||||
//wrap to filter out children
|
||||
//note: this breaks the tree view mode in this generic viewer,
|
||||
//so wrap nodes earlier if want 1 level view
|
||||
//if (!(root instanceof TableFilterNode)) {
|
||||
/// root = new TableFilterNode(root, true);
|
||||
//}
|
||||
|
||||
em.setRootContext(root);
|
||||
|
||||
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
|
||||
final OutlineView ov = ((OutlineView) this.tableScrollPanel);
|
||||
|
||||
if (ov == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
propertiesAcc.clear();
|
||||
|
||||
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
|
||||
List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
|
||||
if(currentRoot != null && !propertiesAcc.isEmpty()) {
|
||||
storeProperties(currentRoot);
|
||||
}
|
||||
currentRoot = root;
|
||||
List<Node.Property<?>> props = loadProperties(currentRoot);
|
||||
|
||||
/*
|
||||
* OutlineView makes the first column be the result of
|
||||
@ -369,14 +392,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
|
||||
ov.setPropertyColumns(propStrings);
|
||||
// *****************************************************************
|
||||
|
||||
// // set the first entry
|
||||
// Children test = root.getChildren();
|
||||
// Node firstEntryNode = test.getNodeAt(0);
|
||||
// try {
|
||||
// this.getExplorerManager().setSelectedNodes(new Node[]{firstEntryNode});
|
||||
// } catch (PropertyVetoException ex) {}
|
||||
// show the horizontal scroll panel and show all the content & header
|
||||
int totalColumns = props.size();
|
||||
|
||||
@ -389,7 +405,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
|
||||
// get first 100 rows values for the table
|
||||
Object[][] content = null;
|
||||
Object[][] content;
|
||||
content = getRowValues(root, 100);
|
||||
|
||||
if (content != null) {
|
||||
@ -408,14 +424,61 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
ov.getOutline().getColumnModel().getColumn(colIndex).setPreferredWidth(colWidth);
|
||||
}
|
||||
}
|
||||
|
||||
// if there's no content just auto resize all columns
|
||||
if (content.length <= 0) {
|
||||
// turn on the auto resize
|
||||
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
}
|
||||
}
|
||||
|
||||
// if there's no content just auto resize all columns
|
||||
if (!(content.length > 0)) {
|
||||
// turn on the auto resize
|
||||
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
}
|
||||
|
||||
// Store the column arrangements of the given Node.
|
||||
private void storeProperties(Node root) {
|
||||
List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
for (int i = 0; i < props.size(); i++) {
|
||||
Property<?> prop = props.get(i);
|
||||
NbPreferences.forModule(this.getClass()).put(getUniqueName(root, prop), String.valueOf(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Load the column arrangement stored for the given node if exists.
|
||||
private List<Node.Property<?>> loadProperties(Node root) {
|
||||
propertiesAcc.clear();
|
||||
this.getAllChildPropertyHeadersRec(root, 100);
|
||||
List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
List<Node.Property<?>> orderedProps = new ArrayList<>(propertiesAcc);
|
||||
for (Property<?> prop : props) {
|
||||
Integer value = Integer.valueOf(NbPreferences.forModule(this.getClass()).get(getUniqueName(root, prop), "-1"));
|
||||
if (value >= 0) {
|
||||
/**
|
||||
* The original contents of orderedProps do not matter when setting the new ordered values. The reason
|
||||
* we copy propertiesAcc into it first is to give it the currect size so we can set() in any index.
|
||||
*/
|
||||
orderedProps.set(value, prop);
|
||||
}
|
||||
}
|
||||
propertiesAcc.clear();
|
||||
for (Property<?> prop : orderedProps) {
|
||||
propertiesAcc.add(prop);
|
||||
}
|
||||
return orderedProps;
|
||||
}
|
||||
|
||||
// Get unique name for node and it's property.
|
||||
private String getUniqueName(Node root, Property<?> prop) {
|
||||
ItemType type = ItemType.GENERIC;
|
||||
if(root instanceof TableFilterNode) {
|
||||
TableFilterNode filterNode = (TableFilterNode) root;
|
||||
type = filterNode.getItemType();
|
||||
}
|
||||
else {
|
||||
Logger.getLogger(DataResultViewerTable.class.getName()).log(Level.SEVERE, "Node is not TableFilterNode");
|
||||
}
|
||||
|
||||
return Case.getCurrentCase().getName() + "." + type + "."
|
||||
+ prop.getName().replaceAll("[^a-zA-Z0-9_]", "") + ".columnOrder";
|
||||
}
|
||||
|
||||
// Populate a two-dimensional array with rows of property values for up
|
||||
// to maxRows children of the node passed in.
|
||||
|
@ -349,7 +349,6 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
}
|
||||
playbin.getState();
|
||||
|
||||
//System.out.println("Seeking to " + timeStamp + "milliseconds.");
|
||||
if (!playbin.seek(timeStamp, unit)) {
|
||||
logger.log(Level.INFO, "There was a problem seeking to " + timeStamp + " " + unit.name().toLowerCase()); //NON-NLS
|
||||
}
|
||||
|
@ -18,9 +18,13 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.corecomponents;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.FilterNode;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.KnownFileFilterNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.ItemType;
|
||||
|
||||
/**
|
||||
* This class is used to filter the nodes that we want to show on the
|
||||
@ -32,6 +36,7 @@ import org.openide.util.NbBundle;
|
||||
public class TableFilterNode extends FilterNode {
|
||||
|
||||
private boolean createChild;
|
||||
private ItemType itemType;
|
||||
|
||||
/**
|
||||
* the constructor
|
||||
@ -39,6 +44,13 @@ public class TableFilterNode extends FilterNode {
|
||||
public TableFilterNode(Node arg, boolean crChild) {
|
||||
super(arg, TableFilterChildren.createInstance(arg, crChild));
|
||||
this.createChild = crChild;
|
||||
this.itemType = ItemType.GENERIC;
|
||||
}
|
||||
|
||||
public TableFilterNode(Node arg, boolean crChild, ItemType itemType) {
|
||||
super(arg, TableFilterChildren.createInstance(arg, crChild));
|
||||
this.createChild = crChild;
|
||||
this.itemType = itemType;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,4 +67,8 @@ public class TableFilterNode extends FilterNode {
|
||||
return super.getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return itemType;
|
||||
}
|
||||
}
|
||||
|
@ -486,4 +486,9 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.BLACKBOARD_ARTIFACT;
|
||||
}
|
||||
}
|
||||
|
@ -107,4 +107,9 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.BLACKBOARD_ARTIFACT_TAG;
|
||||
}
|
||||
}
|
||||
|
@ -121,4 +121,9 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.CONTENT_TAG;
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,11 @@ public class DataSourcesNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.DATA_SOURCES;
|
||||
}
|
||||
|
||||
/*
|
||||
* Custom Keys implementation that listens for new data sources being added.
|
||||
*/
|
||||
|
@ -146,6 +146,11 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.DELETED_CONTENT;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeletedContentsChildren extends ChildFactory<DeletedContent.DeletedContentFilter> {
|
||||
@ -275,6 +280,11 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.DELETED_CONTENT_CHILDREN;
|
||||
}
|
||||
|
||||
// update the display name when new events are fired
|
||||
private class DeletedContentNodeObserver implements Observer {
|
||||
|
||||
|
@ -100,4 +100,9 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.DIRECTORY;
|
||||
}
|
||||
}
|
||||
|
@ -40,4 +40,86 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
||||
public abstract boolean isLeafTypeNode();
|
||||
|
||||
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
|
||||
|
||||
public abstract ItemType getItemType();
|
||||
|
||||
public enum ItemType {
|
||||
GENERIC("Generic"),
|
||||
BLACKBOARD_ARTIFACT("BlackboardArtifact"),
|
||||
BLACKBOARD_ARTIFACT_TAG("BlackboardArtifactTag"),
|
||||
CONTENT_TAG("ContentTag"),
|
||||
DATA_SOURCES("DataSources"),
|
||||
DELETED_CONTENT("DeletedContent"),
|
||||
DELETED_CONTENT_CHILDREN("DeletedContentChildren"),
|
||||
DIRECTORY("Directory"),
|
||||
EMAIL_EXTRACTED_ROOT("EmailExtractedRoot"),
|
||||
EMAIL_EXTRACTED_ACCOUNT("EmailExtractedAccount"),
|
||||
EMAIL_EXTRACTED_FOLDER("EmailExtractedFolder"),
|
||||
EXTRACTED_CONTENT_ROOT("ExtractedContentRoot"),
|
||||
EXTRACTED_CONTENT_TYPE("ExtractedContentType"),
|
||||
EXTRACTED_BOOKMARKS("ExtractedBookmarks"),
|
||||
EXTRACTED_COOKIES("ExtractedCookies"),
|
||||
EXTRACTED_HISTORY("ExtractedHistory"),
|
||||
EXTRACTED_DOWNLOADS("ExtractedDownloads"),
|
||||
EXTRACTED_PROGRAMS("ExtractedPrograms"),
|
||||
EXTRACTED_RECENT("ExtractedRecent"),
|
||||
EXTRACTED_ATTACHED_DEVICES("ExtractedAttachedDevices"),
|
||||
EXTRACTED_SEARCH("ExtractedSearch"),
|
||||
EXTRACTED_METADATA_EXIF("ExtractedMetadataExif"),
|
||||
EXTRACTED_EMAIL_MSG("ExtractedEmailMsg"),
|
||||
EXTRACTED_CONTACTS("ExtractedContacts"),
|
||||
EXTRACTED_MESSAGES("ExtractedMessages"),
|
||||
EXTRACTED_CALL_LOG("ExtractedCallLog"),
|
||||
EXTRACTED_CALENDAR("ExtractedCalendar"),
|
||||
EXTRACTED_SPEED_DIAL("ExtractedSpeedDial"),
|
||||
EXTRACTED_BLUETOOTH("ExtractedBluetooth"),
|
||||
EXTRACTED_GPS_BOOKMARKS("ExtractedGPSBookmarks"),
|
||||
EXTRACTED_GPS_LAST_LOCATION("ExtractedGPSLastLocation"),
|
||||
EXTRACTED_GPS_SEARCH("ExtractedGPSSearch"),
|
||||
EXTRACTED_SERVICE_ACCOUNT("ExtractedServiceAccount"),
|
||||
EXTRACTED_ENCRYPTION("ExtractedEncryption"),
|
||||
EXTRACTED_EXT_MISMATCH("ExtractedExtMismatch"),
|
||||
EXTRACTED_OS("ExtractedOS"),
|
||||
EXTRACTED_FACE_DETECTED("ExtractedFaceDetected"),
|
||||
FILE("File"),
|
||||
FILE_SIZE_ROOT("FileSizeRoot"),
|
||||
FILE_SIZE("FileSize"),
|
||||
FILE_TYPE("FileType"),
|
||||
FILE_TYPES("FileTypes"),
|
||||
FILE_TYPES_DOC("FileTypesDoc"),
|
||||
FILE_TYPES_EXE("FileTypesExe"),
|
||||
HASHSET_ROOT("HashsetRoot"),
|
||||
HASHSET_NAME("HashsetName"),
|
||||
IMAGE("Image"),
|
||||
INTERESTING_HITS_ROOT("InterestingHitsRoot"),
|
||||
INTERESTING_HITS_SET_NAME("InterestingHitsSetName"),
|
||||
KEYWORD_ROOT("KeywordRoot"),
|
||||
KEYWORD_LIST("KeywordList"),
|
||||
KEYWORD_TERM("KeywordTerm"),
|
||||
LAYOUT_FILE("LayoutFile"),
|
||||
LOCAL_FILE("LocalFile"),
|
||||
RECENT_FILES("RecentFiles"),
|
||||
RECENT_FILES_FILTER("RecentFilesFilter"),
|
||||
REPORTS("Reports"),
|
||||
REPORTS_LIST("ReportsList"),
|
||||
RESULTS("Results"),
|
||||
TAGS_ROOT("TagsRoots"),
|
||||
TAGS_NAME("TagsName"),
|
||||
TAGS_CONTENT_TYPE("TagsContentType"),
|
||||
TAGS_BLACKBOARD_ARTIFACT("TagsBlackboardArtifact"),
|
||||
VIEWS("Views"),
|
||||
VIRTUAL_DIRECTORY("VirtualDirectory"),
|
||||
VOLUME("Volume"),
|
||||
EVENT("Event"),
|
||||
EVENT_ROOT("EventRoot");
|
||||
|
||||
private final String name;
|
||||
private ItemType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,6 +190,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.EMAIL_EXTRACTED_ROOT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,6 +345,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.EMAIL_EXTRACTED_ACCOUNT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,6 +436,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.EMAIL_EXTRACTED_FOLDER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,6 +118,11 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.EXTRACTED_CONTENT_ROOT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -367,6 +372,62 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
switch (type) {
|
||||
case TSK_WEB_BOOKMARK:
|
||||
return ItemType.EXTRACTED_BOOKMARKS;
|
||||
case TSK_WEB_COOKIE:
|
||||
return ItemType.EXTRACTED_COOKIES;
|
||||
case TSK_WEB_HISTORY:
|
||||
return ItemType.EXTRACTED_HISTORY;
|
||||
case TSK_WEB_DOWNLOAD:
|
||||
return ItemType.EXTRACTED_DOWNLOADS;
|
||||
case TSK_INSTALLED_PROG:
|
||||
return ItemType.EXTRACTED_PROGRAMS;
|
||||
case TSK_RECENT_OBJECT:
|
||||
return ItemType.EXTRACTED_RECENT;
|
||||
case TSK_DEVICE_ATTACHED:
|
||||
return ItemType.EXTRACTED_ATTACHED_DEVICES;
|
||||
case TSK_WEB_SEARCH_QUERY:
|
||||
return ItemType.EXTRACTED_SEARCH;
|
||||
case TSK_METADATA_EXIF:
|
||||
return ItemType.EXTRACTED_METADATA_EXIF;
|
||||
case TSK_EMAIL_MSG:
|
||||
return ItemType.EXTRACTED_EMAIL_MSG;
|
||||
case TSK_CONTACT:
|
||||
return ItemType.EXTRACTED_CONTACTS;
|
||||
case TSK_MESSAGE:
|
||||
return ItemType.EXTRACTED_MESSAGES;
|
||||
case TSK_CALLLOG:
|
||||
return ItemType.EXTRACTED_CALL_LOG;
|
||||
case TSK_CALENDAR_ENTRY:
|
||||
return ItemType.EXTRACTED_CALENDAR;
|
||||
case TSK_SPEED_DIAL_ENTRY:
|
||||
return ItemType.EXTRACTED_SPEED_DIAL;
|
||||
case TSK_BLUETOOTH_PAIRING:
|
||||
return ItemType.EXTRACTED_BLUETOOTH;
|
||||
case TSK_GPS_BOOKMARK:
|
||||
return ItemType.EXTRACTED_GPS_BOOKMARKS;
|
||||
case TSK_GPS_LAST_KNOWN_LOCATION:
|
||||
return ItemType.EXTRACTED_GPS_LAST_LOCATION;
|
||||
case TSK_GPS_SEARCH:
|
||||
return ItemType.EXTRACTED_GPS_SEARCH;
|
||||
case TSK_SERVICE_ACCOUNT:
|
||||
return ItemType.EXTRACTED_SERVICE_ACCOUNT;
|
||||
case TSK_ENCRYPTION_DETECTED:
|
||||
return ItemType.EXTRACTED_ENCRYPTION;
|
||||
case TSK_EXT_MISMATCH_DETECTED:
|
||||
return ItemType.EXTRACTED_EXT_MISMATCH;
|
||||
case TSK_OS_INFO:
|
||||
return ItemType.EXTRACTED_OS;
|
||||
case TSK_FACE_DETECTED:
|
||||
return ItemType.EXTRACTED_FACE_DETECTED;
|
||||
|
||||
}
|
||||
return ItemType.EXTRACTED_CONTENT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,4 +183,9 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
// not will check if it has children using the Content API
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.FILE;
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +143,11 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.FILE_SIZE_ROOT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -281,6 +286,11 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.FILE_SIZE;
|
||||
}
|
||||
|
||||
// update the display name when new events are fired
|
||||
private class FileSizeNodeObserver implements Observer {
|
||||
|
||||
|
@ -82,6 +82,11 @@ public class FileTypeNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.FILE_TYPE;
|
||||
}
|
||||
|
||||
// update the display name when new events are fired
|
||||
private class FileTypeNodeObserver implements Observer {
|
||||
|
||||
|
@ -39,7 +39,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
public class FileTypesNode extends DisplayableItemNode {
|
||||
|
||||
private static final String FNAME = NbBundle.getMessage(FileTypesNode.class, "FileTypesNode.fname.text");
|
||||
|
||||
private final FileTypeExtensionFilters.RootFilter filter;
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
@ -48,7 +48,8 @@ public class FileTypesNode extends DisplayableItemNode {
|
||||
*/
|
||||
FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) {
|
||||
super(Children.create(new FileTypesChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
init(filter);
|
||||
this.filter = filter;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,10 +61,11 @@ public class FileTypesNode extends DisplayableItemNode {
|
||||
*/
|
||||
private FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) {
|
||||
super(Children.create(new FileTypesChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
init(filter);
|
||||
this.filter = filter;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init(FileTypeExtensionFilters.RootFilter filter) {
|
||||
private void init() {
|
||||
// root node of tree
|
||||
if (filter == null) {
|
||||
super.setName(FNAME);
|
||||
@ -102,6 +104,17 @@ public class FileTypesNode extends DisplayableItemNode {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
if(filter == null)
|
||||
return ItemType.FILE_TYPES;
|
||||
if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER))
|
||||
return ItemType.FILE_TYPES_DOC;
|
||||
if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER))
|
||||
return ItemType.FILE_TYPES_EXE;
|
||||
return ItemType.FILE_TYPES;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -168,6 +168,11 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.HASHSET_ROOT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -321,6 +326,11 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.HASHSET_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,4 +109,9 @@ public class ImageNode extends AbstractContentNode<Image> {
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.IMAGE;
|
||||
}
|
||||
}
|
||||
|
@ -161,6 +161,11 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.INTERESTING_HITS_ROOT;
|
||||
}
|
||||
}
|
||||
|
||||
private class SetNameFactory extends ChildFactory.Detachable<String> implements Observer {
|
||||
@ -307,6 +312,11 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.INTERESTING_HITS_SET_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
private class HitFactory extends ChildFactory<Long> implements Observer {
|
||||
|
@ -239,6 +239,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.KEYWORD_ROOT;
|
||||
}
|
||||
}
|
||||
|
||||
private class ListFactory extends ChildFactory.Detachable<String> implements Observer {
|
||||
@ -389,6 +394,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.KEYWORD_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
private class TermFactory extends ChildFactory.Detachable<String> implements Observer {
|
||||
@ -482,6 +492,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.KEYWORD_TERM;
|
||||
}
|
||||
}
|
||||
|
||||
public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
|
||||
|
@ -38,6 +38,11 @@ import org.sleuthkit.datamodel.TskData;
|
||||
*/
|
||||
public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.LAYOUT_FILE;
|
||||
}
|
||||
|
||||
public static enum LayoutContentPropertyType {
|
||||
|
||||
PARTS {
|
||||
|
@ -115,4 +115,9 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
// not will check if it has children using the Content API
|
||||
return true; //!this.hasContentChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.LOCAL_FILE;
|
||||
}
|
||||
}
|
||||
|
@ -82,4 +82,9 @@ public class RecentFilesFilterNode extends DisplayableItemNode {
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.RECENT_FILES_FILTER;
|
||||
}
|
||||
}
|
||||
|
@ -65,4 +65,9 @@ public class RecentFilesNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.RECENT_FILES;
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,11 @@ public final class Reports implements AutopsyVisitableItem {
|
||||
// - ShowItemVisitor.visit() returns true.
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.REPORTS_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -209,6 +214,11 @@ public final class Reports implements AutopsyVisitableItem {
|
||||
return new OpenReportAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.REPORTS;
|
||||
}
|
||||
|
||||
private static class DeleteReportAction extends AbstractAction {
|
||||
|
||||
private static DeleteReportAction instance;
|
||||
|
@ -68,4 +68,9 @@ public class ResultsNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.RESULTS;
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,11 @@ public class Tags implements AutopsyVisitableItem {
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "TagsNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "TagsNode.createSheet.name.displayName"), "", getName()));
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TAGS_ROOT;
|
||||
}
|
||||
}
|
||||
|
||||
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
|
||||
@ -265,6 +270,11 @@ public class Tags implements AutopsyVisitableItem {
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TAGS_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,6 +370,11 @@ public class Tags implements AutopsyVisitableItem {
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TAGS_CONTENT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
private class ContentTagNodeFactory extends ChildFactory<ContentTag> implements Observer {
|
||||
@ -453,6 +468,11 @@ public class Tags implements AutopsyVisitableItem {
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TAGS_BLACKBOARD_ARTIFACT;
|
||||
}
|
||||
}
|
||||
|
||||
private class BlackboardArtifactTagNodeFactory extends ChildFactory<BlackboardArtifactTag> implements Observer {
|
||||
|
@ -72,4 +72,9 @@ public class ViewsNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.VIEWS;
|
||||
}
|
||||
}
|
||||
|
@ -148,4 +148,9 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.VIRTUAL_DIRECTORY;
|
||||
}
|
||||
}
|
||||
|
@ -189,4 +189,9 @@ public class VolumeNode extends AbstractContentNode<Volume> {
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.VOLUME;
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DataSources;
|
||||
import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits;
|
||||
import org.sleuthkit.autopsy.datamodel.KnownFileFilterNode;
|
||||
@ -630,7 +631,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
//set node, wrap in filter node first to filter out children
|
||||
Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);
|
||||
Node kffn = new KnownFileFilterNode(drfn, KnownFileFilterNode.getSelectionContext(originNode));
|
||||
dataResult.setNode(new TableFilterNode(kffn, true));
|
||||
if(originNode instanceof DisplayableItemNode) {
|
||||
dataResult.setNode(new TableFilterNode(kffn, true, ((DisplayableItemNode) originNode).getItemType()));
|
||||
} else {
|
||||
dataResult.setNode(new TableFilterNode(kffn, true));
|
||||
}
|
||||
|
||||
String displayName = "";
|
||||
Content content = originNode.getLookup().lookup(Content.class);
|
||||
|
@ -139,7 +139,6 @@ class ContactAnalyzer {
|
||||
name = resultSet.getString("display_name"); //NON-NLS
|
||||
data1 = resultSet.getString("data1"); //NON-NLS
|
||||
mimetype = resultSet.getString("mimetype"); //NON-NLS
|
||||
// System.out.println(resultSet.getString("data1") + resultSet.getString("mimetype") + resultSet.getString("display_name")); //Test code
|
||||
if (name.equals(oldName) == false) {
|
||||
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), moduleName, name));
|
||||
|
@ -134,7 +134,6 @@ class ContactAnalyzer {
|
||||
name = resultSet.getString("display_name"); //NON-NLS
|
||||
data1 = resultSet.getString("data1"); //NON-NLS
|
||||
mimetype = resultSet.getString("mimetype"); //NON-NLS
|
||||
// System.out.println(resultSet.getString("data1") + resultSet.getString("mimetype") + resultSet.getString("display_name")); //Test code
|
||||
if (name.equals(oldName) == false) {
|
||||
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), moduleName, name));
|
||||
@ -198,8 +197,6 @@ class ContactAnalyzer {
|
||||
int c;
|
||||
final int EOF = -1;
|
||||
istream = new ReadContentInputStream(file);
|
||||
//File outFile = new File("Data.txt");
|
||||
// System.out.println("Type characters to write in File – Press Ctrl+z to end ");
|
||||
try {
|
||||
ostream = new FileOutputStream(jFile);
|
||||
while ((c = istream.read()) != EOF) {
|
||||
|
@ -181,7 +181,6 @@ class EvalURLHistoryObj extends EvaluatableObject {
|
||||
}
|
||||
if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE.getTypeID())
|
||||
&& (havePageTitle)) {
|
||||
//System.out.println("Page title: " + attr.getValueString() + " " + entry.getPageTitle());
|
||||
foundPageTitleMatch = compareStringObject(entry.getPageTitle(),
|
||||
attr.getValueString());
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.autopsy.datamodel.ItemType;
|
||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
@ -121,6 +122,11 @@ class EventNode extends DisplayableItemNode {
|
||||
throw new UnsupportedOperationException("Not supported yet."); // NON-NLS //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.EVENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* We use TimeProperty instead of a normal NodeProperty to correctly display
|
||||
* the date/time when the user changes the timezone setting.
|
||||
|
@ -34,6 +34,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.ItemType;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ -70,6 +71,11 @@ public class EventRootNode extends DisplayableItemNode {
|
||||
return childCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getItemType() {
|
||||
return ItemType.EVENT_ROOT;
|
||||
}
|
||||
|
||||
/**
|
||||
* The node factories used to make lists of files to send to the result
|
||||
* viewer using the lazy loading (rather than background) loading option to
|
||||
|
@ -185,7 +185,6 @@ class SearchEngineURLQueryAnalyzer extends Extract {
|
||||
}
|
||||
|
||||
SearchEngineURLQueryAnalyzer.SearchEngine Se = new SearchEngineURLQueryAnalyzer.SearchEngine(EngineName, EnginedomainSubstring, keys);
|
||||
//System.out.println("Search Engine: " + Se.toString());
|
||||
listEngines[i] = Se;
|
||||
}
|
||||
engines = listEngines;
|
||||
|
Loading…
x
Reference in New Issue
Block a user