diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/GroupFormController.java b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/GroupFormController.java index 82bcb4c3c..18e11c4ab 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/GroupFormController.java +++ b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/GroupFormController.java @@ -26,12 +26,16 @@ import org.libreccm.security.Group; import org.libreccm.security.GroupManager; import org.libreccm.security.GroupRepository; import org.libreccm.security.RequiresPrivilege; +import org.libreccm.security.User; +import org.libreccm.security.UserRepository; import org.libreccm.ui.admin.AdminMessages; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; @@ -68,12 +72,6 @@ public class GroupFormController { @Inject private Models models; - @Inject - private MvcContext mvc; - - @Inject - private GroupManager groupManager; - @Inject private GroupRepository groupRepository; @@ -105,7 +103,7 @@ public class GroupFormController { @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @Transactional(Transactional.TxType.REQUIRED) - public String updateUser( + public String updateGroup( @PathParam("groupIdentifier") final String groupIdentifierParam ) { if (bindingResult.isFailed()) { @@ -138,53 +136,16 @@ public class GroupFormController { groupRepository.save(group); return "redirect:users-groups-roles/groups"; } else { - models.put("errors", Arrays.asList( - adminMessages.getMessage( - "usersgroupsroles.groups.not_found.message", - Arrays.asList(groupIdentifierParam) - ) - )); + models.put( + "errors", Arrays.asList( + adminMessages.getMessage( + "usersgroupsroles.groups.not_found.message", + Arrays.asList(groupIdentifierParam) + ) + ) + ); return "org/libreccm/ui/admin/users-groups-roles/group-form.xhtml"; } } - @POST - @Path("{groupIdentifier}/groups") - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public String updateGroupMemberships( - @PathParam("groupIdentifier") final String groupIdentifierParam, - @FormParam("groupMembers") final String[] groupMembers - ) { - final Map params = new HashMap<>(); - params.put("groupIdentifier", groupIdentifierParam); - return String.format( - "redirect:", - mvc.uri( - "GroupsController#getGroupDetails", - params - ) - ); - } - - @POST - @Path("{groupIdentifier}/roles") - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public String updateRoleMemberships( - @PathParam("groupIdentifier") final String groupIdentifierParam, - @FormParam("groupRoles") final String[] groupRoles - ) { - // ToDo - return String.format( - "redirect:%s", - mvc.uri( - "UsersController#getUserDetails", - Map.of("userIdentifier", groupIdentifierParam) - ) - ); - } - } diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/GroupMembersRolesController.java b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/GroupMembersRolesController.java new file mode 100644 index 000000000..1c70363de --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/GroupMembersRolesController.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2020 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.libreccm.ui.admin.usersgroupsroles; + +import org.libreccm.api.Identifier; +import org.libreccm.api.IdentifierParser; +import org.libreccm.core.CoreConstants; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.Group; +import org.libreccm.security.GroupManager; +import org.libreccm.security.GroupRepository; +import org.libreccm.security.RequiresPrivilege; +import org.libreccm.security.Role; +import org.libreccm.security.RoleManager; +import org.libreccm.security.RoleRepository; +import org.libreccm.security.User; +import org.libreccm.security.UserRepository; +import org.libreccm.ui.admin.AdminMessages; + +import java.util.Arrays; +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.mvc.Models; +import javax.transaction.Transactional; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +/** + * + * @author Jens Pelzetter + */ +@Controller +@Path("/users-groups-roles/groups/") +@RequestScoped +public class GroupMembersRolesController { + + @Inject + private AdminMessages adminMessages; + + @Inject + private IdentifierParser identifierParser; + + @Inject + private GroupManager groupManager; + + @Inject + private GroupRepository groupRepository; + + @Inject + private Models models; + + @Inject + private RoleManager roleManager; + + @Inject + private RoleRepository roleRepository; + + @Inject + private UserRepository userRepository; + + @POST + @Path("{groupIdentifier}/groups") + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public String updateGroupMemberships( + @PathParam("groupIdentifier") final String groupIdentifierParam, + @FormParam("groupMembers") final String[] groupMembersParam + ) { + final Identifier groupIdentifier = identifierParser.parseIdentifier( + groupIdentifierParam + ); + final Optional result; + switch (groupIdentifier.getType()) { + case ID: + result = groupRepository.findById( + Long.parseLong(groupIdentifier.getIdentifier()) + ); + break; + case UUID: + result = groupRepository.findByUuid( + groupIdentifier.getIdentifier() + ); + break; + default: + result = groupRepository.findByName( + groupIdentifier.getIdentifier() + ); + break; + } + + if (result.isPresent()) { + final Group group = result.get(); + final List memberNames = Arrays.asList(groupMembersParam); + + // Check for new members + final List newMemberNames = memberNames + .stream() + .filter(memberName -> !hasMember(group, memberName)) + .collect(Collectors.toList()); + + // Check for removed members + final List removedMemberNames = group + .getMemberships() + .stream() + .map(membership -> membership.getMember().getName()) + .filter(memberName -> !memberNames.contains(memberName)) + .collect(Collectors.toList()); + + for (final String newMemberName : newMemberNames) { + addNewMember(group, newMemberName); + } + + for (final String removedMemberName : removedMemberNames) { + removeMember(group, removedMemberName); + } + + return String.format( + "redirect:/users-groups-roles/groups/%s/details", + groupIdentifierParam + ); + } else { + models.put( + "errors", Arrays.asList( + adminMessages.getMessage( + "usersgroupsroles.groups.not_found.message", + Arrays.asList(groupIdentifierParam) + ) + ) + ); + return "org/libreccm/ui/admin/users-groups-roles/group-not-found.xhtml"; + } + } + + @POST + @Path("{groupIdentifier}/roles") + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public String updateRoleMemberships( + @PathParam("groupIdentifier") final String groupIdentifierParam, + @FormParam("groupRoles") final String[] groupRoles + ) { + final Identifier groupIdentifier = identifierParser.parseIdentifier( + groupIdentifierParam + ); + final Optional result; + switch (groupIdentifier.getType()) { + case ID: + result = groupRepository.findById( + Long.parseLong(groupIdentifier.getIdentifier()) + ); + break; + case UUID: + result = groupRepository.findByUuid( + groupIdentifier.getIdentifier() + ); + break; + default: + result = groupRepository.findByName( + groupIdentifier.getIdentifier() + ); + break; + } + + if (result.isPresent()) { + final Group group = result.get(); + final List roleNames = Arrays.asList(groupRoles); + + // Check for new roles + final List newRoleNames = roleNames + .stream() + .filter(roleName -> !hasRole(group, roleName)) + .collect(Collectors.toList()); + + // Check for removed roles + final List removedRoleNames = group + .getRoleMemberships() + .stream() + .map(membership -> membership.getRole().getName()) + .filter(roleName -> !roleNames.contains(roleName)) + .collect(Collectors.toList()); + + for (final String newRoleName : newRoleNames) { + addNewRole(group, newRoleName); + } + + for (final String removedRoleName : removedRoleNames) { + removeRole(group, removedRoleName); + } + + return String.format( + "redirect:/users-groups-roles/groups/%s/details", + groupIdentifierParam + ); + } else { + models.put( + "errors", Arrays.asList( + adminMessages.getMessage( + "usersgroupsroles.groups.not_found.message", + Arrays.asList(groupIdentifierParam) + ) + ) + ); + return "org/libreccm/ui/admin/users-groups-roles/group-not-found.xhtml"; + } + } + + private boolean hasMember(final Group group, final String memberName) { + return group + .getMemberships() + .stream() + .map(membership -> membership.getMember().getName()) + .anyMatch(name -> name.equals(memberName)); + } + + private void addNewMember(final Group group, final String newMemberName) { + final Optional result = userRepository.findByName(newMemberName); + if (result.isPresent()) { + final User user = result.get(); + groupManager.addMemberToGroup(user, group); + } + } + + private void removeMember( + final Group group, final String removedMemberName + ) { + final Optional result = userRepository.findByName( + removedMemberName + ); + if (result.isPresent()) { + final User user = result.get(); + groupManager.removeMemberFromGroup(user, group); + } + } + + private boolean hasRole(final Group group, final String roleName) { + return group + .getRoleMemberships() + .stream() + .map(membership -> membership.getMember().getName()) + .anyMatch(name -> name.equals(roleName)); + } + + private void addNewRole(final Group group, final String newRoleName) { + final Optional result = roleRepository.findByName(newRoleName); + if (result.isPresent()) { + final Role role = result.get(); + roleManager.assignRoleToParty(role, group); + } + } + + private void removeRole(final Group group, final String removedRoleName) { + final Optional result = roleRepository.findByName( + removedRoleName + ); + if (result.isPresent()) { + final Role role = result.get(); + roleManager.removeRoleFromParty(role, group); + } + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/RolesController.java b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/RolesController.java index 2154649eb..d694dd0b7 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/RolesController.java +++ b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/RolesController.java @@ -24,8 +24,10 @@ import org.libreccm.security.RequiresPrivilege; import javax.enterprise.context.RequestScoped; import javax.mvc.Controller; +import javax.transaction.Transactional; import javax.ws.rs.GET; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; /** * @@ -44,4 +46,15 @@ public class RolesController { return "org/libreccm/ui/admin/users-groups-roles/roles.xhtml"; } + @GET + @Path("/{roleIdentifier}/details") + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public String getRoleDetails( + @PathParam("roleIdentifier") final String roleIdentifierParam + ) { + throw new UnsupportedOperationException(); + } + } diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UserFormController.java b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UserFormController.java index 3627235da..ee0b9688a 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UserFormController.java +++ b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UserFormController.java @@ -50,7 +50,7 @@ import javax.ws.rs.PathParam; /** * Controller managing the user post requests from the user edit form. - * + * * @author Jens Pelzetter */ @Controller @@ -69,7 +69,7 @@ public class UserFormController { @Inject private Models models; - + @Inject private MvcContext mvc; @@ -208,43 +208,5 @@ public class UserFormController { return "org/libreccm/ui/admin/users-groups-roles/user-form.xhtml"; } } - - @POST - @Path("{userIdentifier}/groups") - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public String updateGroupMemberships( - @PathParam("userIdentifier") final String userIdentifierParam, - @FormParam("userGroups") final String[] userGroups - ) { - // ToDo - return String.format( - "redirect:%s", - mvc.uri( - "UsersController#getUserDetails", - Map.of("userIdentifier", userIdentifierParam) - ) - ); - } - - @POST - @Path("{userIdentifier}/roles") - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public String updateRoleMemberships( - @PathParam("userIdentifier") final String userIdentifierParam, - @FormParam("userRoles") final String[] userRoles - ) { - // ToDo - return String.format( - "redirect:%s", - mvc.uri( - "UsersController#getUserDetails", - Map.of("userIdentifier", userIdentifierParam) - ) - ); - } } diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UserGroupsRolesController.java b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UserGroupsRolesController.java new file mode 100644 index 000000000..9afa33c92 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UserGroupsRolesController.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2020 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.libreccm.ui.admin.usersgroupsroles; + +import org.libreccm.api.Identifier; +import org.libreccm.api.IdentifierParser; +import org.libreccm.core.CoreConstants; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.Group; +import org.libreccm.security.GroupManager; +import org.libreccm.security.GroupRepository; +import org.libreccm.security.RequiresPrivilege; +import org.libreccm.security.Role; +import org.libreccm.security.RoleManager; +import org.libreccm.security.RoleRepository; +import org.libreccm.security.User; +import org.libreccm.security.UserRepository; +import org.libreccm.ui.admin.AdminMessages; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.mvc.Controller; +import javax.mvc.Models; +import javax.transaction.Transactional; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +/** + * + * @author Jens Pelzetter + */ +@Controller +@Path("/users-groups-roles/users/") +@RequestScoped +public class UserGroupsRolesController { + + @Inject + private AdminMessages adminMessages; + + @Inject + private GroupManager groupManager; + + @Inject + private GroupRepository groupRepository; + + @Inject + private IdentifierParser identifierParser; + + @Inject + private Models models; + + @Inject + private RoleManager roleManager; + + @Inject + private RoleRepository roleRepository; + + @Inject + private UserRepository userRepository; + + @POST + @Path("{userIdentifier}/groups") + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public String updateGroupMemberships( + @PathParam("userIdentifier") final String userIdentifierParam, + @FormParam("userGroups") final String[] userGroups + ) { + final Identifier userIdentifier = identifierParser.parseIdentifier( + userIdentifierParam + ); + final Optional result; + switch (userIdentifier.getType()) { + case ID: + result = userRepository.findById( + Long.parseLong(userIdentifier.getIdentifier()) + ); + break; + case UUID: + result = userRepository.findByUuid( + userIdentifier.getIdentifier() + ); + break; + default: + result = userRepository.findByName( + userIdentifier.getIdentifier() + ); + break; + } + + if (result.isPresent()) { + final User user = result.get(); + final List groupNames = Arrays.asList(userGroups); + + // Check for new groups + final List newGroupNames = groupNames + .stream() + .filter(groupName -> !isMember(user, groupName)) + .collect(Collectors.toList()); + + // Check for removed groups + final List removedGroupNames = user + .getGroupMemberships() + .stream() + .map(membership -> membership.getGroup().getName()) + .filter(groupName -> !groupNames.contains(groupName)) + .collect(Collectors.toList()); + + for (final String newGroupName : newGroupNames) { + addNewGroup(user, newGroupName); + } + + for (final String removedGroupName : removedGroupNames) { + removeGroup(user, removedGroupName); + } + + return String.format( + "redirect:/users-groups-roles/users/%s/details", + userIdentifierParam + ); + } else { + models.put( + "errors", Arrays.asList( + adminMessages.getMessage( + "usersgroupsroles.users.not_found.message", + Arrays.asList(userIdentifierParam) + ) + ) + ); + return "org/libreccm/ui/admin/users-groups-roles/user-not-found.xhtml"; + } + } + + @POST + @Path("{userIdentifier}/roles") + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public String updateRoleMemberships( + @PathParam("userIdentifier") final String userIdentifierParam, + @FormParam("userRoles") final String[] userRoles + ) { + final Identifier userIdentifier = identifierParser.parseIdentifier( + userIdentifierParam + ); + final Optional result; + switch (userIdentifier.getType()) { + case ID: + result = userRepository.findById( + Long.parseLong(userIdentifier.getIdentifier()) + ); + break; + case UUID: + result = userRepository.findByUuid( + userIdentifier.getIdentifier() + ); + break; + default: + result = userRepository.findByName( + userIdentifier.getIdentifier() + ); + break; + } + + if (result.isPresent()) { + final User user = result.get(); + final List roleNames = Arrays.asList(userRoles); + + // Check for new roles + final List newRoleNames = roleNames + .stream() + .filter(roleName -> !hasRole(user, roleName)) + .collect(Collectors.toList()); + + // Check for removed roles + final List removedRoleNames = user + .getRoleMemberships() + .stream() + .map(membership -> membership.getRole().getName()) + .filter(roleName -> !roleNames.contains(roleName)) + .collect(Collectors.toList()); + + for (final String newRoleName : newRoleNames) { + addNewRole(user, newRoleName); + } + + for (final String removedRoleName : removedRoleNames) { + removeRole(user, removedRoleName); + } + + return String.format( + "redirect:/users-groups-roles/users/%s/details", + userIdentifierParam + ); + } else { + models.put( + "errors", Arrays.asList( + adminMessages.getMessage( + "usersgroupsroles.users.not_found.message", + Arrays.asList(userIdentifierParam) + ) + ) + ); + return "org/libreccm/ui/admin/users-groups-roles/user-not-found.xhtml"; + } + } + + private boolean isMember(final User user, final String groupName) { + return user + .getGroupMemberships() + .stream() + .map(membership -> membership.getGroup().getName()) + .anyMatch(name -> name.equals(groupName)); + } + + private void addNewGroup(final User user, final String newGroupName) { + final Optional result = groupRepository.findByName(newGroupName); + if (result.isPresent()) { + final Group group = result.get(); + groupManager.addMemberToGroup(user, group); + } + } + + private void removeGroup(final User user, final String removedGroupName) { + final Optional result = groupRepository.findByName( + removedGroupName + ); + if (result.isPresent()) { + final Group group = result.get(); + groupManager.removeMemberFromGroup(user, group); + } + } + + private boolean hasRole(final User user, final String roleName) { + return user + .getRoleMemberships() + .stream() + .map(membership -> membership.getMember().getName()) + .anyMatch(name -> name.equals(roleName)); + } + + private void addNewRole(final User user, final String newRoleName) { + final Optional result = roleRepository.findByName(newRoleName); + if (result.isPresent()) { + final Role role = result.get(); + roleManager.assignRoleToParty(role, user); + } + } + + private void removeRole(final User user, final String removedRoleName) { + final Optional result = roleRepository.findByName( + removedRoleName + ); + if (result.isPresent()) { + final Role role = result.get(); + roleManager.removeRoleFromParty(role, user); + } + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UsersGroupsRolesPage.java b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UsersGroupsRolesPage.java index 812f9b4cb..ec9db6a98 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UsersGroupsRolesPage.java +++ b/ccm-core/src/main/java/org/libreccm/ui/admin/usersgroupsroles/UsersGroupsRolesPage.java @@ -39,9 +39,11 @@ public class UsersGroupsRolesPage implements AdminPage { classes.add(UsersGroupsRolesController.class); classes.add(GroupsController.class); classes.add(GroupFormController.class); + classes.add(GroupMembersRolesController.class); classes.add(RolesController.class); classes.add(UsersController.class); classes.add(UserFormController.class); + classes.add(UserGroupsRolesController.class); classes.add(EmailFormController.class); return classes; } diff --git a/ccm-core/src/main/resources/WEB-INF/views/org/libreccm/ui/admin/users-groups-roles/group-details.xhtml b/ccm-core/src/main/resources/WEB-INF/views/org/libreccm/ui/admin/users-groups-roles/group-details.xhtml index a2c489c5b..232969eea 100644 --- a/ccm-core/src/main/resources/WEB-INF/views/org/libreccm/ui/admin/users-groups-roles/group-details.xhtml +++ b/ccm-core/src/main/resources/WEB-INF/views/org/libreccm/ui/admin/users-groups-roles/group-details.xhtml @@ -77,7 +77,7 @@ id="group-members-dialog" tabindex="-1">