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.LifeCycleConstants;
050import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
051import org.nuxeo.ecm.platform.actions.Action;
052import org.nuxeo.ecm.platform.actions.ActionContext;
053import org.nuxeo.ecm.platform.ui.web.api.WebActions;
054import org.nuxeo.ecm.platform.ui.web.tag.fn.DocumentModelFunctions;
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.getUnfiltredActionsList(POPUP_CATEGORY);
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);
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);
195    }
196
197    @WebRemote
198    public String getNavigationURLOnPopupdoc(String tabId) {
199        return getNavigationURLOnPopupdoc2(tabId, null);
200    }
201
202    protected HttpServletRequest getRequest() {
203        HttpServletRequest request = ServletContexts.instance().getRequest();
204        if (request != null) {
205            return request;
206        }
207        FacesContext context = FacesContext.getCurrentInstance();
208        if (context != null) {
209            return (HttpServletRequest) context.getExternalContext().getRequest();
210        }
211        return null;
212    }
213
214    @WebRemote
215    public String getNavigationURLOnPopupdoc2(String tabId, String subTabId) {
216        Map<String, String> params = new HashMap<String, String>();
217        if (tabId != null) {
218            params.put("tabId", tabId);
219        }
220        if (subTabId != null) {
221            params.put("subTabId", subTabId);
222        }
223        return DocumentModelFunctions.documentUrl(null, currentPopupDocument, null, params, false, getRequest());
224    }
225
226    protected Map<String, String> getCurrentTabParameters() {
227        Map<String, String> params = new HashMap<String, String>();
228        String tabId = webActions.getCurrentTabId();
229        if (tabId != null) {
230            params.put("tabId", tabId);
231        }
232        String subTabId = webActions.getCurrentSubTabId();
233        if (subTabId != null) {
234            params.put("subTabId", subTabId);
235        }
236        return params;
237    }
238
239    @WebRemote
240    public String getCurrentURL() {
241        return DocumentModelFunctions.documentUrl(null, currentContainer, null, getCurrentTabParameters(), false);
242    }
243
244    @WebRemote
245    public String getCurrentURLAfterDelete() {
246        if (!isDocumentDeleted(currentContainer)) {
247            currentParent = currentContainer;
248        }
249        return DocumentModelFunctions.documentUrl(null, currentParent, null, getCurrentTabParameters(), false);
250    }
251
252    @WebRemote
253    public String deleteDocument(String docId) {
254        DocumentModel doc = documentManager.getDocument(new IdRef(docId));
255        currentParent = getFirstParentAfterDelete(doc);
256        List<DocumentModel> docsToDelete = new ArrayList<DocumentModel>(1);
257        docsToDelete.add(doc);
258        return deleteActions.deleteSelection(docsToDelete);
259    }
260
261    @WebRemote
262    public String editTitle(String docId, String newTitle) {
263        DocumentModel doc = documentManager.getDocument(new IdRef(docId));
264        doc.setProperty("dublincore", "title", newTitle);
265        documentManager.saveDocument(doc);
266        documentManager.save();
267        Events.instance().raiseEvent(EventNames.DOCUMENT_CHILDREN_CHANGED);
268        return "OK";
269    }
270
271    public boolean getIsCurrentContainerDirectParent() {
272        if (documentManager != null && currentContainer != null && currentPopupDocument != null) {
273            DocumentModel parent = documentManager.getParentDocument(currentPopupDocument.getRef());
274            return currentContainer.equals(parent);
275        }
276        return false;
277    }
278
279    public boolean isDocumentHasBlobAttached(DocumentModel documentModel) {
280        if (documentModel.hasSchema("file")) {
281            Blob blob = (Blob) documentModel.getProperty("file", "content");
282            return blob != null;
283        } else {
284            return false;
285        }
286    }
287
288    public boolean isDocumentHasBlobs(DocumentModel documentModel) {
289        BlobHolder bh = documentModel.getAdapter(BlobHolder.class);
290        if (bh != null) {
291            List<Blob> docBlobs = bh.getBlobs();
292            if (docBlobs != null && !docBlobs.isEmpty()) {
293                return true;
294            } else {
295                return false;
296            }
297        } else {
298            return false;
299        }
300    }
301
302    @WebRemote
303    public String downloadDocument(String docId, String blobPropertyName, String filenamePropertyName)
304            {
305        DocumentModel documentModel = documentManager.getDocument(new IdRef(docId));
306        String filename = (String) documentModel.getPropertyValue(filenamePropertyName);
307        return DocumentModelFunctions.fileUrl("downloadFile", documentModel, blobPropertyName, filename);
308    }
309
310    @WebRemote
311    public String lockDocument(String docId) {
312        DocumentModel documentModel = documentManager.getDocument(new IdRef(docId));
313        return lockActions.lockDocument(documentModel);
314    }
315
316    @WebRemote
317    public String unlockDocument(String docId) {
318        DocumentModel documentModel = documentManager.getDocument(new IdRef(docId));
319        return lockActions.unlockDocument(documentModel);
320    }
321
322    @WebRemote
323    public String sendEmail(String docId) {
324        DocumentModel doc = documentManager.getDocument(new IdRef(docId));
325        return DocumentModelFunctions.documentUrl(null, doc, "send_notification_email", null, false);
326    }
327
328    private DocumentModel getFirstParentAfterDelete(DocumentModel doc) {
329        List<DocumentModel> parents = documentManager.getParentDocuments(doc.getRef());
330        parents.remove(doc);
331        Collections.reverse(parents);
332        for (DocumentModel currentParent : parents) {
333            try {
334                documentManager.getDocument(currentParent.getRef());
335                return currentParent;
336            } catch (DocumentNotFoundException e) {
337                continue;
338            }
339        }
340        return null;
341    }
342
343    private boolean isDocumentDeleted(DocumentModel doc) {
344        // test if the document still exists in the repository
345        if (!documentManager.exists(doc.getRef())) {
346            return true;
347        }
348        // test if the document is in the trash
349        if (LifeCycleConstants.DELETED_STATE.equals(doc.getCurrentLifeCycleState())) {
350            return true;
351        }
352        return false;
353    }
354
355}