mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
. Soft Delete UI checkpoint
- List of deleted items for an individual user - Object details page for a deleted item - Reworking of some of the Deleted Items UI - Filter by user/date HTML complete (no implementation yet) - Recover a single item to a specific location - I18N messages added for sys:archive aspect and properties git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2817 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -49,7 +49,9 @@ import org.alfresco.web.bean.repository.Node;
|
||||
import org.alfresco.web.bean.repository.NodePropertyResolver;
|
||||
import org.alfresco.web.bean.repository.QNameNodeMap;
|
||||
import org.alfresco.web.bean.repository.Repository;
|
||||
import org.alfresco.web.bean.wizard.NewSpaceWizard;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.Utils.URLMode;
|
||||
import org.alfresco.web.ui.common.component.UIActionLink;
|
||||
import org.alfresco.web.ui.common.component.data.UIRichList;
|
||||
|
||||
@@ -58,6 +60,8 @@ import org.alfresco.web.ui.common.component.data.UIRichList;
|
||||
*/
|
||||
public class TrashcanBean implements IContextListener
|
||||
{
|
||||
private static final String MSG_DELETED_ITEMS_FOR = "deleted_items_for";
|
||||
private static final String MSG_DELETED_ITEMS = "deleted_items";
|
||||
private static final String MSG_RECOVERED_ITEM_INTEGRITY = "recovered_item_integrity";
|
||||
private static final String MSG_RECOVERED_ITEM_PERMISSION = "recovered_item_permission";
|
||||
private static final String MSG_RECOVERED_ITEM_PARENT = "recovered_item_parent";
|
||||
@@ -69,11 +73,15 @@ public class TrashcanBean implements IContextListener
|
||||
private static final String RICHLIST_ID = "trashcan-list";
|
||||
private static final String RICHLIST_MSG_ID = "trashcan" + ':' + RICHLIST_ID;
|
||||
|
||||
private final static String NAME_ATTR = Repository.escapeQName(ContentModel.PROP_NAME);
|
||||
private final static String NAME_ATTR = Repository.escapeQName(ContentModel.PROP_NAME);
|
||||
private final static String USER_ATTR = Repository.escapeQName(ContentModel.PROP_ARCHIVED_BY);
|
||||
|
||||
private final static String SEARCH_ALL = "PARENT:\"%s\" AND ASPECT:\"%s\"";
|
||||
private final static String SEARCH_NAME = "PARENT:\"%s\" AND ASPECT:\"%s\" AND (@" + NAME_ATTR + ":*%s* TEXT:%s)";
|
||||
private final static String SEARCH_NAME_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND (@" + NAME_ATTR + ":\"%s\" TEXT:\"%s\")";
|
||||
private final static String SEARCH_NAME = "PARENT:\"%s\" AND ASPECT:\"%s\" AND @" + NAME_ATTR + ":*%s*";
|
||||
private final static String SEARCH_TEXT = "PARENT:\"%s\" AND ASPECT:\"%s\" AND TEXT:%s";
|
||||
private final static String SEARCH_NAME_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND @" + NAME_ATTR + ":\"%s\"";
|
||||
private final static String SEARCH_TEXT_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND TEXT:\"%s\"";
|
||||
private final static String SEARCH_USERPREFIX = "@" + USER_ATTR + ":%s AND ";
|
||||
|
||||
/** NodeService bean reference */
|
||||
protected NodeService nodeService;
|
||||
@@ -96,6 +104,8 @@ public class TrashcanBean implements IContextListener
|
||||
/** We show an empty list until a Search or Show All is executed */
|
||||
private boolean showItems = false;
|
||||
|
||||
private boolean fullTextSearch = false;
|
||||
|
||||
/** Currently listed items */
|
||||
private List<Node> listedItems = Collections.<Node>emptyList();
|
||||
|
||||
@@ -105,6 +115,9 @@ public class TrashcanBean implements IContextListener
|
||||
/** Root node to the spaces store archive store*/
|
||||
private NodeRef archiveRootRef = null;
|
||||
|
||||
/** Alternative destination for recovered items */
|
||||
private NodeRef destination = null;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Bean property getters and setters
|
||||
@@ -173,6 +186,67 @@ public class TrashcanBean implements IContextListener
|
||||
this.searchText = searchText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the alternative destination to use if recovery fails.
|
||||
*/
|
||||
public NodeRef getDestination()
|
||||
{
|
||||
return this.destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param destination The alternative destination to use if recovery fails.
|
||||
*/
|
||||
public void setDestination(NodeRef destination)
|
||||
{
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Message to display in the title of the panel area
|
||||
*/
|
||||
public String getPanelMessage()
|
||||
{
|
||||
FacesContext fc = FacesContext.getCurrentInstance();
|
||||
String msg = Application.getMessage(fc, MSG_DELETED_ITEMS);
|
||||
if (isAdminUser() == false)
|
||||
{
|
||||
msg = msg + ' ' + MessageFormat.format(
|
||||
Application.getMessage(fc, MSG_DELETED_ITEMS_FOR), Application.getCurrentUser(fc).getUserName());
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to the content for the current document item
|
||||
*
|
||||
* @return Content url to the current document item
|
||||
*/
|
||||
public String getItemBrowserUrl()
|
||||
{
|
||||
return Utils.generateURL(FacesContext.getCurrentInstance(), getItem(), URLMode.HTTP_INLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the download URL to the content for the current document item
|
||||
*
|
||||
* @return Download url to the current document item
|
||||
*/
|
||||
public String getItemDownloadUrl()
|
||||
{
|
||||
return Utils.generateURL(FacesContext.getCurrentInstance(), getItem(), URLMode.HTTP_DOWNLOAD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Alfresco NodeRef URL for the current item node
|
||||
*
|
||||
* @return the Alfresco NodeRef URL
|
||||
*/
|
||||
public String getItemNodeRefUrl()
|
||||
{
|
||||
return getItem().getNodeRef().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the listed items.
|
||||
*/
|
||||
@@ -244,27 +318,24 @@ public class TrashcanBean implements IContextListener
|
||||
{
|
||||
QName type = this.nodeService.getType(nodeRef);
|
||||
|
||||
MapNode node = new MapNode(nodeRef, this.nodeService, false);
|
||||
|
||||
node.addPropertyResolver("locationPath", resolverLocationPath);
|
||||
node.addPropertyResolver("displayPath", resolverDisplayPath);
|
||||
node.addPropertyResolver("deletedDate", resolverDeletedDate);
|
||||
node.addPropertyResolver("deletedBy", resolverDeletedBy);
|
||||
node.addPropertyResolver("isFolder", resolverIsFolder);
|
||||
|
||||
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true &&
|
||||
this.dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER) == false)
|
||||
{
|
||||
MapNode node = new MapNode(nodeRef, this.nodeService, false);
|
||||
node.addPropertyResolver("locationPath", resolverLocationPath);
|
||||
node.addPropertyResolver("displayPath", resolverDisplayPath);
|
||||
node.addPropertyResolver("deletedDate", resolverDeletedDate);
|
||||
node.addPropertyResolver("deletedBy", resolverDeletedBy);
|
||||
node.addPropertyResolver("typeIcon", this.resolverSmallIcon);
|
||||
itemNodes.add(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
MapNode node = new MapNode(nodeRef, this.nodeService, false);
|
||||
node.addPropertyResolver("locationPath", resolverLocationPath);
|
||||
node.addPropertyResolver("displayPath", resolverDisplayPath);
|
||||
node.addPropertyResolver("deletedDate", resolverDeletedDate);
|
||||
node.addPropertyResolver("deletedBy", resolverDeletedBy);
|
||||
node.addPropertyResolver("typeIcon", this.resolverFileType16);
|
||||
itemNodes.add(node);
|
||||
}
|
||||
itemNodes.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,15 +363,12 @@ public class TrashcanBean implements IContextListener
|
||||
|
||||
private NodePropertyResolver resolverLocationPath = new NodePropertyResolver() {
|
||||
public Object get(Node node) {
|
||||
//ChildAssociationRef childRef = (ChildAssociationRef)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC);
|
||||
//return nodeService.getPath(childRef.getChildRef());
|
||||
return (Path)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PATH);
|
||||
}
|
||||
};
|
||||
|
||||
private NodePropertyResolver resolverDisplayPath = new NodePropertyResolver() {
|
||||
public Object get(Node node) {
|
||||
//ChildAssociationRef childRef = (ChildAssociationRef)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC);
|
||||
return Repository.getDisplayPath((Path)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PATH));
|
||||
}
|
||||
};
|
||||
@@ -319,6 +387,20 @@ public class TrashcanBean implements IContextListener
|
||||
}
|
||||
};
|
||||
|
||||
private NodePropertyResolver resolverFileType32 = new NodePropertyResolver() {
|
||||
public Object get(Node node) {
|
||||
return Utils.getFileTypeImage(node.getName(), false);
|
||||
}
|
||||
};
|
||||
|
||||
private NodePropertyResolver resolverLargeIcon = new NodePropertyResolver() {
|
||||
public Object get(Node node) {
|
||||
QNameNodeMap props = (QNameNodeMap)node.getProperties();
|
||||
String icon = (String)props.getRaw("app:icon");
|
||||
return "/images/icons/" + (icon != null ? icon : NewSpaceWizard.SPACE_ICON_DEFAULT) + ".gif";
|
||||
}
|
||||
};
|
||||
|
||||
private NodePropertyResolver resolverDeletedDate = new NodePropertyResolver() {
|
||||
public Object get(Node node) {
|
||||
return node.getProperties().get(ContentModel.PROP_ARCHIVED_DATE);
|
||||
@@ -331,23 +413,42 @@ public class TrashcanBean implements IContextListener
|
||||
}
|
||||
};
|
||||
|
||||
private NodePropertyResolver resolverIsFolder = new NodePropertyResolver() {
|
||||
public Object get(Node node) {
|
||||
return dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_FOLDER);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Action handlers
|
||||
|
||||
// TODO:
|
||||
// need the following Action Handlers:
|
||||
// deleteItemOK, recoverItemOK, deleteAllItemsOK, recoverAllItemsOK, recoverListedItemsOK, deleteListedItemsOK
|
||||
// deleteAllItemsOK, recoverAllItemsOK, recoverListedItemsOK, deleteListedItemsOK
|
||||
|
||||
/**
|
||||
* Search the deleted item store by name
|
||||
*/
|
||||
public void search(ActionEvent event)
|
||||
public void searchName(ActionEvent event)
|
||||
{
|
||||
// simply clear the current list and refresh the screen
|
||||
// the search query text will be found and processed by the getItems() method
|
||||
contextUpdated();
|
||||
this.showItems = true;
|
||||
this.fullTextSearch = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the deleted item store by text
|
||||
*/
|
||||
public void searchContent(ActionEvent event)
|
||||
{
|
||||
// simply clear the current list and refresh the screen
|
||||
// the search query text will be found and processed by the getItems() method
|
||||
contextUpdated();
|
||||
this.showItems = true;
|
||||
this.fullTextSearch = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,11 +477,24 @@ public class TrashcanBean implements IContextListener
|
||||
NodeRef ref = new NodeRef(getArchiveRootRef().getStoreRef(), id);
|
||||
Node node = new Node(ref);
|
||||
|
||||
// resolve icon in-case one has not been set
|
||||
//node.addPropertyResolver("icon", this.resolverSpaceIcon);
|
||||
node.addPropertyResolver("locationPath", resolverLocationPath);
|
||||
node.addPropertyResolver("deletedDate", resolverDeletedDate);
|
||||
node.addPropertyResolver("deletedBy", resolverDeletedBy);
|
||||
node.addPropertyResolver("isFolder", resolverIsFolder);
|
||||
|
||||
if (this.dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_FOLDER) == true &&
|
||||
this.dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_SYSTEM_FOLDER) == false)
|
||||
{
|
||||
node.addPropertyResolver("icon", this.resolverLargeIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
node.addPropertyResolver("icon", this.resolverFileType32);
|
||||
}
|
||||
|
||||
// prepare a node for the action context
|
||||
setItem(node);
|
||||
setDestination(null);
|
||||
}
|
||||
catch (InvalidNodeRefException refErr)
|
||||
{
|
||||
@@ -397,6 +511,9 @@ public class TrashcanBean implements IContextListener
|
||||
contextUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete single item OK button handler
|
||||
*/
|
||||
public String deleteItemOK()
|
||||
{
|
||||
Node item = getItem();
|
||||
@@ -421,6 +538,9 @@ public class TrashcanBean implements IContextListener
|
||||
return OUTCOME_DIALOGCLOSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover single item OK button handler
|
||||
*/
|
||||
public String recoverItemOK()
|
||||
{
|
||||
String outcome = null;
|
||||
@@ -434,7 +554,16 @@ public class TrashcanBean implements IContextListener
|
||||
String msg;
|
||||
FacesMessage errorfacesMsg = null;
|
||||
|
||||
RestoreNodeReport report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef());
|
||||
// restore the node - the user may have requested a restore to a different parent
|
||||
RestoreNodeReport report;
|
||||
if (this.destination == null)
|
||||
{
|
||||
report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef());
|
||||
}
|
||||
else
|
||||
{
|
||||
report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef(), this.destination, null, null);
|
||||
}
|
||||
switch (report.getStatus())
|
||||
{
|
||||
case SUCCESS:
|
||||
@@ -496,7 +625,7 @@ public class TrashcanBean implements IContextListener
|
||||
*/
|
||||
public void resetAll(ActionEvent event)
|
||||
{
|
||||
// TODO: reset all filter and search
|
||||
// TODO: reset all filters
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -540,16 +669,43 @@ public class TrashcanBean implements IContextListener
|
||||
String safeText = QueryParser.escape(this.searchText);
|
||||
if (safeText.indexOf(' ') == -1)
|
||||
{
|
||||
query = String.format(SEARCH_NAME, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText, safeText);
|
||||
if (this.fullTextSearch)
|
||||
{
|
||||
query = String.format(SEARCH_TEXT, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = String.format(SEARCH_NAME, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query = String.format(SEARCH_NAME_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText, safeText);
|
||||
if (this.fullTextSearch)
|
||||
{
|
||||
query = String.format(SEARCH_TEXT_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = String.format(SEARCH_NAME_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isAdminUser() == false)
|
||||
{
|
||||
// prefix username clause
|
||||
String username = Application.getCurrentUser(FacesContext.getCurrentInstance()).getUserName();
|
||||
query = String.format(SEARCH_USERPREFIX, username) + query;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private boolean isAdminUser()
|
||||
{
|
||||
return Application.getCurrentUser(FacesContext.getCurrentInstance()).isAdmin();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// IContextListener implementation
|
||||
|
Reference in New Issue
Block a user