/*
* (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Thierry Delprat
* Florent Guillaume
*/
package org.nuxeo.ecm.webapp.action;
import java.io.Serializable;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.core.Events;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.international.StatusMessage;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.DocumentRef;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.security.SecurityConstants;
import org.nuxeo.ecm.core.trash.TrashInfo;
import org.nuxeo.ecm.core.trash.TrashService;
import org.nuxeo.ecm.platform.actions.Action;
import org.nuxeo.ecm.platform.ui.web.api.NavigationContext;
import org.nuxeo.ecm.platform.ui.web.api.WebActions;
import org.nuxeo.ecm.platform.util.RepositoryLocation;
import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager;
import org.nuxeo.ecm.webapp.edit.lock.LockActions;
import org.nuxeo.ecm.webapp.trashManagement.TrashManager;
import org.nuxeo.runtime.api.Framework;
import static org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager.CURRENT_DOCUMENT_SECTION_SELECTION;
import static org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager.CURRENT_DOCUMENT_SELECTION;
import static org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager.CURRENT_DOCUMENT_TRASH_SELECTION;
import static org.nuxeo.ecm.webapp.helpers.EventNames.DOCUMENT_CHILDREN_CHANGED;
@Name("deleteActions")
@Scope(ScopeType.EVENT)
@Install(precedence = Install.FRAMEWORK)
public class DeleteActionsBean implements DeleteActions, Serializable {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(DeleteActionsBean.class);
@In(create = true, required = false)
protected FacesMessages facesMessages;
@In(create = true)
protected Map<String, String> messages;
@In(create = true, required = false)
protected transient CoreSession documentManager;
@In(create = true, required = false)
protected RepositoryLocation currentServerLocation;
@In(create = true)
protected transient DocumentsListsManager documentsListsManager;
@In(create = true)
protected NavigationContext navigationContext;
@In(create = true)
protected transient TrashManager trashManager;
@In(create = true)
protected transient LockActions lockActions;
@In(create = true)
protected transient WebActions webActions;
@In
protected transient Principal currentUser;
protected transient TrashService trashService;
protected TrashService getTrashService() {
if (trashService == null) {
trashService = Framework.getService(TrashService.class);
}
return trashService;
}
@Override
public boolean getCanDeleteItem(DocumentModel container) {
if (container == null) {
return false;
}
return getTrashService().folderAllowsDelete(container);
}
@Override
public boolean getCanDelete() {
return getCanDelete(CURRENT_DOCUMENT_SELECTION);
}
@Override
public boolean getCanDelete(String listName) {
List<DocumentModel> docs = documentsListsManager.getWorkingList(listName);
return getTrashService().canDelete(docs, currentUser, false);
}
@Override
public boolean getCanDeleteSections() {
List<DocumentModel> docs = documentsListsManager.getWorkingList(CURRENT_DOCUMENT_SECTION_SELECTION);
return getTrashService().canDelete(docs, currentUser, true);
}
@Override
public boolean getCanPurge() {
List<DocumentModel> docs = documentsListsManager.getWorkingList(CURRENT_DOCUMENT_TRASH_SELECTION);
return getTrashService().canPurgeOrUndelete(docs, currentUser);
}
public boolean getCanEmptyTrash() {
List<DocumentModel> selectedDocuments = documentsListsManager.getWorkingList(CURRENT_DOCUMENT_TRASH_SELECTION);
if (selectedDocuments.size() == 0) {
DocumentModelList currentTrashDocuments = getTrashService().getDocuments(navigationContext.getCurrentDocument());
return getTrashService().canPurgeOrUndelete(currentTrashDocuments, currentUser);
}
return false;
}
@Override
public boolean checkDeletePermOnParents(List<DocumentModel> docs) {
return getTrashService().checkDeletePermOnParents(docs);
}
@Override
public String deleteSelection() {
if (!documentsListsManager.isWorkingListEmpty(CURRENT_DOCUMENT_SELECTION)) {
return deleteSelection(documentsListsManager.getWorkingList(CURRENT_DOCUMENT_SELECTION));
} else {
log.debug("No documents selection in context to process delete on...");
return null;
}
}
@Override
public String deleteSelectionSections() {
if (!documentsListsManager.isWorkingListEmpty(CURRENT_DOCUMENT_SECTION_SELECTION)) {
return deleteSelection(documentsListsManager.getWorkingList(CURRENT_DOCUMENT_SECTION_SELECTION));
} else {
log.debug("No documents selection in context to process delete on...");
return null;
}
}
protected static final int OP_DELETE = 1, OP_PURGE = 2, OP_UNDELETE = 3;
@Override
public String deleteSelection(List<DocumentModel> docs) {
int op = isTrashManagementEnabled() ? OP_DELETE : OP_PURGE;
return actOnSelection(op, docs);
}
public String emptyTrash() {
DocumentModelList currentTrashDocuments = trashService.getDocuments(navigationContext.getCurrentDocument());
return purgeSelection(currentTrashDocuments);
}
@Override
public String purgeSelection() {
return purgeSelection(CURRENT_DOCUMENT_TRASH_SELECTION);
}
@Override
public String purgeSelection(String listName) {
if (!documentsListsManager.isWorkingListEmpty(listName)) {
return purgeSelection(documentsListsManager.getWorkingList(listName));
} else {
log.debug("No documents selection in context to process delete on...");
return null;
}
}
@Override
public String purgeSelection(List<DocumentModel> docs) {
return actOnSelection(OP_PURGE, docs);
}
@Override
public String undeleteSelection() {
if (!documentsListsManager.isWorkingListEmpty(CURRENT_DOCUMENT_TRASH_SELECTION)) {
return undeleteSelection(documentsListsManager.getWorkingList(CURRENT_DOCUMENT_TRASH_SELECTION));
} else {
log.debug("No documents selection in context to process delete on...");
return null;
}
}
@Override
public String undeleteSelection(List<DocumentModel> docs) {
return actOnSelection(OP_UNDELETE, docs);
}
protected String actOnSelection(int op, List<DocumentModel> docs) {
if (docs == null) {
return null;
}
TrashInfo info = getTrashService().getTrashInfo(docs, currentUser, false, false);
DocumentModel targetContext = getTrashService().getAboveDocument(navigationContext.getCurrentDocument(),
info.rootPaths);
// remove from all lists
documentsListsManager.removeFromAllLists(info.docs);
Set<DocumentRef> parentRefs;
String msgid;
// operation to do
switch (op) {
case OP_PURGE:
getTrashService().purgeDocuments(documentManager, info.rootRefs);
parentRefs = info.rootParentRefs;
msgid = "n_deleted_docs";
break;
case OP_DELETE:
getTrashService().trashDocuments(info.docs);
parentRefs = info.rootParentRefs;
msgid = "n_deleted_docs";
break;
case OP_UNDELETE:
parentRefs = getTrashService().undeleteDocuments(info.docs);
msgid = "n_undeleted_docs";
break;
default:
throw new AssertionError(op);
}
// Update context if needed
if (op == OP_UNDELETE) {
// undelete is problematic because it may change undeleted
// parent's paths... so we refetch the new context
targetContext = documentManager.getDocument(new IdRef(targetContext.getId()));
} else if (targetContext == null) {
// handle placeless document
targetContext = documentManager.getRootDocument();
}
navigationContext.setCurrentDocument(targetContext);
// Notify parents
if (parentRefs.isEmpty()) {
// Globally refresh content views
Events.instance().raiseEvent(DOCUMENT_CHILDREN_CHANGED);
} else {
for (DocumentRef parentRef : parentRefs) {
if (documentManager.hasPermission(parentRef, SecurityConstants.READ)) {
DocumentModel parent = documentManager.getDocument(parentRef);
if (parent != null) {
Events.instance().raiseEvent(DOCUMENT_CHILDREN_CHANGED, parent);
}
}
}
}
// User feedback
if (info.proxies > 0) {
facesMessages.add(StatusMessage.Severity.WARN, "can_not_delete_proxies");
}
Object[] params = { Integer.valueOf(info.docs.size()) };
facesMessages.add(StatusMessage.Severity.INFO, "#0 " + messages.get(msgid), params);
return null;
}
@Override
public boolean isTrashManagementEnabled() {
return trashManager.isTrashManagementEnabled();
}
public List<Action> getActionsForTrashSelection() {
return webActions.getActionsList(CURRENT_DOCUMENT_TRASH_SELECTION + "_LIST", false);
}
@Override
public void create() {
}
@Override
public void destroy() {
}
@Override
public void restoreCurrentDocument() {
List<DocumentModel> doc = new ArrayList<DocumentModel>();
doc.add(navigationContext.getCurrentDocument());
undeleteSelection(doc);
}
@Override
public boolean getCanRestoreCurrentDoc() {
DocumentModel doc = navigationContext.getCurrentDocument();
if (doc == null) {
// this shouldn't happen, if it happens probably there is a
// customization bug, we guard this though
log.warn("Null currentDocument in navigationContext");
return false;
}
return getTrashService().canPurgeOrUndelete(Collections.singletonList(doc), currentUser);
}
public boolean restoreActionDisplay() {
return getCanRestoreCurrentDoc() && isTrashManagementEnabled();
}
}