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