Commit 8930f7aa by Tuomas Riihimäki

Refactor and fix user searching with role.

1 parent 2b19d7ba
......@@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
......@@ -216,4 +217,6 @@ public interface UserBeanLocal {
* @return Eventusers for all events this user has been associated to.
*/
List<EventUser> findAllEventusers(User user);
Map<Role,List<String>> findUsersRolesWithReason(EventUser user);
}
......@@ -94,13 +94,13 @@ import fi.codecrew.moya.utilities.moyamessage.MoyaEventType;
@LocalBean
@Stateless
@DeclareRoles({
UserPermission.S_VIEW_ALL,
UserPermission.S_CREATE_NEW,
UserPermission.S_INVITE_USERS,
UserPermission.S_MODIFY,
SpecialPermission.S_USER,
EventPermission.S_MANAGE_EVENT,
SpecialPermission.S_SUPERADMIN
UserPermission.S_VIEW_ALL,
UserPermission.S_CREATE_NEW,
UserPermission.S_INVITE_USERS,
UserPermission.S_MODIFY,
SpecialPermission.S_USER,
EventPermission.S_MANAGE_EVENT,
SpecialPermission.S_SUPERADMIN
})
public class UserBean implements UserBeanLocal {
......@@ -186,7 +186,7 @@ public class UserBean implements UserBeanLocal {
@Override
public boolean setUsersLocale(String locale) {
if(permbean.getCurrentUser().isAnonymous()) {
if (permbean.getCurrentUser().isAnonymous()) {
return false;
}
......@@ -234,6 +234,13 @@ public class UserBean implements UserBeanLocal {
}
@Override
@RolesAllowed(UserPermission.S_VIEW_ALL)
public Map<Role, List<String>> findUsersRolesWithReason(EventUser u) {
return localFindUsersRolesWithReason(u);
}
// private EventUser currentEventuser;
// private ArrayList<Role> currentEventuserRoles;
......@@ -241,6 +248,10 @@ public class UserBean implements UserBeanLocal {
// Käytä Viewien puolelta findUsersRoles joka tarkistaa käyttäjän oikeudet
// ensin.
public Set<Role> localFindUsersRoles(EventUser u) {
return localFindUsersRolesWithReason(u).keySet();
}
public HashMap<Role, List<String>> localFindUsersRolesWithReason(EventUser u) {
// if (currentEventuser != null && u.equals(currentEventuser)) {
// logger.debug("Returnin cached eventuserroles for user {}: {}",
// currentEventuser, currentEventuserRoles);
......@@ -248,26 +259,27 @@ public class UserBean implements UserBeanLocal {
// }
LanEvent event = u.getEvent();
Set<Role> checkedRoles = new HashSet<Role>();
//Set<Role> checkedRoles = new HashSet<Role>();
HashMap<Role, List<String>> checkedRoles = new HashMap<>();
if (u != null) {
addRecursive(checkedRoles, rolefacade.findForUser(u));
addRecursive(checkedRoles, orgRoleFacade.findRolesForUser(u));
addRecursive(checkedRoles, rolefacade.findForUser(u), "DIRECT");
addRecursive(checkedRoles, orgRoleFacade.findRolesForUser(u), "ORG_ROLE");
if (permbean.isLoggedIn()) {
// add roles from events default role.
addRecursive(checkedRoles, event.getDefaultRole());
addRecursive(checkedRoles, event.getDefaultRole(), "EVENT_DEFAULT");
}
if (!u.isAnonymous()) {
// add roles from accountEvents of the user
addRecursive(checkedRoles, productbean.getRolesFromAccountEvents(u));
addRecursive(checkedRoles, productbean.getRolesFromAccountEvents(u), "ACCOUNTEVENT");
for (GroupMembership member : gmfacade.findMemberships(u)) {
if (member != null && member.getPlaceReservation() != null) {
addRecursive(checkedRoles, member.getPlaceReservation().getProvidesRole());
addRecursive(checkedRoles, member.getPlaceReservation().getProvidesRole(), "PLACE");
if (member.getPlaceReservation().getProduct() != null) {
addRecursive(checkedRoles, member.getPlaceReservation().getProduct().getProvides());
addRecursive(checkedRoles, member.getPlaceReservation().getProduct().getProvides(), "PLACE_PRODUCT");
}
}
}
......@@ -283,20 +295,28 @@ public class UserBean implements UserBeanLocal {
return checkedRoles;
}
private void addRecursive(Set<Role> checkedRoles, Collection<Role> roles) {
public void addRecursive(Map<Role, List<String>> checkedRoles, Collection<Role> roles, String source) {
for (Role r : roles) {
addRecursive(checkedRoles, r);
addRecursive(checkedRoles, r, source);
}
}
private void addRecursive(Set<Role> checkedRoles, Role role) {
if (role == null || checkedRoles.contains(role)) {
public void addRecursive(Map<Role, List<String>> checkedRoles, Role role, String source) {
if (role == null) {
return;
}
checkedRoles.add(role);
for (Role r : role.getParents()) {
addRecursive(checkedRoles, r);
List<String> reasons = checkedRoles.get(role);
if (reasons == null) {
reasons = new ArrayList<>();
checkedRoles.put(role, reasons);
for (Role r : role.getParents()) {
addRecursive(checkedRoles, r, source);
}
}
reasons.add(source);
}
......@@ -963,11 +983,11 @@ public class UserBean implements UserBeanLocal {
@Override
public boolean isUserInRole(EventUser user, Integer roleId) {
Set<Role> roles = localFindUsersRoles(user);
HashMap<Role, List<String>> roles = localFindUsersRolesWithReason(user);
logger.info("CHecking user {} roleid {} from roles {}, roles size{}", new Object[]{user, roleId, roles, roles.size()});
addRecursive(roles, eventBean.getCurrentEvent().getDefaultRole());
addRecursive(roles, eventBean.getCurrentEvent().getDefaultRole(), "DEFAULT");
for (Role r : roles) {
for (Role r : roles.keySet()) {
if (roleId.equals(r.getId())) {
logger.info("User {} found in role {}", user, roleId);
return true;
......@@ -1043,7 +1063,7 @@ public class UserBean implements UserBeanLocal {
dstUser.addAccountevent(dstacc);
accountEventFacade.create(dstacc);
logger.info("Transferred {} credits with price {} for user {} from {} to {}",
new Object[]{count, creditPrice, srcUser.getUser(), srcUser, dstUser});
new Object[]{count, creditPrice, srcUser.getUser(), srcUser, dstUser});
dstTotal = dstTotal.add(dstacc.getTotal());
}
......@@ -1188,7 +1208,6 @@ public class UserBean implements UserBeanLocal {
return eventUserFacade.findForUser(user);
}
@Override
@RolesAllowed(EventPermission.S_MANAGE_EVENT)
public EventUser getUserByAuthcode(String authcode) {
......
......@@ -56,12 +56,14 @@ public class AccountEventFacade extends IntegerPkGenericFacade<AccountEvent> {
CriteriaQuery<Role> cq = cb.createQuery(Role.class);
Root<AccountEvent> root = cq.from(AccountEvent.class);
Path<Role> role = root.get(AccountEvent_.product).get(Product_.provides);
Path<Product> prodPath = root.get(AccountEvent_.product);
Path<Role> role = prodPath.get(Product_.provides);
cq.select(role);
cq.where(
cb.equal(role.get(Role_.event), event),
cb.equal(root.get(AccountEvent_.user), u)
,cb.isEmpty(prodPath.get(Product_.places))
);
// TypedQuery<Role> q =
......
/*
* Copyright Codecrew Ry
*
*
* All rights reserved.
*
* This license applies to any software containing a notice placed by the
* copyright holder. Such software is herein referred to as the Software.
* This license covers modification, distribution and use of the Software.
*
* Any distribution and use in source and binary forms, with or without
* modification is not permitted without explicit written permission from the
* copyright owner.
*
* A non-exclusive royalty-free right is granted to the copyright owner of the
* Software to use, modify and distribute all modifications to the Software in
* future versions of the Software.
*
*
* This license applies to any software containing a notice placed by the
* copyright holder. Such software is herein referred to as the Software.
* This license covers modification, distribution and use of the Software.
*
* Any distribution and use in source and binary forms, with or without
* modification is not permitted without explicit written permission from the
* copyright owner.
*
* A non-exclusive royalty-free right is granted to the copyright owner of the
* Software to use, modify and distribute all modifications to the Software in
* future versions of the Software.
*
*/
package fi.codecrew.moya.facade.callbacks;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import javax.persistence.criteria.*;
import fi.codecrew.moya.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.model.AccountEvent_;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.EventUser_;
import fi.codecrew.moya.model.GroupMembership_;
import fi.codecrew.moya.model.Place_;
import fi.codecrew.moya.model.Product_;
import fi.codecrew.moya.model.Role;
import fi.codecrew.moya.model.Role_;
import fi.codecrew.moya.utilities.jpa.FacadeCallback;
public class EventUserRolefilter implements FacadeCallback<EventUser> {
private final List<Role> roles;
private static final Logger logger = LoggerFactory.getLogger(EventUserRolefilter.class);
private final LanEvent event;
public EventUserRolefilter(List<Role> filters) {
roles = filters;
roles = Collections.unmodifiableList(filters);
event = roles.get(0).getEvent();
}
private static final Set<Integer> getAllChildren(Collection<Role> roles, Set<Integer> checkedRoles) {
for (Role role : roles)
{
if (checkedRoles == null) {
checkedRoles = new HashSet<>();
}
for (Role role : roles) {
if (role == null || checkedRoles.contains(role.getId())) {
continue;
}
......@@ -66,40 +53,112 @@ public class EventUserRolefilter implements FacadeCallback<EventUser> {
return checkedRoles;
}
private static final Set<Integer> getAllParents(Collection<Role> roles, Set<Integer> checkedRoles) {
if (checkedRoles == null) {
checkedRoles = new HashSet<>();
}
for (Role role : roles) {
if (role == null || checkedRoles.contains(role.getId())) {
continue;
}
checkedRoles.add(role.getId());
getAllParents(role.getParents(), checkedRoles);
}
return checkedRoles;
}
public void exec(CriteriaBuilder cb, CriteriaQuery<?> cq, Path<EventUser> root, List<Predicate> predicates, boolean isFullQuery) {
if (roles != null && !roles.isEmpty())
if (roles == null || roles.isEmpty()) {
return;
}
Set<Integer> roleWChildrenIds = getAllChildren(roles, null);
Set<Integer> roleWParentsIds = getAllParents(roles, null);
logger.warn("roles with children: {}, roles with parent {}", roleWChildrenIds, roleWParentsIds);
Path<Integer> rootId = root.get(EventUser_.id);
ArrayList<Predicate> orPreds = new ArrayList<Predicate>();
/**
* Find all users that have a role "forced" directly to the user
* If role has parents, user belongs also to them, so also parents are included
*/
{
HashSet<Integer> roleids = new HashSet<Integer>();
getAllChildren(roles, roleids);
logger.debug("Requiring roles {}", roleids);
Path<Integer> rootId = root.get(EventUser_.id);
ArrayList<Predicate> orPreds = new ArrayList<Predicate>();
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.users).get(EventUser_.id));
subq.where(subroot.get(Role_.id).in(roleids));
orPreds.add(rootId.in(subq));
}
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.users).get(EventUser_.id));
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.productsProvide).join(Product_.accountEvents).get(AccountEvent_.user).get(EventUser_.id));
subq.where(subroot.get(Role_.id).in(roleids));
orPreds.add(rootId.in(subq));
}
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.productsProvide).join(Product_.places).get(Place_.placeReserver).get(GroupMembership_.user).get(EventUser_.id));
subq.where(subroot.get(Role_.id).in(roleids));
orPreds.add(rootId.in(subq));
}
// Root<Role> rolePath = subq.correlate(roleRoot);
predicates.add(cb.or(orPreds.toArray(new Predicate[orPreds.size()])));
subq.where(subroot.get(Role_.id).in(roleWChildrenIds));
orPreds.add(rootId.in(subq));
}
/**
* Find all products that provide a given role, or a parent of the role via accountevents
* NOTE! Products that have places, do not provide roles to users
*/
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
ListJoin<Role, Product> prodsPath = subroot.join(Role_.productsProvide);
subq.select(prodsPath.join(Product_.accountEvents).get(AccountEvent_.user).get(EventUser_.id));
subq.where(
subroot.get(Role_.id).in(roleWChildrenIds),
cb.isEmpty(prodsPath.get(Product_.places))
);
orPreds.add(rootId.in(subq));
}
/**
* Roles provided by products via places user has been given to.
*/
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.productsProvide).join(Product_.places).get(Place_.placeReserver).get(GroupMembership_.user).get(EventUser_.id));
subq.where(subroot.get(Role_.id).in(roleWChildrenIds));
orPreds.add(rootId.in(subq));
}
/** Roles provided by places user has been given to.
*/
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subq.select(subroot.join(Role_.placesProvide).get(Place_.placeReserver).get(GroupMembership_.user).get(EventUser_.id));
subq.where(subroot.get(Role_.id).in(roleWChildrenIds));
orPreds.add(rootId.in(subq));
}
/** Find all roles provided by organisation roles
*
*/
{
Subquery<Integer> subq = cq.subquery(Integer.class);
Root<Role> subroot = subq.from(Role.class);
subroot.get(Role_.orgRoles);
ListJoin<OrgRole, User> orgRoleUser = subroot.join(Role_.orgRoles).join(OrgRole_.users);
ListJoin<User, EventUser> euJoin = orgRoleUser.join(User_.eventusers);
subq.select(euJoin.get(EventUser_.id));
subq.where(
cb.equal(euJoin.get(EventUser_.event), event),
subroot.get(Role_.id).in(roleWChildrenIds));
orPreds.add(rootId.in(subq));
}
predicates.add(cb.or(orPreds.toArray(new Predicate[orPreds.size()])));
}
}
......@@ -138,6 +138,18 @@ public class User extends GenericEntity implements IUser {
@OrderBy()
private List<LicenseCode> licenseCodes;
@OneToMany(mappedBy="user", fetch = FetchType.LAZY)
private List<EventUser> eventusers;
private List<EventUser> getEventusers(){
throw new RuntimeException("We never want to fetch this. Only here for metamodel");
}
private void setEventusers(List<EventUser> eventusers){
throw new RuntimeException("We never want to fetch this. Only here for metamodel");
}
@Transient
private static final Logger logger = LoggerFactory.getLogger(User.class);
......
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui">
<h:body>
<ui:composition template="#{sessionHandler.template}">
<f:metadata>
<f:event type="preRenderView"
listener="#{applicationApiView.initApplicationListView}" />
</f:metadata>
<ui:define name="content">
<button></button>
<div style="display:none;" id="createApp">
</div>
<h1>#{i18n['apiapp.edit.applist']}</h1>
<p:dataTable value="#{applicationApiView.applist}" var="app">
<p:column headerText="#{i18n['apiapp.name']}">
<h:outputText value="#{app.name}" />
</p:column>
<p:column headerText="#{i18n['apiapp.description']}">
<h:outputText value="#{app.description}" />
</p:column>
<p:column>
<h:outputText value="#{app.created}">
<f:convertDateTime pattern="#{sessionHandler.datetimeFormat}"
timeZone="#{sessionHandler.timezone}" />
</h:outputText>
</p:column>
<p:column headerText="#{i18n['apiapp.enabled']}">
<h:outputText value="#{app.enabled}" />
</p:column>
</p:dataTable>
</ui:define>
</ui:composition>
</h:body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:users="http://java.sun.com/jsf/composite/cditools/user" xmlns:tools="http://java.sun.com/jsf/composite/cditools" xmlns:account="http://java.sun.com/jsf/composite/cditools/account"
xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:p="http://primefaces.org/ui">
xmlns:users="http://java.sun.com/jsf/composite/cditools/user" xmlns:tools="http://java.sun.com/jsf/composite/cditools" xmlns:account="http://java.sun.com/jsf/composite/cditools/account"
xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:p="http://primefaces.org/ui">
<h:body>
<ui:composition template="#{sessionHandler.template}">
<f:metadata>
<f:viewParam name="userid" value="#{userView.userid}" />
<f:event type="preRenderView" listener="#{userView.initView}" />
<f:event type="preRenderView" listener="#{userView.setCaptureForwardUrl('')}" />
<f:viewParam name="userid" value="#{userView.userid}"/>
<f:event type="preRenderView" listener="#{userView.initView}"/>
<f:event type="preRenderView" listener="#{userView.setCaptureForwardUrl('')}"/>
</f:metadata>
<ui:define name="title">
......@@ -16,27 +16,41 @@
<!-- <users:usertabs tabId="edit" /> -->
</ui:define>
<ui:define name="edittab">
<users:usertabs tabId="edit" />
<users:usertabs tabId="edit"/>
</ui:define>
<ui:define name="content">
<users:edit commitaction="#{userCartView.saveUser()}" commitvalue="#{i18n['user.save']}" />
<h:form id="roleform" rendered="#{roleView.canReadRoles}">
<h2>
<h:outputText value="#{i18n['user.roles']}:" />
</h2>
<h:selectManyCheckbox converter="#{roleConverter}" disabled="#{!roleView.canWriteRoles}" layout="pageDirection" id="roles" value="#{userView.usersRoles}">
<f:selectItems var="roleitem" itemLabel="#{roleitem.name}" value="#{roleDataView.roles}" />
</h:selectManyCheckbox>
<div>
<h:message rendered="#{roleView.canReadRoles}" for="roles" />
</div>
<h:commandButton action="#{userView.saveRoles}" value="#{i18n['user.saveRoles']}" />
<users:edit commitaction="#{userCartView.saveUser()}" commitvalue="#{i18n['user.save']}"/>
<div style="display: flex;">
<h:form id="roleform" rendered="#{roleView.canReadRoles}">
</h:form>
<h2>
<h:outputText value="#{i18n['user.roles']}:"/>
</h2>
<h:selectManyCheckbox converter="#{roleConverter}" disabled="#{!roleView.canWriteRoles}" layout="pageDirection" id="roles" value="#{userView.usersRoles}">
<f:selectItems var="roleitem" itemLabel="#{roleitem.name}" value="#{roleDataView.roles}"/>
</h:selectManyCheckbox>
<div>
<p:message rendered="#{roleView.canReadRoles}" for="roles"/>
</div>
<p:commandButton ajax="false" action="#{userView.saveRoles}" value="#{i18n['user.saveRoles']}"/>
</h:form>
<div style="margin-left: 4em;">
<h2>All users roles</h2>
<p:dataTable style="max-width: 600px;" var="r" value="#{userView.allUsersRoles}">
<p:column style="width: 30%;"><f:facet name="header"><h:outputText value="#{i18n['role.name']}"/></f:facet><h:outputText value="#{r.key.name}"/></p:column>
<p:column>
<f:facet name="header">
<h:outputText value="#{i18n['role.source']}"/>
</f:facet>
<ul><ui:repeat var="src" value="#{r.value}">
<li>#{i18n['role.source.'+=src]}</li>
</ui:repeat></ul>
</p:column>
</p:dataTable>
</div>
</div>
</ui:define>
</ui:composition>
</h:body>
......
......@@ -21,9 +21,7 @@ package fi.codecrew.moya.web.cdiview.user;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import javax.ejb.EJB;
import javax.enterprise.context.Conversation;
......@@ -231,6 +229,11 @@ public class UserView extends GenericCDIView {
return null;
}
public ArrayList<Map.Entry<Role, List<String>>> getAllUsersRoles(){
return new ArrayList<>(userbean.findUsersRolesWithReason(user).entrySet());
}
public List<Role> getUserSelectableRoles() {
if (userSelectableRoles == null && user != null) {
userSelectableRoles = rolebean.getRoles(getSelectedUser());
......
......@@ -1678,4 +1678,12 @@ placegroupview.count =Count
user.allergies =Allergies / diets
allergies.save =Save allergies
user.eventproperties =
submenu.permissionDenied =
\ No newline at end of file
submenu.permissionDenied =
role.source =
role.source.DIRECT =
role.source.ORG_ROLE =
role.source.PLACE =
role.source.ACCOUNTEVENT =
role.source.PLACE_PRODUCT =
role.source.EVENT_DEFAULT =
user.allroles =
\ No newline at end of file
......@@ -1915,4 +1915,12 @@ placegroupview.count =Count
user.allergies =Allergies / diets
allergies.save =Save allergies
user.eventproperties = Event specific properties
submenu.permissionDenied = Access denied
\ No newline at end of file
submenu.permissionDenied = Access denied
role.source = Role source
role.source.DIRECT = Forced for user
role.source.ORG_ROLE = Organisation role
role.source.PLACE = Place
role.source.ACCOUNTEVENT = Accountevent (Bought product)
role.source.PLACE_PRODUCT = Product via place
role.source.EVENT_DEFAULT = Event default role
user.allroles = All users roles
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!