diff --git a/ccm-cms/src/main/java/org/librecms/contenttypes/Article.java b/ccm-cms/src/main/java/org/librecms/contenttypes/Article.java index 85c20347d..d4be12de4 100644 --- a/ccm-cms/src/main/java/org/librecms/contenttypes/Article.java +++ b/ccm-cms/src/main/java/org/librecms/contenttypes/Article.java @@ -43,6 +43,7 @@ import org.librecms.ui.contenttypes.MvcArticleCreateStep; import org.librecms.ui.contenttypes.MvcArticlePropertiesStep; import org.librecms.ui.contenttypes.MvcArticleTextBodyStep; import org.librecms.ui.contentsections.documents.MvcAuthoringKit; +import org.librecms.ui.contentsections.documents.MvcAuthoringKitStep; import javax.xml.bind.annotation.XmlRootElement; @@ -78,8 +79,14 @@ import javax.xml.bind.annotation.XmlRootElement; @MvcAuthoringKit( createStep = MvcArticleCreateStep.class, authoringSteps = { - MvcArticlePropertiesStep.class, - MvcArticleTextBodyStep.class + @MvcAuthoringKitStep( + path = "basic-properties", + authoringStep = MvcArticlePropertiesStep.class + ), + @MvcAuthoringKitStep( + path = "basic-properties", + authoringStep = MvcArticleTextBodyStep.class + ) } ) @XmlRootElement(name = "article", namespace = CMS_XML_NS) diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/AbstractMvcAuthoringStep.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/AbstractMvcAuthoringStep.java new file mode 100644 index 000000000..7e767d0fe --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/AbstractMvcAuthoringStep.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2021 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 org.librecms.ui.contentsections; + +import org.libreccm.l10n.GlobalizationHelper; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemManager; +import org.librecms.contentsection.ContentSection; +import org.librecms.ui.contentsections.documents.MvcAuthoringStep; + +import java.util.Map; +import java.util.Objects; + +import javax.inject.Inject; +import javax.mvc.Models; + +/** + * + * @author Jens Pelzetter + */ +public abstract class AbstractMvcAuthoringStep implements MvcAuthoringStep { + + @Inject + private ContentItemManager itemManager; + + @Inject + private GlobalizationHelper globalizationHelper; + + @Inject + private Models models; + + private ContentSection section; + + private ContentItem document; + + @Override + public ContentSection getContentSection() { + return section; + } + + @Override + public void setContentSection(final ContentSection section) { + this.section = section; + } + + @Override + public String getContentSectionLabel() { + return section.getLabel(); + } + + @Override + public String getContentSectionTitle() { + return globalizationHelper + .getValueFromLocalizedString(section.getTitle()); + } + + @Override + public ContentItem getContentItem() { + return document; + } + + @Override + public void setContentItem(final ContentItem document) { + this.document = document; + } + + @Override + public String getContentItemPath() { + return itemManager.getItemPath(document); + } + + @Override + public String getContentItemTitle() { + return globalizationHelper + .getValueFromLocalizedString(document.getTitle()); + } + + protected boolean hasParameter( + final Map parameters, + final String parameterName + ) { + Objects.requireNonNull( + parameters, + "parameters can't be null." + ); + Objects.requireNonNull( + parameterName, + "parameterName can't be null." + ); + return parameters.containsKey(parameterName) + && parameters.get(parameterName) != null + && parameters.get(parameterName).length != 0; + } + + /** + * Helper method to add a form parameter value to {@link #models}. + * + * @param parameters The form parameters. + * @param parameterName The parameter name + */ + protected void addParameterValueToModels( + final Map parameters, + final String parameterName + ) { + models.put( + Objects.requireNonNull( + parameterName, + "parameterName can't be null" + ), + Objects.requireNonNull( + parameters, + "parameters can't be null." + ).getOrDefault(parameterName, new String[]{""})[0] + ); + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java index 098383c7e..a7454ea08 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java @@ -308,7 +308,6 @@ public class DocumentController { sectionIdentifier, "", documentType, - //formParameters request ); } @@ -327,7 +326,8 @@ public class DocumentController { ) { final CreateStepResult result = findCreateStep( sectionIdentifier, - folderPath, documentType + folderPath, + documentType ); if (result.isCreateStepAvailable()) { diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringAction.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringAction.java new file mode 100644 index 000000000..fffda5925 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringAction.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 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 org.librecms.ui.contentsections.documents; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.MediaType; + +/** + * Used to annotate methods of an authoring step processing requests for a + * specific sub path. The annoated MUST have the following signature: + * + *
+ * actionMethod(String parameterPath, Map parameters)
+ * 
+ * + * The {@link DocumentController} will put the rest of the path behind the path + * fragments for the action in the {@code parameterPath} parameter. The + * parameter {@code parameters} will contain the list of parameters for the + * request as returned by {@link HttpServletRequest#getParameterMap() }. + * + * The return type of the annotated method MUST be {@code String} if the action + * is showing a template ({@link #produces()} is set to + * {@link MediaType#TEXT_HTML}), or any object type is {@link #produces() } is + * set the {@link MediaType#APPLICATION_JSON}. + * + * @author Jens Pelzetter + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface MvcAuthoringAction { + + /** + * The HTTP method used to invoke the action. + * + * @return The HTTP method used to invoke the action. + */ + MvcAuthoringActionMethod method() default MvcAuthoringActionMethod.GET; + + /** + * The path fragment for invoking the action. The value of this parameter is + * added to the path of the authoring step. + * + * @return The path fragment for invoking the action. + */ + String path(); + + /** + * The type of data the the action produces. If the action shows a view the + * value should be {@link MediaType#TEXT_HTML} (the default). If the action + * produces JSON data the value MUST BE {@link MediaType#APPLICATION_JSON}. + * + * @return The type of data the the action produces. + */ + String produces() default MediaType.TEXT_HTML; + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringActionMethod.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringActionMethod.java new file mode 100644 index 000000000..358a05cf0 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringActionMethod.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 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 org.librecms.ui.contentsections.documents; + +/** + * Request methods for {@link MvcAuthoringAction}s. + * + * @author Jens Pelzetter + */ +public enum MvcAuthoringActionMethod { + + GET, + POST + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringKit.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringKit.java index 9c0026825..9200ff158 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringKit.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringKit.java @@ -47,10 +47,9 @@ public @interface MvcAuthoringKit { * The authoring steps for editing the properties of the document. They are * used in the same order as they are provided here. * - * @return The descriptor classes ofr the authoring steps for the annotated - * document type. + * @return The authoring steps for the annotated document type. */ - Class[] authoringSteps(); + MvcAuthoringKitStep[] authoringSteps(); /** * If set to {@code true} some authoring steps like categorization or diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringKitStep.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringKitStep.java new file mode 100644 index 000000000..7ba210611 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringKitStep.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 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 org.librecms.ui.contentsections.documents; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Metadata about an authoring step. + * + * @author Jens Pelzetter + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface MvcAuthoringKitStep { + + /** + * The path of authoring step. This value is added the the path for + * authoring steps. + * + * @return The path fragment for th authoring step. + */ + String path(); + + /** + * The class implementing the authoring step. + * + * @return The class implementing the authoring step. + */ + Class authoringStep(); + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringStep.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringStep.java index b3e433f77..4c3a777f4 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringStep.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/MvcAuthoringStep.java @@ -22,10 +22,9 @@ import org.libreccm.l10n.GlobalizationHelper; import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentSection; +import java.util.Map; + import javax.inject.Named; -import javax.transaction.Transactional; -import javax.ws.rs.GET; -import javax.ws.rs.Path; /** * An authoring step for a document (content item). Implementing classes are @@ -139,9 +138,17 @@ public interface MvcAuthoringStep { * * @return The template of the edit step. */ - @GET - @Path("/") - @Transactional(Transactional.TxType.REQUIRED) String showStep(); + /** + * Apply changes from the from of the script.Authoring steps that have + * multiple forms may choose to implement this method as any no-op method + * that simply redirects to the template view (same as {@link #showStep()}. + * + * @param formParameters The form parameters submitted. + * + * @return The template of the view to show. + */ + String applyEdits(Map formParameters); + } diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStep.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStep.java index 4cb818d9e..9a74a1ab9 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStep.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStep.java @@ -19,12 +19,14 @@ package org.librecms.ui.contentsections.documents; import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.security.AuthorizationRequired; import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItemManager; import org.librecms.contentsection.ContentSection; import org.librecms.lifecycle.Lifecycle; import org.librecms.lifecycle.LifecycleDefinition; import org.librecms.lifecycle.LifecycleDefinitionRepository; +import org.librecms.ui.contentsections.AbstractMvcAuthoringStep; import org.librecms.ui.contentsections.ItemPermissionChecker; import java.time.LocalDate; @@ -35,6 +37,7 @@ import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.Date; +import java.util.Map; import java.util.Optional; import javax.enterprise.context.RequestScoped; @@ -57,7 +60,19 @@ import javax.ws.rs.Path; @Path("/") @AuthoringStepPathFragment(PublishStep.PATH_FRAGMENT) @Named("CmsPublishStep") -public class PublishStep implements MvcAuthoringStep { +public class PublishStep extends AbstractMvcAuthoringStep { + + + private static final String SELECTED_LIFECYCLE_DEF_UUID + = "selectedLifecycleDefUuid"; + + private static final String START_DATE = "startDate"; + + private static final String START_TIME = "startTime"; + + private static final String END_DATE = "endDate"; + + private static final String END_TIME = "endTime"; /** * The path fragment of the publish step. @@ -85,9 +100,6 @@ public class PublishStep implements MvcAuthoringStep { @Inject private Models models; - private ContentItem document; - - private ContentSection section; @Override public Class supportedDocumentType() { @@ -113,59 +125,19 @@ public class PublishStep implements MvcAuthoringStep { return DefaultAuthoringStepConstants.BUNDLE; } - @Override - public ContentSection getContentSection() { - return section; - } - - @Override - public void setContentSection(final ContentSection section) { - this.section = section; - } - - @Override - public String getContentSectionLabel() { - return section.getLabel(); - } - - @Override - public String getContentSectionTitle() { - return globalizationHelper - .getValueFromLocalizedString(section.getTitle()); - } - - @Override - public ContentItem getContentItem() { - return document; - } - - @Override - public void setContentItem(final ContentItem document) { - this.document = document; - } - - @Override - public String getContentItemPath() { - return itemManager.getItemPath(document); - } - - @Override - public String getContentItemTitle() { - return globalizationHelper - .getValueFromLocalizedString(document.getTitle()); - } + @Override public String showStep() { - if (itemPermissionChecker.canPublishItems(document)) { + if (itemPermissionChecker.canPublishItems(getContentItem())) { final String lifecycleDefUuid; - if (itemManager.isLive(document)) { - lifecycleDefUuid = document + if (itemManager.isLive(getContentItem())) { + lifecycleDefUuid = getContentItem() .getLifecycle() .getDefinition() .getUuid(); } else { - lifecycleDefUuid = document + lifecycleDefUuid = getContentItem() .getContentType() .getDefaultLifecycle() .getUuid(); @@ -174,8 +146,8 @@ public class PublishStep implements MvcAuthoringStep { return "org/librecms/ui/documents/publish.xhtml"; } else { return documentUi.showAccessDenied( - section, - document, + getContentSection(), + getContentItem(), defaultStepsMessageBundle.getMessage( "access_to_authoringstep_denied", new String[]{getLabel()} ) @@ -183,15 +155,29 @@ public class PublishStep implements MvcAuthoringStep { } } - /** - * Is the current document live? - * - * @return - */ - public boolean isLive() { - return itemManager.isLive(document); + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + @Override + public String applyEdits(final Map formParameters) { + if (!formParameters.containsKey(SELECTED_LIFECYCLE_DEF_UUID) + || formParameters.get(SELECTED_LIFECYCLE_DEF_UUID) == null + || formParameters.get(SELECTED_LIFECYCLE_DEF_UUID).length == 0) { + if (!formParameters.containsKey(SELECTED_LIFECYCLE_DEF_UUID) + || formParameters.get(SELECTED_LIFECYCLE_DEF_UUID) == null + || formParameters.get(SELECTED_LIFECYCLE_DEF_UUID).length == 0) { + models.put("missingLifecycleDefinitionUuid", true); + addParameterValueToModels(formParameters, START_DATE); + addParameterValueToModels(formParameters, START_TIME); + addParameterValueToModels(formParameters, END_DATE); + addParameterValueToModels(formParameters, END_TIME); + + return "org/librecms/ui/documenttypes/publish.xhtml"; + } + } } + + /** * Get the label of the lifecycle assigned to the current content item. The * value is determined from the label of the definition of the lifecycle @@ -204,7 +190,7 @@ public class PublishStep implements MvcAuthoringStep { @Transactional(Transactional.TxType.REQUIRED) public String getAssignedLifecycleLabel() { return Optional - .ofNullable(document.getLifecycle()) + .ofNullable(getContentItem().getLifecycle()) .map(Lifecycle::getDefinition) .map(LifecycleDefinition::getLabel) .map(globalizationHelper::getValueFromLocalizedString) @@ -224,7 +210,7 @@ public class PublishStep implements MvcAuthoringStep { @Transactional(Transactional.TxType.REQUIRED) public String getAssignedLifecycleDecription() { return Optional - .ofNullable(document.getLifecycle()) + .ofNullable(getContentItem().getLifecycle()) .map(Lifecycle::getDefinition) .map(LifecycleDefinition::getDescription) .map(globalizationHelper::getValueFromLocalizedString) @@ -247,16 +233,14 @@ public class PublishStep implements MvcAuthoringStep { * * @return A redirect the the publish step. */ - @POST - @Path("/@publish") + @MvcAuthoringAction( + method = MvcAuthoringActionMethod.POST, + path = "/@publish" + ) @Transactional(Transactional.TxType.REQUIRED) public String publish( - @FormParam("selectedLifecycleDefUuid") - final String selectedLifecycleDefUuid, - @FormParam("startDate") final String startDateParam, - @FormParam("startTime") final String startTimeParam, - @FormParam("endDate") final String endDateParam, - @FormParam("endTime") final String endTimeParam + final String parameterPath, + final Map parameters ) { if (selectedLifecycleDefUuid == null) { models.put("missingLifecycleDefinitionUuid", true); @@ -403,14 +387,14 @@ public class PublishStep implements MvcAuthoringStep { @Path("/@unpublish") @Transactional(Transactional.TxType.REQUIRED) public String unpublish() { - if (!itemPermissionChecker.canPublishItems(document)) { + if (!itemPermissionChecker.canPublishItems(document)) { return documentUi.showAccessDenied( section, document, "item.unpublish" ); } - + itemManager.unpublish(document); return String.format( @@ -420,5 +404,6 @@ public class PublishStep implements MvcAuthoringStep { PATH_FRAGMENT ); } - + + }