Some code formattig, added function for fixing item and asset permissions (sometimes they are not correctly inherited from the folder.

master
Jens Pelzetter 2023-07-12 21:08:18 +02:00
parent 4251fd1df9
commit 7cea45560a
21 changed files with 1272 additions and 166 deletions

View File

@ -580,16 +580,28 @@ public class PagesController {
final Page page = pageManager.findPageForCategory(category);
pagePropertiesModel.setProperties(page.getProperties());
try {
final String result;
if (itemName.equals("index") || itemName.isBlank()) {
return themesMvc.getMvcTemplate(
result = themesMvc.getMvcTemplate(
uriInfo, "pages", page.getDisplayName()
);
} else {
return themesMvc.getMvcTemplate(
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(

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ContentItemListItemModel extends AbstractContentItemListItemModel {
@Override
public String getType() {
return ContentItem.class.getName();
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class ContentItemListModelBuilder
extends AbstractContentItemListItemModelBuilder<ContentItem, ContentItemListItemModel> {
@Override
public Class<ContentItem> buildsListItemModelFor() {
return ContentItem.class;
}
@Override
protected ContentItemListItemModel buildModel() {
return new ContentItemListItemModel();
}
}

View File

@ -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<Category> collectCategories(final Category category) {

View File

@ -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.

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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<ContentSection> 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<ContentItem> 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<Asset> 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);
// }
// }
}

View File

@ -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);

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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<ContentItem> items = new ArrayList<>();
for (final Categorization categorization : folder.getObjects()) {
final CcmObject categorized = categorization.getCategorizedObject();
if (categorized instanceof ContentItem) {
items.add((ContentItem) categorized);
}
}
// final List<ContentItem> 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<Asset> 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);
}
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public enum FixItemPermissionsStatus {
/**
* An error occured during the process.
*/
ERROR,
/**
* The import or export task is finished.
*/
FINISHED,
/**
* The task is still running.
*/
RUNNING,
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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;
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ApplicationScoped
public class FixItemPermissionsTaskManager {
private static final Logger LOGGER = LogManager.getLogger(
FixItemPermissionsTaskManager.class
);
@Inject
private Event<FixItemPermissionsTask> taskSender;
private final SortedSet<FixItemPermissionsTaskStatus> tasks;
public SortedSet<FixItemPermissionsTaskStatus> 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;
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class FixItemPermissionsTaskStatus
implements Comparable<FixItemPermissionsTaskStatus> {
/**
* 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)
);
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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()
);
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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());
}
}

View File

@ -136,6 +136,51 @@
</p>
</div>
</div>
<div class="col mb-4">
<div aria-describedby="configuration-fixitemandassetspermissions-body"
class="card pt-2"
id="configuration-fixitemandassetspermissions">
<svg aria-hidden="true"
class="card-img-top"
fill="currentColor">
<use xlink:href="#{request.contextPath}/assets/bootstrap/bootstrap-icons.svg#screwdriver" />
</svg>
</div>
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/fix-item-and-asset-permissions"
class="card-body"
id="configuration-fixitemandassetspermissions-body"
method="post">
<h2 class="card-title">
<c:choose>
<c:when test="#{FixItemPermissionsTaskStatusModel.taskRunningForContentSection}">
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.title']}
</c:when>
<c:otherwise>
<button class="btn btn-link stretched-link"
type="submit">
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.title']}
</button>
</c:otherwise>
</c:choose>
</h2>
<p class="card-text">
<c:if test="#{FixItemPermissionsTaskStatusModel.taskFailedForContentSection}">
<div class="alert alert-danger" role="alert">
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.failed']}
</div>
</c:if>
<c:choose>
<c:when test="#{FixItemPermissionsTaskStatusModel.taskRunningForContentSection}">
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.running']}
</c:when>
<c:otherwise>
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.description']}
</c:otherwise>
</c:choose>
</p>
</form>
</div>
</div>
</div>
</ui:define>

View File

@ -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.

View File

@ -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.

View File

@ -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;
@ -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");
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(

View File

@ -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<Permission> 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<Permission> findPermissionsForRole(final Role role) {
final TypedQuery<Permission> 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<Permission> findPermissionsForObject(final CcmObject object) {
final TypedQuery<Permission> query = entityManager.createNamedQuery(
"Permission.findPermissionsForCcmObject", Permission.class);
"Permission.findPermissionsForCcmObject",
Permission.class
);
query.setParameter("object", object);
return query.getResultList();
}
public List<Permission> findPermissionsForRoleAndObject(
final Role role, final CcmObject object) {
final Role role,
final CcmObject object
) {
final TypedQuery<Permission> 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,
public Permission grantPrivilege(
final String privilege,
final Role grantee,
final CcmObject object) {
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,
private void grantRecursive(
final String privilege,
final Role grantee,
final CcmObject object,
final Class<?> clazz,
final CcmObject inheritedFrom) {
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,
grantRecursive(
privilege,
grantee,
object,
clazz.getSuperclass(),
inheritedFrom);
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,
private void grantRecursive(
final String privilege,
final Role grantee,
final Field field,
final CcmObject owner,
final CcmObject inheritedFrom) {
final CcmObject inheritedFrom
) {
final CcmObject ownerObject = ccmObjectRepo
.findObjectById(owner.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String.format(
.orElseThrow(
() -> new IllegalArgumentException(
String.format(
"No CcmObject with ID %d in the database. "
+ "Where did that ID come from?",
owner.getObjectId())));
owner.getObjectId()
)
)
);
final CcmObject inheritedFromObject = ccmObjectRepo
.findObjectById(inheritedFrom.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String.format(
.orElseThrow(
() -> new IllegalArgumentException(
String.format(
"No CcmObject with ID %d in the database. "
+ "Where did that ID come from?",
inheritedFrom.getObjectId())));
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,
.forEach(
obj -> grantInherited(
privilege,
grantee,
obj,
inheritedFromObject));
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,
.forEach(
obj -> grantInherited(
privilege,
grantee,
obj,
inheritedFromObject));
inheritedFromObject
)
);
} else if (CcmObject.class.isAssignableFrom(field.getType())) {
// If the provided object is a CcmObject create an inherited
// permission for this object.
grantInherited(privilege,
grantInherited(
privilege,
grantee,
(CcmObject) value,
inheritedFromObject);
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,
grantInherited(
privilege,
grantee,
relation.getRelatedObject(),
inheritedFromObject);
inheritedFromObject
);
}
} else {
throw new IllegalArgumentException(String.format(
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));
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,
private void grantInherited(
final String privilege,
final Role grantee,
final CcmObject object,
final CcmObject inheritedFrom) {
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,
grantRecursive(
privilege,
grantee,
object,
object.getClass(),
inheritedFrom);
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,
public void revokePrivilege(
final String privilege,
final Role grantee,
final CcmObject object) {
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 \"{}\" "
LOGGER.debug(
"Revoking permission granting privilege \"{}\" "
+ "on object \"{}\" to role \"{}\"...",
privilege,
grantee.getName(),
object.getUuid());
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 \"{}\" "
LOGGER.warn(
"No permission granting privilege \"{}\" "
+ "on object \"{}\" to role \"{}\". Ignoring.",
privilege,
grantee.getName(),
object.getUuid());
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,
public void copyPermissions(
final CcmObject source,
final CcmObject target,
final boolean inherited) {
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<Permission> query = entityManager.createNamedQuery(
"Permission.findPermissionsForCcmObject", Permission.class);
"Permission.findPermissionsForCcmObject",
Permission.class
);
query.setParameter(QUERY_PARAM_OBJECT, source);
final List<Permission> 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<String> 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,
private boolean existsPermission(
final String privilege,
final Role grantee,
final CcmObject object) {
final CcmObject object
) {
final TypedQuery<Long> 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,
private boolean existsInheritedPermission(
final String privilege,
final Role grantee,
final CcmObject object) {
final CcmObject object
) {
final TypedQuery<Long> 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<Long> query = entityManager.createNamedQuery(
"Permission.existsForPrivilegeAndRole", Long.class);
"Permission.existsForPrivilegeAndRole",
Long.class
);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee);

View File

@ -57,32 +57,36 @@ class FreemarkerConfigurationProvider {
private final Map<ThemeInfo, Configuration> 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[]{
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 ClassTemplateLoader(
getClass(),
"/themes/freemarker"
)
}
)
);
configurations.put(forTheme, configuration);
@ -103,7 +107,8 @@ class FreemarkerConfigurationProvider {
public Object findTemplateSource(final String name) throws IOException {
final Optional<InputStream> 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();
}

View File

@ -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);