diff --git a/ccm-cms/src/main/java/org/librecms/pages/PagesController.java b/ccm-cms/src/main/java/org/librecms/pages/PagesController.java
index 973a22bd9..64c1d90e1 100644
--- a/ccm-cms/src/main/java/org/librecms/pages/PagesController.java
+++ b/ccm-cms/src/main/java/org/librecms/pages/PagesController.java
@@ -580,16 +580,28 @@ public class PagesController {
final Page page = pageManager.findPageForCategory(category);
pagePropertiesModel.setProperties(page.getProperties());
- if (itemName.equals("index") || itemName.isBlank()) {
- return themesMvc.getMvcTemplate(
- uriInfo, "pages", page.getDisplayName()
- );
- } else {
- return themesMvc.getMvcTemplate(
- uriInfo, "pages", "item-page"
+ try {
+ final String result;
+ if (itemName.equals("index") || itemName.isBlank()) {
+ result = themesMvc.getMvcTemplate(
+ uriInfo, "pages", page.getDisplayName()
+ );
+
+ } else {
+ result = themesMvc.getMvcTemplate(
+ uriInfo, "pages", "item-page"
+ );
+ }
+ return result;
+ } catch (Exception ex) {
+ throw new WebApplicationException(
+ "An error occured while rendering the page.",
+ ex,
+ Response.serverError().entity(
+ "An error occured while rendering the page."
+ ).build()
);
}
-
}
private void initSiteInfoModel(
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemListItemModel.java b/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemListItemModel.java
new file mode 100644
index 000000000..2afd65cd9
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemListItemModel.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.pages.models;
+
+import org.librecms.contentsection.ContentItem;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class ContentItemListItemModel extends AbstractContentItemListItemModel {
+
+ @Override
+ public String getType() {
+ return ContentItem.class.getName();
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemListModelBuilder.java b/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemListModelBuilder.java
new file mode 100644
index 000000000..1e8434846
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/ContentItemListModelBuilder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.pages.models;
+
+import org.librecms.contentsection.ContentItem;
+
+import javax.enterprise.context.RequestScoped;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+public class ContentItemListModelBuilder
+ extends AbstractContentItemListItemModelBuilder {
+
+ @Override
+ public Class buildsListItemModelFor() {
+ return ContentItem.class;
+ }
+
+ @Override
+ protected ContentItemListItemModel buildModel() {
+ return new ContentItemListItemModel();
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/pages/models/ItemListModel.java b/ccm-cms/src/main/java/org/librecms/pages/models/ItemListModel.java
index a391f8e78..b9fde5b9b 100644
--- a/ccm-cms/src/main/java/org/librecms/pages/models/ItemListModel.java
+++ b/ccm-cms/src/main/java/org/librecms/pages/models/ItemListModel.java
@@ -251,10 +251,11 @@ public class ItemListModel {
criteriaBuilder.isNull(catJoin.get("type")),
criteriaBuilder.equal(
from.get("version"), ContentItemVersion.LIVE
- ),
- buildPermissionsCheck(
- criteriaBuilder, from, permissionsJoin
)
+// ,
+// buildPermissionsCheck(
+// criteriaBuilder, from, permissionsJoin
+// )
)
);
@@ -265,7 +266,7 @@ public class ItemListModel {
.collect(Collectors.toList())
);
- return entityManager
+ final List extends AbstractContentItemListItemModel> result = entityManager
.createQuery(criteriaQuery)
.getResultList()
.stream()
@@ -278,6 +279,8 @@ public class ItemListModel {
.limit(pageSize)
.map(this::buildListItemModel)
.collect(Collectors.toList());
+
+ return result;
}
private List collectCategories(final Category category) {
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationController.java
index 93ac282c0..de803fc9e 100644
--- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationController.java
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationController.java
@@ -93,6 +93,8 @@ public class ConfigurationController {
return "org/librecms/ui/contentsection/configuration/index.xhtml";
}
+
+
/**
* Checks if the current user is permitted to access the configurations page
* of the content section.
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationFixItemPermissionsController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationFixItemPermissionsController.java
new file mode 100644
index 000000000..a13f603df
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationFixItemPermissionsController.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.ui.contentsections;
+
+import org.libreccm.categorization.Categorization;
+import org.libreccm.security.AuthorizationRequired;
+import org.libreccm.security.PermissionManager;
+import org.librecms.contentsection.Asset;
+import org.librecms.contentsection.ContentItem;
+import org.librecms.contentsection.ContentSection;
+import org.librecms.contentsection.ContentSectionManager;
+import org.librecms.contentsection.Folder;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.mvc.Controller;
+import javax.transaction.Transactional;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+/**
+ * Controller for the fix item and asset permissions function.
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+@Controller
+@Path("/{sectionIdentifier}/configuration/fix-item-and-asset-permissions")
+public class ConfigurationFixItemPermissionsController {
+
+ /**
+ * Used to check the admin permissions of a content section.
+ */
+ @Inject
+ private AdminPermissionsChecker adminPermissionsChecker;
+
+// @Inject
+// private ContentSectionManager sectionManager;
+ @Inject
+ private ContentSectionModel sectionModel;
+
+ /**
+ * Common functions for views working with {@link ContentSection}s.
+ */
+ @Inject
+ private ContentSectionsUi sectionsUi;
+
+// @Inject
+// private PermissionManager permissionManager;
+//
+
+ @Inject
+ private FixItemPermissionsTaskManager taskManager;
+
+ @POST
+ @Path("/")
+ @AuthorizationRequired
+ @Transactional(Transactional.TxType.REQUIRED)
+ public String fixItemAndAssetPermissions(
+ @PathParam("sectionIdentifier") final String sectionIdentifierParam
+ ) {
+ final Optional sectionResult = sectionsUi
+ .findContentSection(sectionIdentifierParam);
+ if (!sectionResult.isPresent()) {
+ return sectionsUi.showContentSectionNotFound(sectionIdentifierParam);
+ }
+ final ContentSection section = sectionResult.get();
+ sectionModel.setSection(section);
+ if (!adminPermissionsChecker.canAdministerContentTypes(section)) {
+ return sectionsUi.showAccessDenied(
+ "sectionIdentifier", sectionIdentifierParam
+ );
+ }
+
+// fixContentItemPermissions(section.getRootDocumentsFolder());
+// fixAssetPermissions(section.getRootAssetsFolder());
+
+ taskManager.fixItemPermissions(section);
+
+ return String.format(
+ "redirect:%s/configuration", sectionIdentifierParam
+ );
+ }
+
+// private void fixContentItemPermissions(final Folder folder) {
+// final List items = folder
+// .getObjects()
+// .stream()
+// .map(Categorization::getCategorizedObject)
+// .filter(obj -> obj instanceof ContentItem)
+// .map(obj -> (ContentItem) obj)
+// .collect(Collectors.toList());
+//
+// for(final ContentItem item : items) {
+// permissionManager.copyPermissions(folder, item, true);
+// }
+//
+// for(final Folder subFolder : folder.getSubFolders()) {
+// fixContentItemPermissions(subFolder);
+// }
+// }
+//
+// private void fixAssetPermissions(final Folder folder) {
+// final List assets = folder
+// .getObjects()
+// .stream()
+// .map(Categorization::getCategorizedObject)
+// .filter(obj -> obj instanceof Asset)
+// .map(obj -> (Asset) obj)
+// .collect(Collectors.toList());
+//
+// for(final Asset asset : assets) {
+// permissionManager.copyPermissions(folder, asset, true);
+// }
+//
+// for(final Folder subFolder : folder.getSubFolders()) {
+// fixAssetPermissions(subFolder);
+// }
+// }
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContentSectionApplication.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContentSectionApplication.java
index 032ed66ec..f100f8eea 100644
--- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContentSectionApplication.java
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ContentSectionApplication.java
@@ -76,6 +76,7 @@ public class ContentSectionApplication extends Application {
classes.add(ConfigurationController.class);
classes.add(ConfigurationContactEntryKeysController.class);
classes.add(ConfigurationDocumentTypesController.class);
+ classes.add(ConfigurationFixItemPermissionsController.class);
classes.add(ConfigurationLifecyclesController.class);
classes.add(ConfigurationRolesController.class);
classes.add(ConfigurationWorkflowController.class);
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissions.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissions.java
new file mode 100644
index 000000000..f03f9c62e
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissions.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.ui.contentsections;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.libreccm.categorization.Categorization;
+import org.libreccm.core.CcmObject;
+import org.libreccm.security.PermissionManager;
+import org.librecms.contentsection.Asset;
+import org.librecms.contentsection.AssetManager;
+import org.librecms.contentsection.ContentItem;
+import org.librecms.contentsection.ContentItemManager;
+import org.librecms.contentsection.ContentSection;
+import org.librecms.contentsection.ContentSectionRepository;
+import org.librecms.contentsection.Folder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.transaction.Transactional;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@ApplicationScoped
+public class FixItemPermissions {
+
+ private static final Logger LOGGER = LogManager.getLogger(
+ FixItemPermissions.class
+ );
+
+ @Inject
+ private AssetManager assetManager;
+
+ @Inject
+ private ContentItemManager itemManager;
+
+ @Inject
+ private ContentSectionRepository sectionRepo;
+
+ @Inject
+ private PermissionManager permissionManager;
+
+ @Transactional(Transactional.TxType.REQUIRED)
+ public void fixItemPermissions(final ContentSection contentSection) {
+ final String sectionUuid = Optional
+ .ofNullable(contentSection)
+ .map(ContentSection::getUuid)
+ .orElseThrow(
+ () -> new IllegalArgumentException(
+ "Can't fix ItemPermissions for content section null"
+ )
+ );
+
+ final ContentSection section = sectionRepo
+ .findByUuid(sectionUuid)
+ .orElseThrow(
+ () -> new IllegalArgumentException(
+ String.format(
+ "No ContentSection with UUID %s in the database.",
+ sectionUuid
+ )
+ )
+ );
+
+ fixContentItemPermissions(section.getRootDocumentsFolder());
+ fixAssetPermissions(section.getRootAssetsFolder());
+ }
+
+ private void fixContentItemPermissions(final Folder folder) {
+ final List items = new ArrayList<>();
+ for (final Categorization categorization : folder.getObjects()) {
+ final CcmObject categorized = categorization.getCategorizedObject();
+ if (categorized instanceof ContentItem) {
+ items.add((ContentItem) categorized);
+ }
+ }
+
+// final List items = folder
+// .getObjects()
+// .stream()
+// .map(Categorization::getCategorizedObject)
+// .filter(obj -> obj instanceof ContentItem)
+// .map(obj -> (ContentItem) obj)
+// .collect(Collectors.toList());
+ for (final ContentItem item : items) {
+ LOGGER.info(
+ "Fixing permissions for item {} {}",
+ item.getUuid(),
+ itemManager.getItemPath(item)
+ );
+ permissionManager.copyPermissions(folder, item, true);
+
+ if (itemManager.isLive(item)) {
+ permissionManager.copyPermissions(
+ folder,
+ itemManager.getLiveVersion(item, ContentItem.class).get(),
+ true
+ );
+ }
+ }
+
+ for (final Folder subFolder : folder.getSubFolders()) {
+ fixContentItemPermissions(subFolder);
+ }
+ }
+
+ private void fixAssetPermissions(final Folder folder) {
+ final List assets = folder
+ .getObjects()
+ .stream()
+ .map(Categorization::getCategorizedObject)
+ .filter(obj -> obj instanceof Asset)
+ .map(obj -> (Asset) obj)
+ .collect(Collectors.toList());
+
+ for (final Asset asset : assets) {
+ LOGGER.info(
+ "Fixing permissions for asset {} {}...",
+ asset.getUuid(),
+ assetManager.getAssetPath(asset)
+ );
+ permissionManager.copyPermissions(folder, asset, true);
+ }
+
+ for (final Folder subFolder : folder.getSubFolders()) {
+ fixAssetPermissions(subFolder);
+ }
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsStatus.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsStatus.java
new file mode 100644
index 000000000..c493502d3
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsStatus.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.ui.contentsections;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public enum FixItemPermissionsStatus {
+
+ /**
+ * An error occured during the process.
+ */
+ ERROR,
+ /**
+ * The import or export task is finished.
+ */
+ FINISHED,
+ /**
+ * The task is still running.
+ */
+ RUNNING,
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTask.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTask.java
new file mode 100644
index 000000000..be2a8f905
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTask.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.ui.contentsections;
+
+import org.apache.shiro.mgt.SecurityManager;
+import org.librecms.contentsection.ContentSection;
+
+import java.time.LocalDate;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class FixItemPermissionsTask {
+
+ private final ContentSection contentSection;
+
+ private final LocalDate started;
+
+ private final FixItemPermissionsTaskStatus status;
+
+ private final org.apache.shiro.mgt.SecurityManager securityManager;
+
+ public FixItemPermissionsTask(
+ final ContentSection contentSection,
+ final LocalDate started,
+ final FixItemPermissionsTaskStatus status,
+ final org.apache.shiro.mgt.SecurityManager securityManager
+ ) {
+ this.contentSection = contentSection;
+ this.started = started;
+ this.status = status;
+ this.securityManager = securityManager;
+ }
+
+ public ContentSection getContentSection() {
+ return contentSection;
+ }
+
+ public LocalDate getStarted() {
+ return started;
+ }
+
+ public FixItemPermissionsTaskStatus getStatus() {
+ return status;
+ }
+
+ public SecurityManager getSecurityManager() {
+ return securityManager;
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskManager.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskManager.java
new file mode 100644
index 000000000..1a1c6e541
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskManager.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.ui.contentsections;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.shiro.SecurityUtils;
+import org.librecms.contentsection.ContentSection;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Optional;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Event;
+import javax.inject.Inject;
+import javax.transaction.Transactional;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@ApplicationScoped
+public class FixItemPermissionsTaskManager {
+
+ private static final Logger LOGGER = LogManager.getLogger(
+ FixItemPermissionsTaskManager.class
+ );
+
+ @Inject
+ private Event taskSender;
+
+ private final SortedSet tasks;
+
+ public SortedSet getTasks() {
+ return Collections.unmodifiableSortedSet(tasks);
+ }
+
+ public boolean isTaskActiveForContentSection(final ContentSection section) {
+ return isTaskActiveForContentSection(
+ Optional
+ .ofNullable(section)
+ .map(ContentSection::getLabel)
+ .orElseThrow(
+ () -> new IllegalArgumentException(
+ "Can't check task status for ContentSection null."
+ )
+ )
+ );
+ }
+
+ public boolean isTaskActiveForContentSection(final String name) {
+ return tasks
+ .stream()
+ .anyMatch(
+ task -> task.getContentSection().equals(name)
+ && task.getStatus()
+ == FixItemPermissionsStatus.RUNNING
+ );
+ }
+
+ public boolean isTaskFailedForContentSection(final String name) {
+ return tasks
+ .stream()
+ .anyMatch(
+ task -> task.getContentSection().equals(name)
+ && task.getStatus()
+ == FixItemPermissionsStatus.ERROR
+ );
+ }
+
+ public FixItemPermissionsTaskManager() {
+ tasks = new TreeSet<>(
+ Comparator
+ .comparing(FixItemPermissionsTaskStatus::getStarted)
+ .thenComparing(FixItemPermissionsTaskStatus::getContentSection)
+ );
+ }
+
+ @Transactional(Transactional.TxType.REQUIRED)
+ public void fixItemPermissions(final ContentSection section) {
+ if (isTaskActiveForContentSection(section)) {
+ throw new IllegalArgumentException(
+ String.format(
+ "A FixItemPermissionsTask is already active for content "
+ + "section %s.",
+ section.getLabel()
+ )
+ );
+ }
+
+ tasks.removeAll(
+ tasks
+ .stream()
+ .filter(task -> task.getStatus()
+ == FixItemPermissionsStatus.ERROR
+ || task.getStatus()
+ == FixItemPermissionsStatus.FINISHED)
+ .collect(Collectors.toSet())
+ );
+
+ final FixItemPermissionsTaskStatus taskStatus
+ = new FixItemPermissionsTaskStatus();
+ taskStatus.setContentSection(section.getLabel());
+ taskStatus.setStarted(LocalDateTime.now());
+ taskSender.fireAsync(
+ new FixItemPermissionsTask(
+ section,
+ LocalDate.now(),
+ taskStatus,
+ SecurityUtils.getSecurityManager()
+ )
+ ).handle((task, ex) -> handleTaskResult(task, ex, taskStatus));
+
+ taskStatus.setStatus(FixItemPermissionsStatus.RUNNING);
+ }
+
+ private Object handleTaskResult(
+ final FixItemPermissionsTask task,
+ final Throwable ex,
+ final FixItemPermissionsTaskStatus status
+ ) {
+ if (ex == null) {
+ status.setStatus(FixItemPermissionsStatus.FINISHED);
+ } else {
+ status.setStatus(FixItemPermissionsStatus.ERROR);
+ status.setException(ex);
+ LOGGER.error(
+ "Fix Item Permissions for Content Section {} failed ",
+ status.getContentSection()
+ );
+ LOGGER.error("with exception:", ex);
+ }
+
+ return task;
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskStatus.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskStatus.java
new file mode 100644
index 000000000..b12541635
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskStatus.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.ui.contentsections;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class FixItemPermissionsTaskStatus
+ implements Comparable {
+
+ /**
+ * The content section for which the task was started.
+ */
+ private String contentSection;
+
+ /**
+ * When was the task started?
+ */
+ private LocalDateTime started;
+
+ /**
+ * The status of the task.
+ */
+ private FixItemPermissionsStatus status;
+
+ /**
+ * If the proces throw an exception, it is stored here.
+ */
+ private Throwable exception;
+
+ public String getContentSection() {
+ return contentSection;
+ }
+
+ protected void setContentSection(final String contentSection) {
+ this.contentSection = contentSection;
+ }
+
+ public LocalDateTime getStarted() {
+ return started;
+ }
+
+ protected void setStarted(final LocalDateTime started) {
+ this.started = started;
+ }
+
+ public FixItemPermissionsStatus getStatus() {
+ return status;
+ }
+
+ protected void setStatus(final FixItemPermissionsStatus status) {
+ this.status = status;
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+
+ protected void setException(final Throwable exception) {
+ this.exception = exception;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 17 * hash + Objects.hashCode(contentSection);
+ hash = 17 * hash + Objects.hashCode(started);
+ hash = 17 * hash + Objects.hashCode(status);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof FixItemPermissionsTaskStatus) {
+ return false;
+ }
+ final FixItemPermissionsTaskStatus other
+ = (FixItemPermissionsTaskStatus) obj;
+ if (!other.canEqual(this)) {
+ return false;
+ }
+ if (!Objects.equals(contentSection, other.getContentSection())) {
+ return false;
+ }
+ if (!Objects.equals(started, other.getStarted())) {
+ return false;
+ }
+ return status == other.getStatus();
+ }
+
+ public boolean canEqual(final Object obj) {
+ return obj instanceof FixItemPermissionsTaskStatus;
+ }
+
+ @Override
+ public int compareTo(final FixItemPermissionsTaskStatus other) {
+ return Comparator
+ .nullsFirst(
+ Comparator
+ .comparing(FixItemPermissionsTaskStatus::getContentSection)
+ .thenComparing(FixItemPermissionsTaskStatus::getStarted)
+ )
+ .compare(this, other);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "%s{"
+ + "contentSection = %s, "
+ + "started = %s, "
+ + "status = %s"
+ + "}",
+ super.toString(),
+ contentSection,
+ DateTimeFormatter.ISO_DATE_TIME
+ .withZone(ZoneId.systemDefault())
+ .format(started),
+ Objects.toString(status)
+ );
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskStatusModel.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskStatusModel.java
new file mode 100644
index 000000000..c0efd7eac
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTaskStatusModel.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.ui.contentsections;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+@Named("FixItemPermissionsTaskStatusModel")
+public class FixItemPermissionsTaskStatusModel {
+
+ @Inject
+ private ContentSectionModel sectionModel;
+
+ @Inject
+ private FixItemPermissionsTaskManager taskManager;
+
+ public boolean isTaskRunningForContentSection() {
+ return taskManager.isTaskActiveForContentSection(
+ sectionModel.getSectionName()
+ );
+ }
+
+ public boolean isTaskFailedForContentSection() {
+ return taskManager.isTaskFailedForContentSection(
+ sectionModel.getSectionName()
+ );
+ }
+
+}
diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTasks.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTasks.java
new file mode 100644
index 000000000..0c1fae9ca
--- /dev/null
+++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/FixItemPermissionsTasks.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.librecms.ui.contentsections;
+
+import org.apache.shiro.util.ThreadContext;
+import org.libreccm.security.Shiro;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.ObservesAsync;
+import javax.inject.Inject;
+import javax.transaction.Transactional;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@ApplicationScoped
+public class FixItemPermissionsTasks {
+
+ @Inject
+ private FixItemPermissions fixItemPermissions;
+
+ @Inject
+ private Shiro shiro;
+
+ @Transactional(Transactional.TxType.REQUIRED)
+ public void fixItemPermissions(
+ @ObservesAsync final FixItemPermissionsTask task
+ ) {
+ ThreadContext.bind(task.getSecurityManager());
+ shiro.getSystemUser().execute(() -> executeFixItemPermissions(task));
+ }
+
+
+ private void executeFixItemPermissions(final FixItemPermissionsTask task) {
+ fixItemPermissions.fixItemPermissions(task.getContentSection());
+ }
+
+}
diff --git a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/configuration/index.xhtml b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/configuration/index.xhtml
index 78355d968..fc5554d2f 100644
--- a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/configuration/index.xhtml
+++ b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/configuration/index.xhtml
@@ -136,6 +136,51 @@
+
diff --git a/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages.properties b/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages.properties
index e9990b711..72d8aac9f 100644
--- a/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages.properties
+++ b/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages.properties
@@ -1030,3 +1030,7 @@ pages.page.details.displayname.dialog.displayname.help=The display name of the p
pages.page.details.displayname.dialog.submit=Save
pages.page.details.displayname.edit=Edit display name
pages.page.details.dialog.displayname.label=Display name
+contentsection.configuration.fixitemandassetspermissions.title=Fix permissions
+contentsection.configuration.fixitemandassetspermissions.description=Repairs the permissions for items and assets
+contentsection.configuration.fixitemandassetspermissions.running=Fixing permissions for item and assets...
+contentsection.configuration.fixitemandassetspermissions.failed=Failed to repair permissions for items and assets. Check the log for details.
diff --git a/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages_de.properties b/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages_de.properties
index 6c5312fe9..9b749cb2e 100644
--- a/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages_de.properties
+++ b/ccm-cms/src/main/resources/org/librecms/CmsAdminMessages_de.properties
@@ -1031,3 +1031,7 @@ pages.page.details.displayname.dialog.displayname.help=The display name of the p
pages.page.details.displayname.dialog.submit=Speichern
pages.page.details.displayname.edit=Display Name bearbeiten
pages.page.details.dialog.displayname.label=Display Name
+contentsection.configuration.fixitemandassetspermissions.title=Berechtigungen reparieren
+contentsection.configuration.fixitemandassetspermissions.description=Repariert die Berechtigungen f\u00fcr Dokumente und Assets
+contentsection.configuration.fixitemandassetspermissions.running=Repariere Berechtigungen f\u00fcr Dokumente und Assets
+contentsection.configuration.fixitemandassetspermissions.failed=Reparieren der Berechtigungen f\u00fcr Dokumente und Assets fehlgeschlagen. Weitere Informationen im Log.
diff --git a/ccm-core/src/main/java/org/libreccm/mvc/freemarker/MvcFreemarkerConfigurationProducer.java b/ccm-core/src/main/java/org/libreccm/mvc/freemarker/MvcFreemarkerConfigurationProducer.java
index 83c5c6fd9..7135bf078 100644
--- a/ccm-core/src/main/java/org/libreccm/mvc/freemarker/MvcFreemarkerConfigurationProducer.java
+++ b/ccm-core/src/main/java/org/libreccm/mvc/freemarker/MvcFreemarkerConfigurationProducer.java
@@ -18,6 +18,8 @@
*/
package org.libreccm.mvc.freemarker;
+import com.arsdigita.kernel.KernelConfig;
+
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
@@ -26,6 +28,7 @@ import freemarker.template.Configuration;
import freemarker.template.TemplateExceptionHandler;
import org.eclipse.krazo.engine.ViewEngineConfig;
import org.eclipse.krazo.ext.freemarker.DefaultConfigurationProducer;
+import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.theming.Themes;
import javax.enterprise.inject.Produces;
@@ -43,6 +46,9 @@ import javax.servlet.ServletContext;
public class MvcFreemarkerConfigurationProducer
extends DefaultConfigurationProducer {
+ @Inject
+ private ConfigurationManager confManager;
+
@Inject
private Models models;
@@ -51,7 +57,7 @@ public class MvcFreemarkerConfigurationProducer
@Inject
private Themes themes;
-
+
@Inject
private ThemeTemplateUtil themeTemplateUtil;
@@ -60,15 +66,27 @@ public class MvcFreemarkerConfigurationProducer
@Specializes
@Override
public Configuration getConfiguration() {
+ final KernelConfig kernelConfig = confManager.findConfiguration(
+ KernelConfig.class
+ );
+
final Configuration configuration = new Configuration(
Configuration.VERSION_2_3_30
);
configuration.setDefaultEncoding("UTF-8");
- configuration.setTemplateExceptionHandler(
- TemplateExceptionHandler.RETHROW_HANDLER
- );
- configuration.setLogTemplateExceptions(false);
+ if (kernelConfig.isDebugEnabled()) {
+ configuration.setTemplateExceptionHandler(
+ TemplateExceptionHandler.DEBUG_HANDLER
+ );
+ configuration.setLogTemplateExceptions(true);
+ } else {
+ configuration.setTemplateExceptionHandler(
+ TemplateExceptionHandler.RETHROW_HANDLER
+ );
+ configuration.setLogTemplateExceptions(false);
+ }
+
configuration.setWrapUncheckedExceptions(false);
configuration.setLocalizedLookup(false);
configuration.setTemplateLoader(
diff --git a/ccm-core/src/main/java/org/libreccm/security/PermissionManager.java b/ccm-core/src/main/java/org/libreccm/security/PermissionManager.java
index 1b7e3b7dc..969302580 100644
--- a/ccm-core/src/main/java/org/libreccm/security/PermissionManager.java
+++ b/ccm-core/src/main/java/org/libreccm/security/PermissionManager.java
@@ -57,8 +57,10 @@ public class PermissionManager implements Serializable {
@SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_OBJECT = "object";
+
@SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_GRANTEE = "grantee";
+
@SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_PRIVILEGE = "privilege";
@@ -79,8 +81,12 @@ public class PermissionManager implements Serializable {
* @return The permission identified by the provided {@code permissionId).
*/
public Optional findById(final long permissionId) {
- return Optional.ofNullable(entityManager.find(Permission.class,
- permissionId));
+ return Optional.ofNullable(
+ entityManager.find(
+ Permission.class,
+ permissionId
+ )
+ );
}
/**
@@ -93,7 +99,9 @@ public class PermissionManager implements Serializable {
@Transactional(Transactional.TxType.REQUIRED)
public List findPermissionsForRole(final Role role) {
final TypedQuery query = entityManager.createNamedQuery(
- "Permission.findPermissionsForRole", Permission.class);
+ "Permission.findPermissionsForRole",
+ Permission.class
+ );
query.setParameter("grantee", role);
return query.getResultList();
@@ -110,17 +118,22 @@ public class PermissionManager implements Serializable {
@Transactional(Transactional.TxType.REQUIRED)
public List findPermissionsForObject(final CcmObject object) {
final TypedQuery query = entityManager.createNamedQuery(
- "Permission.findPermissionsForCcmObject", Permission.class);
+ "Permission.findPermissionsForCcmObject",
+ Permission.class
+ );
query.setParameter("object", object);
return query.getResultList();
}
public List findPermissionsForRoleAndObject(
- final Role role, final CcmObject object) {
-
+ final Role role,
+ final CcmObject object
+ ) {
final TypedQuery query = entityManager.createNamedQuery(
- "Permission.findPermissionsForRoleAndObject", Permission.class);
+ "Permission.findPermissionsForRoleAndObject",
+ Permission.class
+ );
query.setParameter("object", object);
query.setParameter("grantee", role);
@@ -148,9 +161,11 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
- public Permission grantPrivilege(final String privilege,
- final Role grantee,
- final CcmObject object) {
+ public Permission grantPrivilege(
+ final String privilege,
+ final Role grantee,
+ final CcmObject object
+ ) {
if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException(
"Can't grant a permission without a privilege.");
@@ -182,7 +197,13 @@ public class PermissionManager implements Serializable {
entityManager.persist(permission);
- grantRecursive(privilege, grantee, object, object.getClass(), object);
+ grantRecursive(
+ privilege,
+ grantee,
+ object,
+ object.getClass(),
+ object
+ );
return permission;
}
@@ -202,32 +223,44 @@ public class PermissionManager implements Serializable {
* {@link #grantPrivilege(java.lang.String, org.libreccm.security.Role, org.libreccm.core.CcmObject)}
* was invoked.
*/
- private void grantRecursive(final String privilege,
- final Role grantee,
- final CcmObject object,
- final Class> clazz,
- final CcmObject inheritedFrom) {
+ private void grantRecursive(
+ final String privilege,
+ final Role grantee,
+ final CcmObject object,
+ final Class> clazz,
+ final CcmObject inheritedFrom
+ ) {
final Field[] fields = clazz.getDeclaredFields();
Arrays.stream(fields)
.filter(field -> field.isAnnotationPresent(
RecursivePermissions.class))
- .filter(field -> {
- return checkIfPrivilegeIsRecursive(
+ .filter(
+ field -> checkIfPrivilegeIsRecursive(
field.getAnnotation(RecursivePermissions.class),
- privilege);
- })
- .forEach(field -> {
+ privilege
+ )
+ )
+ .forEach(
+ field -> {
field.setAccessible(true);
- grantRecursive(privilege, grantee, field, object, inheritedFrom);
+ grantRecursive(
+ privilege,
+ grantee,
+ field,
+ object,
+ inheritedFrom
+ );
});
// Repeat for superclass of the current class.
if (clazz.getSuperclass() != null) {
- grantRecursive(privilege,
- grantee,
- object,
- clazz.getSuperclass(),
- inheritedFrom);
+ grantRecursive(
+ privilege,
+ grantee,
+ object,
+ clazz.getSuperclass(),
+ inheritedFrom
+ );
}
}
@@ -246,13 +279,14 @@ public class PermissionManager implements Serializable {
*/
private boolean checkIfPrivilegeIsRecursive(
final RecursivePermissions annotation,
- final String privilege) {
-
+ final String privilege
+ ) {
if (annotation.privileges() == null
|| annotation.privileges().length == 0) {
return true;
} else {
- return Arrays.stream(annotation.privileges())
+ return Arrays
+ .stream(annotation.privileges())
.anyMatch(privilege::equals);
}
}
@@ -266,24 +300,35 @@ public class PermissionManager implements Serializable {
* @param owner The object which own the provided {@code field}.
* @param inheritedFrom The object from which the permission is inherited.
*/
- private void grantRecursive(final String privilege,
- final Role grantee,
- final Field field,
- final CcmObject owner,
- final CcmObject inheritedFrom) {
-
+ private void grantRecursive(
+ final String privilege,
+ final Role grantee,
+ final Field field,
+ final CcmObject owner,
+ final CcmObject inheritedFrom
+ ) {
final CcmObject ownerObject = ccmObjectRepo
.findObjectById(owner.getObjectId())
- .orElseThrow(() -> new IllegalArgumentException(String.format(
- "No CcmObject with ID %d in the database. "
- + "Where did that ID come from?",
- owner.getObjectId())));
+ .orElseThrow(
+ () -> new IllegalArgumentException(
+ String.format(
+ "No CcmObject with ID %d in the database. "
+ + "Where did that ID come from?",
+ owner.getObjectId()
+ )
+ )
+ );
final CcmObject inheritedFromObject = ccmObjectRepo
.findObjectById(inheritedFrom.getObjectId())
- .orElseThrow(() -> new IllegalArgumentException(String.format(
- "No CcmObject with ID %d in the database. "
- + "Where did that ID come from?",
- inheritedFrom.getObjectId())));
+ .orElseThrow(
+ () -> new IllegalArgumentException(
+ String.format(
+ "No CcmObject with ID %d in the database. "
+ + "Where did that ID come from?",
+ inheritedFrom.getObjectId()
+ )
+ )
+ );
final Object value;
try {
@@ -303,10 +348,14 @@ public class PermissionManager implements Serializable {
collection.stream()
.filter(obj -> obj instanceof CcmObject)
.map(obj -> (CcmObject) obj)
- .forEach(obj -> grantInherited(privilege,
- grantee,
- obj,
- inheritedFromObject));
+ .forEach(
+ obj -> grantInherited(
+ privilege,
+ grantee,
+ obj,
+ inheritedFromObject
+ )
+ );
// Relations between two CcmObjects with attributes or n:m relations
// use an object to represent the relation. The object must implement
// the Relation interface. For each Relation object in the collection
@@ -316,33 +365,44 @@ public class PermissionManager implements Serializable {
.map(obj -> (Relation) obj)
.filter(relation -> relation.getRelatedObject() != null)
.map(relation -> relation.getRelatedObject())
- .forEach(obj -> grantInherited(privilege,
- grantee,
- obj,
- inheritedFromObject));
+ .forEach(
+ obj -> grantInherited(
+ privilege,
+ grantee,
+ obj,
+ inheritedFromObject
+ )
+ );
} else if (CcmObject.class.isAssignableFrom(field.getType())) {
// If the provided object is a CcmObject create an inherited
// permission for this object.
- grantInherited(privilege,
- grantee,
- (CcmObject) value,
- inheritedFromObject);
+ grantInherited(
+ privilege,
+ grantee,
+ (CcmObject) value,
+ inheritedFromObject
+ );
} else if (Relation.class.isAssignableFrom(field.getType())) {
// If the provided field is a Relation object created an inherited
// permission on the related object.
final Relation relation = (Relation) value;
if (relation.getRelatedObject() != null) {
- grantInherited(privilege,
- grantee,
- relation.getRelatedObject(),
- inheritedFromObject);
+ grantInherited(
+ privilege,
+ grantee,
+ relation.getRelatedObject(),
+ inheritedFromObject
+ );
}
} else {
- throw new IllegalArgumentException(String.format(
- "Found a field annotated with \"%s\" but the field is not a "
+ throw new IllegalArgumentException(
+ String.format(
+ "Found a field annotated with \"%s\" but the field is not a "
+ "collection nor a CcmObject nore a Relation object. This "
- + "is not supported.",
- RecursivePermissions.class));
+ + "is not supported.",
+ RecursivePermissions.class
+ )
+ );
}
}
@@ -355,11 +415,12 @@ public class PermissionManager implements Serializable {
* granted.
* @param inheritedFrom The object from which the permission is inherited.
*/
- private void grantInherited(final String privilege,
- final Role grantee,
- final CcmObject object,
- final CcmObject inheritedFrom) {
-
+ private void grantInherited(
+ final String privilege,
+ final Role grantee,
+ final CcmObject object,
+ final CcmObject inheritedFrom
+ ) {
if (!existsPermission(privilege, grantee, object)) {
final Permission permission = new Permission();
permission.setGrantee(grantee);
@@ -371,11 +432,13 @@ public class PermissionManager implements Serializable {
entityManager.persist(permission);
- grantRecursive(privilege,
- grantee,
- object,
- object.getClass(),
- inheritedFrom);
+ grantRecursive(
+ privilege,
+ grantee,
+ object,
+ object.getClass(),
+ inheritedFrom
+ );
}
}
@@ -389,16 +452,20 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
- public void grantPrivilege(final String privilege,
- final Role grantee) {
+ public void grantPrivilege(
+ final String privilege,
+ final Role grantee
+ ) {
if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException(
- "Can't grant a permission without a privilege.");
+ "Can't grant a permission without a privilege."
+ );
}
if (grantee == null) {
throw new IllegalArgumentException(
- "Can't grant a permission to grantee null.");
+ "Can't grant a permission to grantee null."
+ );
}
if (!existsPermission(privilege, grantee)) {
@@ -423,42 +490,52 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
- public void revokePrivilege(final String privilege,
- final Role grantee,
- final CcmObject object) {
+ public void revokePrivilege(
+ final String privilege,
+ final Role grantee,
+ final CcmObject object
+ ) {
if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException(
- "Can't revoke a permission without a privilege.");
+ "Can't revoke a permission without a privilege."
+ );
}
if (grantee == null) {
throw new IllegalArgumentException(
- "Can't revoke a permission from grantee null.");
+ "Can't revoke a permission from grantee null."
+ );
}
if (object == null) {
throw new IllegalArgumentException(
- "Can't revoke a permission from object NULL.");
+ "Can't revoke a permission from object NULL."
+ );
}
- LOGGER.debug("Revoking permission granting privilege \"{}\" "
- + "on object \"{}\" to role \"{}\"...",
- privilege,
- grantee.getName(),
- object.getUuid());
+ LOGGER.debug(
+ "Revoking permission granting privilege \"{}\" "
+ + "on object \"{}\" to role \"{}\"...",
+ privilege,
+ grantee.getName(),
+ object.getUuid()
+ );
if (existsPermission(privilege, grantee, object)
|| existsInheritedPermission(privilege, grantee, object)) {
- LOGGER.debug("There is a permission for the provided parameters, "
- + "revoking it...");
+ LOGGER.debug(
+ "There is a permission for the provided parameters, "
+ + "revoking it..."
+ );
final Query deleteQuery = entityManager.createQuery(
"DELETE FROM Permission p "
+ "WHERE p.grantedPrivilege = :privilege "
+ "AND p.grantee = :grantee "
- + "AND p.object = :object");
+ + "AND p.object = :object"
+ );
deleteQuery.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
deleteQuery.setParameter(QUERY_PARAM_GRANTEE, grantee);
deleteQuery.setParameter(QUERY_PARAM_OBJECT, object);
@@ -470,18 +547,21 @@ public class PermissionManager implements Serializable {
+ "WHERE p.grantedPrivilege = :privilege "
+ "AND p.grantee = :grantee "
+ "AND p.inheritedFrom = :object "
- + "AND p.inherited = true");
+ + "AND p.inherited = true"
+ );
deleteInheritedQuery.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
deleteInheritedQuery.setParameter(QUERY_PARAM_GRANTEE, grantee);
deleteInheritedQuery.setParameter("object", object);
final int deletedInherited = deleteInheritedQuery.executeUpdate();
LOGGER.debug("{} inherited permissions deleted.", deletedInherited);
} else {
- LOGGER.warn("No permission granting privilege \"{}\" "
- + "on object \"{}\" to role \"{}\". Ignoring.",
- privilege,
- grantee.getName(),
- object.getUuid());
+ LOGGER.warn(
+ "No permission granting privilege \"{}\" "
+ + "on object \"{}\" to role \"{}\". Ignoring.",
+ privilege,
+ grantee.getName(),
+ object.getUuid()
+ );
}
}
@@ -495,16 +575,20 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
- public void revokePrivilege(final String privilege,
- final Role grantee) {
+ public void revokePrivilege(
+ final String privilege,
+ final Role grantee
+ ) {
if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException(
- "Can't revoke a permission without a privilege.");
+ "Can't revoke a permission without a privilege."
+ );
}
if (grantee == null) {
throw new IllegalArgumentException(
- "Can't revoke a permission from grantee null.");
+ "Can't revoke a permission from grantee null."
+ );
}
if (existsPermission(privilege, grantee)) {
@@ -512,7 +596,8 @@ public class PermissionManager implements Serializable {
"DELETE FROM Permission p "
+ "WHERE p.grantedPrivilege = :privilege "
+ "AND p.grantee = :grantee "
- + "AND p.object IS NULL");
+ + "AND p.object IS NULL"
+ );
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.executeUpdate();
@@ -532,8 +617,10 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
- public void copyPermissions(final CcmObject source,
- final CcmObject target) {
+ public void copyPermissions(
+ final CcmObject source,
+ final CcmObject target
+ ) {
copyPermissions(source, target, false);
}
@@ -552,21 +639,27 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
- public void copyPermissions(final CcmObject source,
- final CcmObject target,
- final boolean inherited) {
+ public void copyPermissions(
+ final CcmObject source,
+ final CcmObject target,
+ final boolean inherited
+ ) {
if (source == null) {
throw new IllegalArgumentException(
- "Can't copy permissions from source NULL.");
+ "Can't copy permissions from source NULL."
+ );
}
if (target == null) {
throw new IllegalArgumentException(
- "Can't copy permissions to target NULL.");
+ "Can't copy permissions to target NULL."
+ );
}
final TypedQuery query = entityManager.createNamedQuery(
- "Permission.findPermissionsForCcmObject", Permission.class);
+ "Permission.findPermissionsForCcmObject",
+ Permission.class
+ );
query.setParameter(QUERY_PARAM_OBJECT, source);
final List result = query.getResultList();
@@ -574,7 +667,11 @@ public class PermissionManager implements Serializable {
final Permission granted = grantPrivilege(
permission.getGrantedPrivilege(),
permission.getGrantee(),
- target);
+ target
+ );
+ if (granted == null) {
+ continue;
+ }
granted.setInherited(inherited);
if (inherited) {
granted.setInheritedFrom(source);
@@ -598,12 +695,17 @@ public class PermissionManager implements Serializable {
* @return A list with all privileges defined by the provided class.
*/
public List listDefiniedPrivileges(final Class> clazz) {
- return Arrays.stream(clazz.getDeclaredFields())
+ return Arrays
+ .stream(clazz.getDeclaredFields())
.filter(field -> field.getType().isAssignableFrom(String.class))
- .filter(field -> Modifier.isStatic(field.getModifiers())
- && Modifier.isFinal(field.getModifiers()))
- .filter(field -> field.getName().startsWith("PRIVILEGE_")
- || clazz.getSimpleName().endsWith("Privileges"))
+ .filter(
+ field -> Modifier.isStatic(field.getModifiers())
+ && Modifier.isFinal(field.getModifiers())
+ )
+ .filter(
+ field -> field.getName().startsWith("PRIVILEGE_")
+ || clazz.getSimpleName().endsWith("Privileges")
+ )
.map(field -> getPrivilegeString(field))
.sorted()
.collect(Collectors.toList());
@@ -629,11 +731,15 @@ public class PermissionManager implements Serializable {
* @return {@code true} if there is a matching permission, {@code false} if
* not.
*/
- private boolean existsPermission(final String privilege,
- final Role grantee,
- final CcmObject object) {
+ private boolean existsPermission(
+ final String privilege,
+ final Role grantee,
+ final CcmObject object
+ ) {
final TypedQuery query = entityManager.createNamedQuery(
- "Permission.existsDirectForPrivilegeRoleObject", Long.class);
+ "Permission.existsDirectForPrivilegeRoleObject",
+ Long.class
+ );
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.setParameter(QUERY_PARAM_OBJECT, object);
@@ -641,11 +747,15 @@ public class PermissionManager implements Serializable {
return query.getSingleResult() > 0;
}
- private boolean existsInheritedPermission(final String privilege,
- final Role grantee,
- final CcmObject object) {
+ private boolean existsInheritedPermission(
+ final String privilege,
+ final Role grantee,
+ final CcmObject object
+ ) {
final TypedQuery query = entityManager.createNamedQuery(
- "Permission.existsInheritedForPrivilegeRoleObject", Long.class);
+ "Permission.existsInheritedForPrivilegeRoleObject",
+ Long.class
+ );
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.setParameter(QUERY_PARAM_OBJECT, object);
@@ -663,10 +773,14 @@ public class PermissionManager implements Serializable {
* @return {@code true} if there is a matching permission, {@code false} if
* not.
*/
- private boolean existsPermission(final String privilege,
- final Role grantee) {
+ private boolean existsPermission(
+ final String privilege,
+ final Role grantee
+ ) {
final TypedQuery query = entityManager.createNamedQuery(
- "Permission.existsForPrivilegeAndRole", Long.class);
+ "Permission.existsForPrivilegeAndRole",
+ Long.class
+ );
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
diff --git a/ccm-core/src/main/java/org/libreccm/theming/freemarker/FreemarkerConfigurationProvider.java b/ccm-core/src/main/java/org/libreccm/theming/freemarker/FreemarkerConfigurationProvider.java
index 000918402..89a7d367a 100644
--- a/ccm-core/src/main/java/org/libreccm/theming/freemarker/FreemarkerConfigurationProvider.java
+++ b/ccm-core/src/main/java/org/libreccm/theming/freemarker/FreemarkerConfigurationProvider.java
@@ -57,32 +57,36 @@ class FreemarkerConfigurationProvider {
private final Map configurations = new HashMap<>();
protected Configuration getConfiguration(final ThemeInfo forTheme) {
-
if (configurations.containsKey(forTheme)) {
-
return configurations.get(forTheme);
} else {
-
final Configuration configuration = new Configuration(
- Configuration.VERSION_2_3_27);
+ Configuration.VERSION_2_3_27
+ );
configuration.setDefaultEncoding("UTF-8");
configuration
.setTemplateExceptionHandler(
- TemplateExceptionHandler.RETHROW_HANDLER);
- configuration.setLogTemplateExceptions(false);
+ TemplateExceptionHandler.DEBUG_HANDLER
+ );
+ configuration.setLogTemplateExceptions(true);
configuration.setWrapUncheckedExceptions(false);
configuration.setLocalizedLookup(false);
configuration.setTemplateLoader(
- new MultiTemplateLoader(new TemplateLoader[]{
- // For for files from themes
- new CcmTemplateLoader(forTheme),
- // Loader for MacroLibs provided by CCM modules
- new WebappTemplateLoader(
- servletContext, "/themes/freemarker"
- ),
- new ClassTemplateLoader(getClass(), "/themes/freemarker")
- })
+ new MultiTemplateLoader(
+ new TemplateLoader[]{
+ // For for files from themes
+ new CcmTemplateLoader(forTheme),
+ // Loader for MacroLibs provided by CCM modules
+ new WebappTemplateLoader(
+ servletContext, "/themes/freemarker"
+ ),
+ new ClassTemplateLoader(
+ getClass(),
+ "/themes/freemarker"
+ )
+ }
+ )
);
configurations.put(forTheme, configuration);
@@ -103,7 +107,8 @@ class FreemarkerConfigurationProvider {
public Object findTemplateSource(final String name) throws IOException {
final Optional source = themes.getFileFromTheme(
- fromTheme, name);
+ fromTheme, name
+ );
if (source.isPresent()) {
return source.get();
} else {
@@ -118,9 +123,10 @@ class FreemarkerConfigurationProvider {
}
@Override
- public Reader getReader(final Object templateSource,
- final String encoding) throws IOException {
-
+ public Reader getReader(
+ final Object templateSource,
+ final String encoding
+ ) throws IOException {
final InputStream inputStream = (InputStream) templateSource;
return new InputStreamReader(inputStream, encoding);
}
@@ -128,7 +134,6 @@ class FreemarkerConfigurationProvider {
@Override
public void closeTemplateSource(final Object templateSource)
throws IOException {
-
final InputStream inputStream = (InputStream) templateSource;
inputStream.close();
}
diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/imexport/ImportExportTaskManager.java b/ccm-core/src/main/java/org/libreccm/ui/admin/imexport/ImportExportTaskManager.java
index ec51a8382..498378362 100644
--- a/ccm-core/src/main/java/org/libreccm/ui/admin/imexport/ImportExportTaskManager.java
+++ b/ccm-core/src/main/java/org/libreccm/ui/admin/imexport/ImportExportTaskManager.java
@@ -217,7 +217,9 @@ public class ImportExportTaskManager {
* @see CompletionStage#handle(java.util.function.BiFunction)
*/
private Object handleExportTaskResult(
- final ExportTask task, final Throwable ex, final ExportTaskStatus status
+ final ExportTask task,
+ final Throwable ex,
+ final ExportTaskStatus status
) {
if (ex == null) {
status.setStatus(ImExportTaskStatus.FINISHED);