package com.psddev.cms.tool.page.content; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import com.psddev.dari.db.ObjectMethod; import com.psddev.dari.util.UuidUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; import com.psddev.cms.db.BulkUploadDraft; import com.psddev.cms.db.ImageTag; import com.psddev.cms.db.ResizeOption; import com.psddev.cms.db.Site; import com.psddev.cms.db.ToolUi; import com.psddev.cms.db.Variation; import com.psddev.cms.tool.PageServlet; import com.psddev.cms.tool.Search; import com.psddev.cms.tool.SearchResultSelection; import com.psddev.cms.tool.ToolPageContext; import com.psddev.cms.tool.page.content.field.FileField; import com.psddev.cms.tool.search.MixedSearchResultView; import com.psddev.dari.db.Database; import com.psddev.dari.db.DatabaseEnvironment; import com.psddev.dari.db.ObjectField; import com.psddev.dari.db.ObjectFieldComparator; import com.psddev.dari.db.ObjectType; import com.psddev.dari.db.State; import com.psddev.dari.util.MultipartRequest; import com.psddev.dari.util.MultipartRequestFilter; import com.psddev.dari.util.ObjectUtils; import com.psddev.dari.util.RoutingFilter; import com.psddev.dari.util.StorageItem; import com.psddev.dari.util.StorageItemFilter; import com.psddev.dari.util.StringUtils; @RoutingFilter.Path(application = "cms", value = "/content/upload") @SuppressWarnings("serial") public class Upload extends PageServlet { private static final String CONTAINER_ID_PARAMETER = "containerId"; private static final Logger LOGGER = LoggerFactory.getLogger(Upload.class); @Override protected String getPermissionId() { return "area/dashboard"; } @Override protected void doService(ToolPageContext page) throws IOException, ServletException { if (page.requireUser()) { return; } if (page.paramOrDefault(Boolean.class, "preview", false)) { writeFilePreview(page); } else { reallyDoService(page); } } private static void reallyDoService(ToolPageContext page) throws IOException, ServletException { Database database = Database.Static.getDefault(); DatabaseEnvironment environment = database.getEnvironment(); Exception postError = null; ObjectType selectedType = environment.getTypeById(page.param(UUID.class, "type")); UUID uploadId = UuidUtils.createSequentialUuid(); String containerId = page.param(String.class, "containerId"); String fileParamName = "file"; if (page.isFormPost()) { database.beginWrites(); try { MultipartRequest request = MultipartRequestFilter.Static.getInstance(page.getRequest()); if (request == null) { throw new IllegalStateException("Not multipart!"); } Preconditions.checkNotNull(selectedType, "Param for [type] is empty."); ObjectField previewField = Preconditions.checkNotNull(getPreviewField(selectedType), "Preview field for type [" + selectedType.getId() + "] is null."); StringBuilder js = new StringBuilder(); Object common = selectedType.createObject(page.param(UUID.class, "typeForm-" + selectedType.getId())); page.updateUsingParameters(common); List<StorageItem> newStorageItems = StorageItemFilter.getParameters(page.getRequest(), fileParamName, FileField.getStorageSetting(Optional.of(previewField))); List<UUID> newObjectIds = new ArrayList<>(); if (!ObjectUtils.isBlank(newStorageItems)) { for (StorageItem item : newStorageItems) { if (item == null) { continue; } Object object = selectedType.createObject(null); State state = State.getInstance(object); state.setValues(State.getInstance(common)); Site site = page.getSite(); if (site != null && site.getDefaultVariation() != null) { state.as(Variation.Data.class).setInitialVariation(site.getDefaultVariation()); } state.put(previewField.getInternalName(), item); state.as(BulkUploadDraft.class).setUploadId(uploadId); state.as(BulkUploadDraft.class).setContainerId(containerId); page.publish(state); newObjectIds.add(state.getId()); js.append("$addButton.repeatable('add', function() {"); js.append("var $added = $(this);"); js.append("$input = $added.find(':input.objectId').eq(0);"); js.append("$input.attr('data-label', '").append(StringUtils.escapeJavaScript(state.getLabel())).append("');"); js.append("$input.attr('data-label-html', '").append(StringUtils.escapeJavaScript(page.createObjectLabelHtml(state))).append("');"); js.append("$input.attr('data-preview', '").append(StringUtils.escapeJavaScript(page.getPreviewThumbnailUrl(object))).append("');"); js.append("$input.val('").append(StringUtils.escapeJavaScript(state.getId().toString())).append("');"); js.append("$input.change();"); js.append("});"); } database.commitWrites(); } if (page.getErrors().isEmpty()) { if (Context.FIELD.equals(page.param(Context.class, "context"))) { page.writeStart("div", "id", page.createId()).writeEnd(); page.writeStart("script", "type", "text/javascript"); page.write("if (typeof jQuery !== 'undefined') (function($, win, undef) {"); page.write("var $page = $('#" + page.getId() + "'),"); page.write("$init = $page.popup('source').repeatable('closestInit'),"); page.write("$addButton = $init.find('.addButton').eq(0),"); page.write("$input;"); page.write("if ($addButton.length > 0) {"); page.write(js.toString()); page.write("$page.popup('close');"); page.write("}"); page.write("})(jQuery, window);"); page.writeEnd(); } else { SearchResultSelection selection = page.getUser().resetCurrentSelection(); newObjectIds.forEach(selection::addItem); database.commitWrites(); Search search = new Search(); search.setAdditionalPredicate(selection.createItemsQuery().getPredicate().toString()); search.setLimit(10); page.writeStart("script", "type", "text/javascript"); page.write("if (typeof jQuery !== 'undefined') (function($, win, undef) {"); page.write("window.location = '"); page.write(page.cmsUrl("/searchAdvancedFull", "search", ObjectUtils.toJson(search.getState().getSimpleValues()), "view", MixedSearchResultView.class.getCanonicalName())); page.write("';"); page.write("})(jQuery, window);"); page.writeEnd(); } return; } } catch (Exception error) { postError = error; } finally { database.endWrites(); } } Set<ObjectType> typesSet = new HashSet<ObjectType>(); for (UUID typeId : page.params(UUID.class, "typeId")) { ObjectType type = environment.getTypeById(typeId); if (type != null) { for (ObjectType t : type.as(ToolUi.class).findDisplayTypes()) { for (ObjectField field : t.getFields()) { if (ObjectField.FILE_TYPE.equals(field.getInternalItemType())) { typesSet.add(t); break; } } } } } List<ObjectType> types = new ArrayList<ObjectType>(typesSet); Collections.sort(types, new ObjectFieldComparator("name", false)); page.writeStart("h1"); page.writeHtml(page.localize(Upload.class, "title")); page.writeEnd(); page.writeStart("form", "method", "post", "enctype", "multipart/form-data", "action", page.url(null)); page.writeElement("input", "type", "hidden", "name", CONTAINER_ID_PARAMETER, "value", containerId); for (ObjectType type : types) { page.writeElement("input", "type", "hidden", "name", "typeId", "value", type.getId()); } if (postError != null) { page.writeStart("div", "class", "message message-error"); page.writeObject(postError); page.writeEnd(); } else if (!page.getErrors().isEmpty()) { page.writeStart("div", "class", "message message-error"); for (Throwable error : page.getErrors()) { page.writeHtml(error.getMessage()); } page.writeEnd(); } page.writeStart("div", "class", "inputContainer bulk-upload-files"); page.writeStart("div", "class", "inputLabel"); page.writeStart("label", "for", page.createId()); page.writeHtml(page.localize(Upload.class, "label.files")); page.writeEnd(); page.writeEnd(); page.writeStart("div", "class", "inputSmall"); page.writeElement("input", "id", page.getId(), page.getCmsTool().isEnableFrontEndUploader() ? "data-bsp-uploader" : "", "", "type", "file", "name", "file", "multiple", "multiple"); page.writeEnd(); page.writeEnd(); page.writeStart("div", "class", "inputContainer"); page.writeStart("div", "class", "inputLabel"); page.writeStart("label", "for", page.createId()); page.writeHtml(page.localize(Upload.class, "label.type")); page.writeEnd(); page.writeEnd(); page.writeStart("div", "class", "inputSmall"); page.writeStart("select", "class", "toggleable", "data-root", "form", "id", page.getId(), "name", "type"); for (ObjectType type : types) { page.writeStart("option", "data-hide", ".typeForm", "data-show", ".typeForm-" + type.getId(), "selected", type.equals(selectedType) ? "selected" : null, "value", type.getId()); page.writeHtml(type.getDisplayName()); page.writeEnd(); } page.writeEnd(); page.writeEnd(); page.writeStart("div", "class", "inputLarge"); for (ObjectType type : types) { String name = "typeForm-" + type.getId(); Object common = type.createObject(null); page.writeStart("div", "class", "typeForm " + name); page.writeElement("input", "type", "hidden", "name", name, "value", State.getInstance(common).getId()); ObjectField previewField = getPreviewField(type); List<String> excludedFields = null; if (previewField != null) { excludedFields = Arrays.asList(previewField.getInternalName()); } page.writeSomeFormFields(common, false, null, excludedFields); page.writeEnd(); } page.writeEnd(); page.writeEnd(); page.writeStart("input", "type", "hidden", "name", "context", "value", page.param(Context.class, "context")); page.writeStart("div", "class", "buttons"); page.writeStart("button", "name", "action-upload"); page.writeHtml(page.localize(Upload.class, "action.upload")); page.writeEnd(); page.writeEnd(); page.writeEnd(); } private static void writeFilePreview(ToolPageContext page) throws IOException, ServletException { String inputName = ObjectUtils.firstNonBlank(page.param(String.class, "inputName"), (String) page.getRequest().getAttribute("inputName"), "file"); StorageItem storageItem = StorageItemFilter.getParameter(page.getRequest(), inputName, null); HttpServletResponse response = page.getResponse(); response.setContentType("text/html"); String contentType = storageItem.getContentType(); if (StringUtils.isBlank(contentType)) { return; } if (contentType.startsWith("image/")) { ImageTag.Builder imageTagBuilder = new ImageTag.Builder(storageItem); imageTagBuilder.setWidth(150); imageTagBuilder.setHeight(110); imageTagBuilder.setResizeOption(ResizeOption.ONLY_SHRINK_LARGER); page.writeStart("div"); page.write(imageTagBuilder.toHtml()); page.writeEnd(); } } private static ObjectField getPreviewField(ObjectType type) { ObjectField previewField = type.getField(type.getPreviewField()); if (previewField instanceof ObjectMethod) { previewField = null; } if (previewField == null) { for (ObjectField field : type.getFields()) { if (ObjectField.FILE_TYPE.equals(field.getInternalItemType())) { previewField = field; break; } } } return previewField; } public enum Context { FIELD, GLOBAL } }