diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationContactEntryKeysController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationContactEntryKeysController.java new file mode 100644 index 000000000..11e5e8334 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationContactEntryKeysController.java @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2021 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui.contentsections; + +import org.libreccm.api.IdentifierParser; +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.l10n.LocalizedString; +import org.libreccm.security.AuthorizationRequired; +import org.librecms.assets.ContactEntryKey; +import org.librecms.assets.ContactEntryKeyRepository; +import org.librecms.contentsection.ContentSection; + +import java.util.List; +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.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +/** + * Controller for managing the available {@link ContactEntryKey}s. + * + * @author Jens Pelzetter + */ +@RequestScoped +@Controller +@Path("/{sectionIdentifier}/configuration/contactentrykeys") +public class ConfigurationContactEntryKeysController { + + /** + * Checks admin permissions for the current content section. + */ + @Inject + private AdminPermissionsChecker adminPermissionsChecker; + + @Inject + private ContactEntryKeysTableModel tableModel; + + @Inject + private ContactEntryKeyRepository contactEntryKeyRepo; + + /** + * Model for the current content section. + */ + @Inject + private ContentSectionModel sectionModel; + + /** + * Provides common functions for controllers working with content sections. + */ + @Inject + private ContentSectionsUi sectionsUi; + + /** + * Provides functions for working with {@link LocalizedString}s. + */ + @Inject + private GlobalizationHelper globalizationHelper; + + /** + * Used to parse identifiers. + */ + @Inject + private IdentifierParser identifierParser; + + @Inject + private Models models; + + @Inject + private SelectedContactEntryKeyModel selectedEntryModel; + + @GET + @Path("/") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String listContactEntryKeys( + @PathParam("sectionIdentifier") final String sectionIdentifierParam + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifierParam); + if (!sectionResult.isPresent()) { + sectionsUi.showContentSectionNotFound(sectionIdentifierParam); + } + final ContentSection section = sectionResult.get(); + sectionModel.setSection(section); + if (!adminPermissionsChecker.canAdministerContentTypes(section)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifierParam + ); + } + + tableModel.setContactEntrykeys( + contactEntryKeyRepo + .findAll() + .stream() + .map(this::buildContactEntryKeyListItemModel) + .collect(Collectors.toList()) + ); + + return "org/librecms/ui/contentsection/configuration/contactentrykeys.xhtml"; + } + + private ContactEntryKeysTableRowModel buildContactEntryKeyListItemModel( + final ContactEntryKey contactEntryKey + ) { + final ContactEntryKeysTableRowModel model + = new ContactEntryKeysTableRowModel(); + + model.setEntryKey(contactEntryKey.getEntryKey()); + model.setKeyId(contactEntryKey.getKeyId()); + model.setLabel( + globalizationHelper.getValueFromLocalizedString( + contactEntryKey.getLabel() + ) + ); + + return model; + } + + @GET + @Path("/{contactEntryKey}") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String showContactEntryKey( + @PathParam("sectionIdentifier") final String sectionIdentifierParam, + @PathParam("contactEntryKey") final String entryKey + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifierParam); + if (!sectionResult.isPresent()) { + sectionsUi.showContentSectionNotFound(sectionIdentifierParam); + } + final ContentSection section = sectionResult.get(); + sectionModel.setSection(section); + if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifierParam + ); + } + + final Optional contactEntryKeyResult + = contactEntryKeyRepo.findByEntryKey(entryKey); + if (!contactEntryKeyResult.isPresent()) { + return showContactEntryKeyNotFound( + section, entryKey + ); + } + + final ContactEntryKey contactEntryKey = contactEntryKeyResult.get(); + selectedEntryModel.setEntryId(contactEntryKey.getKeyId()); + selectedEntryModel.setKey(contactEntryKey.getEntryKey()); + + final List availableLocales = globalizationHelper + .getAvailableLocales(); + + selectedEntryModel.setLabels( + contactEntryKey + .getLabel() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + entry -> entry.getValue() + ) + ) + ); + final Set labelLocales = contactEntryKey + .getLabel() + .getAvailableLocales(); + selectedEntryModel.setUnusedLabelLocales( + availableLocales + .stream() + .filter(locale -> !labelLocales.contains(locale)) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + + return "org/librecms/ui/contentsection/configuration/contactentrykey.xhtml"; + } + + @POST + @Path("/@add") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String addContactEntryKey( + @PathParam("sectionIdentifier") final String sectionIdentifierParam, + @FormParam("contactEntryKey") final String entryKey + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifierParam); + if (!sectionResult.isPresent()) { + sectionsUi.showContentSectionNotFound(sectionIdentifierParam); + } + final ContentSection section = sectionResult.get(); + sectionModel.setSection(section); + if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifierParam + ); + } + + if (!contactEntryKeyRepo.findByEntryKey(entryKey).isPresent()) { + final ContactEntryKey contactEntryKey = new ContactEntryKey(); + contactEntryKey.setEntryKey(entryKey); + contactEntryKeyRepo.save(contactEntryKey); + } + + return String.format( + "redirect:/%s/configuration/contactentrykeys", + sectionIdentifierParam + ); + } + + @POST + @Path("/{contactEntryKey}/@delete") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String deleteContactEntryKey( + @PathParam("sectionIdentifier") final String sectionIdentifierParam, + @PathParam("contactEntryKey") final String entryKey + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifierParam); + if (!sectionResult.isPresent()) { + sectionsUi.showContentSectionNotFound(sectionIdentifierParam); + } + final ContentSection section = sectionResult.get(); + sectionModel.setSection(section); + if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifierParam + ); + } + + final Optional contactEntryKeyResult + = contactEntryKeyRepo.findByEntryKey(entryKey); + if (!contactEntryKeyResult.isPresent()) { + return showContactEntryKeyNotFound( + section, entryKey + ); + } + + final ContactEntryKey contactEntryKey = contactEntryKeyResult.get(); + contactEntryKeyRepo.delete(contactEntryKey); + + return String.format( + "redirect:/%s/configuration/contactentrykeys", + sectionIdentifierParam + ); + } + + @POST + @Path("/{contactEntryKey}/label/@add") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String addEntryLabel( + @PathParam("sectionIdentifier") final String sectionIdentifierParam, + @PathParam("contactEntryKey") final String entryKey, + @FormParam("locale") final String localeParam, + @FormParam("value") final String value + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifierParam); + if (!sectionResult.isPresent()) { + sectionsUi.showContentSectionNotFound(sectionIdentifierParam); + } + final ContentSection section = sectionResult.get(); + sectionModel.setSection(section); + if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifierParam + ); + } + + final Optional contactEntryKeyResult + = contactEntryKeyRepo.findByEntryKey(entryKey); + if (!contactEntryKeyResult.isPresent()) { + return showContactEntryKeyNotFound( + section, entryKey + ); + } + + final ContactEntryKey contactEntryKey = contactEntryKeyResult.get(); + contactEntryKey.getLabel().addValue(new Locale(localeParam), value); + contactEntryKeyRepo.save(contactEntryKey); + + return String.format( + "redirect:/%s/configuration/contactentrykeys/%s", + sectionIdentifierParam, + entryKey + ); + } + + @POST + @Path("/{contactEntryKey}/label/@add/{locale}") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String editEntryLabel( + @PathParam("sectionIdentifier") final String sectionIdentifierParam, + @PathParam("contactEntryKey") final String entryKey, + @PathParam("locale") final String localeParam, + @FormParam("value") final String value + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifierParam); + if (!sectionResult.isPresent()) { + sectionsUi.showContentSectionNotFound(sectionIdentifierParam); + } + final ContentSection section = sectionResult.get(); + sectionModel.setSection(section); + if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifierParam + ); + } + + final Optional contactEntryKeyResult + = contactEntryKeyRepo.findByEntryKey(entryKey); + if (!contactEntryKeyResult.isPresent()) { + return showContactEntryKeyNotFound( + section, entryKey + ); + } + + final ContactEntryKey contactEntryKey = contactEntryKeyResult.get(); + contactEntryKey.getLabel().addValue(new Locale(localeParam), value); + contactEntryKeyRepo.save(contactEntryKey); + + return String.format( + "redirect:/%s/configuration/contactentrykeys/%s", + sectionIdentifierParam, + entryKey + ); + } + + @POST + @Path("/{contactEntryKey}/label/@remove/{locale}") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String removeEntryLabel( + @PathParam("sectionIdentifier") final String sectionIdentifierParam, + @PathParam("contactEntryKey") final String entryKey, + @FormParam("locale") final String localeParam + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifierParam); + if (!sectionResult.isPresent()) { + sectionsUi.showContentSectionNotFound(sectionIdentifierParam); + } + final ContentSection section = sectionResult.get(); + sectionModel.setSection(section); + if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifierParam + ); + } + + final Optional contactEntryKeyResult + = contactEntryKeyRepo.findByEntryKey(entryKey); + if (!contactEntryKeyResult.isPresent()) { + return showContactEntryKeyNotFound( + section, entryKey + ); + } + + final ContactEntryKey contactEntryKey = contactEntryKeyResult.get(); + contactEntryKey.getLabel().removeValue(new Locale(localeParam)); + contactEntryKeyRepo.save(contactEntryKey); + + return String.format( + "redirect:/%s/configuration/contactentrykeys/%s", + sectionIdentifierParam, + entryKey + ); + } + + private String showContactEntryKeyNotFound( + final ContentSection section, final String entryKey + ) { + models.put("sectionIdentifier", section.getLabel()); + models.put("entryKey", entryKey); + + return "org/librecms/ui/contentsection/configuration/contactentrykey-not-found.xhtml"; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContactEntryKeysTableModel.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContactEntryKeysTableModel.java new file mode 100644 index 000000000..c3649bef1 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContactEntryKeysTableModel.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui.contentsections; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("CmsContactEntryKeysTableModel") +public class ContactEntryKeysTableModel { + + private List contactEntrykeys; + + public List getContactEntrykeys() { + return Collections.unmodifiableList(contactEntrykeys); + } + + protected void setContactEntrykeys( + List contactEntrykeys) { + this.contactEntrykeys = new ArrayList<>(contactEntrykeys); + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContactEntryKeysTableRowModel.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContactEntryKeysTableRowModel.java new file mode 100644 index 000000000..b5b3c4230 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContactEntryKeysTableRowModel.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui.contentsections; + + +/** + * + * @author Jens Pelzetter + */ +public class ContactEntryKeysTableRowModel { + + private long keyId; + + private String entryKey; + + private String label; + + public long getKeyId() { + return keyId; + } + + protected void setKeyId(final long keyId) { + this.keyId = keyId; + } + + public String getEntryKey() { + return entryKey; + } + + protected void setEntryKey(final String entryKey) { + this.entryKey = entryKey; + } + + public String getLabel() { + return label; + } + + protected void setLabel(final String label) { + this.label = label; + } + + + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/SelectedContactEntryKeyModel.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/SelectedContactEntryKeyModel.java new file mode 100644 index 000000000..4586858ba --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/SelectedContactEntryKeyModel.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui.contentsections; + +import 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("CmsSelectedContactEntryKeyModel") +public class SelectedContactEntryKeyModel { + + private long entryId; + + private String key; + + private List unusedLabelLocales; + + private Map labels; + + public long getEntryId() { + return entryId; + } + + protected void setEntryId(long entryId) { + this.entryId = entryId; + } + + public String getKey() { + return key; + } + + protected void setKey(String key) { + this.key = key; + } + + public List getUnusedLabelLocales() { + return Collections.unmodifiableList(unusedLabelLocales); + } + + protected void setUnusedLabelLocales(final List unusedLabelLocales) { + this.unusedLabelLocales = new ArrayList<>(unusedLabelLocales); + } + + public Map getLabels() { + return Collections.unmodifiableMap(labels); + } + + protected void setLabels(final Map labels) { + this.labels = new HashMap<>(labels); + } + + + +} diff --git a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/configuration/index.xhtml b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/configuration/index.xhtml index e4e4b1396..78355d968 100644 --- a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/configuration/index.xhtml +++ b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/configuration/index.xhtml @@ -113,6 +113,29 @@

+
+
+ +
+
+

+ + #{CmsAdminMessages['contentsection.configuration.contactentrykeys.title']} + +

+

+ #{CmsAdminMessages['contentsection.configuration.contactentrykeys.description']} +

+
+
diff --git a/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages.properties b/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages.properties index fbd40a8ef..cf846df6f 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages.properties @@ -794,3 +794,5 @@ contentsection.assets.asset_type.not_available.message=No asset type {1} availab contentsection.assets.createstep.not_available.title=No create step available contentsection.assets.createstep.breadcrumb=Create {0} asset contentsection.assets.createstep.not_available.message=Unable to create new asset of type {2} in folder {1} of content section{0}. Create step for asset type {2} not available. +contentsection.configuration.contactentrykeys.title=Contact Entry Keys +contentsection.configuration.contactentrykeys.description=Configure the possible keys for contact data entries. diff --git a/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages_de.properties b/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages_de.properties index f4a4b47dc..223b24cd4 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages_de.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages_de.properties @@ -795,3 +795,5 @@ contentsection.assets.asset_type.not_available.message=Kein Asset Typ {1} f\u00f contentsection.assets.createstep.not_available.title=Kein Formular zum Erstellen verf\u00fcgbar contentsection.assets.createstep.breadcrumb={0} asset anlegen contentsection.assets.createstep.not_available.message=Anlegen eines Assets vom Type {2} in Ordner {1} der Content Section {0} nicht m\u00f6glich. Formular zum Anlegen von Assets des Types {2} nicht verf\u00fcgbar. +contentsection.configuration.contactentrykeys.title=Kontaktdaten-Schl\u00fcssel +contentsection.configuration.contactentrykeys.description=Verwalten der m\u00f6glichen Kontaktdaten-Angaben. diff --git a/ccm-core/src/main/resources/META-INF/resources/components/bootstrap/svgIcon.xhtml b/ccm-core/src/main/resources/META-INF/resources/components/bootstrap/svgIcon.xhtml index c8751f49e..3e03e0f51 100644 --- a/ccm-core/src/main/resources/META-INF/resources/components/bootstrap/svgIcon.xhtml +++ b/ccm-core/src/main/resources/META-INF/resources/components/bootstrap/svgIcon.xhtml @@ -6,9 +6,13 @@ + -