diff --git a/ccm-cms/src/main/java/org/librecms/contenttypes/Event.java b/ccm-cms/src/main/java/org/librecms/contenttypes/Event.java
index e46bbb35c..29cd4e43e 100644
--- a/ccm-cms/src/main/java/org/librecms/contenttypes/Event.java
+++ b/ccm-cms/src/main/java/org/librecms/contenttypes/Event.java
@@ -45,7 +45,7 @@ import org.librecms.contentsection.ContentItem;
import javax.validation.constraints.NotNull;
-import static org.librecms.CmsConstants.*;
+import static org.librecms.CmsConstants.DB_SCHEMA;
/**
* @author Alexander Konermann
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleCreateStep.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleCreateStep.java
index 5ea200093..7da8e5e72 100644
--- a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleCreateStep.java
+++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleCreateStep.java
@@ -35,7 +35,6 @@ import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.inject.Inject;
-import javax.mvc.Models;
import javax.transaction.Transactional;
/**
@@ -56,8 +55,7 @@ public class MvcArticleCreateStep
private static final String FORM_PARAM_INITIAL_LOCALE = "locale";
- private static final String FORM_PARAM_SELECTED_WORKFLOW
- = "workflow";
+ private static final String FORM_PARAM_SELECTED_WORKFLOW = "workflow";
/**
* Provides functions for working with content items.
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/EventMessageBundle.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/EventMessageBundle.java
new file mode 100644
index 000000000..839206a43
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/EventMessageBundle.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.contenttypes.event;
+
+import org.libreccm.ui.AbstractMessagesBean;
+import org.librecms.contenttypes.Event;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Named;
+
+/**
+ * Message bundle for the authorings steps for editing an {@link Event}.
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+@Named("CmsEventMessageBundle")
+public class EventMessageBundle extends AbstractMessagesBean {
+
+ @Override
+ public String getMessageBundle() {
+ return EventStepsConstants.BUNDLE;
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/EventStepsConstants.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/EventStepsConstants.java
new file mode 100644
index 000000000..b9e3d049f
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/EventStepsConstants.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 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.contenttypes.event;
+
+/**
+ * Constants for the authoring steps for editing an {@link Event}.
+ *
+ * @author Jens Pelzetter
+ */
+public final class EventStepsConstants {
+
+ private EventStepsConstants() {
+ // Nothing
+ }
+
+ public static final String BUNDLE
+ = "org.librecms.ui.contenttypes.EventBundle";
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventCreateStep.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventCreateStep.java
new file mode 100644
index 000000000..83a137b70
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventCreateStep.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2022 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.contenttypes.event;
+
+import org.libreccm.l10n.GlobalizationHelper;
+import org.libreccm.security.AuthorizationRequired;
+import org.libreccm.workflow.Workflow;
+import org.librecms.contentsection.ContentItemManager;
+import org.librecms.contentsection.ContentItemRepository;
+import org.librecms.contenttypes.Event;
+import org.librecms.ui.contentsections.documents.AbstractMvcDocumentCreateStep;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.transaction.Transactional;
+
+/**
+ * Describes the create step for an {@link Event}
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+@Named("CmsEventCreateStep")
+public class MvcEventCreateStep
+ extends AbstractMvcDocumentCreateStep {
+
+ private static final String FORM_PARAM_NAME = "name";
+
+ private static final String FORM_PARAM_TITLE = "title";
+
+ private static final String FORM_PARAM_SUMMARY = "summary";
+
+ private static final String FORM_PARAM_INITIAL_LOCALE = "locale";
+
+ private static final String FORM_PARAM_SELECTED_WORKFLOW = "workflow";
+
+ /**
+ * Provides functions for working with content items.
+ */
+ @Inject
+ private ContentItemManager itemManager;
+
+ /**
+ * Used to save the event.
+ */
+ @Inject
+ private ContentItemRepository itemRepo;
+
+ /**
+ * Provides functions for working with {@link LocalizedString}s.
+ */
+ @Inject
+ private GlobalizationHelper globalizationHelper;
+
+ /**
+ * Name of the event.
+ */
+ private String name;
+
+ /**
+ * Title of the event.
+ */
+ private String title;
+
+ /**
+ * Summary of the event.
+ */
+ private String summary;
+
+ /**
+ * The initial locale of the event.
+ */
+ private String initialLocale;
+
+ /**
+ * The workflow to use for the new event.
+ */
+ private String selectedWorkflow;
+
+ @Override
+ public String getDocumentType() {
+ return Event.class.getName();
+ }
+
+ @Override
+ public String getDescription() {
+ return globalizationHelper
+ .getLocalizedTextsUtil(getBundle())
+ .getText("createstep.description");
+ }
+
+ @Override
+ public String getBundle() {
+ return EventStepsConstants.BUNDLE;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ public String getInitialLocale() {
+ return initialLocale;
+ }
+
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String getSelectedWorkflow() {
+ if (selectedWorkflow == null || selectedWorkflow.isEmpty()) {
+ return getContentSection()
+ .getContentTypes()
+ .stream()
+ .filter(
+ type -> type.getContentItemClass().equals(
+ Event.class.getName()
+ )
+ )
+ .findAny()
+ .map(type -> type.getDefaultWorkflow())
+ .map(
+ workflow -> globalizationHelper.getValueFromLocalizedString(
+ workflow.getName()
+ )
+ )
+ .orElse("");
+ } else {
+ return selectedWorkflow;
+ }
+ }
+
+ @Override
+ public String showCreateStep() {
+ return "org/librecms/ui/contenttypes/event/create-event.xhtml";
+ }
+
+ @AuthorizationRequired
+ @Transactional(Transactional.TxType.REQUIRED)
+ @Override
+ public String createItem(final Map formParams) {
+ if (!formParams.containsKey(FORM_PARAM_NAME)
+ || formParams.get(FORM_PARAM_NAME) == null
+ || formParams.get(FORM_PARAM_NAME).length == 0) {
+ addMessage(
+ "danger",
+ globalizationHelper
+ .getLocalizedTextsUtil(getBundle())
+ .getText("createstep.name.error.missing")
+ );
+ return showCreateStep();
+ }
+
+ name = formParams.get(FORM_PARAM_NAME)[0];
+ if (!name.matches("^([a-zA-Z0-9_-]*)$")) {
+ addMessage(
+ "danger",
+ globalizationHelper
+ .getLocalizedTextsUtil(getBundle())
+ .getText("createstep.name.error.invalid")
+ );
+ return showCreateStep();
+ }
+
+ if (!formParams.containsKey(FORM_PARAM_TITLE)
+ || formParams.get(FORM_PARAM_TITLE) == null
+ || formParams.get(FORM_PARAM_TITLE).length == 0) {
+ addMessage(
+ "danger",
+ globalizationHelper
+ .getLocalizedTextsUtil(getBundle())
+ .getText("createstep.title.error.missing")
+ );
+ return showCreateStep();
+ }
+ title = formParams.get(FORM_PARAM_TITLE)[0];
+
+ if (!formParams.containsKey(FORM_PARAM_SUMMARY)
+ || formParams.get(FORM_PARAM_SUMMARY) == null
+ || formParams.get(FORM_PARAM_SUMMARY).length == 0) {
+ addMessage(
+ "danger",
+ globalizationHelper
+ .getLocalizedTextsUtil(getBundle())
+ .getText("createstep.summary.error.missing")
+ );
+ return showCreateStep();
+ }
+ summary = formParams.get(FORM_PARAM_SUMMARY)[0];
+
+ if (!formParams.containsKey(FORM_PARAM_INITIAL_LOCALE)
+ || formParams.get(FORM_PARAM_INITIAL_LOCALE) == null
+ || formParams.get(FORM_PARAM_INITIAL_LOCALE).length == 0) {
+ addMessage(
+ "danger",
+ globalizationHelper.getLocalizedTextsUtil(
+ getBundle()
+ ).getText("createstep.initial_locale.error.missing")
+ );
+ return showCreateStep();
+ }
+ final Locale locale = new Locale(
+ formParams.get(FORM_PARAM_INITIAL_LOCALE)[0]
+ );
+
+ if (!formParams.containsKey(FORM_PARAM_SELECTED_WORKFLOW)
+ || formParams.get(FORM_PARAM_SELECTED_WORKFLOW) == null
+ || formParams.get(FORM_PARAM_SELECTED_WORKFLOW).length == 0) {
+ addMessage(
+ "danger",
+ globalizationHelper.getLocalizedTextsUtil(
+ getBundle()
+ ).getText("createstep.workflow.none_selected")
+ );
+ return showCreateStep();
+ }
+ selectedWorkflow = formParams.get(FORM_PARAM_SELECTED_WORKFLOW)[0];
+
+ final Optional workflowResult = getContentSection()
+ .getWorkflowTemplates()
+ .stream()
+ .filter(template -> template.getUuid().equals(selectedWorkflow))
+ .findAny();
+
+ if (!workflowResult.isPresent()) {
+ addMessage(
+ "danger",
+ globalizationHelper.getLocalizedTextsUtil(
+ getBundle()
+ ).getText("createstep.workflow.error.not_available")
+ );
+ return showCreateStep();
+ }
+
+ if (!getMessages().isEmpty()) {
+ return showCreateStep();
+ }
+
+ final Event event = itemManager.createContentItem(
+ name,
+ getContentSection(),
+ getFolder(),
+ workflowResult.get(),
+ Event.class,
+ locale
+ );
+
+ event.getTitle().putValue(locale, title);
+ event.getDescription().putValue(locale, summary);
+ itemRepo.save(event);
+
+ return String.format(
+ "redirect:/%s/documents/%s/%s/@event-basicproperties",
+ getContentSectionLabel(),
+ getFolderPath(),
+ name
+ );
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventPropertiesStep.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventPropertiesStep.java
new file mode 100644
index 000000000..2cf4d5bc4
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventPropertiesStep.java
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2022 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.contenttypes.event;
+
+import org.libreccm.l10n.GlobalizationHelper;
+import org.libreccm.security.AuthorizationRequired;
+import org.librecms.contentsection.ContentItemManager;
+import org.librecms.contentsection.ContentItemRepository;
+import org.librecms.contentsection.FolderManager;
+import org.librecms.contenttypes.Event;
+import org.librecms.ui.contentsections.ContentSectionNotFoundException;
+import org.librecms.ui.contentsections.ItemPermissionChecker;
+import org.librecms.ui.contentsections.documents.AbstractMvcAuthoringStep;
+import org.librecms.ui.contentsections.documents.DocumentNotFoundException;
+import org.librecms.ui.contentsections.documents.DocumentUi;
+import org.librecms.ui.contentsections.documents.MvcAuthoringStepDef;
+import org.librecms.ui.contentsections.documents.MvcAuthoringSteps;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.mvc.Controller;
+import javax.mvc.Models;
+import javax.transaction.Transactional;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+/**
+ * Authoring step for editing the basic properties of an {@link Event}.
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+@Path(MvcAuthoringSteps.PATH_PREFIX + "event-basicproperties")
+@Controller
+@MvcAuthoringStepDef(
+ bundle = EventStepsConstants.BUNDLE,
+ descriptionKey = "authoringsteps.basicproperties.description",
+ labelKey = "authoringsteps.basicproperties.label",
+ supportedDocumentType = Event.class
+)
+public class MvcEventPropertiesStep extends AbstractMvcAuthoringStep {
+
+ @Inject
+ private EventMessageBundle eventMessageBundle;
+
+ /**
+ * Used for retrieving and saving the events.
+ */
+ @Inject
+ private ContentItemRepository itemRepo;
+
+ /**
+ * Provides functions for working with content items.
+ */
+ @Inject
+ private ContentItemManager itemManager;
+
+ @Inject
+ private DocumentUi documentUi;
+
+ /**
+ * Provides functions for working with folders.
+ */
+ @Inject
+ private FolderManager folderManager;
+
+ /**
+ * Provides functions for working with {@link LocalizedString}s.
+ */
+ @Inject
+ private GlobalizationHelper globalizationHelper;
+
+ @Inject
+ private ItemPermissionChecker itemPermissionChecker;
+
+ @Inject
+ private MvcEventPropertiesStepModel eventPropertiesStepModel;
+
+ @Inject
+ private Models models;
+
+ @Override
+ public Class getStepClass() {
+ return MvcEventPropertiesStep.class;
+ }
+
+ @Override
+ @Transactional(Transactional.TxType.REQUIRED)
+ protected void init() throws ContentSectionNotFoundException,
+ DocumentNotFoundException {
+ super.init();
+
+ eventPropertiesStepModel.setName(getDocument().getDisplayName());
+
+ final Set titleLocales = getDocument()
+ .getTitle()
+ .getAvailableLocales();
+
+ eventPropertiesStepModel.setTitleValues(
+ getDocument()
+ .getTitle()
+ .getValues()
+ .entrySet()
+ .stream()
+ .collect(
+ Collectors.toMap(
+ entry -> entry.getKey().toString(),
+ entry -> entry.getValue()
+ )
+ )
+ );
+
+ eventPropertiesStepModel.setUnusedTitleLocales(
+ globalizationHelper
+ .getAvailableLocales()
+ .stream()
+ .filter(locale -> !titleLocales.contains(locale))
+ .map(Locale::toString)
+ .collect(Collectors.toList())
+ );
+
+ eventPropertiesStepModel.setDescriptionValues(
+ getDocument()
+ .getDescription()
+ .getValues()
+ .entrySet()
+ .stream()
+ .collect(
+ Collectors.toMap(
+ entry -> entry.getKey().toString(),
+ entry -> entry.getValue()
+ )
+ )
+ );
+
+ final Set descriptionLocales = getDocument()
+ .getDescription()
+ .getAvailableLocales();
+
+ eventPropertiesStepModel.setUnusedDescriptionLocales(
+ globalizationHelper
+ .getAvailableLocales()
+ .stream()
+ .filter(locale -> !descriptionLocales.contains(locale))
+ .map(Locale::toString)
+ .collect(Collectors.toList())
+ );
+
+ final Event event = (Event) getDocument();
+ final DateTimeFormatter isoDateTimeFormatter
+ = DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.systemDefault());
+
+ eventPropertiesStepModel.setStartDate(
+ Optional
+ .ofNullable(event.getStartDate())
+ .map(startDate -> startDate.toInstant())
+ .map(startDate -> isoDateTimeFormatter.format(startDate))
+ .orElse("")
+ );
+
+ eventPropertiesStepModel.setEndDate(
+ Optional
+ .ofNullable(event.getEndDate())
+ .map(endDate -> endDate.toInstant())
+ .map(endDate -> isoDateTimeFormatter.format(endDate))
+ .orElse("")
+ );
+
+ eventPropertiesStepModel.setMapLink(event.getMapLink());
+ }
+
+ @GET
+ @Path("/")
+ @AuthorizationRequired
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String showStep(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ return "org/librecms/ui/contenttypes/event/event-basic-properties.xhtml";
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ eventMessageBundle.getMessage("event.edit.denied")
+ );
+ }
+ }
+
+ /**
+ * Updates the name of the current event.
+ *
+ * @param sectionIdentifier
+ * @param documentPath
+ * @param name
+ *
+ * @return A redirect to this authoring step.
+ */
+ @POST
+ @Path("/name")
+ @AuthorizationRequired
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String updateName(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath,
+ @FormParam("name") @DefaultValue("") final String name
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ if (name.isEmpty() || name.matches("\\s*")) {
+ models.put("nameMissing", true);
+
+ return showStep(sectionIdentifier, documentPath);
+ }
+
+ getDocument().setDisplayName(name);
+ itemRepo.save(getDocument());
+
+ updateDocumentPath();
+
+ return buildRedirectPathForStep();
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ getLabel()
+ );
+ }
+ }
+
+ @POST
+ @Path("/eventproperties")
+ @AuthorizationRequired
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String updateEventProperties(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath,
+ @FormParam("startDateTime")
+ final String startDateTime,
+ @FormParam("endDateTime")
+ final String endDateTime,
+ @FormParam("timeZone")
+ final String timeZone,
+ @FormParam("mapLink")
+ final String mapLink
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ final Event event = (Event) getDocument();
+ final DateTimeFormatter isoDateTimeFormatter
+ = DateTimeFormatter.ISO_DATE_TIME
+ .withZone(ZoneId.of(timeZone));
+ event.setStartDate(
+ Date.from(
+ ZonedDateTime.parse(
+ startDateTime,
+ isoDateTimeFormatter
+ ).toInstant()
+ )
+ );
+
+ event.setEndDate(
+ Date.from(
+ ZonedDateTime.parse(
+ endDateTime,
+ isoDateTimeFormatter
+ ).toInstant()
+ )
+ );
+ event.setMapLink(mapLink);
+
+ itemRepo.save(event);
+
+ return buildRedirectPathForStep();
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ getLabel()
+ );
+ }
+ }
+
+ /**
+ * Updates a localized title of the event.
+ *
+ * @param sectionIdentifier
+ * @param documentPath
+ * @param localeParam The locale to update.
+ * @param value The updated title value.
+ *
+ * @return A redirect to this authoring step.
+ */
+ @POST
+ @Path("/title/@add")
+ @AuthorizationRequired
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String addTitle(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath,
+ @FormParam("locale") final String localeParam,
+ @FormParam("value") final String value
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ final Locale locale = new Locale(localeParam);
+ getDocument().getTitle().putValue(locale, value);
+ itemRepo.save(getDocument());
+
+ return buildRedirectPathForStep();
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ getLabel()
+ );
+ }
+ }
+
+ /**
+ * Updates a localized title of the event.
+ *
+ * @param sectionIdentifier
+ * @param documentPath
+ * @param localeParam The locale to update.
+ * @param value The updated title value.
+ *
+ * @return A redirect to this authoring step.
+ */
+ @POST
+ @Path("/title/@edit/{locale}")
+ @AuthorizationRequired
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String editTitle(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath,
+ @PathParam("locale") final String localeParam,
+ @FormParam("value") final String value
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ final Locale locale = new Locale(localeParam);
+ getDocument().getTitle().putValue(locale, value);
+ itemRepo.save(getDocument());
+
+ return buildRedirectPathForStep();
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ getLabel()
+ );
+ }
+ }
+
+ /**
+ * Removes a localized title of the event.
+ *
+ * @param sectionIdentifier
+ * @param documentPath
+ * @param localeParam The locale to remove.
+ *
+ * @return A redirect to this authoring step.
+ */
+ @POST
+ @Path("/title/@remove/{locale}")
+ @AuthorizationRequired
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String removeTitle(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath,
+ @PathParam("locale") final String localeParam
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ final Locale locale = new Locale(localeParam);
+ getDocument().getTitle().removeValue(locale);
+ itemRepo.save(getDocument());
+
+ return buildRedirectPathForStep();
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ getLabel()
+ );
+ }
+ }
+
+ /**
+ * Adds a localized description to the event.
+ *
+ * @param sectionIdentifier
+ * @param documentPath
+ * @param localeParam The locale of the description.
+ * @param value The description value.
+ *
+ * @return A redirect to this authoring step.
+ */
+ @POST
+ @Path("/description/@add")
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String addDescription(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath,
+ @FormParam("locale") final String localeParam,
+ @FormParam("value") final String value
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ final Locale locale = new Locale(localeParam);
+ getDocument().getDescription().putValue(locale, value);
+ itemRepo.save(getDocument());
+
+ return buildRedirectPathForStep();
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ getLabel()
+ );
+ }
+ }
+
+ /**
+ * Updates a localized description of the event.
+ *
+ * @param sectionIdentifier
+ * @param documentPath
+ * @param localeParam The locale to update.
+ * @param value The updated description value.
+ *
+ * @return A redirect to this authoring step.
+ */
+ @POST
+ @Path("/description/@edit/{locale}")
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String editDescription(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath,
+ @PathParam("locale") final String localeParam,
+ @FormParam("value") final String value
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ final Locale locale = new Locale(localeParam);
+ getDocument().getDescription().putValue(locale, value);
+ itemRepo.save(getDocument());
+
+ return buildRedirectPathForStep();
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ getLabel()
+ );
+ }
+ }
+
+ /**
+ * Removes a localized description of the event.
+ *
+ * @param sectionIdentifier
+ * @param documentPath
+ * @param localeParam The locale to remove.
+ *
+ * @return A redirect to this authoring step.
+ */
+ @POST
+ @Path("/description/@remove/{locale}")
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String removeDescription(
+ @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
+ final String sectionIdentifier,
+ @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
+ final String documentPath,
+ @PathParam("locale") final String localeParam
+ ) {
+ try {
+ init();
+ } catch (ContentSectionNotFoundException ex) {
+ return ex.showErrorMessage();
+ } catch (DocumentNotFoundException ex) {
+ return ex.showErrorMessage();
+ }
+
+ if (itemPermissionChecker.canEditItem(getDocument())) {
+ final Locale locale = new Locale(localeParam);
+ getDocument().getDescription().removeValue(locale);
+ itemRepo.save(getDocument());
+
+ return buildRedirectPathForStep();
+ } else {
+ return documentUi.showAccessDenied(
+ getContentSection(),
+ getDocument(),
+ getLabel()
+ );
+ }
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventPropertiesStepModel.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventPropertiesStepModel.java
new file mode 100644
index 000000000..d57a366bb
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventPropertiesStepModel.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 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.contenttypes.event;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Named;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+@Named("CmsEventPropertiesStep")
+public class MvcEventPropertiesStepModel {
+
+ private String name;
+
+ private Map titleValues;
+
+ private List unusedTitleLocales;
+
+ private Map descriptionValues;
+
+ private List unusedDescriptionLocales;
+
+ private String startDate;
+
+ private String endDate;
+
+ private String mapLink;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public Map getTitleValues() {
+ return Collections.unmodifiableMap(titleValues);
+ }
+
+ public void setTitleValues(final Map titleValues) {
+ this.titleValues = new HashMap<>(titleValues);
+ }
+
+ public List getUnusedTitleLocales() {
+ return Collections.unmodifiableList(unusedTitleLocales);
+ }
+
+ public void setUnusedTitleLocales(List unusedTitleLocales) {
+ this.unusedTitleLocales = new ArrayList<>(unusedTitleLocales);
+ }
+
+ public Map getDescriptionValues() {
+ return Collections.unmodifiableMap(descriptionValues);
+ }
+
+ public void setDescriptionValues(
+ final Map descriptionValues
+ ) {
+ this.descriptionValues = new HashMap<>(descriptionValues);
+ }
+
+ public List getUnusedDescriptionLocales() {
+ return Collections.unmodifiableList(unusedDescriptionLocales);
+ }
+
+ public void setUnusedDescriptionLocales(
+ final List unusedDescriptionLocales
+ ) {
+ this.unusedDescriptionLocales = new ArrayList<>(
+ unusedDescriptionLocales
+ );
+ }
+
+ public String getStartDate() {
+ return startDate;
+ }
+
+ public void setStartDate(final String startDate) {
+ this.startDate = startDate;
+ }
+
+ public String getEndDate() {
+ return endDate;
+ }
+
+ public void setEndDate(final String endDate) {
+ this.endDate = endDate;
+ }
+
+ public String getMapLink() {
+ return mapLink;
+ }
+
+ public void setMapLink(final String mapLink) {
+ this.mapLink = mapLink;
+ }
+
+}