Additional forms and controller methods for groups

Former-commit-id: 2ba4536968
pull/7/head
Jens Pelzetter 2020-10-15 19:58:11 +02:00
parent 06fb2c86b0
commit c97a0ebe33
13 changed files with 565 additions and 13 deletions

View File

@ -20,7 +20,11 @@ package org.libreccm.ui.admin.usersgroupsroles;
import org.libreccm.security.Group;
import org.libreccm.security.GroupMembership;
import org.libreccm.security.Role;
import org.libreccm.security.RoleMembership;
import org.libreccm.security.RoleRepository;
import org.libreccm.security.User;
import org.libreccm.security.UserRepository;
import org.libreccm.ui.Message;
import java.util.ArrayList;
@ -30,6 +34,7 @@ import java.util.Objects;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.transaction.Transactional;
@ -42,6 +47,12 @@ import javax.transaction.Transactional;
@Named("GroupDetailsModel")
public class GroupDetailsModel {
@Inject
private RoleRepository roleRepository;
@Inject
private UserRepository userRepository;
private long groupId;
private String uuid;
@ -86,6 +97,22 @@ public class GroupDetailsModel {
return Collections.unmodifiableList(roles);
}
public List<GroupUserFormEntry> getGroupMemberFormEntries() {
return userRepository
.findAll()
.stream()
.map(this::buildGroupUserFormEntry)
.collect(Collectors.toList());
}
public List<PartyRolesFormEntry> getGroupRolesFormEntries() {
return roleRepository
.findAll()
.stream()
.map(this::buildGroupRolesFormEntry)
.collect(Collectors.toList());
}
@Transactional(Transactional.TxType.REQUIRED)
protected void setGroup(final Group group) {
Objects.requireNonNull(group);
@ -113,4 +140,34 @@ public class GroupDetailsModel {
return groupId == 0;
}
private GroupUserFormEntry buildGroupUserFormEntry(final User user) {
final GroupUserFormEntry entry = new GroupUserFormEntry();
entry.setUserId(user.getPartyId());
entry.setUserName(user.getName());
entry.setUserUuid(user.getUuid());
entry.setMember(
members
.stream()
.anyMatch(
membership -> membership.getUserUuid().equals(user.getUuid())
)
);
return entry;
}
private PartyRolesFormEntry buildGroupRolesFormEntry(final Role role) {
final PartyRolesFormEntry entry = new PartyRolesFormEntry();
entry.setRoleId(role.getRoleId());
entry.setRoleName(role.getName());
entry.setRoleUuid(role.getUuid());
entry.setMember(
roles
.stream()
.anyMatch(
membership -> membership.getRoleUuid().equals(role.getUuid())
)
);
return entry;
}
}

View File

@ -0,0 +1,149 @@
/*
* 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.ui.admin.AdminMessages;
import java.util.Arrays;
import java.util.Optional;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.mvc.Models;
import javax.mvc.MvcContext;
import javax.mvc.binding.BindingResult;
import javax.mvc.binding.MvcBinding;
import javax.transaction.Transactional;
import javax.validation.constraints.NotBlank;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Controller
@Path("/users-groups-roles/groups/")
@RequestScoped
public class GroupFormController {
@Inject
private AdminMessages adminMessages;
@Inject
private BindingResult bindingResult;
@Inject
private IdentifierParser identifierParser;
@Inject
private Models models;
@Inject
private MvcContext mvc;
@Inject
private GroupManager groupManager;
@Inject
private GroupRepository groupRepository;
@MvcBinding
@FormParam("groupName")
@NotBlank
private String groupName;
@POST
@Path("/new")
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public String createGroup() {
if (bindingResult.isFailed()) {
models.put("errors", bindingResult.getAllMessages());
return "org/libreccm/ui/admin/users-groups-roles/group-form.xhtml";
}
final Group group = new Group();
group.setName(groupName);
groupRepository.save(group);
return "redirect:users-groups-roles/groups";
}
@POST
@Path("{groupIdentifier}/edit")
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public String updateUser(
@PathParam("groupIdentifier") final String groupIdentifierParam
) {
if (bindingResult.isFailed()) {
models.put("errors", bindingResult.getAllMessages());
return "org/libreccm/ui/admin/users-groups-roles/group-form.xhtml";
}
final Identifier identifier = identifierParser.parseIdentifier(
groupIdentifierParam
);
final Optional<Group> result;
switch (identifier.getType()) {
case ID:
result = groupRepository.findById(
Long.parseLong(identifier.getIdentifier())
);
break;
case UUID:
result = groupRepository.findByUuid(identifier.getIdentifier());
break;
default:
result = groupRepository.findByName(identifier.getIdentifier());
break;
}
if (result.isPresent()) {
final Group group = result.get();
group.setName(groupName);
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)
)
));
return "org/libreccm/ui/admin/users-groups-roles/group-form.xhtml";
}
}
}

View File

@ -0,0 +1,70 @@
/*
* 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;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class GroupUserFormEntry {
private long userId;
private String userUuid;
private String userName;
private boolean member;
public long getUserId() {
return userId;
}
public void setUserId(final long userId) {
this.userId = userId;
}
public String getUserUuid() {
return userUuid;
}
public void setUserUuid(final String userUuid) {
this.userUuid = userUuid;
}
public String getUserName() {
return userName;
}
public void setUserName(final String userName) {
this.userName = userName;
}
public boolean isMember() {
return member;
}
public void setMember(final boolean member) {
this.member = member;
}
}

View File

@ -18,20 +18,29 @@
*/
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.GroupRepository;
import org.libreccm.security.RequiresPrivilege;
import org.libreccm.ui.Message;
import org.libreccm.ui.MessageType;
import org.libreccm.ui.admin.AdminMessages;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
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.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
*
@ -42,9 +51,18 @@ import javax.ws.rs.Path;
@Path("/users-groups-roles/groups")
public class GroupsController {
@Inject
private AdminMessages adminMessages;
@Inject
private GroupDetailsModel groupDetailsModel;
@Inject
private GroupRepository groupRepository;
@Inject
private IdentifierParser identifierParser;
@Inject
private Models models;
@ -59,4 +77,98 @@ public class GroupsController {
return "org/libreccm/ui/admin/users-groups-roles/groups.xhtml";
}
@GET
@Path("/{groupIdentifier}/details")
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public String getGroupDetails(
@PathParam("groupIdentifier") final String groupIdentifierParam
) {
final Identifier identifier = identifierParser.parseIdentifier(
groupIdentifierParam
);
final Optional<Group> result;
switch (identifier.getType()) {
case ID:
result = groupRepository.findById(
Long.parseLong(identifier.getIdentifier())
);
break;
case UUID:
result = groupRepository.findByUuid(identifier.getIdentifier());
break;
default:
result = groupRepository.findByName(identifier.getIdentifier());
break;
}
if (result.isPresent()) {
groupDetailsModel.setGroup(result.get());
return "org/libreccm/ui/admin/users-groups-roles/group-details.xhtml";
} else {
groupDetailsModel.addMessage(
new Message(
adminMessages.getMessage(
"usersgroupsroles.groups.not_found.message",
Arrays.asList(groupIdentifierParam)
),
MessageType.WARNING
)
);
return "org/libreccm/ui/admin/users-groups-roles/group-not-found.xhtml";
}
}
@GET
@Path("/new")
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
public String newGroup() {
return "org/libreccm/ui/admin/users-groups-roles/group-form.xhtml";
}
@GET
@Path("/{groupIdentifier}/edit")
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public String editGroup(
@PathParam("groupIdentifier") final String groupIdentifierParam
) {
final Identifier identifier = identifierParser.parseIdentifier(
groupIdentifierParam
);
final Optional<Group> result;
switch (identifier.getType()) {
case ID:
result = groupRepository.findById(
Long.parseLong(identifier.getIdentifier())
);
break;
case UUID:
result = groupRepository.findByUuid(identifier.getIdentifier());
break;
default:
result = groupRepository.findByName(identifier.getIdentifier());
break;
}
if (result.isPresent()) {
groupDetailsModel.setGroup(result.get());
return "org/libreccm/ui/admin/users-groups-roles/group-form.xhtml";
} else {
groupDetailsModel.addMessage(
new Message(
adminMessages.getMessage(
"usersgroupsroles.groups.not_found.message",
Arrays.asList(groupIdentifierParam)
),
MessageType.WARNING
)
);
return "org/libreccm/ui/admin/users-groups-roles/group-not-found.xhtml";
}
}
}

View File

@ -23,7 +23,7 @@ package org.libreccm.ui.admin.usersgroupsroles;
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class UserRolesFormEntry {
public class PartyRolesFormEntry {
private long roleId;

View File

@ -175,7 +175,7 @@ public class UserDetailsModel {
return Collections.unmodifiableList(roles);
}
public List<UserRolesFormEntry> getUserRolesFormEntries() {
public List<PartyRolesFormEntry> getUserRolesFormEntries() {
return roleRepository
.findAll()
.stream()
@ -202,8 +202,8 @@ public class UserDetailsModel {
return entry;
}
private UserRolesFormEntry buildUserRolesFormEntry(final Role role) {
final UserRolesFormEntry entry = new UserRolesFormEntry();
private PartyRolesFormEntry buildUserRolesFormEntry(final Role role) {
final PartyRolesFormEntry entry = new PartyRolesFormEntry();
entry.setRoleId(role.getRoleId());
entry.setRoleName(role.getName());
entry.setRoleUuid(role.getUuid());

View File

@ -142,9 +142,7 @@ public class UsersController {
@Path("/new")
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
public String newUser(
@PathParam("userIdentifier") final String userIdentifier
) {
public String newUser() {
return "org/libreccm/ui/admin/users-groups-roles/user-form.xhtml";
}

View File

@ -121,7 +121,115 @@
</div>
</form>
</div>
</div>
</div>
<c:choose>
<c:when test="#{GroupDetailsModel.members.size() > 0}">
<ul class="list-group mt-1">
<c:forEach items="#{GroupDetailsModel.members}"
var="member">
<li class="list-group-item">
<a href="#">
#{member.userName}
</a>
</li>
</c:forEach>
</ul>
</c:when>
<c:otherwise>
<div class="alert alert-info" role="alert">
#{AdminMessages['usersgroupsroles.groups.group_details.members.none']}
</div>
</c:otherwise>
</c:choose>
<div class="d-flex mb-1">
<h2 class="mr-2">
#{AdminMessages['usersgroupsroles.groups.groups_details.roles.heading']}
</h2>
<button class="btn btn-primary"
data-toggle="modal"
data-target="#group-roles-dialog"
type="button">
<svg class="bi"
width="1em"
height="1em"
fill="currentColor">
<use xlink:href="#{request.contextPath}/assets/bootstrap/bootstrap-icons.svg#pen" />
</svg>
<span>#{AdminMessages['usersgroupsroles.groups.group_details.roles.edit']}</span>
</button>
<div aria-labelledby="group-roles-dialog-title"
aria-hidden="true"
class="modal fade"
data-backdrop="static"
id="user-roles-dialog"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.uri('UserFormController#updateRoleMemberships', {'userIdentifier': UserDetailsModel.name })}"
class="modal-content"
method="post">
<div class="modal-header">
<h3 class="modal-title"
id="group-roles-dialog.title">
#{AdminMessages['usersgroupsroles.groups.group_details.roles.dialog.title']}
</h3>
<button aria-label="#{AdminMessages['usersgroupsroles.groups.group_details.roles.dialog.close']}"
class="close"
data-dismiss="modal"
type="button">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<c:forEach items="#{GroupDetailsModel.groupRolesFormEntries}"
var="entry">
<div class="form-check form-check-inline">
<input class="form-check-input"
checked="#{entry.member ? 'checked' : ''}"
id="role-#{entry.roleName}"
name="userRoles[]"
value="#{entry.roleName}"
type="checkbox" />
<label for="role#{entry.roleName}">
#{entry.roleName}
</label>
</div>
</c:forEach>
</div>
<div class="modal-footer">
<button class="btn btn-secondary"
data-dismiss="modal"
type="button" >
#{AdminMessages['usersgroupsroles.groups.group_details.roles.dialog.close']}
</button>
<button type="submit" class="btn btn-primary">
#{AdminMessages['usersgroupsroles.groups.group_details.roles.dialog.save']}
</button>
</div>
</form>
</div>
</div>
</div>
<c:choose>
<c:when test="#{GroupDetailsModel.roles.size() > 0}">
<ul class="list-group mt-1 mb-4">
<c:forEach items="#{GroupDetailsModel.roles}"
var="role">
<a href="#">
#{role.roleName}
</a>
</c:forEach>
</ul>
</c:when>
<c:otherwise>
<div class="alert alert-info" role="alert">
#{AdminMessages['usersgroupsroles.groups.group_details.roles.none']}
</div>
</c:otherwise>
</c:choose>
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/libreccm/ui/admin/users-groups-roles.xhtml">
<ui:param name="activePage" value="usersgroupsroles" />
<ui:param name="activePanel" value="groups" />
<ui:param name="title"
value="#{AdminMessages('usersgroupsroles.groups.not_found.title')}" />
<ui:define name="breadcrumb">
<li class="breadcrumb-item">
<a href="#{mvc.uri('UsersGroupsRolesController#getOverview')}">
#{AdminMessages['usersgroupsroles.label']}
</a>
</li>
<li class="breadcrumb-item">
<a href="#{mvc.uri('UsersController#getUsers')}">
#{AdminMessages['usersgroupsroles.users.label']}
</a>
</li>
<li class="breadcrumb-item">
#{AdminMessages['usersgroupsroles.users.not_found.title']}
</li>
</ui:define>
<ui:define name="panel">
<c:forEach items="#{UserDetailsModel.messages}" var="message">
<div class="alert alert-#{message.messageType}" role="alert">
#{message}
</div>
</c:forEach>
</ui:define>
</ui:composition>
</html>

View File

@ -28,7 +28,7 @@
</div>
<div class="col-sm-3 text-right">
<a class="btn btn-secondary"
href="#">
href="#{mvc.uri("GroupsController#newGroup")}">
<svg class="bi"
width="1em"
height="1em"

View File

@ -422,7 +422,7 @@
#{AdminMessages['usersgroupsroles.users.user_details.roles.dialog.close']}
</button>
<button type="submit" class="btn btn-primary">
#{AdminMessages['usersgroupsroles.users.user_details.groups.dialog.save']}
#{AdminMessages['usersgroupsroles.users.user_details.roles.dialog.save']}
</button>
</div>
</form>

View File

@ -157,3 +157,12 @@ usersgroupsroles.groups.group_details.members.edit=Add/remove members
usersgroupsroles.groups.group_details.members.dialog.title=Add/remove members
usersgroupsroles.groups.group_details.members.dialog.close=Cancel
usersgroupsroles.groups.group_details.members.dialog.save=Apply
usersgroupsroles.groups.group_details.members.none=This group has no members
usersgroupsroles.groups.groups_details.roles.heading=Roles
usersgroupsroles.groups.group_details.roles.edit=Edit
usersgroupsroles.groups.group_details.roles.dialog.title=Edit role memberships
usersgroupsroles.groups.group_details.roles.dialog.close=Cancel
usersgroupsroles.users.user_details.roles.dialog.save=Apply
usersgroupsroles.groups.group_details.roles.dialog.save=Apply
usersgroupsroles.groups.group_details.roles.none=No roles assigned to this group
usersgroupsroles.groups.not_found.title=Group not found

View File

@ -157,3 +157,12 @@ usersgroupsroles.groups.group_details.members.edit=Mitglieder hinzuf\u00fcgen/en
usersgroupsroles.groups.group_details.members.dialog.title=Mitglieder hinzuf\u00fcgen/entfernen
usersgroupsroles.groups.group_details.members.dialog.close=Abbrechen
usersgroupsroles.groups.group_details.members.dialog.save=Anwenden
usersgroupsroles.groups.group_details.members.none=Diese Gruppe hat keine Mitglieder
usersgroupsroles.groups.groups_details.roles.heading=Rollen
usersgroupsroles.groups.group_details.roles.edit=Bearbeiten
usersgroupsroles.groups.group_details.roles.dialog.title=Rollenmitgliedschaften bearbeiten
usersgroupsroles.groups.group_details.roles.dialog.close=Abbrechen
usersgroupsroles.users.user_details.roles.dialog.save=Anwenden
usersgroupsroles.groups.group_details.roles.dialog.save=Anwenden
usersgroupsroles.groups.group_details.roles.none=Dieser Gruppe sind keine Rollen zugeordnet
usersgroupsroles.groups.not_found.title=Gruppe nicht gefunden