KmeliaUserTreeViewFilter.java
/*
* Copyright (C) 2000 - 2024 Silverpeas
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.silverpeas.components.kmelia.service;
import org.silverpeas.core.admin.ProfiledObjectType;
import org.silverpeas.core.admin.service.OrganizationController;
import org.silverpeas.core.node.model.NodeDetail;
import org.silverpeas.core.node.model.NodePK;
import org.silverpeas.core.util.ArrayUtil;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static org.silverpeas.kernel.util.StringUtil.defaultStringIfNotDefined;
/**
* This class handles by one method call the following stuffs:
* <ul>
* <li>the computing of best user role on each node of a tree</li>
* <li>the filtering of nodes which the user can't access (not accessible nodes are removed
* from the tree)</li>
* </ul>
* @author Yohann Chastagnier
*/
class KmeliaUserTreeViewFilter {
private static final String NODE_TO_EXCLUDE = "@@@NODE_TO_EXCLUDE@@@";
private final OrganizationController orga = OrganizationController.get();
private final String userId;
private final String instanceId;
private final NodePK initialNodeIdentifier;
private final String bestUserComponentInstanceRole;
private final boolean isRightsOnTopicsUsed;
private Map<String, List<String>> nodeUserRoles = null;
/**
* Initializing the instance.
* @param userId the identifier of a user
* @param instanceId the identifier of a component instance.
* @param initialNodeIdentifier the node root identifier.
* @param bestUserComponentInstanceRole the best role the user has on the component instance.
* @param isRightsOnTopicsUsed true of rights are handled at a node level.
* @return an initialized instance.
*/
public static KmeliaUserTreeViewFilter from(final String userId, final String instanceId,
final NodePK initialNodeIdentifier, final String bestUserComponentInstanceRole,
final boolean isRightsOnTopicsUsed) {
return new KmeliaUserTreeViewFilter(userId, instanceId, initialNodeIdentifier,
bestUserComponentInstanceRole, isRightsOnTopicsUsed);
}
/**
* Hidden constructor.
*/
private KmeliaUserTreeViewFilter(final String userId, final String instanceId,
final NodePK initialNodeIdentifier, final String bestUserComponentInstanceRole,
final boolean isRightsOnTopicsUsed) {
this.userId = userId;
this.instanceId = instanceId;
this.initialNodeIdentifier = initialNodeIdentifier;
this.bestUserComponentInstanceRole = bestUserComponentInstanceRole;
this.isRightsOnTopicsUsed = isRightsOnTopicsUsed;
}
/**
* Computes and sets the best user role on each node of the given tree and filters it by
* excluding from the given tree the nodes that the user can't access.
* @param tree the tree to perform.
*/
void setBestUserRoleAndFilter(List<NodeDetail> tree) {
if (isRightsOnTopicsUsed) {
tree.removeIf(node -> !setBestUserNodeRole(node, bestUserComponentInstanceRole));
} else {
for (NodeDetail node : tree) {
node.setUserRole(bestUserComponentInstanceRole);
}
}
if (!tree.isEmpty()) {
NodeDetail root = tree.get(0);
if (root.getNodePK().isRoot()) {
// Case of root.
// Check if publications on root are allowed
String sNB = defaultStringIfNotDefined(
orga.getComponentParameterValue(initialNodeIdentifier.getInstanceId(), "nbPubliOnRoot"),
"0");
int nbPublisOnRoot = Integer.parseInt(sNB);
if (nbPublisOnRoot != 0) {
root.setUserRole("user");
}
}
}
}
/**
* Sets the best node profile on the given node and its children one.
* @param node the node to perform.
* @param bestParentNodeUserRole the best user role of the parent node.
* @return true if the user can access the node because of its role or because it can access a sub
* node.
*/
private boolean setBestUserNodeRole(final NodeDetail node, final String bestParentNodeUserRole) {
final String nodeUserRole = node.getUserRole();
if (nodeUserRole != null) {
return !NODE_TO_EXCLUDE.equals(nodeUserRole);
}
String bestNodeUserRole = bestParentNodeUserRole;
boolean hasUserNodeAccess = false;
if (node.haveRights()) {
String rightsDependsOn = node.getRightsDependsOn();
String[] profiles = getNodeUserRoles(rightsDependsOn);
bestNodeUserRole = ArrayUtil.isEmpty(profiles) ? null : KmeliaHelper.getProfile(profiles);
}
if (bestNodeUserRole != null) {
node.setUserRole(bestNodeUserRole);
hasUserNodeAccess = true;
}
Iterator<NodeDetail> nodeChildIterator = node.getChildrenDetails().iterator();
while (nodeChildIterator.hasNext()) {
NodeDetail child = nodeChildIterator.next();
boolean hasUserChildNodeAccess = setBestUserNodeRole(child, bestNodeUserRole);
if (!hasUserChildNodeAccess) {
nodeChildIterator.remove();
}
hasUserNodeAccess = hasUserNodeAccess || hasUserChildNodeAccess;
}
if (!hasUserNodeAccess) {
node.setUserRole(NODE_TO_EXCLUDE);
}
return hasUserNodeAccess;
}
/**
* Gets the roles of the user on the node represented by the given identifier.<br>
* Data are loaded only one time.
* @param nodeId a node identifier.
* @return a list of role.
*/
private String[] getNodeUserRoles(String nodeId) {
if (nodeUserRoles == null) {
nodeUserRoles = orga.getUserObjectProfiles(userId, instanceId, ProfiledObjectType.NODE);
}
List<String> roles = nodeUserRoles.get(nodeId);
return (roles != null) ? roles.toArray(new String[0]) : new String[0];
}
}