Merged 5.2.N (5.2.2) to HEAD (5.2)

134310 cturlica: REPO-1304: Create a group
      - added create group logic; fixed a sorting bug for get groups/group members; updated test framework - post/create action; fix toJSON issue for parentIds and zones.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@137338 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Andrei Rebegea
2017-06-14 16:56:42 +00:00
parent b3bfedf964
commit c3748a5ba7
8 changed files with 270 additions and 25 deletions

View File

@@ -1337,6 +1337,7 @@
<!-- --> <!-- -->
<bean id="groups" class="org.alfresco.rest.api.impl.GroupsImpl"> <bean id="groups" class="org.alfresco.rest.api.impl.GroupsImpl">
<property name="authorityService" ref="AuthorityService" /> <property name="authorityService" ref="AuthorityService" />
<property name="authorityDAO" ref="authorityDAO" />
</bean> </bean>
<bean id="Groups" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="Groups" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -47,6 +47,17 @@ public interface Groups
String PARAM_MEMBER_TYPE_GROUP = "GROUP"; String PARAM_MEMBER_TYPE_GROUP = "GROUP";
String PARAM_MEMBER_TYPE_PERSON = "PERSON"; String PARAM_MEMBER_TYPE_PERSON = "PERSON";
/**
* Create a group.
*
* @param group the group to create.
* @param parameters the {@link Parameters} object to get the parameters passed into the request
* including:
* - include param (parentIds, zones)
* @return a {@code org.alfresco.rest.api.model.Group} object
*/
Group create(Group group, Parameters parameters);
/** /**
* Get a group by it's id. * Get a group by it's id.
* *

View File

@@ -28,6 +28,8 @@ package org.alfresco.rest.api.groups;
import org.alfresco.rest.api.Groups; import org.alfresco.rest.api.Groups;
import org.alfresco.rest.api.model.Group; import org.alfresco.rest.api.model.Group;
import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.resource.EntityResource; import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction; import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
@@ -36,13 +38,16 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import java.util.ArrayList;
import java.util.List;
/** /**
* An implementation of an Entity Resource for a Group * An implementation of an Entity Resource for a Group
* *
* @author cturlica * @author cturlica
*/ */
@EntityResource(name = "groups", title = "Groups") @EntityResource(name = "groups", title = "Groups")
public class GroupsEntityResource implements EntityResourceAction.Read<Group>, EntityResourceAction.ReadById<Group>, InitializingBean public class GroupsEntityResource implements EntityResourceAction.Read<Group>, EntityResourceAction.ReadById<Group>, EntityResourceAction.Create<Group>, InitializingBean
{ {
private Groups groups; private Groups groups;
@@ -70,4 +75,15 @@ public class GroupsEntityResource implements EntityResourceAction.Read<Group>, E
{ {
return groups.getGroup(groupId, parameters); return groups.getGroup(groupId, parameters);
} }
@Override
@WebApiDescription(title="Create group", description="Create group")
@WebApiParam(name="entity", title="A single group", description="A single group, multiple groups are not supported.",
kind= ResourceParameter.KIND.HTTP_BODY_OBJECT, allowMultiple=false)
public List<Group> create(List<Group> entity, Parameters parameters)
{
List<Group> result = new ArrayList<>(1);
result.add(groups.create(entity.get(0), parameters));
return result;
}
} }

View File

@@ -42,6 +42,7 @@ import java.util.stream.Collectors;
import org.alfresco.query.CannedQueryPageDetails; import org.alfresco.query.CannedQueryPageDetails;
import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults; import org.alfresco.query.PagingResults;
import org.alfresco.repo.security.authority.AuthorityDAO;
import org.alfresco.repo.security.authority.AuthorityInfo; import org.alfresco.repo.security.authority.AuthorityInfo;
import org.alfresco.repo.security.authority.UnknownAuthorityException; import org.alfresco.repo.security.authority.UnknownAuthorityException;
import org.alfresco.rest.antlr.WhereClauseParser; import org.alfresco.rest.antlr.WhereClauseParser;
@@ -59,6 +60,7 @@ import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalkerOrSupported; import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalkerOrSupported;
import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.util.AlfrescoCollator;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.springframework.extensions.surf.util.I18NUtil; import org.springframework.extensions.surf.util.I18NUtil;
@@ -89,6 +91,7 @@ public class GroupsImpl implements Groups
private final static Set<String> LIST_GROUP_MEMBERS_QUERY_PROPERTIES = new HashSet<>(Arrays.asList(new String[] { PARAM_MEMBER_TYPE })); private final static Set<String> LIST_GROUP_MEMBERS_QUERY_PROPERTIES = new HashSet<>(Arrays.asList(new String[] { PARAM_MEMBER_TYPE }));
protected AuthorityService authorityService; protected AuthorityService authorityService;
private AuthorityDAO authorityDAO;
public AuthorityService getAuthorityService() public AuthorityService getAuthorityService()
{ {
@@ -100,6 +103,35 @@ public class GroupsImpl implements Groups
this.authorityService = authorityService; this.authorityService = authorityService;
} }
public void setAuthorityDAO(AuthorityDAO authorityDAO)
{
this.authorityDAO = authorityDAO;
}
public Group create(Group group, Parameters parameters)
{
validateGroup(group);
// Create authority with default zones.
final Set<String> authorityZones = authorityService.getDefaultZones();
String authorityDisplayName = null;
if(group.getDisplayName() != null && !group.getDisplayName().isEmpty())
{
authorityDisplayName = group.getDisplayName();
}
String authority = authorityService.createAuthority(AuthorityType.GROUP, group.getId(), authorityDisplayName, authorityZones);
// Set a given child authority to be included by the given parent
// authorities.
if (group.getParentIds() != null && !group.getParentIds().isEmpty())
{
authorityService.addAuthority(group.getParentIds(), authority);
}
return getGroup(authority, parameters);
}
public Group getGroup(String groupId, Parameters parameters) throws EntityNotFoundException public Group getGroup(String groupId, Parameters parameters) throws EntityNotFoundException
{ {
AuthorityInfo authorityInfo = getAuthorityInfo(groupId); AuthorityInfo authorityInfo = getAuthorityInfo(groupId);
@@ -243,6 +275,21 @@ public class GroupsImpl implements Groups
* @return The authority info. * @return The authority info.
*/ */
private AuthorityInfo getAuthorityInfo(String id) private AuthorityInfo getAuthorityInfo(String id)
{
return getAuthorityInfo(id, false);
}
/**
* Retrieve authority info by name. <b>Node id field isn't used at this time
* and it is set to null.</b>
*
* @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()) if (id == null || id.isEmpty())
{ {
@@ -254,11 +301,16 @@ public class GroupsImpl implements Groups
throw new EntityNotFoundException(id); throw new EntityNotFoundException(id);
} }
String authorityDisplayName = authorityService.getAuthorityDisplayName(id); String authorityDisplayName = getAuthorityDisplayName(id, defaultDisplayNameIfNull);
return new AuthorityInfo(null, authorityDisplayName, id); 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<String> includeParam, Set<String> rootAuthorities) private Group getGroup(AuthorityInfo authorityInfo, List<String> includeParam, Set<String> rootAuthorities)
{ {
if (authorityInfo == null) if (authorityInfo == null)
@@ -355,7 +407,7 @@ public class GroupsImpl implements Groups
private AuthorityInfoComparator(String sortBy, boolean sortAsc) private AuthorityInfoComparator(String sortBy, boolean sortAsc)
{ {
col = Collator.getInstance(I18NUtil.getLocale()); col = AlfrescoCollator.getInstance(I18NUtil.getLocale());
this.sortBy = sortBy; this.sortBy = sortBy;
this.nameCache = new HashMap<>(); this.nameCache = new HashMap<>();
@@ -376,6 +428,9 @@ public class GroupsImpl implements Groups
String v = nameCache.get(g); String v = nameCache.get(g);
if (v == null) if (v == null)
{ {
// Please see GetAuthoritiesCannedQuery.AuthComparator for details.
// Get the value from the group // Get the value from the group
if (DISPLAY_NAME.equals(sortBy)) if (DISPLAY_NAME.equals(sortBy))
{ {
@@ -383,15 +438,20 @@ public class GroupsImpl implements Groups
} }
else if (SHORT_NAME.equals(sortBy)) else if (SHORT_NAME.equals(sortBy))
{ {
v = g.getAuthorityName(); v = g.getShortName();
} }
else else
{ {
throw new InvalidArgumentException("Invalid sort field: " + sortBy); throw new InvalidArgumentException("Invalid sort field: " + sortBy);
} }
// Lower case it for case insensitive search if (v == null)
v = v.toLowerCase(); {
v = g.getAuthorityName();
}
// // Lower case it for case insensitive search
// v = v.toLowerCase();
// Cache it // Cache it
nameCache.put(g, v); nameCache.put(g, v);
@@ -495,7 +555,14 @@ public class GroupsImpl implements Groups
GroupMember groupMember = new GroupMember(); GroupMember groupMember = new GroupMember();
groupMember.setId(authorityInfo.getAuthorityName()); groupMember.setId(authorityInfo.getAuthorityName());
groupMember.setDisplayName(authorityInfo.getAuthorityDisplayName());
String authorityDisplayName = authorityInfo.getAuthorityDisplayName();
if (authorityDisplayName == null || authorityDisplayName.isEmpty())
{
authorityDisplayName = authorityService.getAuthorityDisplayName(authorityInfo.getAuthorityName());
}
groupMember.setDisplayName(authorityDisplayName);
String memberType = null; String memberType = null;
AuthorityType authorityType = AuthorityType.getAuthorityType(authorityInfo.getAuthorityName()); AuthorityType authorityType = AuthorityType.getAuthorityType(authorityInfo.getAuthorityName());
@@ -526,4 +593,17 @@ public class GroupsImpl implements Groups
throw new EntityNotFoundException(groupId); throw new EntityNotFoundException(groupId);
} }
} }
private void validateGroup(Group group)
{
if (group == null)
{
throw new InvalidArgumentException("group is null");
}
if (group.getId() == null || group.getId().isEmpty())
{
throw new InvalidArgumentException("groupId is null or empty");
}
}
} }

View File

@@ -32,8 +32,10 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@@ -182,6 +184,25 @@ public class GroupsTest extends AbstractSingleNetworkSiteTest
checkList(expected, respPostProcess.getPaging(), respPostProcess); checkList(expected, respPostProcess.getPaging(), respPostProcess);
} }
{
// paging
Paging paging = getPaging(0, Integer.MAX_VALUE);
Map<String, String> otherParams = new HashMap<>();
addOrderBy(otherParams, org.alfresco.rest.api.Groups.PARAM_ID, null);
// Get and sort groups using canned query.
ListResponse<Group> respCannedQuery = getGroups(paging, otherParams);
// Get and sort groups using postprocessing.
otherParams.put("where", "(isRoot=true)");
ListResponse<Group> respPostProcess = getGroups(paging, otherParams);
List<Group> expected = respCannedQuery.getList();
expected.retainAll(respPostProcess.getList());
checkList(expected, respPostProcess.getPaging(), respPostProcess);
}
// Sort by displayName. // Sort by displayName.
{ {
@@ -614,4 +635,80 @@ public class GroupsTest extends AbstractSingleNetworkSiteTest
clearAuthorityContext(); clearAuthorityContext();
} }
} }
@Test
public void testCreateGroup() throws Exception
{
final Groups groupsProxy = publicApiClient.groups();
// User without admin rights can't create a group.
{
setRequestContext(user1);
Group group = generateGroup();
groupsProxy.createGroup(group, null, HttpServletResponse.SC_FORBIDDEN);
}
// Invalid auth.
{
setRequestContext(networkOne.getId(), GUID.generate(), "password");
groupsProxy.createGroup(generateGroup(), null, HttpServletResponse.SC_UNAUTHORIZED);
}
// Create group and subgroup.
{
setRequestContext(networkOne.getId(), networkAdmin, DEFAULT_ADMIN_PWD);
Map<String, String> otherParams = new HashMap<>();
otherParams.put("include", org.alfresco.rest.api.Groups.PARAM_INCLUDE_PARENT_IDS);
Group group = generateGroup();
Group createdGroup01 = groupsProxy.createGroup(group, null, HttpServletResponse.SC_CREATED);
assertNotNull(createdGroup01);
assertNotNull(createdGroup01.getId());
assertTrue(createdGroup01.getIsRoot());
assertNull(createdGroup01.getParentIds());
Set<String> subGroup01Parents = new HashSet<>();
subGroup01Parents.add(createdGroup01.getId());
Group subGroup01 = generateGroup();
subGroup01.setParentIds(subGroup01Parents);
Group createdSubGroup01 = groupsProxy.createGroup(subGroup01, otherParams, HttpServletResponse.SC_CREATED);
assertNotNull(createdSubGroup01);
assertNotNull(createdSubGroup01.getId());
assertFalse(createdSubGroup01.getIsRoot());
assertNotNull(createdSubGroup01.getParentIds());
assertEquals(subGroup01Parents, createdSubGroup01.getParentIds());
}
// Group id is missing.
{
setRequestContext(networkOne.getId(), networkAdmin, DEFAULT_ADMIN_PWD);
Group group = new Group();
groupsProxy.createGroup(group, null, HttpServletResponse.SC_BAD_REQUEST);
}
// Id clashes with an existing group.
{
setRequestContext(networkOne.getId(), networkAdmin, DEFAULT_ADMIN_PWD);
Group group = generateGroup();
groupsProxy.createGroup(group, null, HttpServletResponse.SC_CREATED);
groupsProxy.createGroup(group, null, HttpServletResponse.SC_CONFLICT);
}
}
private Group generateGroup()
{
Group group = new Group();
group.setId("TST" + GUID.generate());
return group;
}
} }

View File

@@ -480,12 +480,23 @@ public class PublicApiClient
public HttpResponse post(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, String body) throws IOException public HttpResponse post(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, String body) throws IOException
{ {
HttpResponse response = client.post(getRequestContext(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId != null ? relationshipEntityId.toString() : null, body); HttpResponse response = client.post(getRequestContext(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId != null ? relationshipEntityId.toString() : null, body);
logger.debug(response.toString()); logger.debug(response.toString());
return response; return response;
} }
public HttpResponse post(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, String body,
final Map<String, String> params) throws IOException
{
HttpResponse response = client.post(getRequestContext(), scope, entityCollectionName, entityId, relationCollectionName,
relationshipEntityId != null ? relationshipEntityId.toString() : null, body, params);
logger.debug(response.toString());
return response;
}
public HttpResponse post(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, public HttpResponse post(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId,
String body, String contentType) throws IOException String body, String contentType) throws IOException
{ {
@@ -747,20 +758,27 @@ public class PublicApiClient
{ {
return create(entityCollectionName, entityId, relationCollectionName, relationId, body, errorMessage, HttpServletResponse.SC_CREATED); return create(entityCollectionName, entityId, relationCollectionName, relationId, body, errorMessage, HttpServletResponse.SC_CREATED);
} }
public HttpResponse create(String entityCollectionName, String entityId, String relationCollectionName, String relationId, String body, String errorMessage, int expectedStatus) throws PublicApiException public HttpResponse create(String entityCollectionName, String entityId, String relationCollectionName, String relationId, String body, String errorMessage,
{ int expectedStatus) throws PublicApiException
try {
{ return create(entityCollectionName, entityId, relationCollectionName, relationId, body, errorMessage, expectedStatus, null);
HttpResponse response = post("public", entityCollectionName, entityId, relationCollectionName, relationId, body); }
public HttpResponse create(String entityCollectionName, String entityId, String relationCollectionName, String relationId, String body, String errorMessage,
int expectedStatus, Map<String, String> params) throws PublicApiException
{
try
{
HttpResponse response = post("public", entityCollectionName, entityId, relationCollectionName, relationId, body, params);
checkStatus(errorMessage, expectedStatus, response); checkStatus(errorMessage, expectedStatus, response);
return response; return response;
} }
catch (IOException e) catch (IOException e)
{ {
throw new PublicApiException(e); throw new PublicApiException(e);
} }
} }
public HttpResponse remove(String entityCollectionName, String entityId, String relationCollectionName, String relationId, String errorMessage) throws PublicApiException public HttpResponse remove(String entityCollectionName, String entityId, String relationCollectionName, String relationId, String errorMessage) throws PublicApiException
{ {
@@ -2265,6 +2283,12 @@ public class PublicApiClient
public class Groups extends AbstractProxy public class Groups extends AbstractProxy
{ {
public Group createGroup(Group group, Map<String, String> params, int expectedStatus) throws PublicApiException
{
HttpResponse response = create("groups", null, null, null, group.toJSON().toString(), "Failed to create group " + group.getId(), expectedStatus, params);
return parseGroupEntity(response);
}
public Group getGroup(String groupId) throws PublicApiException public Group getGroup(String groupId) throws PublicApiException
{ {
return getGroup(groupId, HttpServletResponse.SC_OK); return getGroup(groupId, HttpServletResponse.SC_OK);
@@ -2278,6 +2302,11 @@ public class PublicApiClient
public Group getGroup(String groupId, Map<String, String> params, int expectedStatus) throws PublicApiException public Group getGroup(String groupId, Map<String, String> params, int expectedStatus) throws PublicApiException
{ {
HttpResponse response = getSingle("groups", groupId, null, null, params, "Failed to get group " + groupId, expectedStatus); HttpResponse response = getSingle("groups", groupId, null, null, params, "Failed to get group " + groupId, expectedStatus);
return parseGroupEntity(response);
}
private Group parseGroupEntity(HttpResponse response)
{
if ((response != null) && (response.getJsonResponse() != null)) if ((response != null) && (response.getJsonResponse() != null))
{ {
JSONObject jsonEntity = (JSONObject) response.getJsonResponse().get("entry"); JSONObject jsonEntity = (JSONObject) response.getJsonResponse().get("entry");

View File

@@ -492,16 +492,28 @@ public class PublicApiHttpClient
} }
public HttpResponse post(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId, public HttpResponse post(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, final String body, final Map<String, String> params) throws IOException
{
return post(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, body, "application/json", params);
}
public HttpResponse post(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, final String body, String contentType) throws IOException final String relationCollectionName, final Object relationshipEntityId, final String body, String contentType) throws IOException
{ {
return post(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, body, contentType); return post(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, body, contentType);
} }
public HttpResponse post(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId, public HttpResponse post(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, final String body, String contentType) throws IOException final String relationCollectionName, final Object relationshipEntityId, final String body, String contentType) throws IOException
{ {
return post(rq, scope, version, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, body, contentType, null);
}
public HttpResponse post(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, final String body, String contentType, final Map<String, String> params) throws IOException
{
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName, RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName,
relationshipEntityId, null); relationshipEntityId, params);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
PostMethod req = new PostMethod(url.toString()); PostMethod req = new PostMethod(url.toString());

View File

@@ -32,7 +32,6 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import org.alfresco.rest.api.tests.client.PublicApiClient.ExpectedPaging; import org.alfresco.rest.api.tests.client.PublicApiClient.ExpectedPaging;
import org.alfresco.rest.api.tests.client.PublicApiClient.ListResponse; import org.alfresco.rest.api.tests.client.PublicApiClient.ListResponse;
@@ -73,12 +72,12 @@ public class Group extends org.alfresco.rest.api.model.Group implements Serializ
if (getParentIds() != null) if (getParentIds() != null)
{ {
groupJson.put("parentIds", getParentIds()); groupJson.put("parentIds", new ArrayList(getParentIds()));
} }
if (getZones() != null) if (getZones() != null)
{ {
groupJson.put("zones", getZones()); groupJson.put("zones", new ArrayList(getZones()));
} }
return groupJson; return groupJson;