001/*
002 * (C) Copyright 2006-2013 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 *     bstefanescu
018 *
019 * $Id$
020 */
021
022package org.nuxeo.ecm.mobile.webengine.document;
023
024import java.util.HashMap;
025import java.util.Map;
026
027import javax.servlet.http.HttpServletRequest;
028import javax.ws.rs.GET;
029import javax.ws.rs.Path;
030import javax.ws.rs.core.Response;
031
032import org.apache.commons.lang.StringUtils;
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.nuxeo.ecm.automation.AutomationService;
036import org.nuxeo.ecm.automation.OperationContext;
037import org.nuxeo.ecm.automation.OperationException;
038import org.nuxeo.ecm.core.api.Blob;
039import org.nuxeo.ecm.core.api.DocumentModel;
040import org.nuxeo.ecm.core.api.DocumentRef;
041import org.nuxeo.ecm.core.api.NuxeoException;
042import org.nuxeo.ecm.core.api.NuxeoPrincipal;
043import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
044import org.nuxeo.ecm.core.io.download.DownloadService;
045import org.nuxeo.ecm.core.rest.DocumentObject;
046import org.nuxeo.ecm.mobile.webengine.RedirectHelper;
047import org.nuxeo.ecm.mobile.webengine.adapter.JSonExportAdapter;
048import org.nuxeo.ecm.platform.preview.helper.PreviewHelper;
049import org.nuxeo.ecm.platform.url.api.DocumentViewCodecManager;
050import org.nuxeo.ecm.platform.usermanager.UserManager;
051import org.nuxeo.ecm.platform.web.common.vh.VirtualHostHelper;
052import org.nuxeo.ecm.webengine.WebException;
053import org.nuxeo.ecm.webengine.model.ResourceType;
054import org.nuxeo.ecm.webengine.model.WebContext;
055import org.nuxeo.runtime.api.Framework;
056
057import static org.nuxeo.ecm.mobile.filter.ApplicationRedirectionFilter.INITIAL_TARGET_URL_PARAM_NAME;
058
059/**
060 * This Class resolve a DocumentModel and expose differents restitutions according Adapter defined (PreviewAdapter,
061 * CommentAdapter) in uri and "mode" parameter given as parameter into the url. Default mode if given doesn't exist or
062 * not set is view mode.
063 *
064 * @author <a href="mailto:bjalon@nuxeo.com">Benjamin JALON</a>
065 * @since 5.5
066 */
067public class MobileDocument extends DocumentObject {
068
069    private static final Log log = LogFactory.getLog(MobileDocument.class);
070
071    public MobileDocument(WebContext ctx, DocumentRef docRef) {
072        try {
073            ResourceType resType = ctx.getModule().getType("Document");
074            DocumentModel docModel = ctx.getCoreSession().getDocument(docRef);
075            initialize(ctx, resType, docModel);
076            ctx.push(this);
077        } catch (NuxeoException e) {
078            throw WebException.wrap(e);
079        }
080    }
081
082    /**
083     * Needed to not break the navigation after a false PUT see NXP-8778 as I'm redirected to this /@put URL
084     */
085    @GET
086    @Path("@put")
087    public Object redirectToRealURL() {
088        String uri = ctx.getRequest().getRequestURI();
089        // Remove the @put
090        uri = uri.substring(0, uri.length() - "@put".length() - 1);
091        String queryString = ctx.getRequest().getQueryString();
092        return redirect(uri + (queryString != null ? "?" + queryString : ""));
093    }
094
095    @GET
096    @Path("mailIt")
097    public Object emailToCurrentPrincipal() {
098        try {
099            OperationContext subctx = new OperationContext(ctx.getCoreSession(), null);
100            subctx.setInput(getDocument());
101            getAutomationService().run(subctx, "sendEmailToMe");
102        } catch (NuxeoException | OperationException e) {
103            log.error(e, e);
104            return Response.status(400).build();
105        }
106        return Response.ok().build();
107    }
108
109    @Path("like")
110    public Object doLike() {
111        try {
112            return ctx.newObject("Like", getDocument());
113        } catch (NuxeoException e) {
114            log.debug(e, e);
115            return ctx.newObject("Empty");
116        }
117    }
118
119    @Path("hasLiked")
120    public Object doHasLiked() {
121        try {
122            return ctx.newObject("hasLiked", getDocument());
123        } catch (NuxeoException e) {
124            log.debug(e, e);
125            return ctx.newObject("Empty");
126        }
127    }
128
129    @Override
130    public Object doGet() {
131        Map<String, Object> args = new HashMap<String, Object>();
132
133        // must override the original doGet to override the resolution
134        // so get parameter into the request instead injection
135        HttpServletRequest request = ctx.getRequest();
136        String mode = request.getParameter("mode");
137        if (mode == null) {
138            mode = "view";
139        }
140
141        // if url from JSF => ask to push mobile URL into browser history
142        if (request.getParameter(INITIAL_TARGET_URL_PARAM_NAME) != null) {
143            String mobileURL = String.format("%s/doc/%s?mode=%s", ctx.getRoot().getPath(), doc.getId(), mode);
144            args.put("mobileURL", mobileURL);
145        }
146        args.put("hasBlob", getHasBlob());
147
148        // Add the JSON DForm export
149        JSonExportAdapter json = (JSonExportAdapter) ctx.newObject("JSONExport");
150        args.put("doc", json.doGet(request.getRequestURI(), "post"));
151
152        return getView(mode).args(args);
153    }
154
155    protected boolean getHasBlob() {
156        DocumentModel doc = getDocument();
157        BlobHolder bh = doc.getAdapter(BlobHolder.class);
158        return bh != null && bh.getBlob() != null;
159    }
160
161    public boolean hasPreview() {
162        if (doc.hasSchema("file") && doc.getPropertyValue("file:content") != null) {
163            return PreviewHelper.typeSupportsPreview(doc);
164        }
165        return false;
166    }
167
168    public NuxeoPrincipal getPrincipal() {
169        if (ctx.getPrincipal() instanceof NuxeoPrincipal) {
170            return (NuxeoPrincipal) ctx.getPrincipal();
171        }
172
173        throw new WebException("Principal found is not a NuxeoPrincipal can't generate it!");
174    }
175
176    public String getJSFURLPath(DocumentModel docModel) {
177        return RedirectHelper.getJSFDocumentPath(docModel, VirtualHostHelper.getBaseURL(ctx.getRequest()));
178    }
179
180    public String getDownloadURL() {
181        DocumentModel docModel = getDocument();
182
183        return getDownloadURL(docModel);
184    }
185
186    public String getDownloadURL(DocumentModel docModel) {
187        Blob blob = doc.getAdapter(BlobHolder.class).getBlob();
188        DownloadService downloadService = Framework.getService(DownloadService.class);
189        String xpath = DownloadService.BLOBHOLDER_0;
190        String filename = blob.getFilename();
191        return getNuxeoContextPath() + "/" + downloadService.getDownloadUrl(doc, xpath, filename) + "?mimetype="
192                + blob.getMimeType();
193    }
194
195    public String getJSFURLPath() {
196        return getJSFURLPath(getDocument());
197    }
198
199    // **** TODO REMOVE WHEN PREVIEW WITH NAVIGATION RESOLVED ****
200    private String nuxeoContextPath;
201
202    private DocumentViewCodecManager codecManager;
203
204    public String getPreviewURL() {
205        Object targetObject = ctx.getTargetObject();
206        if (!(targetObject instanceof MobileDocument)) {
207            throw new WebException("Target Object must be MobileDocument");
208        }
209        return getNuxeoContextPath() + "/" + PreviewHelper.getPreviewURL(((MobileDocument) targetObject).getDocument());
210    }
211
212    private String getNuxeoContextPath() {
213        if (nuxeoContextPath == null) {
214            nuxeoContextPath = Framework.getProperty("org.nuxeo.ecm.contextPath");
215        }
216        return nuxeoContextPath;
217    }
218
219    private AutomationService getAutomationService() {
220        return Framework.getService(AutomationService.class);
221    }
222
223    public String getDisplayPrincipalName(String name) {
224        NuxeoPrincipal principal = Framework.getService(UserManager.class).getPrincipal(name);
225        if (principal != null) {
226            return getDisplayPrincipalName(principal);
227        }
228        return name;
229    }
230
231    /**
232     * Return the display name of an expected principal. It passes as an Object to prevent Freemarker to thrown an
233     * exception when creator is null.
234     *
235     * @param object must be of type org.nuxeo.ecm.core.api.NuxeoPrincipal
236     * @return the display name will be empty if not a NuxeoPrincipal
237     */
238    public String getDisplayPrincipalName(Object object) {
239        if (object instanceof NuxeoPrincipal) {
240            NuxeoPrincipal principal = (NuxeoPrincipal) object;
241            String display = (principal.getFirstName() + " " + principal.getLastName()).trim();
242            return StringUtils.isBlank(display) ? principal.getName() : display;
243        }
244        return "";
245    }
246
247    public String getDisplayPrincipalName() {
248        return getDisplayPrincipalName(getPrincipal());
249    }
250
251}