From 1c7bef4f982e714e2c11187634d6187303148883 Mon Sep 17 00:00:00 2001 From: Jens Pelzetter Date: Sat, 1 Oct 2022 17:56:28 +0200 Subject: [PATCH] Java part of UI for sci-types-department --- .../scidepartment/SciDepartment.java | 2 - .../ui/SciDepartmentAuthoringSteps.java | 35 + .../ui/SciDepartmentContact.java | 67 + .../ui/SciDepartmentContactModel.java | 67 + .../ui/SciDepartmentCreateStep.java | 138 +- .../ui/SciDepartmentDescriptionContacts.java | 101 ++ ...SciDepartmentDescriptionContactsModel.java | 57 + .../SciDepartmentDescriptionMembersModel.java | 60 + .../ui/SciDepartmentDescriptionModel.java | 114 ++ .../ui/SciDepartmentDescriptionStep.java | 1177 ++++++++++++++++- ...SciDepartmentDescriptionStepResources.java | 123 ++ .../SciDepartmentDescriptionStepService.java | 130 ++ .../SciDepartmentExtendedPropertiesStep.java | 26 - .../ui/SciDepartmentMembershipModel.java | 143 ++ .../ui/SciDepartmentMessageBundle.java | 21 + .../ui/SciDepartmentPropertiesStep.java | 468 ++++++- .../ui/SciDepartmentPropertiesStepModel.java | 76 ++ .../ui/SciDepartmentTextModel.java | 84 ++ .../ui/SciDepartmentTextsModel.java | 53 + .../ui/SciDepartmentBundle.properties | 7 + .../ui/SciDepartmentBundle_de.properties | 7 + .../ui/SciProjectDescriptionStepService.java | 2 +- scicms-bundle-devel-wildfly/.gitignore | 1 + .../runtime.properties | 7 - 24 files changed, 2909 insertions(+), 57 deletions(-) create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentAuthoringSteps.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentContact.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentContactModel.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionContacts.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionContactsModel.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionMembersModel.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionModel.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStepResources.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStepService.java delete mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentExtendedPropertiesStep.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentMembershipModel.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentMessageBundle.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentPropertiesStepModel.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentTextModel.java create mode 100644 sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentTextsModel.java create mode 100644 sci-types-department/src/main/resources/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentBundle.properties create mode 100644 sci-types-department/src/main/resources/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentBundle_de.properties create mode 100644 scicms-bundle-devel-wildfly/.gitignore delete mode 100644 scicms-bundle-devel-wildfly/runtime.properties diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/SciDepartment.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/SciDepartment.java index 742c941..089c4a3 100644 --- a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/SciDepartment.java +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/SciDepartment.java @@ -10,7 +10,6 @@ import org.librecms.contenttypes.ContentTypeDescription; import org.librecms.ui.contentsections.documents.MvcAuthoringKit; import org.scientificcms.contenttypes.scidepartment.ui.SciDepartmentCreateStep; import org.scientificcms.contenttypes.scidepartment.ui.SciDepartmentDescriptionStep; -import org.scientificcms.contenttypes.scidepartment.ui.SciDepartmentExtendedPropertiesStep; import org.scientificcms.contenttypes.scidepartment.ui.SciDepartmentPropertiesStep; import java.io.Serializable; @@ -48,7 +47,6 @@ import static org.scientificcms.contenttypes.scidepartment.SciDepartmentConstant createStep = SciDepartmentCreateStep.class, authoringSteps = { SciDepartmentPropertiesStep.class, - SciDepartmentExtendedPropertiesStep.class, SciDepartmentDescriptionStep.class } ) diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentAuthoringSteps.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentAuthoringSteps.java new file mode 100644 index 0000000..3579b11 --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentAuthoringSteps.java @@ -0,0 +1,35 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import org.librecms.ui.contentsections.documents.MvcAuthoringSteps; + +import java.util.Set; + +import javax.enterprise.context.ApplicationScoped; + +/** + * + * @author Jens Pelzetter + */ +@ApplicationScoped +public class SciDepartmentAuthoringSteps implements MvcAuthoringSteps { + + @Override + public Set> getClasses() { + return Set.of( + SciDepartmentPropertiesStep.class, + SciDepartmentDescriptionStep.class + ); + } + + @Override + public Set> getResourceClasses() { + return Set.of( + SciDepartmentDescriptionContacts.class, + SciDepartmentDescriptionStepResources.class, + SciDepartmentDescriptionStepService.class + ); + } + + + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentContact.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentContact.java new file mode 100644 index 0000000..efc22e8 --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentContact.java @@ -0,0 +1,67 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +/** + * DTO providing the information about a {@link Contact} of a + * {@link SciDepartment} in a form that is easy to use from a MVC template. + * + * @author Jens Pelzetter + */ +public class SciDepartmentContact { + + /** + * The ID of the {@link Contact} represented by this object. + */ + private long contactId; + + /** + * The type of the contact. + * + * @see Contact#contactType + */ + private String contactType; + + /** + * Order of contact. + */ + private long order; + + /** + * The title of the {@link ContactableEntity} + * + * @see Contact#contactable + */ + private String contactable; + + public long getContactId() { + return contactId; + } + + public void setContactId(final long contactId) { + this.contactId = contactId; + } + + public String getContactType() { + return contactType; + } + + public void setContactType(final String contactType) { + this.contactType = contactType; + } + + public long getOrder() { + return order; + } + + public void setOrder(final long order) { + this.order = order; + } + + public String getContactable() { + return contactable; + } + + public void setContactable(final String contactable) { + this.contactable = contactable; + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentContactModel.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentContactModel.java new file mode 100644 index 0000000..92c9d51 --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentContactModel.java @@ -0,0 +1,67 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +/** + * DTO providing the information about a {@link Contact} of a + * {@link SciDepartment} in a form that is easy usable from a MVC template. + * + * @author Jens Pelzetter + */ +public class SciDepartmentContactModel { + + /** + * The ID of the {@link Contact} represented by this object. + */ + private long contactId; + + /** + * The type of the contact. + * + * @see Contact#contactType + */ + private String contactType; + + /** + * Order of contact. + */ + private long order; + + /** + * The title of the {@link ContactableEntity} + * + * @see Contact#contactable + */ + private String contactable; + + public long getContactId() { + return contactId; + } + + public void setContactId(final long contactId) { + this.contactId = contactId; + } + + public String getContactType() { + return contactType; + } + + public void setContactType(final String contactType) { + this.contactType = contactType; + } + + public long getOrder() { + return order; + } + + public void setOrder(final long order) { + this.order = order; + } + + public String getContactable() { + return contactable; + } + + public void setContactable(final String contactable) { + this.contactable = contactable; + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentCreateStep.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentCreateStep.java index 1978b4e..afd7ba2 100644 --- a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentCreateStep.java +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentCreateStep.java @@ -1,25 +1,142 @@ package org.scientificcms.contenttypes.scidepartment.ui; +import org.libreccm.l10n.GlobalizationHelper; +import org.librecms.contentsection.ContentItemManager; +import org.librecms.contentsection.ContentItemRepository; import org.librecms.ui.contentsections.documents.AbstractMvcDocumentCreateStep; import org.scientificcms.contenttypes.scidepartment.SciDepartment; +import org.scientificcms.contenttypes.sciproject.SciProject; import java.util.Map; import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; import javax.inject.Named; +import javax.transaction.Transactional; /** + * Create step for a {@link SciDepartment}. * * @author Jens Pelzetter */ @RequestScoped @Named("SciDepartmentCreateStep") -public class SciDepartmentCreateStep - extends AbstractMvcDocumentCreateStep{ +public class SciDepartmentCreateStep + extends AbstractMvcDocumentCreateStep { + + private static final String FORM_PARAM_NAME = "name"; + + private static final String FORM_PARAM_TITLE = "title"; + + private static final String FORM_PARAM_SHORT_DESCRIPTION = "shortdesc"; + + 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; + + /** + * Nmae of the department. + */ + private String name; + + /** + * Title of the department. + */ + private String title; + + /** + * The short description of the department. + */ + private String shortDescription; + + /** + * The initial locale of the department. + */ + private String initialLocale; + + /** + * The workflow to use for the new department. + */ + private String selectedWorkflow; + + @Override + public String getDocumentType() { + return SciDepartment.class.getName(); + } + + @Override + public String getDescription() { + return globalizationHelper + .getLocalizedTextsUtil(getBundle()) + .getText("createstep.description"); + } + + @Override + public String getBundle() { + return SciDepartmentStepsConstants.BUNDLE; + } + + public String getName() { + return name; + } + + public String getTitle() { + return title; + } + + public String getShortDescription() { + return shortDescription; + } + + 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( + SciProject.class.getName() + ) + ) + .findAny() + .map(type -> type.getDefaultWorkflow()) + .map( + workflow -> globalizationHelper.getValueFromLocalizedString( + workflow.getName() + ) + ) + .orElse(""); + } else { + return selectedWorkflow; + } + } @Override public String showCreateStep() { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + return "org/scientificcms/contenttypes/scidepartment/ui/create-scidepartment.xhtml"; } @Override @@ -27,19 +144,4 @@ public class SciDepartmentCreateStep throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody } - @Override - public String getDocumentType() { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody - } - - @Override - public String getDescription() { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody - } - - @Override - public String getBundle() { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody - } - } diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionContacts.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionContacts.java new file mode 100644 index 0000000..2b1cc35 --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionContacts.java @@ -0,0 +1,101 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemRepository; +import org.librecms.contentsection.ContentSection; +import org.librecms.ui.contentsections.ContentSectionsUi; +import org.librecms.ui.contentsections.documents.MvcAuthoringSteps; +import org.scientificcms.contenttypes.scidepartment.Contact; +import org.scientificcms.contenttypes.scidepartment.ContactRepository; +import org.scientificcms.contenttypes.scidepartment.SciDepartment; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; +import javax.ws.rs.Consumes; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path(MvcAuthoringSteps.PATH_PREFIX + "scidepartment-description-contacts") +public class SciDepartmentDescriptionContacts { + + @Inject + private ContactRepository contactRepo; + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private ContentSectionsUi sectionsUi; + + @POST + @Path("/save-order") + @Consumes(MediaType.APPLICATION_JSON) + @Transactional(Transactional.TxType.REQUIRED) + public Response saveOrder( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM) + final String documentPath, + final List order + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException( + String.format( + "No content identifed by %s found.", + sectionIdentifier + ) + ) + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPath) + .orElseThrow( + () -> new NotFoundException( + String.format( + "No document for path %s in section %s.", + documentPath, + contentSection.getLabel() + ) + ) + ); + + if (!(document instanceof SciDepartment)) { + throw new NotFoundException( + String.format( + "No SciDepartment for path %s in section %s.", + documentPath, + contentSection.getLabel() + ) + ); + } + + final Map orderMap = new HashMap<>(); + for (int i = 0; i < order.size(); i++) { + orderMap.put(Long.parseLong(order.get(i)), (long) i); + } + + final SciDepartment department = (SciDepartment)document; + for (final Contact contact : department.getContacts()) { + contact.setOrder(orderMap.get(contact.getContactId())); + contactRepo.save(contact); + } + + return Response.ok().build(); + } +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionContactsModel.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionContactsModel.java new file mode 100644 index 0000000..c48c68c --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionContactsModel.java @@ -0,0 +1,57 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import org.librecms.assets.Organization; +import org.librecms.assets.Person; + +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("SciDepartmentDescriptionContacts") +public class SciDepartmentDescriptionContactsModel { + + private boolean canEdit; + + private List contacts; + + private String baseUrl; + + public boolean getCanEdit() { + return canEdit; + } + + protected void setCanEdit(final boolean canEdit) { + this.canEdit = canEdit; + } + + public List getContacts() { + return Collections.unmodifiableList(contacts); + } + + protected void setContacts(final List contacts) { + this.contacts = new ArrayList<>(contacts); + } + + public String getContactableTypes() { + return String.join( + ",", Person.class.getName(), Organization.class.getName() + ); + } + + public String getBaseUrl() { + return baseUrl; + } + + protected void setBaseUrl(final String baseUrl) { + this.baseUrl = baseUrl; + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionMembersModel.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionMembersModel.java new file mode 100644 index 0000000..517219a --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionMembersModel.java @@ -0,0 +1,60 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("SciDepartmentDescriptionMembers") +public class SciDepartmentDescriptionMembersModel { + + private boolean canEdit; + + private List members; + + private Map statusValues; + + private String baseUrl; + + public boolean getCanEdit() { + return canEdit; + } + + protected void setCanEdit(final boolean canEdit) { + this.canEdit = canEdit; + } + + public List getMembers() { + return Collections.unmodifiableList(members); + } + + protected void setMembers(final List member) { + this.members = new ArrayList<>(members); + } + + public Map getStatusValues() { + return Collections.unmodifiableMap(statusValues); + } + + protected void setStatusValues(final Map statusValues) { + this.statusValues = new LinkedHashMap<>(statusValues); + } + + public String getBaseUrl() { + return baseUrl; + } + + protected void setBaseUrl(final String baseUrl) { + this.baseUrl = baseUrl; + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionModel.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionModel.java new file mode 100644 index 0000000..240206b --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionModel.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.scientificcms.contenttypes.scidepartment.ui; + +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("SciDepartmentDescriptionModel") +public class SciDepartmentDescriptionModel { + + private boolean canEdit; + + private Map descriptionValues; + + private List variants; + + private List unusedLocales; + + private String selectedLocale; + + public Map getDescriptionValues() { + return Optional + .ofNullable(descriptionValues) + .map(Collections::unmodifiableMap) + .orElse(Collections.emptyMap()); + } + + protected void setDescriptionValues( + final Map descriptionValues + ) { + this.descriptionValues = Optional + .ofNullable(descriptionValues) + .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/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStep.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStep.java index 0342ed8..569627e 100644 --- a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStep.java +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStep.java @@ -1,12 +1,73 @@ +/* + * 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.scientificcms.contenttypes.scidepartment.ui; +import org.libreccm.api.Identifier; +import org.libreccm.api.IdentifierParser; +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.l10n.LocalizedString; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.ui.BaseUrl; +import org.librecms.assets.ContactableEntity; +import org.librecms.assets.Person; +import org.librecms.contentsection.Asset; +import org.librecms.contentsection.AssetRepository; +import org.librecms.contentsection.ContentItemRepository; +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 org.scientificcms.contenttypes.scidepartment.Contact; +import org.scientificcms.contenttypes.scidepartment.ContactRepository; +import org.scientificcms.contenttypes.scidepartment.DepartmentText; +import org.scientificcms.contenttypes.scidepartment.DepartmentTextRepository; +import org.scientificcms.contenttypes.scidepartment.Membership; +import org.scientificcms.contenttypes.scidepartment.MembershipRepository; +import org.scientificcms.contenttypes.scidepartment.MembershipStatus; import org.scientificcms.contenttypes.scidepartment.SciDepartment; +import org.scientificcms.contenttypes.scidepartment.SciDepartmentManager; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +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.servlet.http.HttpServletRequest; +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; +import javax.ws.rs.core.Context; /** * @@ -21,6 +82,1118 @@ import javax.ws.rs.Path; labelKey = "authoringsteps.description.label", supportedDocumentType = SciDepartment.class ) -public class SciDepartmentDescriptionStep { - +public class SciDepartmentDescriptionStep extends AbstractMvcAuthoringStep { + + @Inject + private AssetRepository assetRepo; + + @Inject + private BaseUrl baseUrl; + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private ContactRepository contactRepo; + + @Inject + private DepartmentTextRepository departmentTextRepo; + + @Inject + private DocumentUi documentUi; + + @Inject + private GlobalizationHelper globalizationHelper; + + @Inject + private IdentifierParser identifierParser; + + @Context + private HttpServletRequest request; + + @Inject + private ItemPermissionChecker itemPermissionChecker; + + @Inject + private MembershipRepository membershipRepo; + + @Inject + private Models models; + + @Inject + private SciDepartmentManager departmentManager; + + @Inject + private SciDepartmentDescriptionModel descriptionModel; + + @Inject + private SciDepartmentDescriptionContactsModel contactsModel; + + @Inject + private SciDepartmentDescriptionMembersModel membersModel; + + @Inject + private SciDepartmentMessageBundle messageBundle; + + @Inject + private SciDepartmentTextsModel textsModel; + + @Override + public Class getStepClass() { + return SciDepartmentDescriptionStep.class; + } + + @GET + @Path("/") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + 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(getDepartment())) { + return "org/scientificcms/contenttypes/scidepartment/ui/scidepartment-description.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @GET + @Path("/description/view/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String viewDescription( + @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(getDepartment())) { + descriptionModel.setSelectedLocale( + new Locale(localeParam).toString() + ); + + return "org/scientificcms/contenttypes/scidepartment/ui/description/view.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/description/add") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String addDescriptionValue( + @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(getDepartment())) { + final String value; + if (getDepartment().getDepartmentDescription().getAvailableLocales() + .isEmpty()) { + value = ""; + } else { + value = globalizationHelper.getValueFromLocalizedString( + getDepartment().getDepartmentDescription() + ); + } + final Locale locale = new Locale(localeParam); + getDepartment().getDepartmentDescription().putValue(locale, value); + itemRepo.save(getDepartment()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @GET + @Path("/description/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String editDescriptionValue( + @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(getDepartment())) { + descriptionModel.setSelectedLocale( + new Locale(localeParam).toString() + ); + + return "org/scientificcms/contenttypes/scidepartment/ui/description/edit.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/description/edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String editDescriptionValue( + @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(getDepartment())) { + final Locale locale = new Locale(localeParam); + getDepartment().getDepartmentDescription().putValue(locale, value); + itemRepo.save(getDepartment()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/description/remove/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String removeDescriptionValue( + @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(getDepartment())) { + final Locale locale = new Locale(localeParam); + getDepartment().getDepartmentDescription().removeValue(locale); + itemRepo.save(getDepartment()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @GET + @Path("/texts/view/{textKey}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String viewDepartmentText( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("textKey") + final String textKey + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + textsModel.setSelectedText(textKey); + + return "org/scientificcms/contenttypes/scidepartment/ui/texts/view-values.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @GET + @Path("/texts/view/{textKey}/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String viewDepartmentText( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("textKey") final String textKey, + @PathParam("locale") final String localeParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + textsModel.setSelectedText(textKey); + textsModel.setSelectedLocale(new Locale(localeParam).toString()); + + return "org/scientificcms/contenttypes/scidepartment/ui/texts/view-text.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/texts/add") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String addText( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @FormParam("textKey") final String textKey, + @FormParam("locale") final String localeParam, + @FormParam("textValue") final String textValue + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + final Locale locale = new Locale(localeParam); + final LocalizedString text = new LocalizedString(); + text.putValue(locale, textValue); + + departmentManager.addText(text, getDepartment(), textKey); + itemRepo.save(getDepartment()); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/texts/add/{textKey}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String addTextValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("textKey") final String textKey, + @FormParam("locale") final String localeParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + if (!getDepartment().getAdditionalTexts().containsKey(textKey)) { + models.put("dpartmentTextNotFound", textKey); + return showStep(sectionIdentifier, documentPath); + } + + final DepartmentText departmentText = getDepartment() + .getAdditionalTexts() + .get(textKey); + + final String value; + if (departmentText.getText().getAvailableLocales().isEmpty()) { + value = ""; + } else { + value = globalizationHelper.getValueFromLocalizedString( + departmentText.getText() + ); + } + final Locale locale = new Locale(localeParam); + departmentText.getText().putValue(locale, value); + departmentTextRepo.save(departmentText); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @GET + @Path("/texts/edit/{textKey}/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String editTextValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("textKey") final String textKey, + @PathParam("locale") final String localeParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + if (!getDepartment().getAdditionalTexts().containsKey(textKey)) { + models.put("dpartmentTextNotFound", textKey); + return showStep(sectionIdentifier, documentPath); + } + + textsModel.setSelectedText(textKey); + textsModel.setSelectedLocale( + new Locale(localeParam).toString() + ); + + return "org/scientificcms/contenttypes/scidepartment/ui/texts/edit-text.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/texts/edit/{textKey}/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String editTextValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("textKey") final String textKey, + @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(getDepartment())) { + if (!getDepartment().getAdditionalTexts().containsKey(textKey)) { + models.put("dpartmentTextNotFound", textKey); + return showStep(sectionIdentifier, documentPath); + } + + final DepartmentText departmentText = getDepartment() + .getAdditionalTexts() + .get(textKey); + + final Locale locale = new Locale(localeParam); + departmentText.getText().putValue(locale, value); + departmentTextRepo.save(departmentText); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/texts/remove/{textKey}/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String removeTextValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("textKey") final String textKey, + @PathParam("locale") final String localeParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + if (!getDepartment().getAdditionalTexts().containsKey(textKey)) { + models.put("dpartmentTextNotFound", textKey); + return showStep(sectionIdentifier, documentPath); + } + + final DepartmentText departmentText = getDepartment() + .getAdditionalTexts() + .get(textKey); + + final Locale locale = new Locale(localeParam); + departmentText.getText().removeValue(locale); + departmentTextRepo.save(departmentText); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/texts/remove/{textKey}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String removeTextValue( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("textKey") final String textKey + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + if (!getDepartment().getAdditionalTexts().containsKey(textKey)) { + models.put("dpartmentTextNotFound", textKey); + return showStep(sectionIdentifier, documentPath); + } + + departmentManager.removeText(getDepartment(), textKey); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/contacts/add") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String addContact( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @FormParam("contactableUuid") + final String contactableUuid, + @FormParam("type") + final String type + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + final Optional result; + final Identifier identifier = identifierParser.parseIdentifier( + contactableUuid + ); + switch (identifier.getType()) { + case ID: + result = assetRepo.findById( + Long.parseLong(identifier.getIdentifier()) + ); + break; + case UUID: + result = assetRepo.findByUuid( + identifier.getIdentifier() + ); + break; + default: + models.put("contactableNotFound", contactableUuid); + return showStep(sectionIdentifier, documentPath); + } + + if (!result.isPresent() + || !(result.get() instanceof ContactableEntity)) { + models.put("contactableNotFound", contactableUuid); + return showStep(sectionIdentifier, documentPath); + } + + final ContactableEntity contactable = (ContactableEntity) result + .get(); + departmentManager.addContact(contactable, getDepartment(), type); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/contacts/edit/{contactId}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String editContact( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("contactId") + final String contactId, + @FormParam("type") + final String type + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + final Optional result = getDepartment() + .getContacts() + .stream() + .filter( + contact -> Long + .toString(contact.getContactId()) + .equals(contactId) + ) + .findFirst(); + + if (!result.isPresent()) { + models.put("contactNotFound", contactId); + return showStep(sectionIdentifier, documentPath); + } + + final Contact contact = result.get(); + contact.setContactType(type); + contactRepo.save(contact); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/contacts/{contactId}/remove") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String removeContact( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("contactId") + final String contactId + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + final Optional result = getDepartment() + .getContacts() + .stream() + .filter( + contact -> Long + .toString(contact.getContactId()) + .equals(contactId) + ) + .findFirst(); + + if (result.isPresent()) { + departmentManager.removeContact( + result.get().getContactable(), + getDepartment() + ); + } + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/members/add") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String addMembership( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @FormParam("personUuid") + final String personUuid, + @FormParam("role") + final String role, + @FormParam("status") + final String statusParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + final Optional result; + final Identifier personIdentifier = identifierParser + .parseIdentifier(personUuid); + switch (personIdentifier.getType()) { + case ID: + result = assetRepo.findById( + Long.parseLong(personIdentifier.getIdentifier()), + Person.class + ); + break; + case UUID: + result = assetRepo + .findByUuidAndType( + personIdentifier.getIdentifier(), + Person.class + ); + break; + default: + models.put("personNotFound", personUuid); + return showStep(sectionIdentifier, documentPath); + + } + + if (!result.isPresent()) { + models.put("personNotFound", personUuid); + return showStep(sectionIdentifier, documentPath); + } + + final Person person = result.get(); + final MembershipStatus status; + try { + status = MembershipStatus.valueOf(statusParam); + } catch (IllegalArgumentException ex) { + models.put("illegalStatusValue", statusParam); + return showStep(sectionIdentifier, documentPath); + } + + departmentManager.addMember(person, getDepartment(), role, status); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/members/edit/{membershipId}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String editMembership( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("membershipId") + final String membershipId, + @FormParam("role") + final String role, + @FormParam("status") + final String statusParam + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + final Optional result = getDepartment() + .getMembers() + .stream() + .filter( + member -> Long + .toString(member.getMembershipId()) + .equals(membershipId) + ) + .findFirst(); + + if (!result.isPresent()) { + models.put("membershipNotFound", membershipId); + return showStep(sectionIdentifier, documentPath); + } + + final Membership membership = result.get(); + membership.setRole(role); + membership.setStatus(MembershipStatus.valueOf(statusParam)); + membershipRepo.save(membership); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @POST + @Path("/members/remove/{membershipId}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String removeMembership( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + @PathParam("membershipId") + final String membershipId + ) { + try { + init(); + } catch (ContentSectionNotFoundException ex) { + return ex.showErrorMessage(); + } catch (DocumentNotFoundException ex) { + return ex.showErrorMessage(); + } + + if (itemPermissionChecker.canEditItem(getDepartment())) { + final Optional result = getDepartment() + .getMembers() + .stream() + .filter( + member -> Long + .toString(member.getMembershipId()) + .equals(membershipId) + ) + .findFirst(); + + if (result.isPresent()) { + departmentManager.removeMember( + result.get().getMember(), + getDepartment() + ); + } + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDepartment(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + @Override + public void init() throws ContentSectionNotFoundException, + DocumentNotFoundException { + super.init(); + + final boolean canEdit = itemPermissionChecker.canEditItem( + getDepartment() + ); + if (canEdit) { + descriptionModel.setCanEdit(canEdit); + descriptionModel.setDescriptionValues( + getDepartment() + .getDepartmentDescription() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + Map.Entry::getValue + ) + ) + ); + descriptionModel.setVariants( + getDepartment() + .getDepartmentDescription() + .getValues() + .entrySet() + .stream() + .map(CmsEditorUtil::buildVariantRow) + .collect(Collectors.toList()) + ); + final Set descriptionLocales = getDepartment() + .getDepartmentDescription() + .getAvailableLocales(); + descriptionModel.setUnusedLocales( + globalizationHelper + .getAvailableLocales() + .stream() + .filter(locale -> !descriptionLocales.contains(locale)) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + + textsModel.setCanEdit(canEdit); + textsModel.setTexts( + getDepartment() + .getAdditionalTexts() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey(), + entry -> buildTextModel(entry.getValue()) + ) + ) + ); + + contactsModel.setCanEdit(canEdit); + contactsModel.setContacts( + getDepartment() + .getContacts() + .stream() + .map(this::buildContactModel) + .collect(Collectors.toList()) + ); + contactsModel.setBaseUrl(baseUrl.getBaseUrl(request)); + + membersModel.setCanEdit(canEdit); + membersModel.setMembers( + getDepartment() + .getMembers() + .stream() + .map(this::buildMembershipModel) + .collect(Collectors.toList()) + ); + membersModel.setStatusValues( + Arrays + .stream(MembershipStatus.values()) + .collect( + Collectors.toMap( + status -> status.toString(), + status -> messageBundle.getMessage( + String.format( + "members.status.%s", + status.toString().toLowerCase() + ) + ), + (value1, value2) -> value1, + LinkedHashMap::new + ) + ) + ); + membersModel.setBaseUrl(baseUrl.getBaseUrl(request)); + } + } + + private SciDepartment getDepartment() { + return (SciDepartment) getDocument(); + } + + private SciDepartmentContactModel buildContactModel(final Contact contact) { + final SciDepartmentContactModel model = new SciDepartmentContactModel(); + model.setContactId(contact.getContactId()); + model.setContactType(contact.getContactType()); + model.setContactable( + contact.getContactable().getTitle().getValue( + globalizationHelper.getNegotiatedLocale() + ) + ); + model.setOrder(contact.getOrder()); + + return model; + } + + private SciDepartmentMembershipModel buildMembershipModel( + final Membership membership + ) { + final SciDepartmentMembershipModel model + = new SciDepartmentMembershipModel(); + model.setGivenName( + membership.getMember().getPersonName().getGivenName() + ); + model.setMembershipId(membership.getMembershipId()); + model.setPrefix( + membership.getMember().getPersonName().getPrefix() + ); + model.setRole(membership.getRole()); + model.setStatus(Objects.toString(membership.getStatus())); + model.setSuffix( + membership.getMember().getPersonName().getSuffix() + ); + model.setSurname( + membership.getMember().getPersonName().getSurname() + ); + + return model; + } + + private SciDepartmentTextModel buildTextModel(final DepartmentText text) { + final SciDepartmentTextModel model = new SciDepartmentTextModel(); + model.setTextValues( + text + .getText() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + entry -> entry.getValue() + ) + ) + ); + model.setUnusedLocales( + globalizationHelper + .getAvailableLocales() + .stream() + .filter( + locale -> !text.getText().getAvailableLocales().contains( + locale + ) + ) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + model.setVariants( + text + .getText() + .getValues() + .entrySet() + .stream() + .map(CmsEditorUtil::buildVariantRow) + .collect(Collectors.toList()) + ); + + return model; + } + } diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStepResources.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStepResources.java new file mode 100644 index 0000000..383b41d --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStepResources.java @@ -0,0 +1,123 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +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.ui.contentsections.ContentSectionsUi; +import org.librecms.ui.contentsections.ItemPermissionChecker; +import org.librecms.ui.contentsections.documents.MvcAuthoringSteps; +import org.scientificcms.contenttypes.scidepartment.SciDepartment; + +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 + "scidepartment-description-resources") +public class SciDepartmentDescriptionStepResources { + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private ContentSectionsUi sectionsUi; + + @Inject + private ItemPermissionChecker itemPermissionChecker; + + @GET + @Path("/department-description/wordcount/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String getDepartmentDescriptionWordCount( + @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 SciDepartment)) { + throw new NotFoundException(); + } + + final SciDepartment department = (SciDepartment) document; + if (itemPermissionChecker.canEditItem(department)) { + final String text = department + .getDepartmentDescription() + .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("/department-description/{locale}") + @Produces(MediaType.TEXT_HTML) + @Transactional(Transactional.TxType.REQUIRED) + public String viewDepartmentDescriptionValue( + @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 SciDepartment)) { + throw new NotFoundException(); + } + + final SciDepartment department = (SciDepartment) document; + if (itemPermissionChecker.canEditItem(department)) { + return department.getDepartmentDescription().getValue( + new Locale(localeParam) + ); + } else { + throw new ForbiddenException(); + } + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStepService.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStepService.java new file mode 100644 index 0000000..f914d36 --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentDescriptionStepService.java @@ -0,0 +1,130 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemRepository; +import org.librecms.contentsection.ContentSection; +import org.librecms.ui.contentsections.ContentSectionsUi; +import org.librecms.ui.contentsections.documents.MvcAuthoringSteps; +import org.scientificcms.contenttypes.scidepartment.Contact; +import org.scientificcms.contenttypes.scidepartment.ContactRepository; +import org.scientificcms.contenttypes.scidepartment.SciDepartment; + +import java.util.List; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; +import javax.ws.rs.BadRequestException; +import javax.ws.rs.Consumes; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path(MvcAuthoringSteps.PATH_PREFIX + "scidepartment-description-service") +public class SciDepartmentDescriptionStepService { + + @Inject + private ContactRepository contactRepo; + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private ContentSectionsUi sectionsUi; + + @POST + @Path("/contacts/save-order") + @Consumes(MediaType.APPLICATION_JSON) + @Transactional(Transactional.TxType.REQUIRED) + public Response saveContactsOrder( + @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) + final String sectionIdentifier, + @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) + final String documentPath, + final List contactsOrder + ) { + final ContentSection contentSection = sectionsUi + .findContentSection(sectionIdentifier) + .orElseThrow( + () -> new NotFoundException( + String.format( + "No content identifed by %s found.", + sectionIdentifier + ) + ) + ); + + final ContentItem document = itemRepo + .findByPath(contentSection, documentPath) + .orElseThrow( + () -> new NotFoundException( + String.format( + "No document for path %s in section %s.", + documentPath, + contentSection.getLabel() + ) + ) + ); + + if (!(document instanceof SciDepartment)) { + throw new BadRequestException( + String.format( + "Document %s is not a %s.", + documentPath, + SciDepartment.class.getSimpleName() + ) + ); + } + + final SciDepartment department = (SciDepartment) document; + + final List contacts = department.getContacts(); + + if (contactsOrder.size() != contacts.size()) { + throw new BadRequestException( + String.format( + "Number of contacts of the SciDepartment %s does " + + "not match the number of values in the order " + + "list. Number of contactas: %d, number of values in " + + "the contacts order list: %d", + documentPath, + contacts.size(), + contactsOrder.size() + ) + ); + } + + for (int i = 0; i < contactsOrder.size(); i++) { + final String contactIdParam = contactsOrder.get(i); + final long contactId = Long.parseLong(contactIdParam); + final Contact contact = contacts + .stream() + .filter(con -> con.getContactId() == contactId) + .findAny() + .orElseThrow( + () -> new BadRequestException( + String.format( + "contactsOrder has an entry for contact with " + + "ID %d, but there is not contact with that " + + "ID.", + contactId + ) + ) + ); + + contact.setOrder(i); + contactRepo.save(contact); + } + + return Response.ok().build(); + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentExtendedPropertiesStep.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentExtendedPropertiesStep.java deleted file mode 100644 index 2de024b..0000000 --- a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentExtendedPropertiesStep.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.scientificcms.contenttypes.scidepartment.ui; - -import org.librecms.ui.contentsections.documents.MvcAuthoringStepDef; -import org.librecms.ui.contentsections.documents.MvcAuthoringSteps; -import org.scientificcms.contenttypes.scidepartment.SciDepartment; - -import javax.enterprise.context.RequestScoped; -import javax.mvc.Controller; -import javax.ws.rs.Path; - -/** - * - * @author Jens Pelzetter - */ -@RequestScoped -@Path(MvcAuthoringSteps.PATH_PREFIX + "scidepartment-extendedproperties") -@Controller -@MvcAuthoringStepDef( - bundle = SciDepartmentStepsConstants.BUNDLE, - descriptionKey = "authoringsteps.extendedproperties.description", - labelKey = "authoringsteps.extendedproperties.label", - supportedDocumentType = SciDepartment.class -) -public class SciDepartmentExtendedPropertiesStep { - -} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentMembershipModel.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentMembershipModel.java new file mode 100644 index 0000000..db39d13 --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentMembershipModel.java @@ -0,0 +1,143 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import org.scientificcms.contenttypes.scidepartment.Membership; +import org.scientificcms.contenttypes.scidepartment.SciDepartment; + +/** + * DTO providing the information about a {@link Membership} of a + * {@link SciDepartment} in an form that easy usable from a MVC template. + * + * @author Jens Pelzetter + */ +public class SciDepartmentMembershipModel { + + /** + * The ID of the {@link Membership}. + */ + private long membershipId; + + /** + * The role of the member. + * + * @see Membership#role + */ + private String role; + + /** + * The status of the membership. + * + * @see Membership#status + */ + private String status; + + /** + * The given name of the member. + * + * @see PersonName#givenName + */ + private String givenName; + + /** + * The surname of the member. + * + * @see PersonName#surname + */ + private String surname; + + /** + * An optional prefix for the name of the member. + * + * @see PersonName#prefix + */ + private String prefix; + + /** + * An optional suffix for the name of the member. + * + * @see PersonName#suffix + */ + private String suffix; + + public long getMembershipId() { + return membershipId; + } + + public void setMembershipId(final long membershipId) { + this.membershipId = membershipId; + } + + public String getRole() { + return role; + } + + public void setRole(final String role) { + this.role = role; + } + + public String getStatus() { + return status; + } + + public void setStatus(final String status) { + this.status = status; + } + + public String getName() { + final StringBuilder builder = new StringBuilder(); + if (prefix != null && !prefix.isBlank()) { + builder.append(prefix); + builder.append(" "); + } + if (surname != null && !surname.isBlank()) { + builder.append(surname); + } + if (surname != null + && !surname.isBlank() + && givenName != null + && !givenName.isBlank()) { + builder.append(", "); + } + if (givenName != null && !givenName.isBlank()) { + builder.append(givenName); + } + if (suffix != null && !suffix.isBlank()) { + builder.append(" "); + builder.append(suffix); + } + + return builder.toString(); + } + + public String getGivenName() { + return givenName; + } + + public void setGivenName(final String givenName) { + this.givenName = givenName; + } + + public String getSurname() { + return surname; + } + + public void setSurname(final String surname) { + this.surname = surname; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(final String prefix) { + this.prefix = prefix; + } + + public String getSuffix() { + return suffix; + } + + public void setSuffix(final String suffix) { + this.suffix = suffix; + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentMessageBundle.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentMessageBundle.java new file mode 100644 index 0000000..8f0e840 --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentMessageBundle.java @@ -0,0 +1,21 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import org.libreccm.ui.AbstractMessagesBean; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("SciDepartmentMessageBundle") +public class SciDepartmentMessageBundle extends AbstractMessagesBean { + + @Override + protected String getMessageBundle() { + return SciDepartmentStepsConstants.BUNDLE; + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentPropertiesStep.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentPropertiesStep.java index 9092fb3..e894add 100644 --- a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentPropertiesStep.java +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentPropertiesStep.java @@ -1,12 +1,33 @@ package org.scientificcms.contenttypes.scidepartment.ui; +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.l10n.LocalizedString; +import org.libreccm.security.AuthorizationRequired; +import org.librecms.contentsection.ContentItemRepository; +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 org.scientificcms.contenttypes.scidepartment.SciDepartment; +import java.util.Locale; +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; /** * @@ -21,6 +42,451 @@ import javax.ws.rs.Path; labelKey = "authoringsteps.basicproperties.label", supportedDocumentType = SciDepartment.class ) -public class SciDepartmentPropertiesStep { +public class SciDepartmentPropertiesStep extends AbstractMvcAuthoringStep { + + @Inject + private SciDepartmentMessageBundle messageBundle; + + /** + * Used for retrieving and saving the departments. + */ + @Inject + private ContentItemRepository itemRepo; + + @Inject + private DocumentUi documentUi; + + /** + * Provides functions for working with {@link LocalizedString}s. + */ + @Inject + private GlobalizationHelper globalizationHelper; + + @Inject + private ItemPermissionChecker itemPermissionChecker; + + @Inject + private SciDepartmentPropertiesStepModel propertiesStepModel; + + @Inject + private Models models; + + @Override + public Class getStepClass() { + return SciDepartmentPropertiesStep.class; + } + + @Override + @Transactional(Transactional.TxType.REQUIRED) + protected void init() throws ContentSectionNotFoundException, + DocumentNotFoundException { + super.init(); + + propertiesStepModel.setName(getDocument().getDisplayName()); + + final Set titleLocales = getDocument() + .getTitle() + .getAvailableLocales(); + + propertiesStepModel.setTitleValues( + getDocument() + .getTitle() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + entry -> entry.getValue() + ) + ) + ); + + propertiesStepModel.setUnusedTitleLocales( + globalizationHelper + .getAvailableLocales() + .stream() + .filter(locale -> !titleLocales.contains(locale)) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + + final SciDepartment department = (SciDepartment) getDocument(); + + propertiesStepModel.setShortDescriptionValues( + department + .getShortDescription() + .getValues() + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().toString(), + entry -> entry.getValue() + ) + ) + ); + final Set shortDescriptionLocales = department + .getShortDescription() + .getAvailableLocales(); + + propertiesStepModel.setUnusedShortDescriptionLocales( + globalizationHelper + .getAvailableLocales() + .stream() + .filter(locale -> !shortDescriptionLocales.contains(locale)) + .map(Locale::toString) + .collect(Collectors.toList()) + ); + } + + @GET + @Path("/") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + 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/scientificcms/contenttypes/scidepartment/ui/scidepartment-basic-properties.xhtml"; + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDocument(), + messageBundle.getMessage("scidepartment.edit.denied") + ); + } + } + + /** + * Updates the name of the current department. + * + * @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.isBlank()) { + models.put("nameMissing", true); + + return showStep(sectionIdentifier, documentPath); + } + + getDocument().setDisplayName(name); + itemRepo.save(getDocument()); + + updateDocumentPath(); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDocument(), + getLabel() + ); + } + } + + /** + * Updates a localized title of the department. + * + * @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 department. + * + * @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 department. + * + * @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 short description to the department. + * + * @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("/short-description/@add") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String addShortDescription( + @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); + final SciDepartment department = (SciDepartment) getDocument(); + department.getShortDescription().putValue(locale, value); + + itemRepo.save(department); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDocument(), + getLabel() + ); + } + } + + /** + * Updates a localized short description to the department. + * + * @param sectionIdentifier + * @param documentPath + * @param localeParam The locale to update. + * @param value The description value. + * + * @return A redirect to this authoring step. + */ + @POST + @Path("/short-description/@edit/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String editShortDescription( + @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); + final SciDepartment department = (SciDepartment) getDocument(); + department.getShortDescription().putValue(locale, value); + + itemRepo.save(department); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDocument(), + getLabel() + ); + } + } + + /** + * Removes a localized short description from the department. + * + * @param sectionIdentifier + * @param documentPath + * @param localeParam The locale to remove. + * + * @return A redirect to this authoring step. + */ + @POST + @Path("/short-description/@remove/{locale}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + public String removeShortDescription( + @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); + final SciDepartment department = (SciDepartment) getDocument(); + department.getShortDescription().removeValue(locale); + itemRepo.save(department); + + return buildRedirectPathForStep(); + } else { + return documentUi.showAccessDenied( + getContentSection(), + getDocument(), + getLabel() + ); + } + } } diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentPropertiesStepModel.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentPropertiesStepModel.java new file mode 100644 index 0000000..ebc788f --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentPropertiesStepModel.java @@ -0,0 +1,76 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +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("SciDepartmentPropertiesStep") +public class SciDepartmentPropertiesStepModel { + + private String name; + + private Map titleValues; + + private List unusedTitleLocales; + + private Map shortDescriptionValues; + + private List unusedShortDescriptionLocales; + + 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(final List unusedTitleLocales) { + this.unusedTitleLocales = new ArrayList<>(unusedTitleLocales); + } + + public Map getShortDescriptionValues() { + return Collections.unmodifiableMap(shortDescriptionValues); + } + + public void setShortDescriptionValues( + final Map shortDescriptionValues + ) { + this.shortDescriptionValues = new HashMap<>(shortDescriptionValues); + } + + public List getUnusedShortDescriptionLocales() { + return Collections.unmodifiableList(unusedShortDescriptionLocales); + } + + public void setUnusedShortDescriptionLocales( + final List unusedShortDescriptionLocales + ) { + this.unusedShortDescriptionLocales = new ArrayList<>( + unusedShortDescriptionLocales + ); + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentTextModel.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentTextModel.java new file mode 100644 index 0000000..b250d98 --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentTextModel.java @@ -0,0 +1,84 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import org.librecms.ui.contentsections.documents.CmsEditorLocaleVariantRow; +import org.scientificcms.contenttypes.scidepartment.DepartmentText; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * DTO providing the data of a {@link DepartmentText} in a form that is easy + * usable from the view. + * + * @author Jens Pelzetter + */ +public class SciDepartmentTextModel { + + private Map textValues; + + private List variants; + + private List unusedLocales; + + private long order; + + public Map getTextValues() { + return Optional + .ofNullable(textValues) + .map(Collections::unmodifiableMap) + .orElse(Collections.emptyMap()); + } + + protected void setTextValues( + final Map textValues + ) { + this.textValues = Optional + .ofNullable(textValues) + .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 long getOrder() { + return order; + } + + public void setOrder(final long order) { + this.order = order; + } + +} diff --git a/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentTextsModel.java b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentTextsModel.java new file mode 100644 index 0000000..e7f7b9d --- /dev/null +++ b/sci-types-department/src/main/java/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentTextsModel.java @@ -0,0 +1,53 @@ +package org.scientificcms.contenttypes.scidepartment.ui; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author Jens Pelzetter + */ +public class SciDepartmentTextsModel { + + private boolean canEdit; + + private Map texts; + + private String selectedText; + + private String selectedLocale; + + public boolean getCanEdit() { + return canEdit; + } + + protected void setCanEdit(final boolean canEdit) { + this.canEdit = canEdit; + } + + public Map getTexts() { + return Collections.unmodifiableMap(texts); + } + + protected void setTexts(final Map texts) { + this.texts = new HashMap<>(texts); + } + + public String getSelectedText() { + return selectedText; + } + + public void setSelectedText(final String selectedText) { + this.selectedText = selectedText; + } + + public String getSelectedLocale() { + return selectedLocale; + } + + protected void setSelectedLocale(final String selectedLocale) { + this.selectedLocale = selectedLocale; + } + +} diff --git a/sci-types-department/src/main/resources/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentBundle.properties b/sci-types-department/src/main/resources/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentBundle.properties new file mode 100644 index 0000000..5e37325 --- /dev/null +++ b/sci-types-department/src/main/resources/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentBundle.properties @@ -0,0 +1,7 @@ + +createstep.description=Creates a new SciDepartment. +authoringsteps.description.description=Description of the department. +authoringsteps.description.label=Description +scidepartment.edit.denied=Access denied. +authoringsteps.basicproperties.description=Basicproperties of the department. +authoringsteps.basicproperties.label=Basic Properties diff --git a/sci-types-department/src/main/resources/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentBundle_de.properties b/sci-types-department/src/main/resources/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentBundle_de.properties new file mode 100644 index 0000000..c7805e8 --- /dev/null +++ b/sci-types-department/src/main/resources/org/scientificcms/contenttypes/scidepartment/ui/SciDepartmentBundle_de.properties @@ -0,0 +1,7 @@ + +createstep.description=Erstellt eine neue Abteilung. +authoringsteps.description.description=Beschreibung der Abteilung. +authoringsteps.description.label=Beschreibung +scidepartment.edit.denied=Zugriff verweigert. +authoringsteps.basicproperties.description=Basiseigenschaften der Abteilung. +authoringsteps.basicproperties.label=Basiseigenschaften diff --git a/sci-types-project/src/main/java/org/scientificcms/contenttypes/sciproject/ui/SciProjectDescriptionStepService.java b/sci-types-project/src/main/java/org/scientificcms/contenttypes/sciproject/ui/SciProjectDescriptionStepService.java index ae66eac..35f9e92 100644 --- a/sci-types-project/src/main/java/org/scientificcms/contenttypes/sciproject/ui/SciProjectDescriptionStepService.java +++ b/sci-types-project/src/main/java/org/scientificcms/contenttypes/sciproject/ui/SciProjectDescriptionStepService.java @@ -76,7 +76,7 @@ public class SciProjectDescriptionStepService { ) ); - if ((document instanceof SciProject)) { + if (!(document instanceof SciProject)) { throw new BadRequestException( String.format( "Document %s is not a %s.", diff --git a/scicms-bundle-devel-wildfly/.gitignore b/scicms-bundle-devel-wildfly/.gitignore new file mode 100644 index 0000000..bae7835 --- /dev/null +++ b/scicms-bundle-devel-wildfly/.gitignore @@ -0,0 +1 @@ +runtime.properties diff --git a/scicms-bundle-devel-wildfly/runtime.properties b/scicms-bundle-devel-wildfly/runtime.properties deleted file mode 100644 index a702584..0000000 --- a/scicms-bundle-devel-wildfly/runtime.properties +++ /dev/null @@ -1,7 +0,0 @@ -libreccm.debug.suspend=n - -libreccm.database.host=localhost -libreccm.database.port=5432 -libreccm.database.name=scicms-devel -libreccm.database.user=ccm -libreccm.database.password=ccm47web