diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/contenttypes/AbstractTextUploadForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/contenttypes/AbstractTextUploadForm.java new file mode 100644 index 000000000..4839dbaae --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/contenttypes/AbstractTextUploadForm.java @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2019 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.cms.ui.contenttypes; + +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.SaveCancelSection; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormValidationListener; +import com.arsdigita.bebop.form.FormErrorDisplay; +import com.arsdigita.bebop.parameters.NotNullValidationListener; +import com.arsdigita.bebop.util.GlobalizationUtil; +import com.arsdigita.cms.ItemSelectionModel; +import com.arsdigita.cms.ui.FileUploadSection; +import com.arsdigita.globalization.Globalization; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.util.UncheckedWrapperException; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.awt.image.Kernel; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +import javax.activation.MimeType; + +/** + * + * @author Jens Pelzetter + */ +/** + *
+ * An abstract base form for uploading Texts. The code of this class has been + * extracted from {@link TextAssetBody}, the form for editing an TextAsset (used + * for example for Article). The TextAsset has the disadvantage of storing its + * information in a separate table, so that information of a content item is + * spread over several tables. + *
+ *+ * To use this form, define a property for your object which has the Java type + * String and the database type CLOB, like this: + *
+ *+ * String[0..1] text = ct_yourContenttype.text CLOB + *+ *
+ * To use this form your have to overwrite three methods: + *
+ *
+ * This method is called to pass the uploaded text to the edited object. In
+ * the method, you have to retrieve the current selected object from the
+ * itemModel parameter and call the appropriate
+ * set of your class, and its save method. An simple example:
+ *
+ * @Override
+ * public void setText(ItemSelectionModel itemModel,
+ * PageState state,
+ * String text) {
+ * YourContentType obj = (YourContentType) itemModel.getSelectedObject(state);
+ * obj.setText(text);
+ * obj.save();
+ * }
+ *
+ *
+ * @param itemModel The {@link ItemSelectionModel} used by the form.
+ * @param state The current {@link PageState}.
+ * @param text The uploaded text.
+ */
+ public abstract void setText(ItemSelectionModel itemModel,
+ PageState state,
+ String text);
+
+ protected void addWidgets() {
+ add(new Label(getLabelText()));
+ fileUploadSection = new FileUploadSection(
+ getMimeTypeLabel(),
+ "mime",
+ "text/plain");
+ fileUploadSection.getFileUploadWidget().addValidationListener(
+ new NotNullValidationListener());
+ fileUploadSection.getMimeTypeWidget().setDefaultValue(
+ FileUploadSection.GUESS_MIME);
+ add(fileUploadSection);
+
+ saveCancelSection = new SaveCancelSection();
+ add(saveCancelSection);
+
+ add(new FormErrorDisplay(this));
+
+ addValidationListener(this);
+ addProcessListener(this);
+ }
+
+ /**
+ * @return the save/cancel section for this form
+ */
+ public SaveCancelSection getSaveCancelSection() {
+ return saveCancelSection;
+ }
+
+ @Override
+ public void init(final FormSectionEvent event) throws FormProcessException {
+ final PageState state = event.getPageState();
+
+ setVisible(state, true);
+ }
+
+ /**
+ * Validate file upload
+ *
+ * @param event
+ *
+ * @throws FormProcessException
+ */
+ @Override
+ public void validate(final FormSectionEvent event) throws
+ FormProcessException {
+
+ final MimeType mime = fileUploadSection.getMimeType(event);
+ boolean textType = mime.getPrimaryType().equals("text");
+
+ validateFileType(mime, textType);
+
+ // Convert the file to HTML, if possible
+ final File file = fileUploadSection.getFile(event);
+ byte[] file_bytes = readFileBytes(file);
+ boolean[] used_inso = new boolean[1];
+ String file_content = convertBytes(file_bytes, textType, used_inso);
+
+ if ("text/html".equals(mime.toString())) {
+ file_content = extractHTMLBody(file_content);
+ }
+
+ final PageState state = event.getPageState();
+ fileUploadContent.set(state, file_content);
+ fileUploadContentUsedInso.set(state, used_inso[0]);
+ }
+
+ @Override
+ public void process(final FormSectionEvent event)
+ throws FormProcessException {
+ LOGGER.debug("Processing upload...");
+ final PageState state = event.getPageState();
+ //File file = fileUploadSection.getFile(fse);
+ //SciProject project = (SciProject) itemModel.getSelectedObject(state);
+
+ final String uploadContent = (String) fileUploadContent.get(state);
+ //boolean usedInso = (Boolean) fileUploadContentUsedInso.get(state);
+
+ LOGGER.debug(String.format("Setting project description to: %s",
+ uploadContent));
+ //project.setProjectDescription(uploadContent);
+ LOGGER.debug("Saving project.");
+ //project.save();
+ setText(itemModel, state, uploadContent);
+ }
+
+ private void validateFileType(final MimeType mime, final boolean textType)
+ throws FormProcessException {
+
+ boolean validType = textType;
+
+ if (!validType) {
+ throw new FormProcessException(GlobalizationUtil.globalize(
+ "cms.ui.authoring.invalid_file_type"));
+ }
+ }
+
+ /**
+ * read in the content of the file (in bytes).
+ */
+ private byte[] readFileBytes(final File file) throws FormProcessException {
+ final byte[] fileBytes;
+ try (FileInputStream fileInputStream = new FileInputStream(file)) {
+ fileBytes = new byte[fileInputStream.available()];
+ fileInputStream.read(fileBytes);
+ } catch (IOException ex) {
+ throw new FormProcessException(GlobalizationUtil.globalize(
+ "cms.ui.authoring.unable_to_load_file"));
+ }
+ return fileBytes;
+ }
+
+ /**
+ * Convert bytes to String, possibly using INSO filter to convert to HTML
+ * type
+ */
+ private String convertBytes(final byte[] fileBytes,
+ final boolean textType,
+ final boolean[] usedInso)
+ throws FormProcessException {
+
+ return new String(fileBytes, StandardCharsets.UTF_8);
+ }
+
+ /**
+ * Extract the contents of the html Body tag. (Done to prevent base and
+ * other header tags from interfering with page display).
+ */
+ private String extractHTMLBody(final String htmlText)
+ throws FormProcessException {
+
+ final String lc = htmlText.toLowerCase();
+ final int bodyStart = lc.indexOf("", bodyStart);
+ final int bodyEnd = lc.indexOf("", bodyStart_v);
+ if (bodyStart == -1 || bodyEnd == -1) {
+ throw new FormProcessException(GlobalizationUtil.globalize(
+ "cms.ui.authoring.html_file_missing_body_tags"));
+ }
+ return htmlText.substring(bodyStart_v + 1, bodyEnd);
+ }
+
+}