diff --git a/pom.xml b/pom.xml index 8a7f0a2a39..191d255b9b 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ ${project.build.directory}/alf_data convert - 8.232 + 8.235 8.132 8.36 diff --git a/src/main/java/org/alfresco/rest/api/Sites.java b/src/main/java/org/alfresco/rest/api/Sites.java index a543647927..15a4dbd299 100644 --- a/src/main/java/org/alfresco/rest/api/Sites.java +++ b/src/main/java/org/alfresco/rest/api/Sites.java @@ -67,6 +67,12 @@ public interface Sites String getSiteRole(String siteId); String getSiteRole(String siteId, String personId); + CollectionWithPagingInfo getSiteGroupMemberships(String siteId, Parameters parameters); + SiteGroup addSiteGroupMembership(String siteId, SiteGroup group); + SiteGroup getSiteGroupMembership(String siteId, String groupId); + SiteGroup updateSiteGroupMembership(String siteId, SiteGroup group); + void removeSiteGroupMembership(String groupId, String siteId); + String PARAM_PERMANENT = "permanent"; String PARAM_SKIP_ADDTOFAVORITES = "skipAddToFavorites"; String PARAM_SKIP_SURF_CONFIGURATION = "skipConfiguration"; diff --git a/src/main/java/org/alfresco/rest/api/groups/SiteGroupsRelation.java b/src/main/java/org/alfresco/rest/api/groups/SiteGroupsRelation.java new file mode 100644 index 0000000000..00b13af7a6 --- /dev/null +++ b/src/main/java/org/alfresco/rest/api/groups/SiteGroupsRelation.java @@ -0,0 +1,128 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api.groups; + +import org.alfresco.rest.api.Sites; +import org.alfresco.rest.api.model.SiteGroup; +import org.alfresco.rest.api.sites.SiteEntityResource; +import org.alfresco.rest.framework.WebApiDescription; +import org.alfresco.rest.framework.resource.RelationshipResource; +import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.Parameters; +import org.alfresco.util.ParameterCheck; +import org.springframework.beans.factory.InitializingBean; + +import java.util.List; +import java.util.stream.Collectors; + +@RelationshipResource(name = "group-members", entityResource = SiteEntityResource.class, title = "Site Groups") +public class SiteGroupsRelation implements RelationshipResourceAction.Read, + RelationshipResourceAction.Delete, + RelationshipResourceAction.Create, + RelationshipResourceAction.Update, + RelationshipResourceAction.ReadById, + InitializingBean +{ + + private Sites sites; + + public void setSites(Sites sites) + { + this.sites = sites; + } + + @Override + public void afterPropertiesSet() + { + ParameterCheck.mandatory("sites", this.sites); + } + + /** + * POST sites//group-members + *

+ * Adds groups to site + *

+ * If group does not exist throws NotFoundException (status 404). + * + * @see RelationshipResourceAction.Create#create(String, List, Parameters) + */ + @Override + @WebApiDescription(title = "Adds groups as a member of site siteId.") + public List create(String siteId, List siteMembers, Parameters parameters) + { + return siteMembers.stream().map((group) -> sites.addSiteGroupMembership(siteId, group)).collect(Collectors.toList()); + } + + /** + * Returns a paged list of all the groups of the site 'siteId'. + *

+ * If siteId does not exist, throws NotFoundException (status 404). + */ + @Override + @WebApiDescription(title = "A paged list of all the groups of the site 'siteId'.") + public CollectionWithPagingInfo readAll(String siteId, Parameters parameters) + { + return sites.getSiteGroupMemberships(siteId, parameters); + } + + /** + * Returns site membership information for groupId in siteId. + *

+ * GET sites//group-members/ + */ + @Override + @WebApiDescription(title = "Returns site membership information for groupId in siteId.") + public SiteGroup readById(String siteId, String groupId, Parameters parameters) + { + return sites.getSiteGroupMembership(siteId, groupId); + } + + /** + * PUT sites//group-members/ + *

+ * Updates the membership of group in the site. + */ + @Override + @WebApiDescription(title = "Updates the membership of groupId in the site.") + public SiteGroup update(String siteId, SiteGroup groupMember, Parameters parameters) + { + return sites.updateSiteGroupMembership(siteId, groupMember); + } + + /** + * DELETE sites//group-members/ + *

+ * Remove a group from site. + */ + @Override + @WebApiDescription(title = "Removes groupId as a member of site siteId.") + public void delete(String siteId, String groupId, Parameters parameters) + { + sites.removeSiteGroupMembership(siteId, groupId); + } + +} \ No newline at end of file diff --git a/src/main/java/org/alfresco/rest/api/impl/SitesImpl.java b/src/main/java/org/alfresco/rest/api/impl/SitesImpl.java index 96d4c47384..26c038914d 100644 --- a/src/main/java/org/alfresco/rest/api/impl/SitesImpl.java +++ b/src/main/java/org/alfresco/rest/api/impl/SitesImpl.java @@ -40,6 +40,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; @@ -53,11 +54,7 @@ import org.alfresco.repo.node.getchildren.FilterPropString; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authority.UnknownAuthorityException; import org.alfresco.repo.security.permissions.AccessDeniedException; -import org.alfresco.repo.site.SiteMembership; -import org.alfresco.repo.site.SiteMembershipComparator; -import org.alfresco.repo.site.SiteModel; -import org.alfresco.repo.site.SiteServiceException; -import org.alfresco.repo.site.SiteServiceImpl; +import org.alfresco.repo.site.*; import org.alfresco.rest.antlr.WhereClauseParser; import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.People; @@ -76,6 +73,7 @@ import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.SortColumn; import org.alfresco.rest.framework.resource.parameters.where.Query; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; +import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker; import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalkerOrSupported; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.favourites.FavouritesService; @@ -84,14 +82,16 @@ import org.alfresco.service.cmr.preference.PreferenceService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.site.SiteInfo; +import org.alfresco.service.cmr.site.SiteMemberInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.cmr.view.ImportPackageHandler; import org.alfresco.service.cmr.view.ImporterBinding; import org.alfresco.service.cmr.view.ImporterContentCache; -import org.alfresco.service.cmr.view.ImporterProgress; import org.alfresco.service.cmr.view.ImporterService; import org.alfresco.service.cmr.view.Location; import org.alfresco.service.namespace.QName; @@ -121,6 +121,7 @@ public class SitesImpl implements Sites private static final String SITE_ID_VALID_CHARS_PARTIAL_REGEX = "A-Za-z0-9\\-"; private static final String DEFAULT_SITE_PRESET = "site-dashboard"; + private static final String PARAM_IS_MEMBER_OF_GROUP = "isMemberOfGroup"; private final static Map SORT_PARAMS_TO_QNAMES; static @@ -146,7 +147,7 @@ public class SitesImpl implements Sites } // list children filtering (via where clause) - private final static Set LIST_SITES_EQUALS_QUERY_PROPERTIES = new HashSet<>(Arrays.asList(new String[] { PARAM_VISIBILITY, PARAM_PRESET })); + private final static Set LIST_SITES_EQUALS_QUERY_PROPERTIES = new HashSet<>(Arrays.asList(PARAM_VISIBILITY, PARAM_PRESET)); protected Nodes nodes; protected People people; @@ -159,6 +160,7 @@ public class SitesImpl implements Sites protected SiteSurfConfig siteSurfConfig; protected PermissionService permissionService; protected SiteServiceImpl siteServiceImpl; + protected AuthorityService authorityService; public void setPreferenceService(PreferenceService preferenceService) { @@ -215,6 +217,15 @@ public class SitesImpl implements Sites this.siteServiceImpl = siteServiceImpl; } + public AuthorityService getAuthorityService() + { + return authorityService; + } + + public void setAuthorityService(AuthorityService authorityService) + { + this.authorityService = authorityService; + } public SiteInfo validateSite(NodeRef guid) { @@ -267,25 +278,31 @@ public class SitesImpl implements Sites siteId = siteInfo.getShortName(); Paging paging = parameters.getPaging(); - PagingRequest pagingRequest = Util.getPagingRequest(paging); + pagingRequest.setRequestTotalCountMax(100); + + MapBasedQueryWalker propertyWalker = new MapBasedQueryWalker(new HashSet<>(Collections.singletonList(PARAM_IS_MEMBER_OF_GROUP)), null);; + QueryHelper.walk(parameters.getQuery(), propertyWalker); + + Boolean expandGroups = propertyWalker.getProperty(PARAM_IS_MEMBER_OF_GROUP, WhereClauseParser.EQUALS, Boolean.class); + + if (expandGroups == null) { + expandGroups = true; + } final List> sort = new ArrayList>(); sort.add(new Pair(SiteService.SortFields.LastName, Boolean.TRUE)); sort.add(new Pair(SiteService.SortFields.FirstName, Boolean.TRUE)); sort.add(new Pair(SiteService.SortFields.Role, Boolean.TRUE)); sort.add(new Pair(SiteService.SortFields.Username, Boolean.TRUE)); - PagingResults pagedResults = siteService.listMembersPaged(siteId, true, sort, pagingRequest); + PagingResults pagedResults = siteService.listMembersPaged(siteId, expandGroups, sort, pagingRequest); - List siteMembers = pagedResults.getPage(); - List ret = new ArrayList(siteMembers.size()); - for(SiteMembership siteMembership : siteMembers) - { - SiteMember siteMember = new SiteMember(siteMembership.getPersonId(), siteMembership.getRole()); - ret.add(siteMember); - } + List ret = pagedResults.getPage() + .stream() + .map((siteMembership) -> new SiteMember(siteMembership.getPersonId(), siteMembership.getRole(), siteMembership.isMemberOfGroup())) + .collect(Collectors.toList()); - return CollectionWithPagingInfo.asPaged(paging, ret, pagedResults.hasMoreItems(), null); + return CollectionWithPagingInfo.asPaged(paging, ret, pagedResults.hasMoreItems(), pagedResults.getTotalResultCount().getFirst()); } public String getSiteRole(String siteId) @@ -910,7 +927,7 @@ public class SitesImpl implements Sites StringBuilder prefKey = new StringBuilder(FAVOURITE_SITES_PREFIX); prefKey.append(siteId); String value = (String)preferenceService.getPreference(personId, prefKey.toString()); - boolean isFavouriteSite = (value == null ? false : value.equalsIgnoreCase("true")); + boolean isFavouriteSite = (value != null && value.equalsIgnoreCase("true")); if(isFavouriteSite) { @@ -939,7 +956,7 @@ public class SitesImpl implements Sites StringBuilder prefKey = new StringBuilder(FAVOURITE_SITES_PREFIX); prefKey.append(siteId); String value = (String)preferenceService.getPreference(personId, prefKey.toString()); - boolean isFavouriteSite = (value == null ? false : value.equalsIgnoreCase("true")); + boolean isFavouriteSite = (value != null && value.equalsIgnoreCase("true")); if(!isFavouriteSite) { @@ -1304,6 +1321,125 @@ public class SitesImpl implements Sites return null; } }; - importerService.importView(acpHandler, location, binding, (ImporterProgress)null); + importerService.importView(acpHandler, location, binding, null); + } + + @Override + public CollectionWithPagingInfo getSiteGroupMemberships(String siteId, Parameters parameters) + { + validateSite(siteId); + + PagingRequest pagingRequest = Util.getPagingRequest(parameters.getPaging()); + pagingRequest.setRequestTotalCountMax(100); + PagingResults pagedResults = siteService.listGroupMembersPaged(siteId, new ArrayList<>(), pagingRequest); + List groups = pagedResults.getPage().stream().map(siteMembership -> new SiteGroup(siteMembership.getId(), siteMembership.getRole())).collect(Collectors.toList()); + return CollectionWithPagingInfo.asPaged(parameters.getPaging(), groups, pagedResults.hasMoreItems(), pagedResults.getTotalResultCount().getFirst()); + } + + @Override + public SiteGroup addSiteGroupMembership(String siteId, SiteGroup group) + { + SiteInfo siteInfo = validateSite(siteId); + if(siteInfo == null) + { + logger.debug("Site does not exist: " + siteId); + throw new EntityNotFoundException(siteId); + } + + validateGroup(group.getId()); + + SiteMemberInfo groupInfo = siteService.getMembersRoleInfo(siteId, group.getId()); + if(groupInfo != null) + { + logger.debug("addSiteGroupMembership: "+ group.getId() + " is already a member of site " + siteId); + throw new ConstraintViolatedException(group.getId() + " is already a member of site " + siteId); + } + if(group.getRole() == null) + { + logger.debug("Getting member role but role is null"); + throw new RelationshipResourceNotFoundException(group.getId(), siteId); + } + + siteService.setMembership(siteId, group.getId(), group.getRole()); + return group; + } + + @Override + public SiteGroup getSiteGroupMembership(String siteId, String groupId) + { + SiteMemberInfo groupInfo = isMemberOfSite(siteId, groupId); + return new SiteGroup(groupId, groupInfo.getMemberRole()); + } + + @Override + public SiteGroup updateSiteGroupMembership(String siteId, SiteGroup group) + { + isMemberOfSite(siteId, group.getId()); + siteService.setMembership(siteId, group.getId(), group.getRole()); + return group; + } + + @Override + public void removeSiteGroupMembership(String siteId, String groupId) + { + isMemberOfSite(siteId, groupId); + String role = this.siteService.getMembersRole(siteId, groupId); + if(role != null) + { + if(role.equals(SiteModel.SITE_MANAGER)) + { + int numAuthorities = this.siteService.countAuthoritiesWithRole(siteId, SiteModel.SITE_MANAGER); + if(numAuthorities <= 1) + { + throw new InvalidArgumentException("Can't remove last manager of site " + siteId); + } + this.siteService.removeMembership(siteId, groupId); + } + else + { + this.siteService.removeMembership(siteId, groupId); + } + } + else + { + throw new AlfrescoRuntimeException("Unable to determine role of site member"); + } + + } + + private SiteMemberInfo isMemberOfSite(String siteId, String id) + { + + SiteInfo siteInfo = validateSite(siteId); + if(siteInfo == null) + { + logger.debug("Site does not exist: " + siteId); + throw new EntityNotFoundException(siteId); + } + + validateGroup(id); + + SiteMemberInfo memberInfo = this.siteService.getMembersRoleInfo(siteId, id); + if(memberInfo == null) + { + logger.debug("Given authority is not a member of the site"); + throw new InvalidArgumentException("Given authority is not a member of the site"); + } + if(memberInfo.getMemberRole() == null) + { + logger.debug("Getting authority role but role is null"); + throw new RelationshipResourceNotFoundException(memberInfo.getMemberName(), siteId); + } + return memberInfo; + } + + private void validateGroup(String groupId) throws EntityNotFoundException + { + String authorityName = authorityService.getName(AuthorityType.GROUP, groupId); + if(authorityName == null) + { + logger.debug("AuthorityName does not exist: " + groupId); + throw new EntityNotFoundException(groupId); + } } } diff --git a/src/main/java/org/alfresco/rest/api/model/SiteGroup.java b/src/main/java/org/alfresco/rest/api/model/SiteGroup.java new file mode 100644 index 0000000000..45b33381aa --- /dev/null +++ b/src/main/java/org/alfresco/rest/api/model/SiteGroup.java @@ -0,0 +1,143 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.alfresco.rest.api.groups.GroupsEntityResource; +import org.alfresco.rest.framework.resource.EmbeddedEntityResource; +import org.alfresco.rest.framework.resource.UniqueId; + +public class SiteGroup implements Comparable +{ + private String role; + private String id; // group id (aka authority name) + + public SiteGroup() {} + + public SiteGroup(String id, String role) + { + if (id == null) + { + throw new IllegalArgumentException(); + } + if (role == null) + { + throw new IllegalArgumentException(); + } + this.role = role; + this.id = id; + } + + public static SiteGroup getMemberOfSite(String id, String role) + { + return new SiteGroup(id, role); + } + + @JsonProperty("id") + @UniqueId + @EmbeddedEntityResource(propertyName = "group", entityResource = GroupsEntityResource.class) + public String getId() + { + return id; + } + + public String getRole() + { + return role; + } + + public void setRole(String role) + { + if (role == null) + { + throw new IllegalArgumentException(); + } + this.role = role; + } + + public void setId(String id) + { + if (id == null) + { + throw new IllegalArgumentException(); + } + this.id = id; + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + ((role == null) ? 0 : role.hashCode()); + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + + if (obj == null) + { + return false; + } + + if (getClass() != obj.getClass()) + { + return false; + } + + SiteGroup other = (SiteGroup) obj; + if (role != other.role) + { + return false; + } + + return id.equals(other.id); + } + + @Override + public int compareTo(SiteGroup o) + { + int i = id.compareTo(o.getId()); + if (i == 0) + { + i = role.compareTo(o.getRole()); + } + return i; + } + + @Override + public String toString() + { + return "SiteGroup [role='" + role + '\'' + ", id='" + id + '\'' + ", role='" + role + '\'' + "]"; + } +} \ No newline at end of file diff --git a/src/main/java/org/alfresco/rest/api/model/SiteMember.java b/src/main/java/org/alfresco/rest/api/model/SiteMember.java index 088d638c2f..f51757cba2 100644 --- a/src/main/java/org/alfresco/rest/api/model/SiteMember.java +++ b/src/main/java/org/alfresco/rest/api/model/SiteMember.java @@ -29,7 +29,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.alfresco.rest.api.people.PeopleEntityResource; import org.alfresco.rest.framework.resource.EmbeddedEntityResource; import org.alfresco.rest.framework.resource.UniqueId; -import org.alfresco.service.cmr.site.SiteRole; /** * Represents site membership. @@ -41,6 +40,7 @@ public class SiteMember { private String personId; private String role; + private boolean isMemberOfGroup; public SiteMember() { @@ -61,6 +61,22 @@ public class SiteMember this.role = role; } + public SiteMember(String personId, String role, boolean isMemberOfGroup) + { + super(); + if(personId == null) + { + throw new IllegalArgumentException(); + } + if(role == null) + { + throw new IllegalArgumentException(); + } + this.personId = personId; + this.role = role; + this.isMemberOfGroup = isMemberOfGroup; + } + @JsonProperty("id") @UniqueId @EmbeddedEntityResource(propertyName = "person", entityResource = PeopleEntityResource.class) @@ -92,6 +108,16 @@ public class SiteMember this.personId = personId; } + public void setIsMemberOfGroup(boolean isMemberOfGroup) + { + this.isMemberOfGroup = isMemberOfGroup; + } + + public boolean getIsMemberOfGroup() + { + return isMemberOfGroup; + } + @Override public int hashCode() { @@ -127,13 +153,18 @@ public class SiteMember return false; } + if (isMemberOfGroup != other.isMemberOfGroup) + { + return false; + } + return(role == other.role); } @Override public String toString() { - return "SiteMember [personId=" + personId + ", role=" + role + "]"; + return "SiteMember [personId=" + personId + ", isMemberOfGroup=" + isMemberOfGroup + ", role=" + role + "]"; } } \ No newline at end of file diff --git a/src/main/resources/alfresco/public-rest-context.xml b/src/main/resources/alfresco/public-rest-context.xml index 52542c8e1b..271c51fbf0 100644 --- a/src/main/resources/alfresco/public-rest-context.xml +++ b/src/main/resources/alfresco/public-rest-context.xml @@ -762,6 +762,7 @@ + @@ -1471,4 +1472,8 @@ + + + + diff --git a/src/test/java/org/alfresco/rest/api/tests/ApiTest.java b/src/test/java/org/alfresco/rest/api/tests/ApiTest.java index 75375d53df..5a2191b711 100644 --- a/src/test/java/org/alfresco/rest/api/tests/ApiTest.java +++ b/src/test/java/org/alfresco/rest/api/tests/ApiTest.java @@ -71,6 +71,7 @@ import org.junit.runners.Suite; GroupsTest.class, TestPeople.class, TestSiteMembers.class, + TestSiteGroups.class, TestPersonSites.class, TestSiteMembershipRequests.class, TestFavourites.class, diff --git a/src/test/java/org/alfresco/rest/api/tests/TestSiteGroups.java b/src/test/java/org/alfresco/rest/api/tests/TestSiteGroups.java new file mode 100644 index 0000000000..7cf6cc23c3 --- /dev/null +++ b/src/test/java/org/alfresco/rest/api/tests/TestSiteGroups.java @@ -0,0 +1,286 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.rest.api.tests; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.tenant.TenantUtil; +import org.alfresco.rest.api.tests.RepoService.TestSite; +import org.alfresco.rest.api.tests.client.PublicApiClient; +import org.alfresco.rest.api.tests.client.PublicApiClient.Sites; +import org.alfresco.rest.api.tests.client.PublicApiException; +import org.alfresco.rest.api.tests.client.data.SiteGroup; +import org.alfresco.rest.api.tests.client.data.SiteMember; +import org.alfresco.rest.api.tests.client.data.SiteRole; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.cmr.site.SiteVisibility; +import org.alfresco.util.GUID; +import org.apache.commons.httpclient.HttpStatus; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +public class TestSiteGroups extends AbstractBaseApiTest +{ + protected AuthorityService authorityService; + private String groupName = null; + private PublicApiClient.Paging paging = getPaging(0, 10); + private PublicApiClient.ListResponse siteMembers = null; + + @Before + public void setup() throws Exception + { + super.setup(); + authorityService = (AuthorityService) applicationContext.getBean("AuthorityService"); + } + + @Test + public void shouldCrudSiteGroups() throws Exception + { + Sites sitesProxy = publicApiClient.sites(); + try + { + groupName = createAuthorityContext(user1); + setRequestContext(networkOne.getId(), DEFAULT_ADMIN, DEFAULT_ADMIN_PWD); + + TestSite site = TenantUtil.runAsUserTenant(() -> networkOne.createSite(SiteVisibility.PRIVATE), DEFAULT_ADMIN, networkOne.getId()); + + + SiteGroup response = sitesProxy.addGroup(site.getSiteId(), new SiteGroup(groupName, SiteRole.SiteCollaborator.name())); + assertEquals(response.getGroup().getId(), groupName); + assertEquals(response.getRole(), SiteRole.SiteCollaborator.name()); + + response = sitesProxy.getGroup(site.getSiteId(), groupName); + assertEquals(response.getGroup().getId(), groupName); + assertEquals(response.getRole(), SiteRole.SiteCollaborator.name()); + + siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); + assertEquals(siteMembers.getList().size(), 3); + + Map params = new HashMap<>(1); + params.put("where", "(isMemberOfGroup=false)"); + siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, params)); + assertFalse(siteMembers.getList().get(0).isMemberOfGroup()); + assertEquals(siteMembers.getList().size(), 1); + + params = new HashMap<>(1); + params.put("where", "(isMemberOfGroup=true)"); + siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, params)); + assertEquals(siteMembers.getList().size(), 3); + + PublicApiClient.ListResponse groups = sitesProxy.getGroups(site.getSiteId(), createParams(paging, null)); + assertEquals(groups.getList().size(), 1); + assertEquals(groups.getList().get(0).getRole(), SiteRole.SiteCollaborator.name()); + + response = sitesProxy.updateGroup(site.getSiteId(), new SiteGroup(groupName, SiteRole.SiteContributor.name())); + groups = sitesProxy.getGroups(site.getSiteId(), createParams(paging, null)); + assertEquals(groups.getList().size(), 1); + assertEquals(groups.getList().get(0).getRole(), SiteRole.SiteContributor.name()); + + sitesProxy.deleteGroup(site.getSiteId(), response.getId()); + groups = sitesProxy.getGroups(site.getSiteId(), createParams(paging, null)); + assertEquals(groups.getList().size(), 0); + + siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); + assertEquals(siteMembers.getList().size(), 1); + } + finally + { + clearAuthorityContext(groupName); + } + } + + @Test + public void shouldAddGroup() throws Exception + { + Sites sitesProxy = publicApiClient.sites(); + try + { + groupName = createAuthorityContext(user1); + setRequestContext(networkOne.getId(), DEFAULT_ADMIN, DEFAULT_ADMIN_PWD); + + TestSite site = TenantUtil.runAsUserTenant(() -> networkOne.createSite(SiteVisibility.PRIVATE), DEFAULT_ADMIN, networkOne.getId()); + + // Should throw 404 error + try + { + sitesProxy.addGroup(site.getSiteId(), new SiteGroup(GUID.generate(), SiteRole.SiteCollaborator.name())); + } + catch (PublicApiException e) + { + assertEquals(HttpStatus.SC_NOT_FOUND, e.getHttpResponse().getStatusCode()); + } + + SiteGroup response = sitesProxy.addGroup(site.getSiteId(), new SiteGroup(groupName, SiteRole.SiteCollaborator.name())); + assertEquals(response.getGroup().getId(), groupName); + assertEquals(response.getRole(), SiteRole.SiteCollaborator.name()); + + // Should throw 409 error + try + { + sitesProxy.addGroup(site.getSiteId(), new SiteGroup(groupName, SiteRole.SiteCollaborator.name())); + } + catch (PublicApiException e) + { + assertEquals(HttpStatus.SC_CONFLICT, e.getHttpResponse().getStatusCode()); + } + + siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); + assertEquals(siteMembers.getList().size(), 3); + + PublicApiClient.ListResponse groups = sitesProxy.getGroups(site.getSiteId(), createParams(paging, null)); + assertEquals(groups.getList().size(), 1); + assertEquals(groups.getList().get(0).getRole(), SiteRole.SiteCollaborator.name()); + + } + finally + { + clearAuthorityContext(groupName); + } + } + + @Test + public void shouldUpdateGroup() throws Exception + { + Sites sitesProxy = publicApiClient.sites(); + try + { + groupName = createAuthorityContext(user1); + setRequestContext(networkOne.getId(), DEFAULT_ADMIN, DEFAULT_ADMIN_PWD); + + TestSite site = TenantUtil.runAsUserTenant(() -> networkOne.createSite(SiteVisibility.PRIVATE), DEFAULT_ADMIN, networkOne.getId()); + + // Should throw 400 error + try + { + sitesProxy.updateGroup(site.getSiteId(), new SiteGroup(GUID.generate(), SiteRole.SiteCollaborator.name())); + } + catch (PublicApiException e) + { + assertEquals(HttpStatus.SC_BAD_REQUEST, e.getHttpResponse().getStatusCode()); + } + + SiteGroup response = sitesProxy.addGroup(site.getSiteId(), new SiteGroup(groupName, SiteRole.SiteCollaborator.name())); + assertEquals(response.getGroup().getId(), groupName); + assertEquals(response.getRole(), SiteRole.SiteCollaborator.name()); + + response = sitesProxy.updateGroup(site.getSiteId(), new SiteGroup(groupName, SiteRole.SiteContributor.name())); + assertEquals(response.getGroup().getId(), groupName); + assertEquals(response.getRole(), SiteRole.SiteContributor.name()); + + siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); + assertEquals(siteMembers.getList().size(), 3); + assertEquals(siteMembers.getList().get(1).getRole(), SiteRole.SiteContributor.name()); + assertEquals(siteMembers.getList().get(2).getRole(), SiteRole.SiteContributor.name()); + + } + finally + { + clearAuthorityContext(groupName); + } + } + + @Test + public void shouldDeleteGroup() throws Exception + { + Sites sitesProxy = publicApiClient.sites(); + try + { + groupName = createAuthorityContext(user1); + setRequestContext(networkOne.getId(), DEFAULT_ADMIN, DEFAULT_ADMIN_PWD); + + TestSite site = TenantUtil.runAsUserTenant(() -> networkOne.createSite(SiteVisibility.PRIVATE), DEFAULT_ADMIN, networkOne.getId()); + + // Should throw 400 error + try + { + sitesProxy.updateGroup(site.getSiteId(), new SiteGroup(GUID.generate(), SiteRole.SiteCollaborator.name())); + } + catch (PublicApiException e) + { + assertEquals(HttpStatus.SC_BAD_REQUEST, e.getHttpResponse().getStatusCode()); + } + + SiteGroup response = sitesProxy.addGroup(site.getSiteId(), new SiteGroup(groupName, SiteRole.SiteCollaborator.name())); + assertEquals(response.getGroup().getId(), groupName); + assertEquals(response.getRole(), SiteRole.SiteCollaborator.name()); + + siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); + assertEquals(siteMembers.getList().size(), 3); + + sitesProxy.deleteGroup(site.getSiteId(), response.getId()); + + siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); + assertEquals(siteMembers.getList().size(), 1); + } + finally + { + clearAuthorityContext(groupName); + } + } + + private String createAuthorityContext(String userName) throws PublicApiException + { + String groupName = "Test_GroupA" + GUID.generate(); + AuthenticationUtil.setRunAsUser(userName); + + groupName = authorityService.getName(AuthorityType.GROUP, groupName); + + if (!authorityService.authorityExists(groupName)) + { + AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); + + groupName = authorityService.createAuthority(AuthorityType.GROUP, groupName); + authorityService.setAuthorityDisplayName(groupName, "Test Group A"); + } + + + authorityService.addAuthority(groupName, user1); + authorityService.addAuthority(groupName, user2); + + return groupName; + } + + private void clearAuthorityContext(String groupName) + { + if (groupName != null && authorityService.authorityExists(groupName)) + { + AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); + authorityService.deleteAuthority(groupName, true); + } + } + + @Override + public String getScope() + { + return "public"; + } +} diff --git a/src/test/java/org/alfresco/rest/api/tests/TestSiteMembers.java b/src/test/java/org/alfresco/rest/api/tests/TestSiteMembers.java index 7ef6e0c2fc..33b0cedbe8 100644 --- a/src/test/java/org/alfresco/rest/api/tests/TestSiteMembers.java +++ b/src/test/java/org/alfresco/rest/api/tests/TestSiteMembers.java @@ -105,7 +105,7 @@ public class TestSiteMembers extends EnterpriseTestApi { int skipCount = 0; int maxItems = 2; - Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), null); + Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), 6); publicApiClient.setRequestContext(new RequestContext(testNetwork.getId(), personId)); ListResponse siteMembers = sitesProxy.getSiteMembers(testSite.getSiteId(), createParams(paging, null)); checkList(expectedSiteMembers.subList(skipCount, skipCount + paging.getExpectedPaging().getCount()), paging.getExpectedPaging(), siteMembers); @@ -114,7 +114,7 @@ public class TestSiteMembers extends EnterpriseTestApi { int skipCount = 2; int maxItems = 10; - Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), null); + Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), 6); publicApiClient.setRequestContext(new RequestContext(testNetwork.getId(), personId)); ListResponse siteMembers = sitesProxy.getSiteMembers(testSite.getSiteId(), createParams(paging, null)); checkList(expectedSiteMembers.subList(skipCount, skipCount + paging.getExpectedPaging().getCount()), paging.getExpectedPaging(), siteMembers); @@ -132,7 +132,7 @@ public class TestSiteMembers extends EnterpriseTestApi { int skipCount = 2; int maxItems = 10; - Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), null); + Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), 6); publicApiClient.setRequestContext(new RequestContext(testNetwork.getId(), personId)); sitesProxy.getSiteMembers(GUID.generate(), createParams(paging, null)); fail(); @@ -415,7 +415,7 @@ public class TestSiteMembers extends EnterpriseTestApi { int skipCount = 0; int maxItems = Integer.MAX_VALUE; - Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), null); + Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), 2); ListResponse siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); checkList(expectedSiteMembers.subList(skipCount, skipCount + paging.getExpectedPaging().getCount()), paging.getExpectedPaging(), siteMembers); } @@ -559,7 +559,7 @@ public class TestSiteMembers extends EnterpriseTestApi { int skipCount = 0; int maxItems = Integer.MAX_VALUE; - Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), null); + Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), 2); publicApiClient.setRequestContext(new RequestContext(network1.getId(), person2.getId())); ListResponse siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); checkList(expectedSiteMembers.subList(skipCount, skipCount + paging.getExpectedPaging().getCount()), paging.getExpectedPaging(), siteMembers); @@ -658,7 +658,7 @@ public class TestSiteMembers extends EnterpriseTestApi int skipCount = 0; int maxItems = Integer.MAX_VALUE; - Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), null); + Paging paging = getPaging(skipCount, maxItems, expectedSiteMembers.size(), 3); publicApiClient.setRequestContext(new RequestContext(network1.getId(), person2.getId())); ListResponse siteMembers = sitesProxy.getSiteMembers(site.getSiteId(), createParams(paging, null)); checkList(expectedSiteMembers.subList(skipCount, skipCount + paging.getExpectedPaging().getCount()), paging.getExpectedPaging(), siteMembers); diff --git a/src/test/java/org/alfresco/rest/api/tests/client/PublicApiClient.java b/src/test/java/org/alfresco/rest/api/tests/client/PublicApiClient.java index aeb5315610..c72398ba15 100644 --- a/src/test/java/org/alfresco/rest/api/tests/client/PublicApiClient.java +++ b/src/test/java/org/alfresco/rest/api/tests/client/PublicApiClient.java @@ -74,6 +74,7 @@ import org.alfresco.rest.api.tests.client.data.Site; import org.alfresco.rest.api.tests.client.data.SiteContainer; import org.alfresco.rest.api.tests.client.data.SiteImpl; import org.alfresco.rest.api.tests.client.data.SiteMember; +import org.alfresco.rest.api.tests.client.data.SiteGroup; import org.alfresco.rest.api.tests.client.data.SiteMembershipRequest; import org.alfresco.rest.api.tests.client.data.Tag; import org.alfresco.rest.api.tests.util.RestApiUtil; @@ -1132,6 +1133,35 @@ public class PublicApiClient { remove("people", personId, "favorite-sites", site.getSiteId(), "Failed to remove favourite site"); } + + public SiteGroup addGroup(String siteId, SiteGroup group) throws PublicApiException + { + HttpResponse response = create("sites", siteId, "group-members", null, group.toJSON().toString() , "Failed to add site groups"); + return SiteGroup.parseSiteGroup(siteId, (JSONObject)response.getJsonResponse().get("entry")); + } + + public ListResponse getGroups(String siteId, Map params) throws PublicApiException + { + HttpResponse response = getAll("sites", siteId, "group-members", null, params, "Failed to fetch all site groups"); + return SiteGroup.parseGroupMemberOfSites(siteId, response.getJsonResponse()); + } + + public SiteGroup getGroup(String siteId, String groupId) throws PublicApiException + { + HttpResponse response = getSingle("sites", siteId, "group-members", groupId.toString() , "Failed to get a site group"); + return SiteGroup.parseSiteGroup(siteId, (JSONObject)response.getJsonResponse().get("entry")); + } + + public SiteGroup updateGroup(String siteId, SiteGroup group) throws PublicApiException + { + HttpResponse response = update("sites", siteId, "group-members", group.getId(), group.toJSON().toString() , "Failed to update a site group"); + return SiteGroup.parseSiteGroup(siteId, (JSONObject)response.getJsonResponse().get("entry")); + } + + public void deleteGroup(String siteId, String groupId) throws PublicApiException + { + remove("sites", siteId, "group-members", groupId , "Failed to delete site group"); + } } public class SiteMembershipRequests extends AbstractProxy diff --git a/src/test/java/org/alfresco/rest/api/tests/client/data/SiteGroup.java b/src/test/java/org/alfresco/rest/api/tests/client/data/SiteGroup.java new file mode 100644 index 0000000000..862cc4c834 --- /dev/null +++ b/src/test/java/org/alfresco/rest/api/tests/client/data/SiteGroup.java @@ -0,0 +1,208 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.rest.api.tests.client.data; + +import org.alfresco.rest.api.tests.client.PublicApiClient; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import java.io.Serializable; +import java.text.Collator; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class SiteGroup implements Serializable, ExpectedComparison, Comparable +{ + private static final long serialVersionUID = 505331886661880399L; + + private String role; + private String id; // group id (aka authority name) + private Group group; + + public SiteGroup() + { + super(); + } + + public SiteGroup(String id, String role) + { + this.role = role; + this.id = id; + } + + public SiteGroup(String id, Group group, String role) + { + this.role = role; + this.id = id; + this.group = group; + } + + public String getRole() + { + return role; + } + + public void setRole(String role) + { + this.role = role; + } + + public String getId() + { + return id; + } + + public void setId(String id) + { + this.id = id; + } + + public Group getGroup() + { + return group; + } + + public void setGroup(Group group) + { + this.group = group; + } + + public Collator getCollator() + { + return collator; + } + + public void setCollator(Collator collator) + { + this.collator = collator; + } + + public static SiteGroup parseSiteGroup(String siteId, JSONObject jsonObject) + { + String id = (String)jsonObject.get("id"); + String role = (String)jsonObject.get("role"); + JSONObject personJSON = (JSONObject)jsonObject.get("group"); + Group group = Group.parseGroup(personJSON); + SiteGroup siteMember = new SiteGroup(id, group, role); + return siteMember; + } + + public static PublicApiClient.ListResponse parseGroupMemberOfSites(String siteId, JSONObject jsonObject) + { + List groups = new ArrayList(); + + JSONObject jsonList = (JSONObject)jsonObject.get("list"); + assertNotNull(jsonList); + + JSONArray jsonEntries = (JSONArray)jsonList.get("entries"); + assertNotNull(jsonEntries); + + for(int i = 0; i < jsonEntries.size(); i++) + { + JSONObject jsonEntry = (JSONObject)jsonEntries.get(i); + JSONObject entry = (JSONObject)jsonEntry.get("entry"); + groups.add(parseSiteGroup(siteId, entry)); + } + + PublicApiClient.ExpectedPaging paging = PublicApiClient.ExpectedPaging.parsePagination(jsonList); + return new PublicApiClient.ListResponse(paging, groups); + } + + @SuppressWarnings("unchecked") + public JSONObject toJSON() + { + JSONObject entry = new JSONObject(); + + if (getId() != null) + { + entry.put("id", getId()); + } + + if (getRole() != null) + { + entry.put("role", getRole()); + } + + return entry; + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result; + result = prime * result + ((role == null) ? 0 : role.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SiteGroup other = (SiteGroup) obj; + if (getId() == null) + { + if (other.getId() != null) + return false; + } else if (!getId().equals(other.getId())) + return false; + if (role == null) + { + if (other.role != null) + return false; + } else if (!role.equals(other.role)) + return false; + return true; + } + + @Override + public void expected(Object o) + { + assertTrue(o instanceof SiteGroup); + SiteGroup other = (SiteGroup)o; + AssertUtil.assertEquals("id", getId(), other.getId()); + } + + private Collator collator = Collator.getInstance(); + + @Override + public int compareTo(SiteGroup o) + { + String displayName = group.getDisplayName(); + return collator.compare(displayName, o.getGroup().getDisplayName()); + } + +} diff --git a/src/test/java/org/alfresco/rest/api/tests/client/data/SiteMember.java b/src/test/java/org/alfresco/rest/api/tests/client/data/SiteMember.java index 57ed044a5a..d5ae8299bb 100644 --- a/src/test/java/org/alfresco/rest/api/tests/client/data/SiteMember.java +++ b/src/test/java/org/alfresco/rest/api/tests/client/data/SiteMember.java @@ -51,6 +51,7 @@ public class SiteMember implements Serializable, ExpectedComparison, Comparable< private String siteId; private String role; private Status status; + private boolean isMemberOfGroup; public SiteMember() { @@ -75,6 +76,15 @@ public class SiteMember implements Serializable, ExpectedComparison, Comparable< this.role = role; } + public SiteMember(String memberId, Person member, String siteId, String role, boolean isMemberOfGroup) + { + this.memberId = memberId; + this.member = member; + this.siteId = siteId; + this.role = role; + this.isMemberOfGroup = isMemberOfGroup; + } + public String getMemberId() { return memberId; @@ -120,22 +130,32 @@ public class SiteMember implements Serializable, ExpectedComparison, Comparable< return role; } + public boolean isMemberOfGroup() + { + return isMemberOfGroup; + } + + public void setMemberOfGroup(boolean memberOfGroup) + { + isMemberOfGroup = memberOfGroup; + } + @Override public String toString() { return "SiteMember [memberId=" + memberId + ", member=" + member + ", siteId=" + siteId + ", role=" + role + ", status=" - + status + "]"; + + status + ", isMemberOfGroup=" + isMemberOfGroup + "]"; } public static SiteMember parseSiteMember(String siteId, JSONObject jsonObject) { String id = (String)jsonObject.get("id"); String role = (String)jsonObject.get("role"); + boolean isMemberOfGroup = (boolean)jsonObject.get("isMemberOfGroup"); JSONObject personJSON = (JSONObject)jsonObject.get("person"); Person member = Person.parsePerson(personJSON); - SiteMember siteMember = new SiteMember(id, member, siteId, role); - return siteMember; + return new SiteMember(id, member, siteId, role, isMemberOfGroup); } public static ListResponse parseSiteMembers(String siteId, JSONObject jsonObject)