001/* 002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Thierry Delprat 018 * Florent Guillaume 019 */ 020 021package org.nuxeo.ecm.webapp.action; 022 023import static org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager.CURRENT_DOCUMENT_SECTION_SELECTION; 024import static org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager.CURRENT_DOCUMENT_SELECTION; 025import static org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager.CURRENT_DOCUMENT_TRASH_SELECTION; 026import static org.nuxeo.ecm.webapp.helpers.EventNames.DOCUMENT_CHILDREN_CHANGED; 027 028import java.io.Serializable; 029import java.security.Principal; 030import java.util.ArrayList; 031import java.util.List; 032import java.util.Map; 033import java.util.Set; 034 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037import org.jboss.seam.ScopeType; 038import org.jboss.seam.annotations.In; 039import org.jboss.seam.annotations.Install; 040import org.jboss.seam.annotations.Name; 041import org.jboss.seam.annotations.Scope; 042import org.jboss.seam.core.Events; 043import org.jboss.seam.faces.FacesMessages; 044import org.jboss.seam.international.StatusMessage; 045import org.nuxeo.ecm.core.api.CoreSession; 046import org.nuxeo.ecm.core.api.DocumentModel; 047import org.nuxeo.ecm.core.api.DocumentModelList; 048import org.nuxeo.ecm.core.api.DocumentRef; 049import org.nuxeo.ecm.core.api.IdRef; 050import org.nuxeo.ecm.core.api.security.SecurityConstants; 051import org.nuxeo.ecm.core.trash.TrashInfo; 052import org.nuxeo.ecm.core.trash.TrashService; 053import org.nuxeo.ecm.platform.actions.Action; 054import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 055import org.nuxeo.ecm.platform.ui.web.api.WebActions; 056import org.nuxeo.ecm.platform.util.RepositoryLocation; 057import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager; 058import org.nuxeo.ecm.webapp.edit.lock.LockActions; 059import org.nuxeo.ecm.webapp.trashManagement.TrashManager; 060import org.nuxeo.runtime.api.Framework; 061 062@Name("deleteActions") 063@Scope(ScopeType.EVENT) 064@Install(precedence = Install.FRAMEWORK) 065public class DeleteActionsBean implements DeleteActions, Serializable { 066 067 private static final long serialVersionUID = 1L; 068 069 private static final Log log = LogFactory.getLog(DeleteActionsBean.class); 070 071 @In(create = true, required = false) 072 protected FacesMessages facesMessages; 073 074 @In(create = true) 075 protected Map<String, String> messages; 076 077 @In(create = true, required = false) 078 protected transient CoreSession documentManager; 079 080 @In(create = true, required = false) 081 protected RepositoryLocation currentServerLocation; 082 083 @In(create = true) 084 protected transient DocumentsListsManager documentsListsManager; 085 086 @In(create = true) 087 protected NavigationContext navigationContext; 088 089 @In(create = true) 090 protected transient TrashManager trashManager; 091 092 @In(create = true) 093 protected transient LockActions lockActions; 094 095 @In(create = true) 096 protected transient WebActions webActions; 097 098 @In 099 protected transient Principal currentUser; 100 101 protected transient TrashService trashService; 102 103 protected TrashService getTrashService() { 104 if (trashService == null) { 105 trashService = Framework.getService(TrashService.class); 106 } 107 return trashService; 108 } 109 110 @Override 111 public boolean getCanDeleteItem(DocumentModel container) { 112 if (container == null) { 113 return false; 114 } 115 return getTrashService().folderAllowsDelete(container); 116 } 117 118 @Override 119 public boolean getCanDelete() { 120 return getCanDelete(CURRENT_DOCUMENT_SELECTION); 121 } 122 123 @Override 124 public boolean getCanDelete(String listName) { 125 List<DocumentModel> docs = documentsListsManager.getWorkingList(listName); 126 return getTrashService().canDelete(docs, currentUser, false); 127 } 128 129 @Override 130 public boolean getCanDeleteSections() { 131 List<DocumentModel> docs = documentsListsManager.getWorkingList(CURRENT_DOCUMENT_SECTION_SELECTION); 132 return getTrashService().canDelete(docs, currentUser, true); 133 } 134 135 @Override 136 public boolean getCanPurge() { 137 List<DocumentModel> docs = documentsListsManager.getWorkingList(CURRENT_DOCUMENT_TRASH_SELECTION); 138 return getTrashService().canPurgeOrUntrash(docs, currentUser); 139 } 140 141 public boolean getCanEmptyTrash() { 142 List<DocumentModel> selectedDocuments = documentsListsManager.getWorkingList(CURRENT_DOCUMENT_TRASH_SELECTION); 143 if (selectedDocuments.size() == 0) { 144 DocumentModelList currentTrashDocuments = getTrashService().getDocuments(navigationContext.getCurrentDocument()); 145 return getTrashService().canPurgeOrUntrash(currentTrashDocuments, currentUser); 146 } 147 return false; 148 } 149 150 @Override 151 public boolean checkDeletePermOnParents(List<DocumentModel> docs) { 152 return getTrashService().checkDeletePermOnParents(docs); 153 } 154 155 @Override 156 public String deleteSelection() { 157 if (!documentsListsManager.isWorkingListEmpty(CURRENT_DOCUMENT_SELECTION)) { 158 return deleteSelection(documentsListsManager.getWorkingList(CURRENT_DOCUMENT_SELECTION)); 159 } else { 160 log.debug("No documents selection in context to process delete on..."); 161 return null; 162 } 163 } 164 165 @Override 166 public String deleteSelectionSections() { 167 if (!documentsListsManager.isWorkingListEmpty(CURRENT_DOCUMENT_SECTION_SELECTION)) { 168 return deleteSelection(documentsListsManager.getWorkingList(CURRENT_DOCUMENT_SECTION_SELECTION)); 169 } else { 170 log.debug("No documents selection in context to process delete on..."); 171 return null; 172 } 173 } 174 175 protected static final int OP_DELETE = 1, OP_PURGE = 2, OP_UNDELETE = 3; 176 177 @Override 178 public String deleteSelection(List<DocumentModel> docs) { 179 int op = isTrashManagementEnabled() ? OP_DELETE : OP_PURGE; 180 return actOnSelection(op, docs); 181 } 182 183 public String emptyTrash() { 184 DocumentModelList currentTrashDocuments = trashService.getDocuments(navigationContext.getCurrentDocument()); 185 return purgeSelection(currentTrashDocuments); 186 } 187 188 @Override 189 public String purgeSelection() { 190 return purgeSelection(CURRENT_DOCUMENT_TRASH_SELECTION); 191 } 192 193 @Override 194 public String purgeSelection(String listName) { 195 if (!documentsListsManager.isWorkingListEmpty(listName)) { 196 return purgeSelection(documentsListsManager.getWorkingList(listName)); 197 } else { 198 log.debug("No documents selection in context to process delete on..."); 199 return null; 200 } 201 } 202 203 @Override 204 public String purgeSelection(List<DocumentModel> docs) { 205 return actOnSelection(OP_PURGE, docs); 206 } 207 208 @Override 209 public String undeleteSelection() { 210 if (!documentsListsManager.isWorkingListEmpty(CURRENT_DOCUMENT_TRASH_SELECTION)) { 211 return undeleteSelection(documentsListsManager.getWorkingList(CURRENT_DOCUMENT_TRASH_SELECTION)); 212 } else { 213 log.debug("No documents selection in context to process delete on..."); 214 return null; 215 } 216 } 217 218 @Override 219 public String undeleteSelection(List<DocumentModel> docs) { 220 return actOnSelection(OP_UNDELETE, docs); 221 222 } 223 224 @SuppressWarnings("deprecation") 225 protected String actOnSelection(int op, List<DocumentModel> docs) { 226 if (docs == null) { 227 return null; 228 } 229 TrashInfo info = getTrashService().getTrashInfo(docs, currentUser, false, false); 230 231 DocumentModel targetContext = getTrashService().getAboveDocument(navigationContext.getCurrentDocument(), 232 info.rootPaths); 233 234 // remove from all lists 235 documentsListsManager.removeFromAllLists(info.docs); 236 237 Set<DocumentRef> parentRefs; 238 String msgid; 239 // operation to do 240 switch (op) { 241 case OP_PURGE: 242 getTrashService().purgeDocuments(documentManager, info.rootRefs); 243 parentRefs = info.rootParentRefs; 244 msgid = "n_deleted_docs"; 245 break; 246 case OP_DELETE: 247 getTrashService().trashDocuments(info.docs); 248 parentRefs = info.rootParentRefs; 249 msgid = "n_deleted_docs"; 250 break; 251 case OP_UNDELETE: 252 parentRefs = getTrashService().undeleteDocuments(info.docs); 253 msgid = "n_undeleted_docs"; 254 break; 255 default: 256 throw new AssertionError(op); 257 } 258 259 // Update context if needed 260 if (op == OP_UNDELETE) { 261 // undelete is problematic because it may change undeleted 262 // parent's paths... so we refetch the new context 263 targetContext = documentManager.getDocument(new IdRef(targetContext.getId())); 264 } else if (targetContext == null) { 265 // handle placeless document 266 targetContext = documentManager.getRootDocument(); 267 } 268 navigationContext.setCurrentDocument(targetContext); 269 270 // Notify parents 271 if (parentRefs.isEmpty()) { 272 // Globally refresh content views 273 Events.instance().raiseEvent(DOCUMENT_CHILDREN_CHANGED); 274 } else { 275 for (DocumentRef parentRef : parentRefs) { 276 if (documentManager.hasPermission(parentRef, SecurityConstants.READ)) { 277 DocumentModel parent = documentManager.getDocument(parentRef); 278 if (parent != null) { 279 Events.instance().raiseEvent(DOCUMENT_CHILDREN_CHANGED, parent); 280 } 281 } 282 } 283 } 284 285 // User feedback 286 if (info.proxies > 0) { 287 facesMessages.add(StatusMessage.Severity.WARN, "can_not_delete_proxies"); 288 } 289 Object[] params = { Integer.valueOf(info.docs.size()) }; 290 facesMessages.add(StatusMessage.Severity.INFO, "#0 " + messages.get(msgid), params); 291 292 return null; 293 } 294 295 @Override 296 public boolean isTrashManagementEnabled() { 297 return trashManager.isTrashManagementEnabled(); 298 } 299 300 public List<Action> getActionsForTrashSelection() { 301 return webActions.getActionsList(CURRENT_DOCUMENT_TRASH_SELECTION + "_LIST", false); 302 } 303 304 @Override 305 public void create() { 306 } 307 308 @Override 309 public void destroy() { 310 } 311 312 @Override 313 public void restoreCurrentDocument() { 314 List<DocumentModel> doc = new ArrayList<DocumentModel>(); 315 doc.add(navigationContext.getCurrentDocument()); 316 undeleteSelection(doc); 317 } 318 319 @Override 320 public boolean getCanRestoreCurrentDoc() { 321 DocumentModel doc = navigationContext.getCurrentDocument(); 322 if (doc == null) { 323 // this shouldn't happen, if it happens probably there is a 324 // customization bug, we guard this though 325 log.warn("Null currentDocument in navigationContext"); 326 return false; 327 } 328 return getTrashService().canPurgeOrUntrash(doc, currentUser); 329 } 330 331 public boolean restoreActionDisplay() { 332 return getCanRestoreCurrentDoc() && isTrashManagementEnabled(); 333 } 334}