New annotations for authoring steps

pull/10/head
Jens Pelzetter 2021-04-20 20:05:48 +02:00
parent 5239c601a8
commit a31e242c48
9 changed files with 367 additions and 84 deletions

View File

@ -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)

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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<String, String[]> 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<String, String[]> 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]
);
}
}

View File

@ -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()) {

View File

@ -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:
*
* <pre>
* actionMethod(String parameterPath, Map<String, String[]> parameters)
* </pre>
*
* 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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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;
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public enum MvcAuthoringActionMethod {
GET,
POST
}

View File

@ -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<? extends MvcAuthoringStep>[] authoringSteps();
MvcAuthoringKitStep[] authoringSteps();
/**
* If set to {@code true} some authoring steps like categorization or

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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<? extends MvcAuthoringStep> authoringStep();
}

View File

@ -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<String, String[]> formParameters);
}

View File

@ -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<? extends ContentItem> 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<String, String[]> 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<String, String[]> 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
);
}
}