diff --git a/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle.properties b/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle.properties
index 0df3668bde..da5cf68f32 100644
--- a/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle.properties
+++ b/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle.properties
@@ -64,4 +64,6 @@ community.members.history.item.leftOn=Quitt\u00e9 le
community.member.status.committed=Membre
community.member.status.pending=En attente de validation
community.member.status.refused=Refus\u00e9e
-community.member.status.removed=Retir\u00e9e
\ No newline at end of file
+community.member.status.removed=Retir\u00e9e
+community.membership.management.label=Gestion des adhésions
+community.membership.management.desc=Application pour gérer les adhésions à la communauté
\ No newline at end of file
diff --git a/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_de.properties b/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_de.properties
index 1037cd4106..e0cdc5fe88 100644
--- a/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_de.properties
+++ b/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_de.properties
@@ -64,4 +64,6 @@ community.members.history.item.leftOn=Abmeldung bei
community.member.status.committed=Mitglied
community.member.status.pending=Wartet auf Validierung
community.member.status.refused=Mitgliedschaft abgelehnt
-community.member.status.removed=Entfernt
\ No newline at end of file
+community.member.status.removed=Entfernt
+community.membership.management.desc=Anwendung zur Verwaltung von Community-Mitgliedschaft
+community.membership.management.label=Mitgliederverwaltung
\ No newline at end of file
diff --git a/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_en.properties b/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_en.properties
index 256ecf7f5c..95d8b6df28 100644
--- a/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_en.properties
+++ b/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_en.properties
@@ -64,4 +64,6 @@ community.members.history.item.leftOn=Leave on
community.member.status.committed=Member
community.member.status.pending=Pending validation
community.member.status.refused=Membership refused
-community.member.status.removed=Removed
\ No newline at end of file
+community.member.status.removed=Removed
+community.membership.management.desc=Application for managing the community membership
+community.membership.management.label=Membership Management
\ No newline at end of file
diff --git a/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_fr.properties b/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_fr.properties
index 0df3668bde..bf7232e6d8 100644
--- a/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_fr.properties
+++ b/community/community-configuration/src/main/config/properties/org/silverpeas/components/community/multilang/communityBundle_fr.properties
@@ -64,4 +64,6 @@ community.members.history.item.leftOn=Quitt\u00e9 le
community.member.status.committed=Membre
community.member.status.pending=En attente de validation
community.member.status.refused=Refus\u00e9e
-community.member.status.removed=Retir\u00e9e
\ No newline at end of file
+community.member.status.removed=Retir\u00e9e
+community.membership.management.desc=Application pour gérer les adhésions à la communauté
+community.membership.management.label=Gestion des adhésions
\ No newline at end of file
diff --git a/community/community-configuration/src/main/config/xmlcomponents/community.xml b/community/community-configuration/src/main/config/xmlcomponents/community.xml
index 8a808687b5..cce281100f 100644
--- a/community/community-configuration/src/main/config/xmlcomponents/community.xml
+++ b/community/community-configuration/src/main/config/xmlcomponents/community.xml
@@ -54,7 +54,7 @@
false
true
- true
+ false
false
@@ -113,7 +113,7 @@
2
true
- no
+ reader
diff --git a/community/community-library/src/integration-test/resources/community-database.sql b/community/community-library/src/integration-test/resources/community-database.sql
index 8fd65e6205..80d7a45f20 100644
--- a/community/community-library/src/integration-test/resources/community-database.sql
+++ b/community/community-library/src/integration-test/resources/community-database.sql
@@ -56,6 +56,7 @@ CREATE TABLE IF NOT EXISTS ST_Group
id int NOT NULL,
domainId int NOT NULL,
specificId varchar(500) NOT NULL,
+ spaceId varchar(500) NULL,
superGroupId int,
name varchar(100) NOT NULL,
description varchar(400),
@@ -102,6 +103,7 @@ CREATE TABLE IF NOT EXISTS ST_Space
look varchar(50),
displaySpaceFirst smallint,
isPersonal smallint,
+ isCommunity smallint default 0 NOT NULL,
CONSTRAINT PK_Space PRIMARY KEY (id),
CONSTRAINT UN_Space_1 UNIQUE (domainFatherId, name),
CONSTRAINT FK_Space_1 FOREIGN KEY (createdBy) REFERENCES ST_User (id),
diff --git a/community/community-library/src/integration-test/resources/community-dataset.sql b/community/community-library/src/integration-test/resources/community-dataset.sql
index 6bcdeae7d5..b61d48294f 100644
--- a/community/community-library/src/integration-test/resources/community-dataset.sql
+++ b/community/community-library/src/integration-test/resources/community-dataset.sql
@@ -12,11 +12,11 @@ values (-1, 'internal', 'Do not remove - Used by Silverpeas engine', '-', '-', '
'org.silverpeas.core.admin.domain.driver.SilverpeasDomainDriver', 'autDomainSP', '0',
'https://localhost:8000/silverpeas');
-INSERT INTO st_space (id, domainFatherId, name, lang, firstPageType, isInheritanceBlocked)
-VALUES (1, NULL, 'Space 1', 'fr', 0, 1),
- (2, 1, 'Space 1-2', 'fr', 0, 0),
- (3, NULL, 'Space 2', 'fr', 0, 1),
- (4, NULL, 'Space 3', 'fr', 0, 0);
+INSERT INTO st_space (id, domainFatherId, name, lang, firstPageType, isInheritanceBlocked, isCommunity)
+VALUES (1, NULL, 'Space 1', 'fr', 0, 1, 1),
+ (2, 1, 'Space 1-2', 'fr', 0, 0, 1),
+ (3, NULL, 'Space 2', 'fr', 0, 1, 1),
+ (4, NULL, 'Space 3', 'fr', 0, 0, 0);
INSERT INTO st_componentinstance (id, spaceId, name, componentName, isPublic, isInheritanceBlocked)
VALUES (1, 1, 'Community 1', 'community', 1, 1),
diff --git a/community/community-library/src/main/java/org/silverpeas/components/community/CommunityInstanceFactory.java b/community/community-library/src/main/java/org/silverpeas/components/community/CommunityInstanceFactory.java
new file mode 100644
index 0000000000..f29d891651
--- /dev/null
+++ b/community/community-library/src/main/java/org/silverpeas/components/community/CommunityInstanceFactory.java
@@ -0,0 +1,71 @@
+/*
+ * 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 .
+ */
+
+package org.silverpeas.components.community;
+
+import org.silverpeas.core.admin.component.model.ComponentInst;
+import org.silverpeas.core.admin.component.model.WAComponent;
+import org.silverpeas.core.admin.service.CommunityFactory;
+import org.silverpeas.core.admin.space.SpaceInst;
+import org.silverpeas.core.admin.user.model.User;
+import org.silverpeas.core.annotation.Provider;
+import org.silverpeas.kernel.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * Implementation of the {@link CommunityFactory}. It will automatically creates an instance of this
+ * Silverpeas component for a given community space.
+ *
+ * @author mmoquillon
+ */
+@Provider
+public class CommunityInstanceFactory implements CommunityFactory {
+
+ @Override
+ @NonNull
+ public ComponentInst createCommunity(@NonNull SpaceInst communitySpace) {
+ Objects.requireNonNull(communitySpace);
+ String language = User.getCurrentUser().getUserPreferences().getLanguage();
+ var bundle = CommunityComponentSettings.getMessagesIn(language);
+ var maybeComponent = WAComponent.getByName(CommunityComponentSettings.COMPONENT_NAME);
+ var component = maybeComponent.orElseThrow(() ->
+ new IllegalStateException("The community application should be defined!"));
+
+ ComponentInst membershipMgtApp = new ComponentInst();
+ membershipMgtApp.setName(component.getName());
+ membershipMgtApp.setDomainFatherId(communitySpace.getId());
+ membershipMgtApp.setInheritanceBlocked(true);
+ membershipMgtApp.setPublic(true);
+ membershipMgtApp.setHidden(false);
+ membershipMgtApp.setLabel(bundle.getString("community.membership.management.label"));
+ membershipMgtApp.setDescription(bundle.getString("community.membership.management.desc"));
+ membershipMgtApp.setOrderNum(0);
+ membershipMgtApp.setParameters(new ArrayList<>(component.getParameters()));
+
+ return membershipMgtApp;
+ }
+}
+
\ No newline at end of file
diff --git a/community/community-library/src/main/java/org/silverpeas/components/community/CommunityInstancePostConstruction.java b/community/community-library/src/main/java/org/silverpeas/components/community/CommunityInstancePostConstruction.java
index fd39c890cf..a962389d06 100644
--- a/community/community-library/src/main/java/org/silverpeas/components/community/CommunityInstancePostConstruction.java
+++ b/community/community-library/src/main/java/org/silverpeas/components/community/CommunityInstancePostConstruction.java
@@ -26,8 +26,6 @@
import org.silverpeas.components.community.model.CommunityOfUsers;
import org.silverpeas.components.community.notification.CommunityEventNotifier;
import org.silverpeas.components.community.repository.CommunityOfUsersRepository;
-import org.silverpeas.core.notification.system.ResourceEvent;
-import org.silverpeas.kernel.SilverpeasRuntimeException;
import org.silverpeas.core.admin.component.ComponentInstancePostConstruction;
import org.silverpeas.core.admin.component.model.ComponentInst;
import org.silverpeas.core.admin.service.AdminException;
@@ -35,6 +33,8 @@
import org.silverpeas.core.admin.space.SpaceHomePageType;
import org.silverpeas.core.admin.space.SpaceInst;
import org.silverpeas.core.annotation.Bean;
+import org.silverpeas.core.notification.system.ResourceEvent;
+import org.silverpeas.kernel.SilverpeasRuntimeException;
import javax.inject.Inject;
import javax.inject.Named;
@@ -68,8 +68,13 @@ public void postConstruct(final String componentInstanceId) {
CommunityOfUsers community = new CommunityOfUsers(instance.getId(), spaceInst.getId());
CommunityOfUsers savedCommunity = repository.save(community);
+ if (!spaceInst.isCommunitySpace()) {
+ spaceInst.setFirstPageExtraParam(componentInstanceId);
+ spaceInst.setInheritanceBlocked(true);
+ spaceInst.setCommunitySpace(true);
+ spaceInst.setFirstPageType(SpaceHomePageType.COMPONENT_INST.ordinal());
+ }
spaceInst.setFirstPageExtraParam(componentInstanceId);
- spaceInst.setInheritanceBlocked(true);
spaceInst.setFirstPageType(SpaceHomePageType.COMPONENT_INST.ordinal());
updateSpaceInst(spaceInst);
diff --git a/community/community-library/src/main/java/org/silverpeas/components/community/model/CommunityOfUsers.java b/community/community-library/src/main/java/org/silverpeas/components/community/model/CommunityOfUsers.java
index c176f5c139..31d608e8c4 100644
--- a/community/community-library/src/main/java/org/silverpeas/components/community/model/CommunityOfUsers.java
+++ b/community/community-library/src/main/java/org/silverpeas/components/community/model/CommunityOfUsers.java
@@ -28,6 +28,8 @@
import org.silverpeas.core.admin.component.model.InheritableSpaceRoles;
import org.silverpeas.core.admin.service.AdminException;
import org.silverpeas.core.admin.service.Administration;
+import org.silverpeas.core.admin.service.CommunityMembersGroup;
+import org.silverpeas.core.admin.service.CommunityMembershipService;
import org.silverpeas.core.admin.space.SpaceHomePageType;
import org.silverpeas.core.admin.space.SpaceInst;
import org.silverpeas.core.admin.space.SpaceProfileInst;
@@ -43,8 +45,10 @@
import org.silverpeas.core.security.authorization.ComponentAccessControl;
import org.silverpeas.kernel.SilverpeasRuntimeException;
import org.silverpeas.kernel.annotation.NonNull;
+import org.silverpeas.kernel.annotation.Nullable;
import org.silverpeas.kernel.bundle.ResourceLocator;
import org.silverpeas.kernel.bundle.SettingBundle;
+import org.silverpeas.kernel.util.Mutable;
import org.silverpeas.kernel.util.Pair;
import javax.annotation.Nonnull;
@@ -135,6 +139,7 @@ public CommunityOfUsers(final String componentInstanceId, final String spaceId)
/**
* Gets all the communities of users existing in Silverpeas.
+ *
* @return a list of exiting community of users.
*/
public static List getAll() {
@@ -359,7 +364,7 @@ public CommunityMembership refuseMembership(final User user) {
* @implSpec the user will be removed from all the roles of the parent space (the community space)
* and then his membership status is updated to {@link MembershipStatus#REMOVED}.
*/
- public CommunityMembership removeMembership(final User user) {
+ public @Nullable CommunityMembership removeMembership(final User user) {
return Transaction.performInOne(() -> {
getCommunitySpace().removeUser(user);
return getMembershipsProvider().get(user)
@@ -410,7 +415,7 @@ public void delete() {
// to ensure the community is removed (and hence its link to the group) before deleting the
// referenced group
repository.flush();
- getCommunitySpace().deleteMembersGroup();
+ getCommunitySpace().delete();
return null;
});
}
@@ -431,18 +436,11 @@ public GroupDetail getGroupOfMembers() {
if (!isPersisted()) {
return null;
}
- GroupDetail group;
try {
- if (groupId == null) {
- SpaceInst spaceInst = getCommunitySpace().getSilverpeasSpace();
- group = getCommunitySpace().createMembersGroup(spaceInst);
- } else {
- group = getCommunitySpace().getMembersGroup();
- }
+ return getCommunitySpace().getOrCreateMembersGroup();
} catch (AdminException e) {
throw new SilverpeasRuntimeException(e);
}
- return group;
}
@Override
@@ -515,8 +513,7 @@ static class CommunitySpace {
private static final SettingBundle settings = ResourceLocator.getSettingBundle(
"org.silverpeas.components.community.settings.communitySettings");
- private final Administration administration;
- private final User requester;
+ private final CommunityMembershipService communityService = CommunityMembershipService.get();
private final CommunityOfUsers community;
/**
@@ -527,8 +524,6 @@ static class CommunitySpace {
*/
public CommunitySpace(CommunityOfUsers community) {
this.community = community;
- administration = Administration.get();
- requester = User.getCurrentRequester();
}
/**
@@ -547,10 +542,8 @@ public void addUser(@NonNull User user, @NonNull SilverpeasRole role) {
Objects.requireNonNull(user);
Objects.requireNonNull(role);
execute(() -> {
- var space = getSilverpeasSpace();
- var profile = getSpaceProfile(role, space);
- addUserInSpaceProfile(user, profile);
- addUserInMembershipGroup(user, space);
+ var group = getOrCreateMembersGroup();
+ communityService.addMember(user, group, role);
});
}
@@ -566,24 +559,20 @@ public void addUser(@NonNull User user, @NonNull SilverpeasRole role) {
public void removeUser(@NonNull User user) {
Objects.requireNonNull(user);
execute(() -> {
- var space = getSilverpeasSpace();
- removeUserFromAllSpaceProfiles(user, space);
- removeUserFromMembershipGroup(user);
+ var group = getOrCreateMembersGroup();
+ communityService.removeMember(user, group);
});
}
/**
- * Deletes definitely the members group associated with this community space. This method is to
- * be invoked in community deletion. If no members group has been created before the deletion of
- * a space, then nothing is done.
+ * Deletes this community space. This will delete the members groups associated with this
+ * community space and, in the case the actual space yet exists, it unset it as a community
+ * space (the space becomes then an usual collaborative space).
*/
- private void deleteMembersGroup() {
- execute(() -> {
- var group = getMembersGroup();
- if (group != null) {
- administration.deleteGroupById(group.getId(), true);
- }
- });
+ public void delete() {
+ execute(() ->
+ communityService.deleteCommunity(community.spaceId,
+ community.groupId == null ? null : String.valueOf(community.groupId)));
}
/**
@@ -626,6 +615,21 @@ public Set getAllSpaceProfilesOfUser(String userId) {
return profiles;
}
+ /**
+ * Gets the group of members of this community.
+ *
+ * @return optionally the group of members or nothing if the group hasn't been yet created.
+ */
+ Optional getMembersGroup() {
+ if (community.groupId == null) {
+ return Optional.empty();
+ }
+ Mutable group = Mutable.empty();
+ execute(() ->
+ group.set(communityService.getGroup(String.valueOf(community.groupId))));
+ return Optional.ofNullable(group.get());
+ }
+
/**
* Gets a synchronization task related to ensure the community space data are up-to-date with
* the membership of a user. This method is for the {@link CommunityMembershipsProvider}.
@@ -636,107 +640,49 @@ private SynchronizationTask getSynchronizationTask() {
return new SynchronizationTask();
}
- private SpaceProfileInst getSpaceProfile(SilverpeasRole role, SpaceInst space)
- throws AdminException {
- var profile = space.getDirectSpaceProfileInst(role.getName());
- if (profile == null) {
- profile = new SpaceProfileInst();
- profile.setName(role.getName());
- profile.setSpaceFatherId(space.getId());
- profile.setInherited(false);
- administration.addSpaceProfileInst(profile, requester.getId());
- space.addSpaceProfileInst(profile);
- }
- return profile;
- }
-
- private void addUserInSpaceProfile(User user, SpaceProfileInst profile) throws AdminException {
- if (!isUserHasProfile(user, profile)) {
- profile.addUser(user.getId());
- administration.updateSpaceProfileInst(profile, requester.getId());
- }
- }
-
- private void addUserInMembershipGroup(User user, SpaceInst space) throws AdminException {
- var group = getMembersGroup();
- boolean newGroup = group == null;
- if (newGroup) {
- group = createMembersGroup(space);
- }
- if (newGroup || !isUserInGroup(user, group)) {
- administration.addUserInGroup(user.getId(), group.getId());
- }
- }
-
/**
- * Creates the group of the members for the specified community space.
+ * Creates the group of the members for this community space.
*
- * @param space an existing community space in Silverpeas
* @return the created group of members
* @throws AdminException if an error occurs while creating the group of members.
*/
- private GroupDetail createMembersGroup(SpaceInst space) throws AdminException {
- GroupDetail group;
- group = new GroupDetail();
- String groupName = settings.getString("community.group.symbol", "") + " " +
- space.getName();
- group.setName(groupName.trim());
- community.groupId = Integer.parseInt(administration.addGroup(group, true));
+ private CommunityMembersGroup createMembersGroup() throws AdminException {
+ String symbol = settings.getString("community.group.symbol", "");
+ var group = communityService.setUpCommunity(community.spaceId, symbol);
+ community.groupId = Integer.parseInt(group.getId());
community.save();
- var profile = getSpaceProfile(SilverpeasRole.READER, space);
- profile.addGroup(group.getId());
- administration.updateSpaceProfileInst(profile, requester.getId());
return group;
}
- private void removeUserFromAllSpaceProfiles(User user, SpaceInst space) {
- streamOnNonInheritedSpaceProfiles(space)
- .filter(p -> isUserHasProfile(user, p))
- .forEach(p -> execute(() -> {
- p.removeUser(user.getId());
- administration.updateSpaceProfileInst(p, requester.getId());
- }));
- }
-
private Stream streamOnNonInheritedSpaceProfiles(SpaceInst space) {
return space.getAllSpaceProfilesInst().stream()
.filter(not(SpaceProfileInst::isManager).and(not(SpaceProfileInst::isInherited)));
}
- private void removeUserFromMembershipGroup(User user) throws AdminException {
- var group = getMembersGroup();
- if (group != null && isUserInGroup(user, group)) {
- administration.removeUserFromGroup(user.getId(), group.getId());
- }
- }
-
- private GroupDetail getMembersGroup() throws AdminException {
+ private CommunityMembersGroup getOrCreateMembersGroup() throws AdminException {
+ CommunityMembersGroup group;
if (community.groupId == null) {
- return null;
- }
- GroupDetail group = administration.getGroup(String.valueOf(community.groupId));
-
- // check the symbol for group of members didn't change
- String symbol = settings.getString("community.group.symbol", "") + " ";
- SpaceInst space = getSilverpeasSpace();
- if ((symbol.isBlank() && !group.getName().equals(space.getName())) ||
- (!symbol.isBlank() && !group.getName().startsWith(symbol))) {
- group.setName((symbol + space.getName()).trim());
- administration.updateGroup(group, true);
+ group = createMembersGroup();
+ } else {
+ group = getMembersGroup()
+ .orElseThrow(() -> new IllegalStateException(
+ "No group of members defined for the community " + this.community.getId()));
+
+ // check the symbol for group of members didn't change
+ String symbol = settings.getString("community.group.symbol", "") + " ";
+ SpaceInst space = getSilverpeasSpace();
+ if ((symbol.isBlank() && !group.getName().equals(space.getName())) ||
+ (!symbol.isBlank() && !group.getName().startsWith(symbol))) {
+ group.setName((symbol + space.getName()).trim());
+ communityService.updateGroup(group);
+ }
}
+
return group;
}
private SpaceInst getSilverpeasSpace() throws AdminException {
- return administration.getSpaceInstById(community.spaceId);
- }
-
- private boolean isUserInGroup(User user, GroupDetail group) {
- return List.of(group.getUserIds()).contains(user.getId());
- }
-
- public boolean isUserHasProfile(User user, SpaceProfileInst profile) {
- return profile.getAllUsers().contains(user.getId());
+ return communityService.getCommunity(community.spaceId);
}
private void execute(AdminTask task) {
@@ -776,11 +722,8 @@ void synchronizeMembersGroup(final Set usersPlayingARole) {
// if there is no users, no need of synchronization
return;
}
- var space = CommunitySpace.this.getSilverpeasSpace();
- var group = getMembersGroup();
- if (group == null) {
- group = createMembersGroup(space);
- }
+ var administration = Administration.get();
+ var group = getOrCreateMembersGroup();
var members = Set.of(group.getUserIds());
// ensure the users playing a role in the community space are also in the members group
diff --git a/community/community-library/src/main/java/org/silverpeas/components/community/model/MembersGroupRemovalFromRoleListener.java b/community/community-library/src/main/java/org/silverpeas/components/community/model/MembersGroupRemovalFromRoleListener.java
new file mode 100644
index 0000000000..775ddf30a6
--- /dev/null
+++ b/community/community-library/src/main/java/org/silverpeas/components/community/model/MembersGroupRemovalFromRoleListener.java
@@ -0,0 +1,100 @@
+/*
+ * 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 .
+ */
+
+package org.silverpeas.components.community.model;
+
+import org.silverpeas.components.community.repository.CommunityOfUsersRepository;
+import org.silverpeas.core.admin.service.AdminException;
+import org.silverpeas.core.admin.service.Administration;
+import org.silverpeas.core.admin.space.SpaceInst;
+import org.silverpeas.core.admin.space.notification.SpaceProfileInstEvent;
+import org.silverpeas.core.admin.user.model.SilverpeasRole;
+import org.silverpeas.core.admin.user.model.User;
+import org.silverpeas.core.annotation.Bean;
+import org.silverpeas.core.notification.system.CDIResourceEventListener;
+import org.silverpeas.kernel.SilverpeasRuntimeException;
+import org.silverpeas.kernel.annotation.Technical;
+
+import javax.inject.Inject;
+
+/**
+ * A listener of events about the removing of a group of users from a space role profile. The goal
+ * is to detect any attempts to remove a group of community members from its community in order to
+ * restore it automatically. It is a workaround until such removal becomes impossible in Silverpeas
+ * Core. The group of members are put by default in the reader role of a community space and hence
+ * the check is done for any update of this role for a community. Thus, any other roles aren't
+ * considered even if the group of members has been added/removed in those roles.
+ *
+ * @author mmoquillon
+ */
+@Technical
+@Bean
+public class MembersGroupRemovalFromRoleListener extends CDIResourceEventListener {
+
+ @Inject
+ private Administration admin;
+
+ @Inject
+ private CommunityOfUsersRepository repository;
+
+ @Override
+ public void onUpdate(SpaceProfileInstEvent event) {
+ var spaceProfileBefore = event.getTransition().getBefore();
+ // nothing to do if the role concerned by the update isn't the reader one. Indeed, the group
+ // of community members is put in this role by rule and it is from this role the group must
+ // not to be removed
+ if (!spaceProfileBefore.getName().equals(SilverpeasRole.READER.getName())) {
+ return;
+ }
+ var spaceProfileAfter = event.getTransition().getAfter();
+ String spaceId = SpaceInst.SPACE_KEY_PREFIX + spaceProfileBefore.getSpaceFatherId();
+ var groupsBefore = spaceProfileBefore.getAllGroups();
+ var groupsAfter = spaceProfileAfter.getAllGroups();
+ repository.getBySpaceId(spaceId)
+ .flatMap(communityOfUsers ->
+ communityOfUsers.getCommunitySpace().getMembersGroup()
+ .flatMap(g -> groupsBefore.stream()
+ .filter(id -> id.equals(g.getId()))
+ .filter(id -> !groupsAfter.contains(id))
+ .findFirst())).ifPresent(id -> execute(() -> {
+ spaceProfileAfter.addGroup(id);
+ admin.updateSpaceProfileInst(spaceProfileAfter, User.getSystemUser().getId());
+ }));
+ }
+
+ private void execute(AdminOperation operation) {
+ try {
+ operation.perform();
+ } catch (AdminException e) {
+ throw new SilverpeasRuntimeException("Unexpected error: " + e.getMessage());
+ }
+ }
+
+ @FunctionalInterface
+ private interface AdminOperation {
+
+ void perform() throws AdminException;
+ }
+}
+
\ No newline at end of file
diff --git a/community/community-library/src/test/java/org/silverpeas/components/community/CommunityOfUsersTest.java b/community/community-library/src/test/java/org/silverpeas/components/community/CommunityOfUsersTest.java
index fbd8420a03..675a193475 100644
--- a/community/community-library/src/test/java/org/silverpeas/components/community/CommunityOfUsersTest.java
+++ b/community/community-library/src/test/java/org/silverpeas/components/community/CommunityOfUsersTest.java
@@ -34,6 +34,8 @@
import org.silverpeas.components.community.repository.CommunityOfUsersRepository;
import org.silverpeas.core.admin.service.AdminException;
import org.silverpeas.core.admin.service.Administration;
+import org.silverpeas.core.admin.service.CommunityMembershipService;
+import org.silverpeas.core.admin.service.OrganizationController;
import org.silverpeas.core.admin.space.SpaceHomePageType;
import org.silverpeas.core.admin.space.SpaceInst;
import org.silverpeas.core.admin.space.SpaceProfileInst;
@@ -52,6 +54,8 @@
import org.silverpeas.core.persistence.datasource.model.jpa.JpaUpdateOperation;
import org.silverpeas.core.test.unit.EntityIdSetter;
import org.silverpeas.core.test.unit.extention.JEETestContext;
+import org.silverpeas.core.util.ServiceProvider;
+import org.silverpeas.kernel.test.annotations.TestManagedBean;
import org.silverpeas.kernel.test.annotations.TestManagedBeans;
import org.silverpeas.kernel.test.annotations.TestManagedMock;
import org.silverpeas.kernel.test.extension.EnableSilverTestEnv;
@@ -84,8 +88,12 @@
class CommunityOfUsersTest {
private static final String USER_ID = "0";
+
+ /* A given community space with its community membership management application */
private static final String SPACE_ID = "WA42";
private static final String INSTANCE_ID = "community42";
+
+ /* The roles played in the community space */
private static final String[] SPACE_MANAGERS = new String[]{"0"};
private static final String[] ADMINS = new String[]{"1"};
private static final String[] PUBLISHERS = new String[]{"2", "3"};
@@ -94,6 +102,11 @@ class CommunityOfUsersTest {
private static final String[] INHERITED_MANAGERS = new String[]{"42"};
private static final String NO_MEMBER = "666";
+ @TestManagedMock Administration administration;
+ @TestManagedMock
+ OrganizationController organization;
+ @TestManagedBean CommunityMembershipService service;
+
@TestManagedMock
EntityManagerProvider entityManagerProvider;
@TestManagedMock
@@ -108,7 +121,7 @@ class CommunityOfUsersTest {
@BeforeEach
- public void fillMembers() {
+ void fillMembers() {
members.addAll(List.of(ADMINS));
members.addAll(List.of(PUBLISHERS));
members.addAll(List.of(WRITERS));
@@ -116,9 +129,8 @@ public void fillMembers() {
}
@BeforeEach
- public void mockRequiredResources(
- @TestManagedMock Administration administration,
- @TestManagedMock UserProvider userProvider) throws AdminException {
+ void mockRequiredResources() throws AdminException {
+ UserProvider userProvider = ServiceProvider.getService(UserProvider.class);
mockUsersProviding(userProvider);
// for the current requester. Requires the user providing to be mocked
@@ -520,6 +532,7 @@ private void mockExpectedAdministrationBehaviour(Administration administration)
SpaceInst space = mock(SpaceInst.class);
when(space.getId()).thenReturn(spaceId);
when(space.getName()).thenReturn("My community");
+ when(space.isCommunitySpace()).thenReturn(true);
if (profiles.isEmpty()) {
when(space.getAllSpaceProfilesInst()).thenAnswer(j -> {
initProfiles(spaceId, profiles);
@@ -564,6 +577,7 @@ private void mockExpectedAdministrationBehaviour(Administration administration)
when(administration.getGroup(anyString())).thenAnswer(i -> {
GroupDetail group = new GroupDetail();
group.setName("foo");
+ group.setSpaceId(SPACE_ID);
group.setId(i.getArgument(0));
return group;
});
diff --git a/community/community-war/src/integration-test/resources/community-dataset.sql b/community/community-war/src/integration-test/resources/community-dataset.sql
index de1c00cd85..584333b8f8 100644
--- a/community/community-war/src/integration-test/resources/community-dataset.sql
+++ b/community/community-war/src/integration-test/resources/community-dataset.sql
@@ -5,11 +5,11 @@ VALUES ('1', 'st_domain'),
('6', 'st_user'),
('13', 'st_spaceuserrole');
-INSERT INTO st_space (id, domainFatherId, name, lang, firstPageType, isInheritanceBlocked)
-VALUES (1, NULL, 'Space 1', 'fr', 0, 0),
- (2, 1, 'Space 1-2', 'fr', 0, 0),
- (3, NULL, 'Space 2', 'fr', 0, 0),
- (4, NULL, 'Space 3', 'fr', 0, 0);
+INSERT INTO st_space (id, domainFatherId, name, lang, firstPageType, isInheritanceBlocked, isCommunity)
+VALUES (1, NULL, 'Space 1', 'fr', 0, 0, 1),
+ (2, 1, 'Space 1-2', 'fr', 0, 0, 1),
+ (3, NULL, 'Space 2', 'fr', 0, 0, 1),
+ (4, NULL, 'Space 3', 'fr', 0, 0, 1);
INSERT INTO st_componentinstance (id, spaceId, name, componentName, isPublic, isInheritanceBlocked)
VALUES (1, 1, 'Community 1', 'community', 1, 0),
diff --git a/mailinglist/mailinglist-library/src/integration-test/resources/org/silverpeas/components/mailinglist/service/model/create-database.sql b/mailinglist/mailinglist-library/src/integration-test/resources/org/silverpeas/components/mailinglist/service/model/create-database.sql
index 63599ac29c..67dcf0c0ab 100644
--- a/mailinglist/mailinglist-library/src/integration-test/resources/org/silverpeas/components/mailinglist/service/model/create-database.sql
+++ b/mailinglist/mailinglist-library/src/integration-test/resources/org/silverpeas/components/mailinglist/service/model/create-database.sql
@@ -131,6 +131,7 @@ CREATE TABLE ST_Group
id INT NOT NULL,
domainId INT NOT NULL,
specificId VARCHAR(500) NOT NULL,
+ spaceId VARCHAR(500),
superGroupId INT,
name VARCHAR(100) NOT NULL,
description VARCHAR(400),
@@ -167,7 +168,8 @@ CREATE TABLE ST_Space
isInheritanceBlocked INT DEFAULT (0) NOT NULL,
look VARCHAR(50),
displaySpaceFirst SMALLINT,
- isPersonal SMALLINT
+ isPersonal SMALLINT,
+ isCommunity SMALLINT DEFAULT(0) NOT NULL
);
CREATE TABLE ST_SpaceI18N
diff --git a/mailinglist/mailinglist-library/src/integration-test/resources/org/silverpeas/components/mailinglist/service/model/dao/create-database.sql b/mailinglist/mailinglist-library/src/integration-test/resources/org/silverpeas/components/mailinglist/service/model/dao/create-database.sql
index 0c068ec2d1..eb3a5ebdbb 100644
--- a/mailinglist/mailinglist-library/src/integration-test/resources/org/silverpeas/components/mailinglist/service/model/dao/create-database.sql
+++ b/mailinglist/mailinglist-library/src/integration-test/resources/org/silverpeas/components/mailinglist/service/model/dao/create-database.sql
@@ -130,6 +130,7 @@ CREATE TABLE ST_Group
id INT NOT NULL,
domainId INT NOT NULL,
specificId VARCHAR(500) NOT NULL,
+ spaceId VARCHAR(500),
superGroupId INT,
name VARCHAR(100) NOT NULL,
description VARCHAR(400),
@@ -166,7 +167,8 @@ CREATE TABLE ST_Space
isInheritanceBlocked INT DEFAULT (0) NOT NULL,
look VARCHAR(50),
displaySpaceFirst SMALLINT,
- isPersonal SMALLINT
+ isPersonal SMALLINT,
+ isCommunity SMALLINT DEFAULT(0) NOT NULL
);
CREATE TABLE ST_SpaceI18N
diff --git a/resourcesManager/resourcesManager-library/src/integration-test/resources/org/silverpeas/components/resourcesmanager/service/create-database.sql b/resourcesManager/resourcesManager-library/src/integration-test/resources/org/silverpeas/components/resourcesmanager/service/create-database.sql
index 5ff4ffb172..a4754fba1e 100644
--- a/resourcesManager/resourcesManager-library/src/integration-test/resources/org/silverpeas/components/resourcesmanager/service/create-database.sql
+++ b/resourcesManager/resourcesManager-library/src/integration-test/resources/org/silverpeas/components/resourcesmanager/service/create-database.sql
@@ -30,6 +30,7 @@ CREATE TABLE ST_Group
id INT NOT NULL,
domainId INT NOT NULL,
specificId VARCHAR(500) NOT NULL,
+ spaceId VARCHAR(500),
superGroupId INT,
name VARCHAR(100) NOT NULL,
description VARCHAR(400),