diff --git a/.gitignore b/.gitignore index 1f678f857..374a1f2a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ it-pgsql-datasources.properties nb-configuration.xml +nbproject node node_modules runtime 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..36c4479af 100644 --- a/ccm-cms/src/main/java/org/librecms/contenttypes/Event.java +++ b/ccm-cms/src/main/java/org/librecms/contenttypes/Event.java @@ -42,10 +42,12 @@ import org.libreccm.l10n.LocalizedString; import org.librecms.CmsConstants; import org.librecms.contentsection.ContentItem; +import org.librecms.ui.contentsections.documents.MvcAuthoringKit; +import org.librecms.ui.contenttypes.event.MvcEventCreateStep; +import org.librecms.ui.contenttypes.event.MvcEventInfoStep; +import org.librecms.ui.contenttypes.event.MvcEventPropertiesStep; -import javax.validation.constraints.NotNull; - -import static org.librecms.CmsConstants.*; +import static org.librecms.CmsConstants.DB_SCHEMA; /** * @author Alexander Konermann @@ -77,6 +79,13 @@ import static org.librecms.CmsConstants.*; order = 2 ) }) +@MvcAuthoringKit( + createStep = MvcEventCreateStep.class, + authoringSteps = { + MvcEventPropertiesStep.class, + MvcEventInfoStep.class + } +) public class Event extends ContentItem implements Serializable { private static final long serialVersionUID = -9104886733503414635L; @@ -94,9 +103,8 @@ public class Event extends ContentItem implements Serializable { )) private LocalizedString text; - @Column(name = "START_DATE", nullable = false) + @Column(name = "START_DATE") @Temporal(TemporalType.TIMESTAMP) - @NotNull private Date startDate; @Column(name = "END_DATE") diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CmsEditorUtil.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CmsEditorUtil.java new file mode 100644 index 000000000..c4c40de99 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CmsEditorUtil.java @@ -0,0 +1,52 @@ +/* + * 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.contentsections.documents; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * + * @author Jens Pelzetter + */ +public final class CmsEditorUtil { + + private CmsEditorUtil() { + // Nothing + } + + public static CmsEditorLocaleVariantRow buildVariantRow( + final Map.Entry entry + ) { + final CmsEditorLocaleVariantRow variant + = new CmsEditorLocaleVariantRow(); + variant.setLocale(entry.getKey().toString()); + final Document document = Jsoup.parseBodyFragment(entry.getValue()); + variant.setWordCount( + new StringTokenizer(document.body().text()).countTokens() + ); + + return variant; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CmsMvcAuthoringSteps.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CmsMvcAuthoringSteps.java index 4c54011e3..fcd8672a4 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CmsMvcAuthoringSteps.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CmsMvcAuthoringSteps.java @@ -25,6 +25,9 @@ import org.librecms.ui.contentsections.documents.relatedinfo.RelatedInfoStepServ import org.librecms.ui.contenttypes.article.MvcArticlePropertiesStep; import org.librecms.ui.contenttypes.article.MvcArticleTextBodyStep; import org.librecms.ui.contenttypes.article.MvcArticleTextBodyStepResources; +import org.librecms.ui.contenttypes.event.MvcEventInfoStep; +import org.librecms.ui.contenttypes.event.MvcEventInfoStepResources; +import org.librecms.ui.contenttypes.event.MvcEventPropertiesStep; import org.librecms.ui.contenttypes.mpa.MpaSectionsResources; import org.librecms.ui.contenttypes.mpa.MvcMpaPropertiesStep; import org.librecms.ui.contenttypes.mpa.MvcMpaSectionsStep; @@ -51,6 +54,8 @@ public class CmsMvcAuthoringSteps implements MvcAuthoringSteps { RelatedInfoStep.class, MvcArticlePropertiesStep.class, MvcArticleTextBodyStep.class, + MvcEventPropertiesStep.class, + MvcEventInfoStep.class, MvcMpaPropertiesStep.class, MvcMpaSectionsStep.class ); @@ -61,6 +66,7 @@ public class CmsMvcAuthoringSteps implements MvcAuthoringSteps { return Set.of( MediaStepService.class, MvcArticleTextBodyStepResources.class, + MvcEventInfoStepResources.class, MpaSectionsResources.class, RelatedInfoStepService.class ); 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/article/MvcArticleTextBodyStep.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleTextBodyStep.java index 80befc6a6..261c4db08 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleTextBodyStep.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleTextBodyStep.java @@ -29,6 +29,7 @@ import org.librecms.ui.contentsections.ItemPermissionChecker; import org.librecms.ui.contentsections.documents.AbstractMvcAuthoringStep; import org.librecms.ui.contentsections.documents.CmsEditorLocaleVariantRow; import org.librecms.ui.contentsections.ContentSectionNotFoundException; +import org.librecms.ui.contentsections.documents.CmsEditorUtil; import org.librecms.ui.contentsections.documents.DocumentNotFoundException; import org.librecms.ui.contentsections.documents.DocumentUi; @@ -144,6 +145,7 @@ public class MvcArticleTextBodyStep extends AbstractMvcAuthoringStep { * @param sectionIdentifier * @param documentPath * @param localeParam + * * @return The template for showing a preview of the text. */ @GET @@ -167,7 +169,7 @@ public class MvcArticleTextBodyStep extends AbstractMvcAuthoringStep { articleTextBodyStepModel.setSelectedLocale( new Locale(localeParam).toString() ); - + return "org/librecms/ui/contenttypes/article/article-text/view.xhtml"; } @@ -351,16 +353,16 @@ public class MvcArticleTextBodyStep extends AbstractMvcAuthoringStep { ); articleTextBodyStepModel.setTitleValues( getArticle() - .getTitle() - .getValues() - .entrySet() - .stream() - .collect( - Collectors.toMap( - entry -> entry.getKey().toString(), - Map.Entry::getValue + .getTitle() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + Map.Entry::getValue + ) ) - ) ); articleTextBodyStepModel.setTextValues( getArticle() @@ -382,7 +384,7 @@ public class MvcArticleTextBodyStep extends AbstractMvcAuthoringStep { .getValues() .entrySet() .stream() - .map(this::buildVariantRow) + .map(CmsEditorUtil::buildVariantRow) .collect(Collectors.toList()) ); @@ -404,18 +406,4 @@ public class MvcArticleTextBodyStep extends AbstractMvcAuthoringStep { return (Article) getDocument(); } - private CmsEditorLocaleVariantRow buildVariantRow( - final Map.Entry entry - ) { - final CmsEditorLocaleVariantRow variant - = new CmsEditorLocaleVariantRow(); - variant.setLocale(entry.getKey().toString()); - final Document document = Jsoup.parseBodyFragment(entry.getValue()); - variant.setWordCount( - new StringTokenizer(document.body().text()).countTokens() - ); - - return variant; - } - } diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleTextBodyStepModel.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleTextBodyStepModel.java index 02b163275..b3c2e3fcf 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleTextBodyStepModel.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/article/MvcArticleTextBodyStepModel.java @@ -38,9 +38,9 @@ import javax.inject.Named; public class MvcArticleTextBodyStepModel { private boolean canEdit; - + private Map titleValues; - + private Map textValues; private List variants; @@ -48,7 +48,7 @@ public class MvcArticleTextBodyStepModel { private List unusedLocales; private String selectedLocale; - + public Map getTitleValues() { return Collections.unmodifiableMap(titleValues); } @@ -60,7 +60,7 @@ public class MvcArticleTextBodyStepModel { public String getTitle() { return titleValues.get(selectedLocale); } - + /** * Get all localized values of the main text. * @@ -74,7 +74,7 @@ public class MvcArticleTextBodyStepModel { this.textValues = new HashMap<>(textValues); } - /** + /** * Gets the locales for which the main text has not been defined yet. * * @return The locales for which the main text has not been defined yet. 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..298f4e985 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventCreateStep.java @@ -0,0 +1,342 @@ +/* + * 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.l10n.LocalizedString; +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.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Date; +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_STARTDATE = "startDate"; + + 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; + + /** + * The start date of the event (ISO 8601 string) + */ + private String startDate; + + /** + * 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 getStartDate() { + return startDate; + } + + 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_STARTDATE) + || formParams.get(FORM_PARAM_STARTDATE) == null + || formParams.get(FORM_PARAM_STARTDATE).length == 0) { + addMessage( + "danger", + globalizationHelper + .getLocalizedTextsUtil(getBundle()) + .getText("createstep.startdate.error.missing") + ); + return showCreateStep(); + } + startDate = formParams.get(FORM_PARAM_STARTDATE)[0]; + final DateTimeFormatter isoDateTimeFormatter + = DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.systemDefault()); + + final LocalDateTime startDateTime; + try { + startDateTime = LocalDateTime.parse( + startDate, + isoDateTimeFormatter + ); + } catch (DateTimeParseException ex) { + addMessage( + "danger", + globalizationHelper + .getLocalizedTextsUtil(getBundle()) + .getText("createstep.startdate.error.malformed") + ); + return showCreateStep(); + } + + 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.setStartDate( + Date.from( + startDateTime.toInstant( + ZoneId.systemDefault().getRules().getOffset(startDateTime) + ) + ) + ); + 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/MvcEventInfoStep.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStep.java new file mode 100644 index 000000000..286b6f57d --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStep.java @@ -0,0 +1,943 @@ +/* + * 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.configuration.ConfigurationManager; +import org.libreccm.l10n.GlobalizationHelper; +import org.librecms.contentsection.ContentItemRepository; +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.CmsEditorUtil; +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.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.mvc.Controller; +import javax.transaction.Transactional; +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 localizable information of an event. + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path(MvcAuthoringSteps.PATH_PREFIX + "event-info") +@Controller +@MvcAuthoringStepDef( + bundle = EventStepsConstants.BUNDLE, + descriptionKey = "authoringsteps.info.description", + labelKey = "authoringstep.info.label", + supportedDocumentType = Event.class +) +public class MvcEventInfoStep extends AbstractMvcAuthoringStep { + + @Inject + private EventMessageBundle eventMessageBundle; + + @Inject + private ConfigurationManager confManager; + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private DocumentUi documentUi; + + @Inject + private GlobalizationHelper globalizationHelper; + + @Inject + private ItemPermissionChecker itemPermissionChecker; + + @Inject + private MvcEventInfoStepEventDateModel eventDateModel; + + @Inject + private MvcEventInfoStepLocationModel locationModel; + + @Inject + private MvcEventInfoStepMainContributorModel mainContributorModel; + + @Inject + private MvcEventInfoStepEventTypeModel eventTypeModel; + + @Override + public Class getStepClass() { + return MvcEventInfoStep.class; + } + + @GET + @Path("/") + @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(getEvent())) { + return "org/librecms/ui/contenttypes/event/event-info.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + eventMessageBundle.getMessage("event.edit.denied") + ); + } + } + + // EventDate + @GET + @Path("/eventdate/view/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String viewEventDate( + @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(); + } + + eventDateModel.setSelectedLocale(new Locale(localeParam).toString()); + + return "org/librecms/ui/contenttypes/event/eventdate/view.xhtml"; + } + + @POST + @Path("/eventdate/add") + @Transactional(Transactional.TxType.REQUIRED) + public String addEventDateValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @FormParam("locale") final String localeParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getEvent())) { + final String value; + if (getEvent().getEventDate().getAvailableLocales().isEmpty()) { + value = ""; + } else { + value = globalizationHelper.getValueFromLocalizedString( + getEvent().getText() + ); + } + final Locale locale = new Locale(localeParam); + getEvent().getEventDate().putValue(locale, value); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @GET + @Path("/eventdate/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String editEventDateValue( + @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(getEvent())) { + eventDateModel.setSelectedLocale( + new Locale(localeParam).toString() + ); + + return "org/librecms/ui/contenttypes/event/eventdate/edit.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @POST + @Path("/eventdate/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String editEventDateValue( + @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(getEvent())) { + final Locale locale = new Locale(localeParam); + getEvent().getEventDate().putValue(locale, value); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @POST + @Path("/eventdate/remove/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String removeEventDateValue( + @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(getEvent())) { + final Locale locale = new Locale(localeParam); + getEvent().getEventDate().removeValue(locale); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + // Location + @GET + @Path("/location/view/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String viewLocation( + @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(); + } + + locationModel.setSelectedLocale(new Locale(localeParam).toString()); + + return "org/librecms/ui/contenttypes/event/location/view.xhtml"; + } + + @POST + @Path("/location/add") + @Transactional(Transactional.TxType.REQUIRED) + public String addLocationValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @FormParam("locale") final String localeParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getEvent())) { + final String value; + if (getEvent().getLocation().getAvailableLocales().isEmpty()) { + value = ""; + } else { + value = globalizationHelper.getValueFromLocalizedString( + getEvent().getLocation() + ); + } + final Locale locale = new Locale(localeParam); + getEvent().getLocation().putValue(locale, value); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @GET + @Path("/location/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String editLocationValue( + @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(getEvent())) { + locationModel.setSelectedLocale(new Locale(localeParam).toString()); + + return "org/librecms/ui/contenttypes/event/location/edit.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @POST + @Path("/location/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String editLocationValue( + @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(getEvent())) { + final Locale locale = new Locale(localeParam); + getEvent().getLocation().putValue(locale, value); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @POST + @Path("/location/remove/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String removeLocationValue( + @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(getEvent())) { + final Locale locale = new Locale(localeParam); + getEvent().getLocation().removeValue(locale); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + // Main Contributor + @GET + @Path("/main-contributor/view/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String viewMainContributor( + @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(); + } + + mainContributorModel.setSelectedLocale( + new Locale(localeParam).toString() + ); + + return "org/librecms/ui/contenttypes/event/main-contributor/view.xhtml"; + } + + @POST + @Path("/main-contributor/add") + @Transactional(Transactional.TxType.REQUIRED) + public String addMainContributorValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @FormParam("locale") final String localeParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getEvent())) { + final String value; + if (getEvent() + .getMainContributor() + .getAvailableLocales() + .isEmpty()) { + value = ""; + } else { + value = globalizationHelper.getValueFromLocalizedString( + getEvent().getMainContributor() + ); + } + final Locale locale = new Locale(localeParam); + getEvent().getMainContributor().putValue(locale, value); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @GET + @Path("/main-contributor/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String editMainContributorValue( + @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(getEvent())) { + mainContributorModel.setSelectedLocale( + new Locale(localeParam).toString() + ); + + return "org/librecms/ui/contenttypes/event/main-contributor/edit.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @POST + @Path("/main-contributor/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String editMainContributorValue( + @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(getEvent())) { + final Locale locale = new Locale(localeParam); + getEvent().getMainContributor().putValue(locale, value); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @POST + @Path("/main-contributor/remove/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String removeMainContributorValue( + @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(getEvent())) { + final Locale locale = new Locale(localeParam); + getEvent().getMainContributor().removeValue(locale); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + // Event Type + @GET + @Path("/eventtype/view/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String viewEventType( + @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(); + } + + eventTypeModel.setSelectedLocale(new Locale(localeParam).toString()); + + return "org/librecms/ui/contenttypes/event/eventtype/view.xhtml"; + } + + @POST + @Path("/eventtype/add") + @Transactional(Transactional.TxType.REQUIRED) + public String addEventTypeValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @FormParam("locale") final String localeParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getEvent())) { + final String value; + if (getEvent().getEventType().getAvailableLocales().isEmpty()) { + value = ""; + } else { + value = globalizationHelper.getValueFromLocalizedString( + getEvent().getEventType() + ); + } + final Locale locale = new Locale(localeParam); + getEvent().getEventType().putValue(locale, value); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @GET + @Path("/eventtype/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String editEventTypeValue( + @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(getEvent())) { + eventTypeModel.setSelectedLocale(new Locale(localeParam).toString()); + + return "org/librecms/ui/contenttypes/event/eventtype/edit.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @POST + @Path("/eventtype/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String editEventTypeValue( + @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(getEvent())) { + final Locale locale = new Locale(localeParam); + getEvent().getEventType().putValue(locale, value); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @POST + @Path("/eventtype/remove/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + public String removeEventTypeValue( + @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(getEvent())) { + final Locale locale = new Locale(localeParam); + getEvent().getEventType().removeValue(locale); + itemRepo.save(getEvent()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getEvent(), + getLabel() + ); + } + } + + @Override + public void init() throws ContentSectionNotFoundException, + DocumentNotFoundException { + super.init(); + + final boolean canEdit = itemPermissionChecker.canEditItem(getEvent()); + if (canEdit) { + + eventDateModel.setCanEdit(canEdit); + eventDateModel.setEventDateValues( + getEvent() + .getEventDate() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + Map.Entry::getValue + ) + ) + ); + eventDateModel.setVariants( + getEvent() + .getEventDate() + .getValues() + .entrySet() + .stream() + .map(CmsEditorUtil::buildVariantRow) + .collect(Collectors.toList()) + ); + final Set eventDateLocales = getEvent() + .getEventDate() + .getAvailableLocales(); + eventDateModel.setUnusedLocales( + globalizationHelper + .getAvailableLocales() + .stream() + .filter(locale -> !eventDateLocales.contains(locale)) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + + locationModel.setCanEdit(canEdit); + locationModel.setLocationValues( + getEvent() + .getLocation() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + Map.Entry::getValue + ) + ) + ); + locationModel.setVariants( + getEvent() + .getLocation() + .getValues() + .entrySet() + .stream() + .map(CmsEditorUtil::buildVariantRow) + .collect(Collectors.toList()) + ); + final Set locationLocales = getEvent() + .getLocation() + .getAvailableLocales(); + locationModel.setUnusedLocales( + globalizationHelper + .getAvailableLocales() + .stream() + .filter(locale -> !locationLocales.contains(locale)) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + + mainContributorModel.setCanEdit(canEdit); + mainContributorModel.setContributorValues( + getEvent() + .getMainContributor() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + Map.Entry::getValue + ) + ) + ); + mainContributorModel.setVariants( + getEvent() + .getMainContributor() + .getValues() + .entrySet() + .stream() + .map(CmsEditorUtil::buildVariantRow) + .collect(Collectors.toList()) + ); + final Set contributorLocales = getEvent() + .getMainContributor() + .getAvailableLocales(); + mainContributorModel.setUnusedLocales( + globalizationHelper + .getAvailableLocales() + .stream() + .filter(locale -> !contributorLocales.contains(locale)) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + + eventTypeModel.setCanEdit(canEdit); + eventTypeModel.setEventTypeValues( + getEvent() + .getEventType() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + Map.Entry::getValue + ) + ) + ); + eventTypeModel.setVariants( + getEvent() + .getEventType() + .getValues() + .entrySet() + .stream() + .map(CmsEditorUtil::buildVariantRow) + .collect(Collectors.toList()) + ); + final Set eventTypeLocales = getEvent() + .getEventType() + .getAvailableLocales(); + eventTypeModel.setUnusedLocales( + globalizationHelper + .getAvailableLocales() + .stream() + .filter(locale -> !eventTypeLocales.contains(locale)) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + } + } + + private Event getEvent() { + return (Event) getDocument(); + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepEventDateModel.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepEventDateModel.java new file mode 100644 index 000000000..8ca9fc415 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepEventDateModel.java @@ -0,0 +1,114 @@ +/* + * 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.librecms.ui.contentsections.documents.CmsEditorLocaleVariantRow; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("CmsEventInfoStepEventDate") +public class MvcEventInfoStepEventDateModel { + + private boolean canEdit; + + private Map eventDateValues; + + private List variants; + + private List unusedLocales; + + private String selectedLocale; + + public Map getEventDateValues() { + return Optional + .ofNullable(eventDateValues) + .map(Collections::unmodifiableMap) + .orElse(Collections.emptyMap()); + } + + protected void setEventDateValues( + final Map eventDateValues + ) { + this.eventDateValues = Optional + .ofNullable(eventDateValues) + .map(values -> new HashMap<>(values)) + .map(values -> (Map) values) + .orElse(Collections.emptyMap()); + } + + public List getVariants() { + return Optional + .ofNullable(variants) + .map(Collections::unmodifiableList) + .orElse(Collections.emptyList()); + } + + protected void setVariants(final List variants) { + this.variants = Optional + .ofNullable(variants) + .map(list -> new ArrayList<>(list)) + .map(list -> (List) list) + .orElse(Collections.emptyList()); + } + + public List getUnusedLocales() { + return Optional + .ofNullable(unusedLocales) + .map(Collections::unmodifiableList) + .orElse(Collections.emptyList()); + } + + protected void setUnusedLocales(final List unusedLocales) { + this.unusedLocales = Optional + .ofNullable(unusedLocales) + .map(list -> new ArrayList<>(list)) + .map(list -> (List) list) + .orElse(Collections.emptyList()); + } + + public String getSelectedLocale() { + return selectedLocale; + } + + protected void setSelectedLocale(final String selectedLocale) { + this.selectedLocale = selectedLocale; + } + + public boolean getCanEdit() { + return canEdit; + } + + protected void setCanEdit(final boolean canEdit) { + this.canEdit = canEdit; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepEventTypeModel.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepEventTypeModel.java new file mode 100644 index 000000000..1e9552ed9 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepEventTypeModel.java @@ -0,0 +1,114 @@ +/* + * 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.librecms.ui.contentsections.documents.CmsEditorLocaleVariantRow; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("CmsEventInfoStepEventType") +public class MvcEventInfoStepEventTypeModel { + + private boolean canEdit; + + private Map eventTypeValues; + + private List variants; + + private List unusedLocales; + + private String selectedLocale; + + public Map getEventTypeValues() { + return Optional + .ofNullable(eventTypeValues) + .map(Collections::unmodifiableMap) + .orElse(Collections.emptyMap()); + } + + protected void setEventTypeValues( + final Map eventTypeValues + ) { + this.eventTypeValues = Optional + .ofNullable(eventTypeValues) + .map(values -> new HashMap<>(values)) + .map(values -> (Map) values) + .orElse(Collections.emptyMap()); + } + + public List getVariants() { + return Optional + .ofNullable(variants) + .map(Collections::unmodifiableList) + .orElse(Collections.emptyList()); + } + + protected void setVariants(final List variants) { + this.variants = Optional + .ofNullable(variants) + .map(list -> new ArrayList<>(list)) + .map(list -> (List) list) + .orElse(Collections.emptyList()); + } + + public List getUnusedLocales() { + return Optional + .ofNullable(unusedLocales) + .map(Collections::unmodifiableList) + .orElse(Collections.emptyList()); + } + + protected void setUnusedLocales(final List unusedLocales) { + this.unusedLocales = Optional + .ofNullable(unusedLocales) + .map(list -> new ArrayList<>(list)) + .map(list -> (List) list) + .orElse(Collections.emptyList()); + } + + public String getSelectedLocale() { + return selectedLocale; + } + + protected void setSelectedLocale(final String selectedLocale) { + this.selectedLocale = selectedLocale; + } + + public boolean getCanEdit() { + return canEdit; + } + + protected void setCanEdit(final boolean canEdit) { + this.canEdit = canEdit; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepLocationModel.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepLocationModel.java new file mode 100644 index 000000000..cdbe7abc6 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepLocationModel.java @@ -0,0 +1,112 @@ +/* + * 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.librecms.ui.contentsections.documents.CmsEditorLocaleVariantRow; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("CmsEventInfoStepLocation") +public class MvcEventInfoStepLocationModel { + + private boolean canEdit; + + private Map locationValues; + + private List variants; + + private List unusedLocales; + + private String selectedLocale; + + public Map getLocationValues() { + return Optional + .ofNullable(locationValues) + .map(Collections::unmodifiableMap) + .orElse(Collections.emptyMap()); + } + + protected void setLocationValues(final Map locationValues) { + this.locationValues = Optional + .ofNullable(locationValues) + .map(values -> new HashMap<>(values)) + .map(values -> (Map) values) + .orElse(Collections.emptyMap()); + } + + public List getVariants() { + return Optional + .ofNullable(variants) + .map(Collections::unmodifiableList) + .orElse(Collections.emptyList()); + } + + protected void setVariants(final List variants) { + this.variants = Optional + .ofNullable(variants) + .map(list -> new ArrayList<>(list)) + .map(list -> (List) list) + .orElse(Collections.emptyList()); + } + + public List getUnusedLocales() { + return Optional + .ofNullable(unusedLocales) + .map(Collections::unmodifiableList) + .orElse(Collections.emptyList()); + } + + protected void setUnusedLocales(final List unusedLocales) { + this.unusedLocales = Optional + .ofNullable(unusedLocales) + .map(list -> new ArrayList<>(list)) + .map(list -> (List) list) + .orElse(Collections.emptyList()); + } + + public String getSelectedLocale() { + return selectedLocale; + } + + protected void setSelectedLocale(final String selectedLocale) { + this.selectedLocale = selectedLocale; + } + + public boolean getCanEdit() { + return canEdit; + } + + protected void setCanEdit(final boolean canEdit) { + this.canEdit = canEdit; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepMainContributorModel.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepMainContributorModel.java new file mode 100644 index 000000000..faab96494 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepMainContributorModel.java @@ -0,0 +1,114 @@ +/* + * 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.librecms.ui.contentsections.documents.CmsEditorLocaleVariantRow; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("CmsEventInfoStepMainContributor") +public class MvcEventInfoStepMainContributorModel { + + private boolean canEdit; + + private Map contributorValues; + + private List variants; + + private List unusedLocales; + + private String selectedLocale; + + public Map getContributorValues() { + return Optional + .ofNullable(contributorValues) + .map(Collections::unmodifiableMap) + .orElse(Collections.emptyMap()); + } + + protected void setContributorValues( + final Map contributorValues + ) { + this.contributorValues = Optional + .ofNullable(contributorValues) + .map(values -> new HashMap<>(values)) + .map(values -> (Map) values) + .orElse(Collections.emptyMap()); + } + + public List getVariants() { + return Optional + .ofNullable(variants) + .map(Collections::unmodifiableList) + .orElse(Collections.emptyList()); + } + + protected void setVariants(final List variants) { + this.variants = Optional + .ofNullable(variants) + .map(list -> new ArrayList<>(list)) + .map(list -> (List) list) + .orElse(Collections.emptyList()); + } + + public List getUnusedLocales() { + return Optional + .ofNullable(unusedLocales) + .map(Collections::unmodifiableList) + .orElse(Collections.emptyList()); + } + + protected void setUnusedLocales(final List unusedLocales) { + this.unusedLocales = Optional + .ofNullable(unusedLocales) + .map(list -> new ArrayList<>(list)) + .map(list -> (List) list) + .orElse(Collections.emptyList()); + } + + public String getSelectedLocale() { + return selectedLocale; + } + + protected void setSelectedLocale(final String selectedLocale) { + this.selectedLocale = selectedLocale; + } + + public boolean getCanEdit() { + return canEdit; + } + + protected void setCanEdit(final boolean canEdit) { + this.canEdit = canEdit; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepResources.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepResources.java new file mode 100644 index 000000000..210f1fa9d --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventInfoStepResources.java @@ -0,0 +1,374 @@ +/* + * 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.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemRepository; +import org.librecms.contentsection.ContentSection; +import org.librecms.contenttypes.Event; +import org.librecms.ui.contentsections.ContentSectionsUi; +import org.librecms.ui.contentsections.ItemPermissionChecker; +import org.librecms.ui.contentsections.documents.MvcAuthoringSteps; + +import java.util.Locale; +import java.util.StringTokenizer; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; +import javax.ws.rs.ForbiddenException; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path(MvcAuthoringSteps.PATH_PREFIX + "event-info-resources") +public class MvcEventInfoStepResources { + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private ContentSectionsUi sectionsUi; + + @Inject + private ItemPermissionChecker itemPermissionChecker; + + // Event Date + @GET + @Path("/eventdate/wordcount/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String getEventDateWordCount( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPathParam, + @PathParam("locale") final String localeParam + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException() + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPathParam) + .orElseThrow( + () -> new NotFoundException() + ); + + if (!(document instanceof Event)) { + throw new NotFoundException(); + } + + final Event event = (Event) document; + if (itemPermissionChecker.canEditItem(event)) { + final String text = event + .getEventDate() + .getValue(new Locale(localeParam)); + final Document jsoupDoc = Jsoup.parseBodyFragment(text); + final long result = new StringTokenizer( + jsoupDoc.body().text() + ).countTokens(); + return Long.toString(result); + } else { + throw new ForbiddenException(); + } + } + + @GET + @Path("/eventdate/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String viewEventDateValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPathParam, + @PathParam("locale") final String localeParam + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException() + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPathParam) + .orElseThrow( + () -> new NotFoundException() + ); + + if (!(document instanceof Event)) { + throw new NotFoundException(); + } + + final Event event = (Event) document; + if (itemPermissionChecker.canEditItem(event)) { + return event.getEventDate().getValue(new Locale(localeParam)); + } else { + throw new ForbiddenException(); + } + } + + // Location + @GET + @Path("/location/wordcount/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String getLocationWordCount( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPathParam, + @PathParam("locale") final String localeParam + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException() + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPathParam) + .orElseThrow( + () -> new NotFoundException() + ); + + if (!(document instanceof Event)) { + throw new NotFoundException(); + } + + final Event event = (Event) document; + if (itemPermissionChecker.canEditItem(event)) { + final String text = event + .getLocation() + .getValue(new Locale(localeParam)); + final Document jsoupDoc = Jsoup.parseBodyFragment(text); + final long result = new StringTokenizer( + jsoupDoc.body().text() + ).countTokens(); + return Long.toString(result); + } else { + throw new ForbiddenException(); + } + } + + @GET + @Path("/location/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String viewLocationValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPathParam, + @PathParam("locale") final String localeParam + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException() + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPathParam) + .orElseThrow( + () -> new NotFoundException() + ); + + if (!(document instanceof Event)) { + throw new NotFoundException(); + } + + final Event event = (Event) document; + if (itemPermissionChecker.canEditItem(event)) { + return event.getLocation().getValue(new Locale(localeParam)); + } else { + throw new ForbiddenException(); + } + } + + // Main Contributor + @GET + @Path("/main-contributor/wordcount/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String getMainContributorWordCount( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPathParam, + @PathParam("locale") final String localeParam + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException() + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPathParam) + .orElseThrow( + () -> new NotFoundException() + ); + + if (!(document instanceof Event)) { + throw new NotFoundException(); + } + + final Event event = (Event) document; + if (itemPermissionChecker.canEditItem(event)) { + final String text = event + .getMainContributor() + .getValue(new Locale(localeParam)); + final Document jsoupDoc = Jsoup.parseBodyFragment(text); + final long result = new StringTokenizer( + jsoupDoc.body().text() + ).countTokens(); + return Long.toString(result); + } else { + throw new ForbiddenException(); + } + } + + @GET + @Path("/main-contributor/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String viewMainContributorValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPathParam, + @PathParam("locale") final String localeParam + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException() + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPathParam) + .orElseThrow( + () -> new NotFoundException() + ); + + if (!(document instanceof Event)) { + throw new NotFoundException(); + } + + final Event event = (Event) document; + if (itemPermissionChecker.canEditItem(event)) { + return event.getMainContributor().getValue(new Locale(localeParam)); + } else { + throw new ForbiddenException(); + } + } + + // Event Type + @GET + @Path("/eventtype/wordcount/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String getEventTypeWordCount( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPathParam, + @PathParam("locale") final String localeParam + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException() + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPathParam) + .orElseThrow( + () -> new NotFoundException() + ); + + if (!(document instanceof Event)) { + throw new NotFoundException(); + } + + final Event event = (Event) document; + if (itemPermissionChecker.canEditItem(event)) { + final String text = event + .getEventType() + .getValue(new Locale(localeParam)); + final Document jsoupDoc = Jsoup.parseBodyFragment(text); + final long result = new StringTokenizer( + jsoupDoc.body().text() + ).countTokens(); + return Long.toString(result); + } else { + throw new ForbiddenException(); + } + } + + @GET + @Path("/eventtype/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String viewEventTypeValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPathParam, + @PathParam("locale") final String localeParam + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException() + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPathParam) + .orElseThrow( + () -> new NotFoundException() + ); + + if (!(document instanceof Event)) { + throw new NotFoundException(); + } + + final Event event = (Event) document; + if (itemPermissionChecker.canEditItem(event)) { + return event.getEventType().getValue(new Locale(localeParam)); + } else { + throw new ForbiddenException(); + } + } + +} 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..bf73f831e --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventPropertiesStep.java @@ -0,0 +1,668 @@ +/* + * 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 isoDateFormatter + = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneId.systemDefault()); + final DateTimeFormatter isoTimeFormatter + = DateTimeFormatter.ISO_TIME.withZone(ZoneId.systemDefault()); + final DateTimeFormatter isoDateTimeFormatter + = DateTimeFormatter.ISO_LOCAL_DATE_TIME + .withZone(ZoneId.systemDefault()); + + eventPropertiesStepModel.setStartDateTime( + Optional + .ofNullable(event.getStartDate()) + .map(startDate -> startDate.toInstant()) + .map(startDate -> isoDateTimeFormatter.format(startDate)) + .orElse("") + ); + eventPropertiesStepModel.setFormattedStartDateTime( + Optional + .ofNullable(event.getStartDate()) + .map(startDate -> startDate.toInstant()) + .map( + startDate -> String.format( + "%s %s", + isoDateFormatter.format(startDate), + isoTimeFormatter.format(startDate) + ) + ) + .orElse("") + ); + + eventPropertiesStepModel.setEndDateTime( + Optional + .ofNullable(event.getEndDate()) + .map(endDate -> endDate.toInstant()) + .map(endDate -> isoDateTimeFormatter.format(endDate)) + .orElse("") + ); + eventPropertiesStepModel.setFormattedEndDateTime( + Optional + .ofNullable(event.getEndDate()) + .map(endDate -> endDate.toInstant()) + .map( + endDate -> String.format( + "%s %s", + isoDateFormatter.format(endDate), + isoTimeFormatter.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("/eventdatetime") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String updateEventDateTime( + @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 + ) { + 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.systemDefault()); + event.setStartDate( + Date.from( + ZonedDateTime.parse( + startDateTime, + isoDateTimeFormatter + ).toInstant() + ) + ); + + event.setEndDate( + Date.from( + ZonedDateTime.parse( + endDateTime, + isoDateTimeFormatter + ).toInstant() + ) + ); + + itemRepo.save(event); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDocument(), + getLabel() + ); + } + } + + @POST + @Path("/maplink") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String updateMapLink( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @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(); + + 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..ce022210e --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/event/MvcEventPropertiesStepModel.java @@ -0,0 +1,156 @@ +/* + * 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 startDateTime; + + private String formattedStartDateTime; + + private String endDateTime; + + private String formattedEndDateTime; + + 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 getStartDateTime() { + return startDateTime; + } + + public void setStartDateTime(final String startDateTime) { + this.startDateTime = startDateTime; + } + + public String getFormattedStartDateTime() { + return formattedStartDateTime; + } + + public void setFormattedStartDateTime(final String formattedStartDateTime) { + this.formattedStartDateTime = formattedStartDateTime; + } + + public boolean getHasStartDate() { + return !startDateTime.isBlank(); + } + + public String getEndDateTime() { + return endDateTime; + } + + public void setEndDateTime(final String endDateTime) { + this.endDateTime = endDateTime; + } + + public String getFormattedEndDateTime() { + return formattedEndDateTime; + } + + public void setFormattedEndDateTime(final String formattedEndDateTime) { + this.formattedEndDateTime = formattedEndDateTime; + } + + public boolean getHasEndDate() { + return !endDateTime.isBlank(); + } + + public String getMapLink() { + return mapLink; + } + + public void setMapLink(final String mapLink) { + this.mapLink = mapLink; + } + + public boolean getHasMapLink() { + return !mapLink.isBlank(); + } + +} diff --git a/ccm-cms/src/main/resources/META-INF/resources/components/librecms/cmsEditorVariants.xhtml b/ccm-cms/src/main/resources/META-INF/resources/components/librecms/cmsEditorVariants.xhtml index 6318a72a7..d084b0477 100644 --- a/ccm-cms/src/main/resources/META-INF/resources/components/librecms/cmsEditorVariants.xhtml +++ b/ccm-cms/src/main/resources/META-INF/resources/components/librecms/cmsEditorVariants.xhtml @@ -189,6 +189,13 @@ shortDescription="Info about the available variants. Must be a List of CmsEditorLocaleVariantRow objects." type="java.util.List" /> +