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/BRANCHES/DEV/5.2.N/root@134310 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Cristian Turlica
2017-01-12 16:11:40 +00:00
parent 9f34aa9f85
commit 93fc6fe945
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">
<property name="authorityService" ref="AuthorityService" />
<property name="authorityDAO" ref="authorityDAO" />
</bean>
<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_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.
*

View File

@@ -28,6 +28,8 @@ package org.alfresco.rest.api.groups;
import org.alfresco.rest.api.Groups;
import org.alfresco.rest.api.model.Group;
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.resource.EntityResource;
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.springframework.beans.factory.InitializingBean;
import java.util.ArrayList;
import java.util.List;
/**
* An implementation of an Entity Resource for a Group
*
* @author cturlica
*/
@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;
@@ -70,4 +75,15 @@ public class GroupsEntityResource implements EntityResourceAction.Read<Group>, E
{
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.PagingRequest;
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.UnknownAuthorityException;
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.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.util.AlfrescoCollator;
import org.alfresco.util.Pair;
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 }));
protected AuthorityService authorityService;
private AuthorityDAO authorityDAO;
public AuthorityService getAuthorityService()
{
@@ -100,6 +103,35 @@ public class GroupsImpl implements Groups
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
{
AuthorityInfo authorityInfo = getAuthorityInfo(groupId);
@@ -243,6 +275,21 @@ public class GroupsImpl implements Groups
* @return The authority info.
*/
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())
{
@@ -254,11 +301,16 @@ public class GroupsImpl implements Groups
throw new EntityNotFoundException(id);
}
String authorityDisplayName = authorityService.getAuthorityDisplayName(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<String> includeParam, Set<String> rootAuthorities)
{
if (authorityInfo == null)
@@ -355,7 +407,7 @@ public class GroupsImpl implements Groups
private AuthorityInfoComparator(String sortBy, boolean sortAsc)
{
col = Collator.getInstance(I18NUtil.getLocale());
col = AlfrescoCollator.getInstance(I18NUtil.getLocale());
this.sortBy = sortBy;
this.nameCache = new HashMap<>();
@@ -376,6 +428,9 @@ public class GroupsImpl implements Groups
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))
{
@@ -383,15 +438,20 @@ public class GroupsImpl implements Groups
}
else if (SHORT_NAME.equals(sortBy))
{
v = g.getAuthorityName();
v = g.getShortName();
}
else
{
throw new InvalidArgumentException("Invalid sort field: " + sortBy);
}
// Lower case it for case insensitive search
v = v.toLowerCase();
if (v == null)
{
v = g.getAuthorityName();
}
// // Lower case it for case insensitive search
// v = v.toLowerCase();
// Cache it
nameCache.put(g, v);
@@ -495,7 +555,14 @@ public class GroupsImpl implements Groups
GroupMember groupMember = new GroupMember();
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;
AuthorityType authorityType = AuthorityType.getAuthorityType(authorityInfo.getAuthorityName());
@@ -526,4 +593,17 @@ public class GroupsImpl implements Groups
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 java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
@@ -182,6 +184,25 @@ public class GroupsTest extends AbstractSingleNetworkSiteTest
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.
{
@@ -614,4 +635,80 @@ public class GroupsTest extends AbstractSingleNetworkSiteTest
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

@@ -486,6 +486,17 @@ public class PublicApiClient
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,
String body, String contentType) throws IOException
{
@@ -748,11 +759,18 @@ public class PublicApiClient
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
{
return create(entityCollectionName, entityId, relationCollectionName, relationId, body, errorMessage, expectedStatus, null);
}
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);
HttpResponse response = post("public", entityCollectionName, entityId, relationCollectionName, relationId, body, params);
checkStatus(errorMessage, expectedStatus, response);
return response;
}
@@ -2265,6 +2283,12 @@ public class PublicApiClient
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
{
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
{
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))
{
JSONObject jsonEntity = (JSONObject) response.getJsonResponse().get("entry");

View File

@@ -491,6 +491,12 @@ public class PublicApiHttpClient
return post(rq, scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, body, "application/json");
}
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
{
@@ -499,9 +505,15 @@ public class PublicApiHttpClient
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
{
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,
relationshipEntityId, null);
relationshipEntityId, params);
String url = endpoint.getUrl();
PostMethod req = new PostMethod(url.toString());

View File

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