From c3748a5ba73bd3f75febb50150900c95ea0e239f Mon Sep 17 00:00:00 2001 From: Andrei Rebegea Date: Wed, 14 Jun 2017 16:56:42 +0000 Subject: [PATCH] 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 --- config/alfresco/public-rest-context.xml | 1 + source/java/org/alfresco/rest/api/Groups.java | 11 +++ .../rest/api/groups/GroupsEntityResource.java | 18 +++- .../alfresco/rest/api/impl/GroupsImpl.java | 92 ++++++++++++++++-- .../alfresco/rest/api/tests/GroupsTest.java | 97 +++++++++++++++++++ .../api/tests/client/PublicApiClient.java | 55 ++++++++--- .../api/tests/client/PublicApiHttpClient.java | 16 ++- .../rest/api/tests/client/data/Group.java | 5 +- 8 files changed, 270 insertions(+), 25 deletions(-) diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml index bf3bc658ae..6b9b96a46b 100644 --- a/config/alfresco/public-rest-context.xml +++ b/config/alfresco/public-rest-context.xml @@ -1337,6 +1337,7 @@ + diff --git a/source/java/org/alfresco/rest/api/Groups.java b/source/java/org/alfresco/rest/api/Groups.java index c864b1d64e..927a570810 100644 --- a/source/java/org/alfresco/rest/api/Groups.java +++ b/source/java/org/alfresco/rest/api/Groups.java @@ -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. * diff --git a/source/java/org/alfresco/rest/api/groups/GroupsEntityResource.java b/source/java/org/alfresco/rest/api/groups/GroupsEntityResource.java index dfca89ab73..af478caa04 100644 --- a/source/java/org/alfresco/rest/api/groups/GroupsEntityResource.java +++ b/source/java/org/alfresco/rest/api/groups/GroupsEntityResource.java @@ -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, EntityResourceAction.ReadById, InitializingBean +public class GroupsEntityResource implements EntityResourceAction.Read, EntityResourceAction.ReadById, EntityResourceAction.Create, InitializingBean { private Groups groups; @@ -70,4 +75,15 @@ public class GroupsEntityResource implements EntityResourceAction.Read, 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 create(List entity, Parameters parameters) + { + List result = new ArrayList<>(1); + result.add(groups.create(entity.get(0), parameters)); + return result; + } } \ No newline at end of file diff --git a/source/java/org/alfresco/rest/api/impl/GroupsImpl.java b/source/java/org/alfresco/rest/api/impl/GroupsImpl.java index 08d25672a8..58489c39a9 100644 --- a/source/java/org/alfresco/rest/api/impl/GroupsImpl.java +++ b/source/java/org/alfresco/rest/api/impl/GroupsImpl.java @@ -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 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 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. 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()) { @@ -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 includeParam, Set 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"); + } + } } diff --git a/source/test-java/org/alfresco/rest/api/tests/GroupsTest.java b/source/test-java/org/alfresco/rest/api/tests/GroupsTest.java index fe2afc76e7..b37f807ead 100644 --- a/source/test-java/org/alfresco/rest/api/tests/GroupsTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/GroupsTest.java @@ -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 otherParams = new HashMap<>(); + addOrderBy(otherParams, org.alfresco.rest.api.Groups.PARAM_ID, null); + + // Get and sort groups using canned query. + ListResponse respCannedQuery = getGroups(paging, otherParams); + + // Get and sort groups using postprocessing. + otherParams.put("where", "(isRoot=true)"); + ListResponse respPostProcess = getGroups(paging, otherParams); + + List 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 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 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; + } } diff --git a/source/test-java/org/alfresco/rest/api/tests/client/PublicApiClient.java b/source/test-java/org/alfresco/rest/api/tests/client/PublicApiClient.java index ab5a7dcf95..1054fb2394 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/PublicApiClient.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/PublicApiClient.java @@ -480,12 +480,23 @@ public class PublicApiClient 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); - + logger.debug(response.toString()); return response; } + public HttpResponse post(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, String body, + final Map 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 { @@ -747,20 +758,27 @@ 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 - { - try - { - 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) 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 params) throws PublicApiException + { + try + { + HttpResponse response = post("public", entityCollectionName, entityId, relationCollectionName, relationId, body, params); checkStatus(errorMessage, expectedStatus, response); return response; - } - catch (IOException e) - { - throw new PublicApiException(e); - } - } + } + catch (IOException e) + { + throw new PublicApiException(e); + } + } 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 Group createGroup(Group group, Map 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 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"); diff --git a/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java b/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java index 84a5436516..934a560ca4 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java @@ -492,16 +492,28 @@ public class PublicApiHttpClient } 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 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 { 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, - 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 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()); diff --git a/source/test-java/org/alfresco/rest/api/tests/client/data/Group.java b/source/test-java/org/alfresco/rest/api/tests/client/data/Group.java index 075a38ec89..ba062ebba4 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/data/Group.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/data/Group.java @@ -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;