001/*
002 * (C) Copyright 2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Thierry Delprat
016 *     Quentin Lamerand
017 */
018
019package org.nuxeo.ecm.webapp.action;
020
021import static org.jboss.seam.ScopeType.CONVERSATION;
022
023import java.io.Serializable;
024import java.util.ArrayList;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.List;
028import java.util.Map;
029
030import javax.faces.context.FacesContext;
031import javax.servlet.http.HttpServletRequest;
032
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.jboss.seam.annotations.In;
036import org.jboss.seam.annotations.Name;
037import org.jboss.seam.annotations.Scope;
038import org.jboss.seam.annotations.remoting.WebRemote;
039import org.jboss.seam.core.Events;
040import org.jboss.seam.web.ServletContexts;
041import org.nuxeo.ecm.core.api.Blob;
042import org.nuxeo.ecm.core.api.CoreSession;
043import org.nuxeo.ecm.core.api.DocumentModel;
044import org.nuxeo.ecm.core.api.DocumentNotFoundException;
045import org.nuxeo.ecm.core.api.DocumentRef;
046import org.nuxeo.ecm.core.api.IdRef;
047import org.nuxeo.ecm.core.api.LifeCycleConstants;
048import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
049import org.nuxeo.ecm.platform.actions.Action;
050import org.nuxeo.ecm.platform.actions.ActionContext;
051import org.nuxeo.ecm.platform.ui.web.api.WebActions;
052import org.nuxeo.ecm.platform.ui.web.tag.fn.DocumentModelFunctions;
053import org.nuxeo.ecm.webapp.edit.lock.LockActions;
054import org.nuxeo.ecm.webapp.helpers.EventNames;
055
056@Name("popupHelper")
057@Scope(CONVERSATION)
058public class PopupHelper implements Serializable {
059
060    private static final long serialVersionUID = 1L;
061
062    private static final Log log = LogFactory.getLog(PopupHelper.class);
063
064    public static final String POPUP_CATEGORY = "POPUP";
065
066    @In(required = true, create = true)
067    protected transient ActionContextProvider actionContextProvider;
068
069    @In(create = true)
070    protected transient WebActions webActions;
071
072    @In(create = true)
073    protected transient DeleteActions deleteActions;
074
075    @In(create = true, required = false)
076    protected transient CoreSession documentManager;
077
078    @In(create = true)
079    protected transient LockActions lockActions;
080
081    protected DocumentModel currentContainer;
082
083    protected DocumentModel currentParent;
084
085    protected DocumentModel currentPopupDocument;
086
087    protected List<Action> unfiltredActions;
088
089    protected void computeUnfiltredPopupActions() {
090        unfiltredActions = webActions.getAllActions(POPUP_CATEGORY);
091        // unfiltredActions =
092        // webActions.getUnfiltredActionsList(POPUP_CATEGORY);
093    }
094
095    /**
096     * Returns all popup actions: used to construct HTML menu template.
097     */
098    public List<Action> getUnfiltredPopupActions() {
099        if (unfiltredActions == null) {
100            computeUnfiltredPopupActions();
101        }
102
103        // post filters links to add docId
104        for (Action act : unfiltredActions) {
105            String lnk = act.getLink();
106            if (lnk.startsWith("javascript:")) {
107                lnk = lnk.replaceFirst("javascript:", "");
108                act.setLink(lnk);
109            }
110        }
111        return unfiltredActions;
112    }
113
114    public List<Action> getAvailablePopupActions(String popupDocId) {
115        return webActions.getActionsList(POPUP_CATEGORY, createActionContext(popupDocId));
116    }
117
118    @WebRemote
119    public List<String> getAvailableActionId(String popupDocId) {
120        List<Action> availableActions = getAvailablePopupActions(popupDocId);
121        List<String> availableActionsIds = new ArrayList<String>(availableActions.size());
122        for (Action act : availableActions) {
123            availableActionsIds.add(act.getId());
124        }
125        return availableActionsIds;
126    }
127
128    @WebRemote
129    public List<String> getUnavailableActionId(String popupDocId) {
130        List<String> result = new ArrayList<String>();
131
132        List<Action> allActions = getUnfiltredPopupActions();
133        List<String> allActionsIds = new ArrayList<String>(allActions.size());
134        for (Action act : allActions) {
135            allActionsIds.add(act.getId());
136        }
137
138        List<Action> availableActions = getAvailablePopupActions(popupDocId);
139        List<String> availableActionsIds = new ArrayList<String>(availableActions.size());
140        for (Action act : availableActions) {
141            availableActionsIds.add(act.getId());
142        }
143
144        for (String act : allActionsIds) {
145            if (!availableActionsIds.contains(act)) {
146                result.add(act);
147            }
148        }
149
150        return result;
151    }
152
153    protected ActionContext createActionContext(String popupDocId) {
154        ActionContext ctx = actionContextProvider.createActionContext();
155
156        DocumentModel currentDocument = ctx.getCurrentDocument();
157
158        DocumentRef popupDocRef = new IdRef(popupDocId);
159        try {
160            DocumentModel popupDoc = documentManager.getDocument(popupDocRef);
161            ctx.setCurrentDocument(popupDoc);
162            ctx.putLocalVariable("container", currentDocument);
163            currentPopupDocument = popupDoc;
164            currentContainer = currentDocument;
165        } catch (DocumentNotFoundException e) {
166            log.error(e, e);
167        }
168
169        return ctx;
170    }
171
172    @WebRemote
173    public String getNavigationURL(String docId, String tabId) {
174        Map<String, String> params = new HashMap<String, String>();
175
176        if (tabId != null) {
177            params.put("tabId", tabId);
178        }
179
180        DocumentModel doc = documentManager.getDocument(new IdRef(docId));
181
182        return DocumentModelFunctions.documentUrl(null, doc, null, params, false);
183    }
184
185    @WebRemote
186    public String getNavigationURLOnContainer(String tabId) {
187        Map<String, String> params = new HashMap<String, String>();
188        if (tabId != null) {
189            params.put("tabId", tabId);
190        }
191
192        return DocumentModelFunctions.documentUrl(null, currentContainer, null, params, false);
193    }
194
195    @WebRemote
196    public String getNavigationURLOnPopupdoc(String tabId) {
197        return getNavigationURLOnPopupdoc2(tabId, null);
198    }
199
200    protected HttpServletRequest getRequest() {
201        HttpServletRequest request = ServletContexts.instance().getRequest();
202        if (request != null) {
203            return request;
204        }
205        FacesContext context = FacesContext.getCurrentInstance();
206        if (context != null) {
207            return (HttpServletRequest) context.getExternalContext().getRequest();
208        }
209        return null;
210    }
211
212    @WebRemote
213    public String getNavigationURLOnPopupdoc2(String tabId, String subTabId) {
214        Map<String, String> params = new HashMap<String, String>();
215        if (tabId != null) {
216            params.put("tabId", tabId);
217        }
218        if (subTabId != null) {
219            params.put("subTabId", subTabId);
220        }
221        return DocumentModelFunctions.documentUrl(null, currentPopupDocument, null, params, false, getRequest());
222    }
223
224    protected Map<String, String> getCurrentTabParameters() {
225        Map<String, String> params = new HashMap<String, String>();
226        String tabId = webActions.getCurrentTabId();
227        if (tabId != null) {
228            params.put("tabId", tabId);
229        }
230        String subTabId = webActions.getCurrentSubTabId();
231        if (subTabId != null) {
232            params.put("subTabId", subTabId);
233        }
234        return params;
235    }
236
237    @WebRemote
238    public String getCurrentURL() {
239        return DocumentModelFunctions.documentUrl(null, currentContainer, null, getCurrentTabParameters(), false);
240    }
241
242    @WebRemote
243    public String getCurrentURLAfterDelete() {
244        if (!isDocumentDeleted(currentContainer)) {
245            currentParent = currentContainer;
246        }
247        return DocumentModelFunctions.documentUrl(null, currentParent, null, getCurrentTabParameters(), false);
248    }
249
250    @WebRemote
251    public String deleteDocument(String docId) {
252        DocumentModel doc = documentManager.getDocument(new IdRef(docId));
253        currentParent = getFirstParentAfterDelete(doc);
254        List<DocumentModel> docsToDelete = new ArrayList<DocumentModel>(1);
255        docsToDelete.add(doc);
256        return deleteActions.deleteSelection(docsToDelete);
257    }
258
259    @WebRemote
260    public String editTitle(String docId, String newTitle) {
261        DocumentModel doc = documentManager.getDocument(new IdRef(docId));
262        doc.setProperty("dublincore", "title", newTitle);
263        documentManager.saveDocument(doc);
264        documentManager.save();
265        Events.instance().raiseEvent(EventNames.DOCUMENT_CHILDREN_CHANGED);
266        return "OK";
267    }
268
269    public boolean getIsCurrentContainerDirectParent() {
270        if (documentManager != null && currentContainer != null && currentPopupDocument != null) {
271            DocumentModel parent = documentManager.getParentDocument(currentPopupDocument.getRef());
272            return currentContainer.equals(parent);
273        }
274        return false;
275    }
276
277    public boolean isDocumentHasBlobAttached(DocumentModel documentModel) {
278        if (documentModel.hasSchema("file")) {
279            Blob blob = (Blob) documentModel.getProperty("file", "content");
280            return blob != null;
281        } else {
282            return false;
283        }
284    }
285
286    public boolean isDocumentHasBlobs(DocumentModel documentModel) {
287        BlobHolder bh = documentModel.getAdapter(BlobHolder.class);
288        if (bh != null) {
289            List<Blob> docBlobs = bh.getBlobs();
290            if (docBlobs != null && !docBlobs.isEmpty()) {
291                return true;
292            } else {
293                return false;
294            }
295        } else {
296            return false;
297        }
298    }
299
300    @WebRemote
301    public String downloadDocument(String docId, String blobPropertyName, String filenamePropertyName)
302            {
303        DocumentModel documentModel = documentManager.getDocument(new IdRef(docId));
304        String filename = (String) documentModel.getPropertyValue(filenamePropertyName);
305        return DocumentModelFunctions.fileUrl("downloadFile", documentModel, blobPropertyName, filename);
306    }
307
308    @WebRemote
309    public String lockDocument(String docId) {
310        DocumentModel documentModel = documentManager.getDocument(new IdRef(docId));
311        return lockActions.lockDocument(documentModel);
312    }
313
314    @WebRemote
315    public String unlockDocument(String docId) {
316        DocumentModel documentModel = documentManager.getDocument(new IdRef(docId));
317        return lockActions.unlockDocument(documentModel);
318    }
319
320    @WebRemote
321    public String sendEmail(String docId) {
322        DocumentModel doc = documentManager.getDocument(new IdRef(docId));
323        return DocumentModelFunctions.documentUrl(null, doc, "send_notification_email", null, false);
324    }
325
326    private DocumentModel getFirstParentAfterDelete(DocumentModel doc) {
327        List<DocumentModel> parents = documentManager.getParentDocuments(doc.getRef());
328        parents.remove(doc);
329        Collections.reverse(parents);
330        for (DocumentModel currentParent : parents) {
331            try {
332                documentManager.getDocument(currentParent.getRef());
333                return currentParent;
334            } catch (DocumentNotFoundException e) {
335                continue;
336            }
337        }
338        return null;
339    }
340
341    private boolean isDocumentDeleted(DocumentModel doc) {
342        // test if the document still exists in the repository
343        if (!documentManager.exists(doc.getRef())) {
344            return true;
345        }
346        // test if the document is in the trash
347        if (LifeCycleConstants.DELETED_STATE.equals(doc.getCurrentLifeCycleState())) {
348            return true;
349        }
350        return false;
351    }
352
353}