zones = null;
if (zone != null)
{
// Don't bother doing this lookup unless the zone filter is non-null.
zones = authorityService.getAuthorityZones(groupName);
}
return zonePredicate(zones, zone);
}
/**
* Test to see if a result should be included, using the isRoot parameter.
*
* If isRootParam is null, then no results will be filtered. Otherwise
* results will be filtered to return only those that are root or non-root,
* depending on the value of isRootParam.
*
* @param isRootParam
* @param rootAuthorities
* @param authority
* @return
*/
private boolean isRootPredicate(Boolean isRootParam, Set rootAuthorities, String authority)
{
if (isRootParam != null)
{
return isRootParam == isRootAuthority(rootAuthorities, authority);
}
return true;
}
/**
* Checks a list of zones to see if it matches the supplied zone filter
* ({@code requiredZone} parameter).
*
* If the requiredZone parameter is null, then the filter will not be applied (returns true.)
*
* If the requiredZone parameter is not null (i.e. a filter must be applied) and the
* {@code zones}) list is {@code null} then the predicate will return false.
*
* @param zones
* @param requiredZone
* @return true if result should be included.
*/
private boolean zonePredicate(Set zones, String requiredZone)
{
if (requiredZone != null)
{
return zones != null && zones.contains(requiredZone);
}
return true;
}
private Set getAllRootAuthorities(AuthorityType authorityType)
{
Set authorities;
try
{
authorities = authorityService.getAllRootAuthorities(authorityType);
}
catch (UnknownAuthorityException e)
{
authorities = Collections.emptySet();
}
return authorities;
}
/**
* Retrieve authority info by name. Node id field isn't used at this time
* and it is set to null.
*
* @param id
* The authority name.
* @return The authority info.
*/
private AuthorityInfo getAuthorityInfo(String id)
{
return getAuthorityInfo(id, false);
}
/**
* Retrieve authority info by name. Node id field isn't used at this time
* and it is set to null.
*
* @param id
* The authority name.
* @param defaultDisplayNameIfNull
* True if we would like to get a default value (e.g. shortName of the authority) if the authority display name is null.
* @return The authority info.
*/
private AuthorityInfo getAuthorityInfo(String id, boolean defaultDisplayNameIfNull)
{
if (id == null || id.isEmpty())
{
throw new InvalidArgumentException("id is null or empty");
}
// authorityService.authorityExists(ALL_AUTHORITIES) returns false!
if (!id.equals(PermissionService.ALL_AUTHORITIES) && !authorityService.authorityExists(id))
{
throw new EntityNotFoundException(id);
}
String authorityDisplayName = getAuthorityDisplayName(id, defaultDisplayNameIfNull);
return new AuthorityInfo(null, authorityDisplayName, id);
}
private String getAuthorityDisplayName(String id, boolean defaultDisplayNameIfNull)
{
return defaultDisplayNameIfNull ? authorityService.getAuthorityDisplayName(id) : authorityDAO.getAuthorityDisplayName(id);
}
private Group getGroup(AuthorityInfo authorityInfo, List includeParam, Set rootAuthorities)
{
if (authorityInfo == null)
{
return null;
}
Group group = new Group();
group.setId(authorityInfo.getAuthorityName());
// REPO-1743
String authorityDisplayName = authorityInfo.getAuthorityDisplayName();
if (authorityDisplayName == null || authorityDisplayName.isEmpty())
{
authorityDisplayName = authorityService.getAuthorityDisplayName(authorityInfo.getAuthorityName());
}
group.setDisplayName(authorityDisplayName);
group.setIsRoot(isRootAuthority(rootAuthorities, authorityInfo.getAuthorityName()));
// Optionally include
if (includeParam != null)
{
if (includeParam.contains(PARAM_INCLUDE_PARENT_IDS))
{
String authority = authorityInfo.getAuthorityName();
Set containingAuthorities = Collections.emptySet();
// Workaround for AuthorityDAO.listAuthorities, where although AuthorityType.GUEST
// is a special case, AuthorityType.EVERYONE is not, and an exception is thrown.
if (!authority.equalsIgnoreCase(PermissionService.ALL_AUTHORITIES))
{
containingAuthorities = authorityService.getContainingAuthorities(AuthorityType.GROUP, authority, true);
}
group.setParentIds(containingAuthorities);
}
if (includeParam.contains(PARAM_INCLUDE_ZONES))
{
Set authorityZones = authorityService.getAuthorityZones(authorityInfo.getAuthorityName());
group.setZones(authorityZones);
}
}
return group;
}
private boolean isRootAuthority(Set rootAuthorities, String authorityName)
{
return rootAuthorities.contains(authorityName);
}
private Pair getGroupsSortProp(Parameters parameters)
{
Pair sortProp;
List sortCols = parameters.getSorting();
if ((sortCols != null) && (sortCols.size() > 0))
{
if (sortCols.size() > 1)
{
throw new InvalidArgumentException("Multiple sort fields not allowed.");
}
SortColumn sortCol = sortCols.get(0);
String sortPropName = SORT_PARAMS_TO_NAMES.get(sortCol.column);
if (sortPropName == null)
{
throw new InvalidArgumentException("Invalid sort field: " + sortCol.column);
}
sortProp = new Pair<>(sortPropName, (sortCol.asc ? Boolean.TRUE : Boolean.FALSE));
}
else
{
sortProp = getGroupsSortPropDefault();
}
return sortProp;
}
/**
*
* Returns the default sort order.
*
*
* @return The default Pair<QName, Boolean>
sort
* property.
*/
private Pair getGroupsSortPropDefault()
{
return new Pair<>(DISPLAY_NAME, Boolean.TRUE);
}
private class AuthorityInfoComparator implements Comparator
{
private Map nameCache;
private String sortBy;
private Collator col;
private int orderMultiplier = 1;
private AuthorityInfoComparator(String sortBy, boolean sortAsc)
{
col = AlfrescoCollator.getInstance(I18NUtil.getLocale());
this.sortBy = sortBy;
this.nameCache = new HashMap<>();
if (!sortAsc)
{
orderMultiplier = -1;
}
}
@Override
public int compare(AuthorityInfo g1, AuthorityInfo g2)
{
return col.compare(get(g1), get(g2)) * orderMultiplier;
}
private String get(AuthorityInfo g)
{
String v = nameCache.get(g);
if (v == null)
{
// Please see GetAuthoritiesCannedQuery.AuthComparator for details.
// Get the value from the group
if (DISPLAY_NAME.equals(sortBy))
{
v = g.getAuthorityDisplayName();
}
else if (SHORT_NAME.equals(sortBy))
{
v = g.getShortName();
}
else
{
throw new InvalidArgumentException("Invalid sort field: " + sortBy);
}
if (v == null)
{
v = g.getAuthorityName();
}
// // Lower case it for case insensitive search
// v = v.toLowerCase();
// Cache it
nameCache.put(g, v);
}
return v;
}
}
public void delete(String groupId, Parameters parameters)
{
if (!isGroupAuthority(groupId))
{
throw new InvalidArgumentException("Invalid group id: " + groupId);
}
// Get cascade param - default false (if not provided).
boolean cascade = Boolean.valueOf(parameters.getParameter(PARAM_CASCADE));
try
{
authorityService.deleteAuthority(groupId, cascade);
}
catch (AuthorityException ae)
{
if (ae.getMsgId().equals("Trying to modify a fixed authority"))
{
throw new ConstraintViolatedException("Trying to modify a fixed authority");
}
else
{
throw ae;
}
}
}
public CollectionWithPagingInfo getGroupMembers(String groupId, final Parameters parameters)
{
validateGroupId(groupId, false);
Paging paging = parameters.getPaging();
// Retrieve sort column. This is limited for now to sort column due to
// v0 api implementation. Should be improved in the future.
Pair sortProp = getGroupsSortProp(parameters);
AuthorityType authorityType = null;
// Parse where clause properties.
Query q = parameters.getQuery();
if (q != null)
{
MapBasedQueryWalkerOrSupported propertyWalker = new MapBasedQueryWalkerOrSupported(LIST_GROUP_MEMBERS_QUERY_PROPERTIES, null);
QueryHelper.walk(q, propertyWalker);
String memberTypeStr = propertyWalker.getProperty(PARAM_MEMBER_TYPE, WhereClauseParser.EQUALS, String.class);
authorityType = getAuthorityType(memberTypeStr);
}
PagingResults pagingResult = getAuthoritiesInfo(authorityType, groupId, sortProp, paging);
// Create response.
final List page = pagingResult.getPage();
int totalItems = pagingResult.getTotalResultCount().getFirst();
List groupMembers = new AbstractList()
{
@Override
public GroupMember get(int index)
{
AuthorityInfo authorityInfo = page.get(index);
return getGroupMember(authorityInfo);
}
@Override
public int size()
{
return page.size();
}
};
return CollectionWithPagingInfo.asPaged(paging, groupMembers, pagingResult.hasMoreItems(), totalItems);
}
@Override
public GroupMember createGroupMember(String groupId, GroupMember groupMember)
{
validateGroupId(groupId, false);
validateGroupMember(groupMember);
AuthorityType authorityType = getAuthorityType(groupMember.getMemberType());
if (!authorityService.authorityExists(groupMember.getId()))
{
throw new EntityNotFoundException(groupMember.getId());
}
AuthorityType existingAuthorityType = AuthorityType.getAuthorityType(groupMember.getId());
if (existingAuthorityType != authorityType)
{
throw new IllegalArgumentException("Incorrect group member type, "
+ (AuthorityType.USER.equals(existingAuthorityType) ? Groups.PARAM_MEMBER_TYPE_PERSON : existingAuthorityType) + " exists with the given id");
}
authorityService.addAuthority(groupId, groupMember.getId());
String authority = authorityService.getName(authorityType, groupMember.getId());
return getGroupMember(authority);
}
public void deleteGroupMembership(String groupId, String groupMemberId)
{
validateGroupId(groupId, false);
validateGroupMemberId(groupMemberId);
// TODO: Verify if groupMemberId is member of groupId
authorityService.removeAuthority(groupId, groupMemberId);
}
private AuthorityType getAuthorityType(String memberType)
{
AuthorityType authorityType = null;
if (memberType != null && !memberType.isEmpty())
{
switch (memberType)
{
case PARAM_MEMBER_TYPE_GROUP:
authorityType = AuthorityType.GROUP;
break;
case PARAM_MEMBER_TYPE_PERSON:
authorityType = AuthorityType.USER;
break;
default:
throw new InvalidArgumentException("MemberType is invalid (expected eg. GROUP, PERSON)");
}
}
return authorityType;
}
private PagingResults getAuthoritiesInfo(AuthorityType authorityType, String groupId, Pair sortProp, Paging paging)
{
Set authorities;
try
{
authorities = authorityService.findAuthorities(authorityType, groupId, true, null, null);
}
catch (UnknownAuthorityException e)
{
authorities = Collections.emptySet();
}
List authorityInfoList = new ArrayList<>(authorities.size());
authorityInfoList.addAll(authorities.stream().map(this::getAuthorityInfo).collect(Collectors.toList()));
// Post process sorting - this should be moved to service
// layer. It is done here because sorting is not supported at
// service layer.
AuthorityInfoComparator authorityComparator = new AuthorityInfoComparator(sortProp.getFirst(), sortProp.getSecond());
Collections.sort(authorityInfoList, authorityComparator);
// Post process paging - this should be moved to service layer.
return Util.wrapPagingResults(paging, authorityInfoList);
}
private GroupMember getGroupMember(AuthorityInfo authorityInfo)
{
if (authorityInfo == null)
{
return null;
}
GroupMember groupMember = new GroupMember();
groupMember.setId(authorityInfo.getAuthorityName());
String authorityDisplayName = authorityInfo.getAuthorityDisplayName();
if (authorityDisplayName == null || authorityDisplayName.isEmpty())
{
authorityDisplayName = authorityService.getAuthorityDisplayName(authorityInfo.getAuthorityName());
}
groupMember.setDisplayName(authorityDisplayName);
String memberType = null;
AuthorityType authorityType = AuthorityType.getAuthorityType(authorityInfo.getAuthorityName());
switch (authorityType)
{
case GROUP:
memberType = PARAM_MEMBER_TYPE_GROUP;
break;
case USER:
memberType = PARAM_MEMBER_TYPE_PERSON;
break;
default:
}
groupMember.setMemberType(memberType);
return groupMember;
}
private GroupMember getGroupMember(String authorityId)
{
AuthorityInfo authorityInfo = getAuthorityInfo(authorityId);
return getGroupMember(authorityInfo);
}
private void validateGroupId(String groupId, boolean inferPrefix)
{
if (groupId == null || groupId.isEmpty())
{
throw new InvalidArgumentException("groupId is null or empty");
}
if (!groupAuthorityExists(groupId, inferPrefix))
{
throw new EntityNotFoundException(groupId);
}
}
private void validateGroupMemberId(String groupMemberId)
{
if (groupMemberId == null || groupMemberId.isEmpty())
{
throw new InvalidArgumentException("group member id is null or empty");
}
if (!(personAuthorityExists(groupMemberId) || groupAuthorityExists(groupMemberId, false)))
{
throw new EntityNotFoundException(groupMemberId);
}
}
private void validateGroup(Group group, boolean isUpdate)
{
if (group == null)
{
throw new InvalidArgumentException("group is null");
}
if (!isUpdate)
{
if (group.getId() == null || group.getId().isEmpty())
{
throw new InvalidArgumentException("groupId is null or empty");
}
if (group.getId().indexOf('/') != -1)
{
throw new IllegalArgumentException("groupId contains characters that are not permitted.");
}
if (groupAuthorityExists(group.getId()))
{
throw new ConstraintViolatedException("Group '" + group.getId() + "' already exists.");
}
}
else
{
if (group.wasSet(Group.ID))
{
throw new InvalidArgumentException("Group update does not support field: id");
}
if (group.wasSet(Group.IS_ROOT))
{
throw new InvalidArgumentException("Group update does not support field: isRoot");
}
if (group.wasSet(Group.PARENT_IDS))
{
throw new InvalidArgumentException("Group update does not support field: parentIds");
}
if (group.wasSet(Group.ZONES))
{
throw new InvalidArgumentException("Group update does not support field: zones");
}
}
}
private void validateGroupMember(GroupMember groupMember)
{
if (groupMember == null)
{
throw new InvalidArgumentException("group member is null");
}
if (groupMember.getId() == null || groupMember.getId().isEmpty())
{
throw new InvalidArgumentException("group member Id is null or empty");
}
if (groupMember.getMemberType() == null || groupMember.getMemberType().isEmpty())
{
throw new InvalidArgumentException("group member type is null or empty");
}
}
private boolean groupAuthorityExists(String authorityName)
{
return groupAuthorityExists(authorityName, true);
}
private boolean groupAuthorityExists(String authorityName, boolean inferPrefix)
{
return authorityExists(AuthorityType.GROUP, authorityName, inferPrefix);
}
private boolean personAuthorityExists(String authorityName)
{
return authorityExists(AuthorityType.USER, authorityName, false);
}
private boolean authorityExists(AuthorityType authorityType, String authorityName, boolean inferPrefix)
{
String name = inferPrefix ? authorityService.getName(authorityType, authorityName) : authorityName;
return (name != null && authorityService.authorityExists(name));
}
private boolean isGroupAuthority(String authorityName)
{
AuthorityType authorityType = AuthorityType.getAuthorityType(authorityName);
return AuthorityType.GROUP.equals(authorityType) || AuthorityType.EVERYONE.equals(authorityType);
}
private static class GroupsQueryWalker extends MapBasedQueryWalker
{
private List zones;
public GroupsQueryWalker()
{
super(LIST_GROUPS_EQUALS_QUERY_PROPERTIES, null);
}
@Override
public void and()
{
// allow AND, e.g. isRoot=true AND zones in ('BLAH')
}
@Override
public void in(String propertyName, boolean negated, String... propertyValues)
{
if (propertyName.equalsIgnoreCase("zones"))
{
zones = Arrays.asList(propertyValues);
}
}
/**
* The list of zones specified in the where clause.
*
* @return The zones list if specified, or null if not.
*/
public List getZones()
{
return zones;
}
/**
* Get the value of the isRoot clause, if specified.
*
* @return The isRoot param if specified, null if not.
*/
public Boolean getIsRoot()
{
return getProperty(PARAM_IS_ROOT, WhereClauseParser.EQUALS, Boolean.class);
}
}
}