Skip to content

Commit

Permalink
Feature #3990
Browse files Browse the repository at this point in the history
A group of users can now be copied/cut and then pasted either as a root
group of the domain of users it belongs to or as a subgroup of another
group of users in the same domain of users. The cut&paste of a group
result to a move of this group. A group cannot be paste to where there
is another group with the same name (groups at the same level have to be
unique by their name).
Control has be added to allow only admins to be able to copy and to move
groups in a given domain of users.
Only the Silverpeas domain, the mixed domain, and the SQL-backed domains
support the copy/move of group of users.
  • Loading branch information
mmoqui committed Dec 16, 2024
1 parent 322e628 commit 226ad9c
Show file tree
Hide file tree
Showing 27 changed files with 843 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ static List<Group> getAllRootsInDomain(String domainId) {
String getDescription();

/**
* Get the list of users in the group
* @return the identifiers of the users in this group.
* Get the list of the direct users in the group
* @return the identifiers of the direct users in this group.
*/
String[] getUserIds();

Expand All @@ -113,23 +113,23 @@ static List<Group> getAllRootsInDomain(String domainId) {
boolean isSynchronized();

/**
* Gets the number of direct users in this group; the users from its subgroups aren't counted. To
* Gets the count of direct users in this group; the users from its subgroups aren't counted. To
* count also the users in its subgroups, please use the
* {@code org.silverpeas.core.admin.user.model.Group#getTotalNbUsers} method instead.
* {@link Group#getTotalUsersCount()} method instead.
* @return the number of direct users.
*/
int getNbUsers();
int getDirectUsersCount();

/**
* Gets the total number of users in this group and in its subgroups. Users that are in several
* Gets the total count of users in this group and in its subgroups. Users that are in several
* groups are counted only once.
* <p>
* Depending on the requester, the total number of users can omit some users by their state
* Depending on the requester, the total count of users can omit some users by their state
* (usually the users whose their account is deactivated). By default, all the users whose
* the account is deleted aren't taken into account.
* @return the total number of distinct users in its group and subgroups.
*/
int getTotalNbUsers();
int getTotalUsersCount();

/**
* Is this group is a root one?
Expand All @@ -142,15 +142,27 @@ static List<Group> getAllRootsInDomain(String domainId) {
* Gets the direct subgroups of this user group.
* @return a list with its direct subgroups. If this group hasn't children group, then the
* returned list is empty.
* @param <T> the concrete type of the {@link Group}
*/
List<Group> getSubGroups();
<T extends Group> List<T> getSubGroups();

/**
* Gets the detail about all the direct users in this group. The users in the subgroups of this
* group aren't taken into account; to get all the users, whatever they are in this group or in
* one of its subgroup, please consider the {@link Group#getAllUsers()} method.
* @return a list of all of the direct users in this group. An empty list if the group has no
* direct users.
* @param <T> the concrete type of the {@link User}
*/
<T extends User> List<T> getUsers();

/**
* Gets the detail about all the users that are in this group (and in the subgroups of this
* group).
* @return a list of all the user details in this group.
* @param <T> the concrete type of the {@link User}
*/
List<User> getAllUsers();
<T extends User> List<T> getAllUsers();

/**
* Gets the date of the group creation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ private Set<UserRecipient> getUsersForReceiverBlock()
protected boolean displayGroup(String groupId) {
int threshold = NotificationManagerSettings.getReceiverThresholdAfterThatReplaceUserNameListByGroupName();
Group group = Group.getById(groupId);
int nbUsers = group.getNbUsers();
int nbUsers = group.getDirectUsersCount();
boolean res1 = NotificationManagerSettings.isDisplayingUserNameListInsteadOfGroupEnabled();
boolean res2 = threshold > 0 && nbUsers > threshold;
return res1 || res2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ JDP.groupSynchro = Synchroniser ce groupe
JDP.groupSynchro.removed = Le groupe a \u00e9t\u00e9 mis en attente de suppression
JDP.groupUnsynchro = Supprimer la synchronisation de ce groupe
JDP.groupUpdate = Modifier
JDP.groupPaste = Coller le groupe

JDP.missingFieldStart = Le champ '
JDP.missingFieldEnd = ' est obligatoire
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ JDP.groupSynchro = Synchronisieren dieser Gruppe
JDP.groupSynchro.removed = The group has been removed (waiting for definitive deletion)
JDP.groupUnsynchro = L\u00f6schen Sie die Synchronisation dieser Gruppe
JDP.groupUpdate = Editieren der Gruppen-Informationen
JDP.groupPaste = Einf\u00fcgen der Gruppe

JDP.missingFieldStart = Das Feld '
JDP.missingFieldEnd = ' ist obligatorisch
Expand Down Expand Up @@ -193,11 +194,11 @@ JDP.usersWithSensitiveData=Benutzer mit sensiblen Daten
JDP.disableDataSensitivity=Deaktivieren Sie die Datenvertraulichkeit
JDP.dataSensitivity=Data privacy
JDP.enableDataSensitivity=Aktivieren Sie die Datenvertraulichkeit
JDP.userWithSensitiveDataMessage=Daten, denen ein Vorhängeschloss vorangestellt ist, sind vertraulich. Sie sind innerhalb der Plattform versteckt.
JDP.dataSensitivityEnabled=ermöglicht
JDP.user.state.label.VALID=Gültige Konten
JDP.userWithSensitiveDataMessage=Daten, denen ein Vorh\u00e4ngeschloss vorangestellt ist, sind vertraulich. Sie sind innerhalb der Plattform versteckt.
JDP.dataSensitivityEnabled=erm\u00f6glicht
JDP.user.state.label.VALID=G\u00fcltige Konten
JDP.user.state.label.BLOCKED=Gesperrte Konten
JDP.user.state.label.DEACTIVATED=Deaktivierte Konten
JDP.user.state.label.ALL=Alle
JDP.potentialSensitiveData=Daten, die vertraulich sein können
JDP.potentialSensitiveData=Daten, die vertraulich sein k\u00f6nnen
JDP.effectivelySensitiveData=Datenvertraulichkeit aktiviert
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ JDP.groupSynchro = Synchronize this group
JDP.groupSynchro.removed = The group has been removed (waiting for definitive deletion)
JDP.groupUnsynchro = Delete this group synchronization
JDP.groupUpdate = Edit the group data
JDP.groupPaste = Paste the group

JDP.missingFieldStart = The field '
JDP.missingFieldEnd = ' is missing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ JDP.groupSynchro = Synchroniser ce groupe
JDP.groupSynchro.removed = Le groupe a \u00e9t\u00e9 mis en attente de suppression
JDP.groupUnsynchro = Supprimer la synchronisation de ce groupe
JDP.groupUpdate = Modifier
JDP.groupPaste = Coller le groupe

JDP.missingFieldStart = Le champ '
JDP.missingFieldEnd = ' est obligatoire
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ JDP.group = /util/icons/groupe.gif
JDP.groupSynchronized = /jobDomainPeas/jsp/icons/scheduledGroup.gif
JDP.groupAdd = /util/icons/create-action/add-group.png
JDP.groupDel = /util/icons/userPanelPeas_to_del.gif
JDP.groupCopy = /util/icons/copyComponent.gif
JDP.groupCut = /util/icons/copyComponent.gif
JDP.groupPaste = /util/icons/pasteComponent.gif
JDP.groupImport = /util/icons/group_add_to_domain.gif
JDP.groupSynchro = /util/icons/group_synchro.gif
JDP.groupUnsynchro = /util/icons/group_unsynchro.gif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import static java.util.stream.Collectors.toList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import static org.silverpeas.core.SilverpeasExceptionMessages.failureOnDeleting;
import static org.silverpeas.core.test.util.TestRuntime.awaitUntil;
Expand Down Expand Up @@ -497,6 +498,137 @@ public void shouldDeleteGroup() throws Exception {
assertThat(group, is(nullValue()));
}

@Test
public void shouldMoveGroupInSameDomain() throws AdminException {
GroupDetail group = admin.getGroup("1");
GroupDetail expectedParentGroup = admin.getGroup("3");
List<UserDetail> expectedUsers = group.getUsers();
List<GroupDetail> expectedSubGroups = group.getSubGroups();
assertThat(group.getSuperGroupId(), not(expectedParentGroup.getId()));

admin.moveGroup(group, expectedParentGroup.getId());

GroupDetail actualGroup = admin.getGroup(group.getId());
assertThat(actualGroup.getSuperGroupId(), is(expectedParentGroup.getId()));
assertThat(actualGroup.getUsers(), containsInAnyOrder(expectedUsers.toArray()));
assertThat(actualGroup.getSubGroups(), containsInAnyOrder(expectedSubGroups.toArray()));
}

@Test
public void shouldMoveGroupAsRootOne() throws AdminException {
GroupDetail group = admin.getGroup("4");
List<UserDetail> expectedUsers = group.getUsers();
List<GroupDetail> expectedSubGroups = group.getSubGroups();
assertThat(group.getSuperGroupId(), notNullValue());

admin.moveGroup(group, null);

GroupDetail actualGroup = admin.getGroup(group.getId());
assertThat(actualGroup.getSuperGroupId(), nullValue());
assertThat(actualGroup.getUsers(), containsInAnyOrder(expectedUsers.toArray()));
assertThat(actualGroup.getSubGroups(), containsInAnyOrder(expectedSubGroups.toArray()));
}

@Test
public void shouldNotMoveGroupInInvalidGroup() throws AdminException {
GroupDetail group = admin.getGroup("1");
GroupDetail expectedParentGroup = admin.getGroup("2");

assertThrows(AdminException.class, () -> admin.moveGroup(group, expectedParentGroup.getId()));
}

@Test
public void shouldNotMoveGroupInDifferentDomain() throws AdminException {
GroupDetail group = admin.getGroup("1");
GroupDetail expectedParentGroup = admin.getGroup("10");

assertThrows(AdminException.class, () -> admin.moveGroup(group, expectedParentGroup.getId()));
}

@Test
public void shouldNotMoveGroupInANonExistingGroup() throws AdminException {
GroupDetail group = admin.getGroup("1");

assertThrows(AdminException.class, () -> admin.moveGroup(group, "666"));
}

@Test
public void shouldMoveGroupInSameGroup() throws AdminException {
GroupDetail group = admin.getGroup("4");
GroupDetail parentGroup = admin.getGroup(group.getSuperGroupId());
assertThat(parentGroup, notNullValue());

admin.moveGroup(group, parentGroup.getId());

GroupDetail expectedGroup = admin.getGroup(group.getId());
assertThat(expectedGroup.getSuperGroupId(), is(parentGroup.getId()));
}

@Test
public void shouldCopyGroupInSameDomain() throws AdminException {
GroupDetail group = admin.getGroup("1");
GroupDetail expectedParentGroup = admin.getGroup("3");
List<UserDetail> expectedUsers = group.getUsers();
List<GroupDetail> expectedSubGroups = group.getSubGroups();
assertThat(group.getSuperGroupId(), not(expectedParentGroup.getId()));

String copiedGroupId = admin.copyGroup(group, expectedParentGroup.getId());
assertThat(copiedGroupId, is(not(group.getId())));

GroupDetail actualGroup = admin.getGroup(copiedGroupId);
assertThat(actualGroup.getSuperGroupId(), is(expectedParentGroup.getId()));
assertThat(actualGroup.getUsers(), containsInAnyOrder(expectedUsers.toArray()));
assertThat(actualGroup.getSubGroups(), containsInAnyOrder(expectedSubGroups.toArray()));
}

@Test
public void shouldCopyGroupAsRootOne() throws AdminException {
GroupDetail group = admin.getGroup("4");
List<UserDetail> expectedUsers = group.getUsers();
List<GroupDetail> expectedSubGroups = group.getSubGroups();
assertThat(group.getSuperGroupId(), notNullValue());

String copiedGroupId = admin.copyGroup(group, null);
assertThat(copiedGroupId, is(not(group.getId())));

GroupDetail actualGroup = admin.getGroup(copiedGroupId);
assertThat(actualGroup.getSuperGroupId(), nullValue());
assertThat(actualGroup.getUsers(), containsInAnyOrder(expectedUsers.toArray()));
assertThat(actualGroup.getSubGroups(), containsInAnyOrder(expectedSubGroups.toArray()));
}

@Test
public void shouldNotCopyGroupInInvalidGroup() throws AdminException {
GroupDetail group = admin.getGroup("1");
GroupDetail expectedParentGroup = admin.getGroup("2");

assertThrows(AdminException.class, () -> admin.copyGroup(group, expectedParentGroup.getId()));
}

@Test
public void shouldNotCopyGroupInDifferentDomain() throws AdminException {
GroupDetail group = admin.getGroup("1");
GroupDetail expectedParentGroup = admin.getGroup("10");

assertThrows(AdminException.class, () -> admin.copyGroup(group, expectedParentGroup.getId()));
}

@Test
public void shouldNotCopyGroupInANonExistingGroup() throws AdminException {
GroupDetail group = admin.getGroup("1");

assertThrows(AdminException.class, () -> admin.copyGroup(group, "666"));
}

@Test
public void shouldNotCopyGroupInSameGroup() throws AdminException {
GroupDetail group = admin.getGroup("4");
GroupDetail parentGroup = admin.getGroup(group.getSuperGroupId());

// a group cannot have two subgroups with the same name
assertThrows(AdminException.class, () -> admin.copyGroup(group, parentGroup.getId()));
}

@Test
public void shouldFindUsersInGroup() throws Exception {
GroupDetail subGroup = new GroupDetail();
Expand Down Expand Up @@ -526,53 +658,61 @@ public void shouldFindUsersInGroup() throws Exception {

@Test
public void getGroups() throws Exception {
List<String> groupIds = admin.getAllGroups()
List<Integer> groupIds = admin.getAllGroups()
.stream()
.map(GroupDetail::getId)
.map(Integer::parseInt)
.sorted()
.collect(toList());
assertThat(groupIds, contains("1", "10"));
assertThat(groupIds, contains(1, 3, 4, 10));

groupIds = Stream.of(admin.getRootGroupsOfDomain("0"))
.map(GroupDetail::getId)
.map(Integer::parseInt)
.sorted()
.collect(toList());
assertThat(groupIds, contains("1"));
assertThat(groupIds, contains(1, 3));

groupIds = Stream.of(admin.getRootGroupsOfDomain("1"))
.map(GroupDetail::getId)
.map(Integer::parseInt)
.sorted()
.collect(toList());
assertThat(groupIds, contains("10"));
assertThat(groupIds, contains(10));
}

@Test
public void getGroupsWithChildren() throws Exception {
createSubGroupsAndGetSortedPath();
List<String> groupIds = admin.getAllRootGroups()
List<Integer> groupIds = admin.getAllRootGroups()
.stream()
.map(GroupDetail::getId)
.map(Integer::parseInt)
.sorted()
.collect(toList());
assertThat(groupIds, contains(1, 3, 10));

assertThat(groupIds, contains("1", "10"));groupIds = admin.getAllGroups()
groupIds = admin.getAllGroups()
.stream()
.map(GroupDetail::getId)
.map(Integer::parseInt)
.sorted()
.collect(toList());
assertThat(groupIds, contains("1", "10", "21", "22"));
assertThat(groupIds, contains(1, 3, 4, 10, 21, 22));

groupIds = Stream.of(admin.getRootGroupsOfDomain("0"))
.map(GroupDetail::getId)
.map(Integer::parseInt)
.sorted()
.collect(toList());
assertThat(groupIds, contains("1"));
assertThat(groupIds, contains(1, 3));

groupIds = Stream.of(admin.getRootGroupsOfDomain("1"))
.map(GroupDetail::getId)
.map(Integer::parseInt)
.sorted()
.collect(toList());
assertThat(groupIds, contains("10"));
assertThat(groupIds, contains(10));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public void idCriteria() throws Exception {
assertSortedGroupIds(groups, GROUP_MIX_312_ID);
final GroupDetail group = groups.iterator().next();
assertGroupData(group);
assertThat(group.getTotalNbUsers(), is(dbGroupRelations.size() - 1));
assertThat(group.getTotalUsersCount(), is(dbGroupRelations.size() - 1));

// without children
groups = admin.searchGroups(newGroupSearchCriteriaBuilder()
Expand Down Expand Up @@ -775,19 +775,19 @@ private void assertGroupListData(final List<? extends Group> groups,
final int index = ArrayUtils.indexOf(ALL_GROUP_IDS_SORTED_BY_NAME, group.getId());
expectedNbUsers.add(ALL_GROUP_NB_USERS_SORTED_BY_NAME[index]);
}
final List<Integer> actualNbUsers = extractData(groups, Group::getNbUsers);
final List<Integer> actualNbUsers = extractData(groups, Group::getDirectUsersCount);
assertThat("Nb Users (not filled) " + actualNbUsers,
actualNbUsers, contains(expectedNbUsers.toArray()));
final List<Integer> actualTotalNbUsers = extractData(groups, Group::getTotalNbUsers);
final List<Integer> actualTotalNbUsers = extractData(groups, Group::getTotalUsersCount);
assertThat("Total nb Users (filled) " + actualTotalNbUsers,
actualTotalNbUsers, contains(expectedTotalNbUsers.toArray()));
}

private void assertGroupData(final Group group) {
final int index = ArrayUtils.indexOf(ALL_GROUP_IDS_SORTED_BY_NAME, group.getId());
assertThat("Nb Users (not filled)", group.getNbUsers(),
assertThat("Nb Users (not filled)", group.getDirectUsersCount(),
is(ALL_GROUP_NB_USERS_SORTED_BY_NAME[index]));
assertThat("Total nb Users (filled)",group.getTotalNbUsers(),
assertThat("Total nb Users (filled)",group.getTotalUsersCount(),
is(ALL_GROUP_TOTAL_NB_USERS_SORTED_BY_NAME[index]));
}
}
Loading

0 comments on commit 226ad9c

Please sign in to comment.