Skip to content

Bug #14787 #1412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 20, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -219,6 +219,37 @@ CREATE TABLE ST_UserRole_Group_Rel
CONSTRAINT FK_UserRole_Group_Rel_2 FOREIGN KEY (groupId) REFERENCES ST_Group (id)
);

CREATE TABLE SB_Node_Node
(
nodeId INT NOT NULL,
nodeName VARCHAR (1000) NOT NULL,
nodeDescription VARCHAR (2000) NULL,
nodeCreationDate VARCHAR (10) NOT NULL,
nodeCreatorId VARCHAR (100) NOT NULL,
nodePath VARCHAR (1000) NOT NULL,
nodeLevelNumber INT NOT NULL,
nodeFatherId INT NOT NULL,
modelId VARCHAR (1000) NULL,
nodeStatus VARCHAR (1000) NULL,
instanceId VARCHAR (50) NOT NULL,
type VARCHAR (50) NULL,
orderNumber INT DEFAULT (0) NULL,
lang CHAR(2),
rightsDependsOn INT DEFAULT (-1) NOT NULL,
CONSTRAINT PK_Node_Node PRIMARY KEY (nodeId, instanceId)
);

CREATE TABLE SB_Node_NodeI18N
(
id INT NOT NULL,
nodeId INT NOT NULL,
lang CHAR (2) NOT NULL,
nodeName VARCHAR (1000) NOT NULL,
nodeDescription VARCHAR (2000),
CONSTRAINT PK_Node_NodeI18N PRIMARY KEY (id),
CONSTRAINT UN_Node_NodeI18N UNIQUE (nodeId, lang)
);

/*
* The SQL tables of a given component used in tests
*/
Original file line number Diff line number Diff line change
@@ -30,12 +30,15 @@
import org.silverpeas.core.admin.user.model.ProfileInst;
import org.silverpeas.core.admin.user.notification.ProfileInstEvent;
import org.silverpeas.core.annotation.Service;
import org.silverpeas.core.notification.system.CDIResourceEventListener;
import org.silverpeas.core.notification.system.CDIAfterSuccessfulTransactionResourceEventListener;
import org.silverpeas.core.notification.system.ResourceEvent;

import javax.inject.Inject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@@ -50,7 +53,8 @@
* @author mmoquillon
*/
@Service
class ProfileInstUpdateEventListener extends CDIResourceEventListener<ProfileInstEvent> {
class ProfileInstUpdateEventListener
extends CDIAfterSuccessfulTransactionResourceEventListener<ProfileInstEvent> {

@Inject
private OrganizationController organization;
@@ -62,15 +66,19 @@ class ProfileInstUpdateEventListener extends CDIResourceEventListener<ProfileIns
public void onUpdate(ProfileInstEvent event) {
ProfileInst before = event.getTransition().getBefore();
ProfileInst after = event.getTransition().getAfter();
ComponentInst componentInst = getComponentInstanceId(before.getComponentFatherId());
Set<String> removedUsers = findRemovedUsersId(componentInst, before, after);
if (!removedUsers.isEmpty()) {
UserRoleEvent userRoleEvent = UserRoleEvent.builderFor(ResourceEvent.Type.DELETION)
.role(before.getName())
.instanceId(componentInst.getId())
.userIds(removedUsers)
.build();
notifier.notify(userRoleEvent);
if (before.getObjectId().isNotDefined()) {
// we take in charge only changes in the right profiles of component instances, no those of
// resources managed by the component instances
ComponentInst componentInst = getComponentInstanceId(before.getComponentFatherId());
Set<String> removedUsers = findRemovedUsersId(componentInst, before, after);
if (!removedUsers.isEmpty()) {
UserRoleEvent userRoleEvent = UserRoleEvent.builderFor(ResourceEvent.Type.DELETION)
.role(before.getName())
.instanceId(componentInst.getId())
.userIds(removedUsers)
.build();
notifier.notify(userRoleEvent);
}
}
}

@@ -90,13 +98,15 @@ private Set<String> findRemovedUsersId(ComponentInst componentInst, ProfileInst
ProfileInst after) {
List<String> usersAfter = after.getAllUsers();
List<String> groupsAfter = after.getAllGroups();
String roleName = before.getName();
String roleName = before.getName();
NoAnymorePlayedRole roleNotAnymorePlayedByUser = new NoAnymorePlayedRole(roleName,
componentInst.getId());

// get all the users directly removed from the profile instance and who don't play anymore
// the role for the application (they can be play another role)
Stream<String> removedUsers = before.getAllUsers().stream()
.filter(user -> !usersAfter.contains(user))
.filter(u -> Stream.of(organization.getUserProfiles(u, componentInst.getId()))
.noneMatch(p -> p.equalsIgnoreCase(roleName)));
.filter(roleNotAnymorePlayedByUser);


// get all the users belonging to the groups removed from the profile instance and who's not
@@ -107,14 +117,33 @@ private Set<String> findRemovedUsersId(ComponentInst componentInst, ProfileInst
.map(g -> organization.getGroup(g))
.flatMap(g -> Stream.of(((Group) g).getUserIds()))
.distinct()
.filter(u -> Stream.of(organization.getUserProfiles(u, componentInst.getId()))
.noneMatch(p -> p.equalsIgnoreCase(roleName)));
.filter(roleNotAnymorePlayedByUser);

return Stream.concat(removedUsers, removedUsersInGroups).collect(Collectors.toSet());
}

private ComponentInst getComponentInstanceId(int localComponentId) {
return organization.getComponentInst(String.valueOf(localComponentId));
}

private class NoAnymorePlayedRole implements Predicate<String> {

private final Map<String, String[]> cache = new HashMap<>();
private final String instanceId;
private final String roleName;

public NoAnymorePlayedRole(String roleName, String componentInstanceId) {
this.instanceId = componentInstanceId;
this.roleName = roleName;
}

@Override
public boolean test(String userId) {
String[] roles = cache.computeIfAbsent(userId,
u -> organization.getUserProfiles(u, instanceId));
return roles.length == 0 ||
Stream.of(roles).noneMatch(p -> p.equalsIgnoreCase(roleName));
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2000 - 2025 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:
* "https://www.silverpeas.org/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.core.node.service;

import org.silverpeas.core.admin.component.model.ComponentInst;
import org.silverpeas.core.admin.service.AdminException;
import org.silverpeas.core.admin.service.Administration;
import org.silverpeas.core.admin.user.model.ProfileInst;
import org.silverpeas.core.admin.user.notification.ProfileInstEvent;
import org.silverpeas.core.annotation.Service;
import org.silverpeas.core.notification.system.CDIResourceEventListener;
import org.silverpeas.kernel.SilverpeasRuntimeException;

import javax.inject.Inject;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Listener of events about changes in a given right profile instance of a component instance.
* For all the user groups removed from the profile instance related by the event, an invocation
* to the {@link NodeProfileInstUpdater} is performed.
*
* @author mmoquillon
*/
@Service
public class NodeProfileInstEventListener extends CDIResourceEventListener<ProfileInstEvent> {

@Inject
private Administration admin;
@Inject
private NodeProfileInstUpdater updater;

@Transactional
@Override
public void onUpdate(ProfileInstEvent event) {
ProfileInst before = event.getTransition().getBefore();
if (before.isOnComponentInstance()) {
ProfileInst after = event.getTransition().getAfter();
int instanceId = before.getComponentFatherId();
ComponentInst instance = getComponentInstanceId(instanceId);
List<String> groupsAfter = after.getAllGroups();
Set<String> removedGroups = before.getAllGroups().stream()
.filter(group -> !groupsAfter.contains(group))
.collect(Collectors.toSet());
updater.getRemoverFor(instance.getId())
.ofGroups(removedGroups)
.apply();
}
}

private ComponentInst getComponentInstanceId(int localComponentId) {
try {
return admin.getComponentInst(String.valueOf(localComponentId));
} catch (AdminException e) {
throw new SilverpeasRuntimeException(e);
}
}

}

Loading
Oops, something went wrong.