/* * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * troger * * $Id$ */ package org.nuxeo.ecm.webapp.note; import static org.jboss.seam.ScopeType.CONVERSATION; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.Part; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.web.RequestParameter; import org.nuxeo.ecm.core.api.Blob; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.ListDiff; import org.nuxeo.ecm.core.api.NuxeoException; import org.nuxeo.ecm.platform.query.api.PageProvider; import org.nuxeo.ecm.platform.query.api.PageProviderService; import org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider; import org.nuxeo.ecm.platform.ui.web.tag.fn.DocumentModelFunctions; import org.nuxeo.ecm.platform.ui.web.util.files.FileUtils; import org.nuxeo.ecm.webapp.base.InputController; import org.nuxeo.runtime.api.Framework; /** * Seam component implementing actions related to inserting an image in a Note document. * <p> * The uploaded image is stored in the <code>files</code> schema of the document. * <p> * After uploading an image, the REST URL for this image can be retrieve through the appropriate method. * <p> * The search method retrieves only the Picture document of the repository. * * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a> */ @Name("editorImageActions") @Scope(CONVERSATION) public class EditorImageActionsBean extends InputController implements EditorImageActions, Serializable { private static final String FILES_SCHEMA = "files"; private static final List<Map<String, String>> SIZES; /** @since 5.9.5 */ private static final String PP_SEARCH_MEDIA_BY_TITLE = "search_media_by_title"; /** @since 5.9.5 */ private static final String PP_SEARCH_MEDIA_ALL = "search_media_all"; static { SIZES = new ArrayList<Map<String, String>>(); Map<String, String> m = new HashMap<String, String>(); m.put("label", "label.imageUpload.originalSize"); m.put("value", "OriginalJpeg"); SIZES.add(m); m = new HashMap<String, String>(); m.put("label", "label.imageUpload.mediumSize"); m.put("value", "Medium"); SIZES.add(m); m = new HashMap<String, String>(); m.put("label", "label.imageUpload.thumbnailSize"); m.put("value", "Thumbnail"); SIZES.add(m); } private static final long serialVersionUID = 8716548847393060676L; private static final Log log = LogFactory.getLog(EditorImageActionsBean.class); @In(create = true, required = false) private transient CoreSession documentManager; @RequestParameter private String selectedTab; private String oldSelectedTab; private Part uploadedImage; /** * @deprecated since 7.1 */ @Deprecated private String uploadedImageName; private String imageUrl; private boolean isImageUploaded = false; private List<DocumentModel> resultDocuments; private List<DocumentModel> resultVideos; private boolean hasSearchResults = false; private boolean hasSearchVideosResults = false; private String searchKeywords; private String selectedSize = "OriginalJpeg"; @Override public String getSelectedTab() { if (selectedTab != null) { oldSelectedTab = selectedTab; } else if (oldSelectedTab == null) { oldSelectedTab = "UPLOAD"; } return oldSelectedTab; } @Override public String getUrlForImage() { isImageUploaded = false; return imageUrl; } @Override public boolean getIsImageUploaded() { return isImageUploaded; } @Override public void setUploadedImage(Part uploadedImage) { this.uploadedImage = uploadedImage; } @Override public Part getUploadedImage() { return uploadedImage; } @Override public String getUploadedImageName() { return uploadedImageName; } @Override public void setUploadedImageName(String uploadedImageName) { this.uploadedImageName = uploadedImageName; } @Override @SuppressWarnings("unchecked") public String uploadImage() { if (uploadedImage == null) { return null; } DocumentModel doc = navigationContext.getCurrentDocument(); List<Map<String, Object>> filesList = (List<Map<String, Object>>) doc.getProperty("files", "files"); int fileIndex = filesList == null ? 0 : filesList.size(); Map<String, Object> props = new HashMap<String, Object>(); Blob blob; try { blob = FileUtils.createBlob(uploadedImage); } catch (IOException e) { throw new NuxeoException(e); } props.put("file", blob); ListDiff listDiff = new ListDiff(); listDiff.add(props); doc.setProperty("files", "files", listDiff); documentManager.saveDocument(doc); documentManager.save(); imageUrl = DocumentModelFunctions.complexFileUrl("downloadFile", doc, fileIndex, blob.getFilename()); isImageUploaded = true; return "editor_image_upload"; } @Override public boolean getInCreationMode() { DocumentModel doc = navigationContext.getChangeableDocument(); if (doc == null || doc.getRef() != null) { // if changeableDocument is null or has an existing ref, assume we // are not in creation and use the currentDocument instead doc = navigationContext.getCurrentDocument(); } if (doc == null) { return false; } if (doc.getId() == null) { return true; } else { return !doc.hasSchema(FILES_SCHEMA); } } @Override public boolean getHasSearchResults() { return hasSearchResults; } @Override public boolean getHasSearchVideosResults() { return hasSearchVideosResults; } @Override public List<DocumentModel> getSearchImageResults() { return resultDocuments; } @Override public List<DocumentModel> getSearchVideosResults() { return resultVideos; } @Override public String getSearchKeywords() { return searchKeywords; } @Override public String searchImages() { // Init the list of results resultDocuments = null; // Search the images resultDocuments = searchMedia("Picture"); hasSearchResults = !resultDocuments.isEmpty(); log.debug("query result contains: " + resultDocuments.size() + " docs."); return "editor_image_upload"; } /** * @since 5.9.5 */ @Override public String searchVideos() { // Init the list of results resultVideos = null; // Search the videos resultVideos = searchMedia("Video"); hasSearchVideosResults = !resultVideos.isEmpty(); log.debug("query result contains: " + resultVideos.size() + " videos."); return "editor_image_upload"; } /** * Generic method to search a media. * * @param typeDocument The type of document to search. * @since 5.9.5 */ @SuppressWarnings("unchecked") private List<DocumentModel> searchMedia(String typeDocument) { log.debug("Entering searchDocuments with keywords: " + searchKeywords); // use page providers PageProviderService ppService = Framework.getService(PageProviderService.class); Map<String, Serializable> props = new HashMap<String, Serializable>(); props.put(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) documentManager); PageProvider<DocumentModel> pp = null; if (searchKeywords != null) { searchKeywords = searchKeywords.trim(); if (searchKeywords.length() > 0) { if (!searchKeywords.equals("*")) { // full text search pp = (PageProvider<DocumentModel>) ppService.getPageProvider(PP_SEARCH_MEDIA_BY_TITLE, null, null, null, props, new Object[] { typeDocument, searchKeywords }); } } } // If the pageprovider is null, we search all medias for the specific type if (pp == null) { pp = (PageProvider<DocumentModel>) ppService.getPageProvider(PP_SEARCH_MEDIA_ALL, null, null, null, props, new Object[] { typeDocument }); } return pp.getCurrentPage(); } @Override public void setSearchKeywords(final String searchKeywords) { this.searchKeywords = searchKeywords; } @Override public List<Map<String, String>> getSizes() { return SIZES; } @Override public String getSelectedSize() { return selectedSize; } @Override public void setSelectedSize(final String selectedSize) { this.selectedSize = selectedSize; } @Override public String getImageProperty() { return selectedSize + ":content"; } @Override public String getURLVideo(DocumentModel video, String type) { if (video == null || type == null) { return null; } @SuppressWarnings("unchecked") List<Map<String, Serializable>> transcodedVideos = (List<Map<String, Serializable>>) video.getPropertyValue("vid:transcodedVideos"); int position = 0; for (Map<String, Serializable> prop : transcodedVideos) { if (type.equals(prop.get("name"))) { Blob content = (Blob) prop.get("content"); String blobPropertyName = "vid:transcodedVideos/" + position + "/content"; return DocumentModelFunctions.bigFileUrl(video, blobPropertyName, content.getFilename()); } position++; } return null; } }