diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestGroupsModel.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestGroupsModel.java index ec8c28b1058..c126ac72cff 100644 --- a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestGroupsModel.java +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestGroupsModel.java @@ -25,7 +25,7 @@ */ package org.alfresco.rest.model; -import java.util.ArrayList; +import java.util.List; import com.fasterxml.jackson.annotation.JsonProperty; @@ -38,13 +38,17 @@ public class RestGroupsModel extends TestModel implements IRestModel parentIds; + private List parentIds; @JsonProperty("zones") - private ArrayList zones; + private List zones; @JsonProperty(value = "entry") RestGroupsModel model; @@ -75,6 +79,22 @@ public void setDisplayName(String displayName) this.displayName = displayName; } + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean getHasSubgroups() { + return hasSubgroups; + } + + public void setHasSubgroups(Boolean hasSubgroups) { + this.hasSubgroups = hasSubgroups; + } + public Boolean getIsRoot() { return isRoot; @@ -85,22 +105,22 @@ public void setIsRoot(Boolean isRoot) this.isRoot = isRoot; } - public ArrayList getParentIds() + public List getParentIds() { return parentIds; } - public void setParentIds(ArrayList parentIds) + public void setParentIds(List parentIds) { this.parentIds = parentIds; } - public ArrayList getZones() + public List getZones() { return zones; } - public void setZones(ArrayList zones) + public void setZones(List zones) { this.zones = zones; } diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/groups/GroupsTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/groups/GroupsTests.java index 80442c84cb1..270dba45057 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/groups/GroupsTests.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/groups/GroupsTests.java @@ -31,44 +31,73 @@ public void dataPreparation() throws Exception @Test(groups = { TestGroup.REST_API, TestGroup.GROUPS, TestGroup.SANITY }) @TestRail(section = { TestGroup.REST_API, TestGroup.NODES }, executionType = ExecutionType.SANITY, description = "Verify creation, listing, updating and deletion of groups.") - public void createListUpdateAndDeleteGroup() throws Exception + public void createListUpdateAndDeleteGroup() { - String groupName = "ZtestGroup" + UUID.randomUUID().toString(); - JsonObject groupBody = Json.createObjectBuilder().add("id", groupName).add("displayName", groupName).build(); + String groupName = "ZtestGroup" + UUID.randomUUID(); + String subGroupName = "ZtestSubgroup" + UUID.randomUUID(); + String groupDescription = "ZtestGroup description" + UUID.randomUUID(); + JsonObject groupBody = Json.createObjectBuilder().add("id", groupName).add("displayName", groupName).add("description", groupDescription).build(); + JsonObject subgroupBody = Json.createObjectBuilder().add("id", subGroupName).add("displayName", subGroupName).build(); String groupBodyCreate = groupBody.toString(); + String subgroupBodyCreate = subgroupBody.toString(); //GroupCreation: //-ve restClient.authenticateUser(userModel).withCoreAPI().usingGroups().createGroup(groupBodyCreate); restClient.assertStatusCodeIs(HttpStatus.FORBIDDEN); //+ve - restClient.authenticateUser(adminUser).withCoreAPI().usingParams("include=zones").usingGroups().createGroup(groupBodyCreate) + restClient.authenticateUser(adminUser).withCoreAPI().usingParams("include=zones,hasSubgroups,description").usingGroups().createGroup(groupBodyCreate) .assertThat().field("zones").contains("APP.DEFAULT") .and().field("isRoot").is(true) - .and().field("displayName").is(groupName); + .and().field("displayName").is(groupName) + .and().field("description").is(groupDescription) + .and().field("hasSubgroups").is(false); + restClient.assertStatusCodeIs(HttpStatus.CREATED); + + //AddChildGroup + restClient.authenticateUser(adminUser).withCoreAPI().usingParams("include=zones").usingGroups().createGroup(subgroupBodyCreate); + restClient.assertStatusCodeIs(HttpStatus.CREATED); + + //LinkChildGroupToParent + JsonObject groupMembershipGroupBody = Json.createObjectBuilder().add("id", "GROUP_"+subGroupName).add("memberType", "GROUP").build(); + String groupMembershipGroupBodyCreate = groupMembershipGroupBody.toString(); + restClient.authenticateUser(adminUser).withCoreAPI().usingGroups().createGroupMembership("GROUP_"+groupName, groupMembershipGroupBodyCreate); restClient.assertStatusCodeIs(HttpStatus.CREATED); //ListGroups: restClient.withCoreAPI().usingParams("orderBy=displayName DESC&maxItems=10").usingGroups().listGroups() .assertThat().entriesListContains("id", "GROUP_"+groupName) + .and().entriesListContains("id", "GROUP_"+subGroupName) .and().entriesListDoesNotContain("zones") .and().paginationField("maxItems").is("10"); restClient.assertStatusCodeIs(HttpStatus.OK); - groupBody = Json.createObjectBuilder().add("displayName", "Z"+groupName).build(); + groupBody = Json.createObjectBuilder().add("displayName", "Z"+groupName).add("description", "Z"+groupDescription).build(); String groupBodyUpdate = groupBody.toString(); //UpdateGroup: - restClient.withCoreAPI().usingGroups().updateGroupDetails("GROUP_"+groupName, groupBodyUpdate) + restClient.withCoreAPI().usingParams("include=description").usingGroups().updateGroupDetails("GROUP_"+groupName, groupBodyUpdate) .assertThat().field("displayName").is("Z"+groupName) + .and().field("description").is("Z"+groupDescription) .and().field("id").is("GROUP_"+groupName) .and().field("zones").isNull(); restClient.assertStatusCodeIs(HttpStatus.OK); //GetGroupDetails: - restClient.withCoreAPI().usingParams("include=zones").usingGroups().getGroupDetail("GROUP_"+groupName) + restClient.withCoreAPI().usingParams("include=zones,hasSubgroups").usingGroups().getGroupDetail("GROUP_"+groupName) .assertThat().field("id").is("GROUP_"+groupName) .and().field("zones").contains("APP.DEFAULT") - .and().field("isRoot").is(true); + .and().field("isRoot").is(true) + .and().field("hasSubgroups").is(true); + restClient.assertStatusCodeIs(HttpStatus.OK); + + //DeleteChildGroup: + restClient.authenticateUser(adminUser).withCoreAPI().usingGroups().deleteGroup("GROUP_"+subGroupName); + restClient.assertStatusCodeIs(HttpStatus.NO_CONTENT); + + //VerifyIfParentHasNoSubgroups: + restClient.withCoreAPI().usingParams("include=zones,hasSubgroups").usingGroups().getGroupDetail("GROUP_"+groupName) + .assertThat().field("id").is("GROUP_"+groupName) + .and().field("hasSubgroups").is(false); restClient.assertStatusCodeIs(HttpStatus.OK); //DeleteGroup: @@ -83,9 +112,9 @@ public void createListUpdateAndDeleteGroup() throws Exception @Test(groups = { TestGroup.REST_API, TestGroup.GROUPS, TestGroup.SANITY }) @TestRail(section = { TestGroup.REST_API, TestGroup.NODES }, executionType = ExecutionType.SANITY, description = "Verify creation, listing(only for person) and deletion of group memberships. ") - public void createListDeleteGroupMembership() throws Exception + public void createListDeleteGroupMembership() { - String groupName = "ZtestGroup" + UUID.randomUUID().toString(); + String groupName = "ZtestGroup" + UUID.randomUUID(); JsonObject groupBody = Json.createObjectBuilder().add("id", groupName).add("displayName", groupName).build(); String groupBodyCreate = groupBody.toString(); @@ -95,6 +124,7 @@ public void createListDeleteGroupMembership() throws Exception JsonObject groupMembershipBody = Json.createObjectBuilder().add("id", userModel.getUsername()).add("memberType", "PERSON").build(); String groupMembershipBodyCreate = groupMembershipBody.toString(); + //MembershipCreation: //-ve restClient.authenticateUser(userModel).withCoreAPI().usingGroups().createGroupMembership("GROUP_"+groupName, groupMembershipBodyCreate); @@ -127,7 +157,7 @@ public void createListDeleteGroupMembership() throws Exception description = "Verify listing of group memberships.") public void listGroupMembership() throws Exception { - String groupName = "testGroup" + UUID.randomUUID().toString(); + String groupName = "testGroup" + UUID.randomUUID(); JsonObject groupBody = Json.createObjectBuilder().add("id", groupName).add("displayName", groupName).build(); String groupBodyCreate = groupBody.toString(); @@ -146,12 +176,10 @@ public void listGroupMembership() throws Exception restClient.assertStatusCodeIs(HttpStatus.CREATED); //ListGroupMembership - RetryOperation op = new RetryOperation(){ - public void execute() throws Exception{ - restClient.withCoreAPI().usingGroups().listGroupMemberships("GROUP_"+groupName) - .assertThat().entriesListContains("id", userModel.getUsername()); - restClient.assertStatusCodeIs(HttpStatus.OK); - } + RetryOperation op = () -> { + restClient.withCoreAPI().usingGroups().listGroupMemberships("GROUP_"+groupName) + .assertThat().entriesListContains("id", userModel.getUsername()); + restClient.assertStatusCodeIs(HttpStatus.OK); }; Utility.sleep(500, 35000, op);// Allow indexing to complete. } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/Groups.java b/remote-api/src/main/java/org/alfresco/rest/api/Groups.java index 53eb2203875..58b6d13aa8e 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/Groups.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/Groups.java @@ -40,8 +40,10 @@ public interface Groups { String PARAM_ID = "id"; String PARAM_DISPLAY_NAME = "displayName"; + String PARAM_INCLUDE_DESCRIPTION = "description"; String PARAM_INCLUDE_PARENT_IDS = "parentIds"; String PARAM_INCLUDE_ZONES = "zones"; + String PARAM_INCLUDE_HAS_SUBGROUPS = "hasSubgroups"; String PARAM_IS_ROOT = "isRoot"; String PARAM_CASCADE = "cascade"; String PARAM_MEMBER_TYPE = "memberType"; diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/GroupsImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/GroupsImpl.java index 784de7be2bd..d291b1293b6 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/GroupsImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/GroupsImpl.java @@ -27,6 +27,7 @@ import static org.alfresco.repo.security.authentication.AuthenticationUtil.runAsSystem; +import java.io.Serializable; import java.text.Collator; import java.util.AbstractList; import java.util.ArrayList; @@ -40,6 +41,7 @@ import java.util.Set; import java.util.stream.Collectors; +import org.alfresco.model.ContentModel; import org.alfresco.query.CannedQueryPageDetails; import org.alfresco.query.EmptyPagingResults; import org.alfresco.query.PagingRequest; @@ -71,8 +73,10 @@ 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.namespace.QName; import org.alfresco.util.AlfrescoCollator; import org.alfresco.util.Pair; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.extensions.surf.util.I18NUtil; @@ -101,9 +105,9 @@ public class GroupsImpl implements Groups } // List groups filtering (via where clause) - private final static Set LIST_GROUPS_EQUALS_QUERY_PROPERTIES = new HashSet<>(Arrays.asList(new String[] { PARAM_IS_ROOT })); + private final static Set LIST_GROUPS_EQUALS_QUERY_PROPERTIES = new HashSet<>(List.of(PARAM_IS_ROOT)); - private final static Set LIST_GROUP_MEMBERS_QUERY_PROPERTIES = new HashSet<>(Arrays.asList(new String[] { PARAM_MEMBER_TYPE })); + private final static Set LIST_GROUP_MEMBERS_QUERY_PROPERTIES = new HashSet<>(List.of(PARAM_MEMBER_TYPE)); protected AuthorityService authorityService; private AuthorityDAO authorityDAO; @@ -142,7 +146,12 @@ public Group create(Group group, Parameters parameters) authorityDisplayName = group.getDisplayName(); } - String authority = authorityService.createAuthority(AuthorityType.GROUP, group.getId(), authorityDisplayName, authorityZones); + Map props = new HashMap<>(); + if (StringUtils.isNotEmpty(group.getDescription())) + { + props.put(ContentModel.PROP_DESCRIPTION, group.getDescription()); + } + String authority = authorityService.createAuthority(AuthorityType.GROUP, group.getId(), authorityDisplayName, authorityZones, props); // Set a given child authority to be included by the given parent // authorities. @@ -161,7 +170,14 @@ public Group update(String groupId, Group group, Parameters parameters) try { - authorityService.setAuthorityDisplayName(groupId, group.getDisplayName()); + if (StringUtils.isNotEmpty(group.getDescription())) + { + authorityService.setAuthorityDisplayNameAndDescription(groupId, group.getDisplayName(), group.getDescription()); + } + else + { + authorityService.setAuthorityDisplayName(groupId, group.getDisplayName()); + } } catch (AuthorityException ae) { @@ -173,10 +189,10 @@ public Group update(String groupId, Group group, Parameters parameters) public Group getGroup(String groupId, Parameters parameters) throws EntityNotFoundException { - AuthorityInfo authorityInfo = getAuthorityInfo(groupId); + final List includeParam = parameters.getInclude(); + AuthorityInfo authorityInfo = getAuthorityInfo(groupId, includeParam.contains(PARAM_INCLUDE_DESCRIPTION)); final Set rootAuthorities = getAllRootAuthorities(AuthorityType.GROUP); - final List includeParam = parameters.getInclude(); return getGroup(authorityInfo, includeParam, rootAuthorities); } @@ -196,7 +212,7 @@ public CollectionWithPagingInfo getGroups(final Parameters parameters) PagingResults pagingResult; try { - pagingResult = getAuthoritiesInfo(authorityType, groupsFilters, rootAuthorities, sortProp, paging); + pagingResult = getAuthoritiesInfo(authorityType, groupsFilters, rootAuthorities, sortProp, paging, parameters.getInclude().contains(PARAM_INCLUDE_DESCRIPTION)); } catch (UnknownAuthorityException e) { @@ -213,7 +229,7 @@ public CollectionWithPagingInfo getGroups(final Parameters parameters) private List createGroupsResponse(final List page, final List includeParam, final Set rootAuthorities) { - List groups = new AbstractList() + List groups = new AbstractList<>() { @Override public Group get(int index) @@ -336,7 +352,7 @@ public CollectionWithPagingInfo getGroupsByPersonId(String requestedPerso filter(a -> a.startsWith(AuthorityType.GROUP.getPrefixString())). filter(a -> isRootPredicate(finalIsRootParam, rootAuthorities, a)). filter(a -> zonePredicate(a, finalZoneFilter)). - map(this::getAuthorityInfo). + map(a -> getAuthorityInfo(a, includeParam.contains(PARAM_INCLUDE_DESCRIPTION))). sorted(new AuthorityInfoComparator(sortProp.getFirst(), sortProp.getSecond())). collect(Collectors.toList()); @@ -355,23 +371,25 @@ public CollectionWithPagingInfo getGroupsByPersonId(String requestedPerso } private PagingResults getAuthoritiesInfo(AuthorityType authorityType, GroupsFilter groupsFilter, Set rootAuthorities, - Pair sortProp, Paging paging) + Pair sortProp, Paging paging, boolean includeDescription) { Boolean isRootParam = groupsFilter.getIsRoot(); String zoneFilter = groupsFilter.getZoneFilter(); String displayNameFilter = groupsFilter.getDisplayNameFilter(); PagingResults pagingResult; - if (isRootParam != null || displayNameFilter != null) + // Don't use canned queries when fetching authorities with description + // if better performance is requested for loading descriptions we can add canned queries in the future + if (isRootParam != null || displayNameFilter != null || includeDescription) { List groupList; - if (isRootParam != null && isRootParam) + if ((isRootParam != null && isRootParam) || includeDescription) { // Limit the post processing work by using the already loaded // list of root authorities. List authorities = rootAuthorities.stream(). - map(this::getAuthorityInfo). + map(auth -> getAuthorityInfo(auth, includeDescription)). filter(auth -> zonePredicate(auth.getAuthorityName(), zoneFilter)). filter(auth -> displayNamePredicate(auth.getAuthorityDisplayName(), displayNameFilter)). collect(Collectors.toList()); @@ -526,9 +544,9 @@ private Set getAllRootAuthorities(AuthorityType authorityType) * The authority name. * @return The authority info. */ - private AuthorityInfo getAuthorityInfo(String id) + private AuthorityInfo getAuthorityInfo(String id, boolean includeDescription) { - return getAuthorityInfo(id, false); + return getAuthorityInfo(id, includeDescription, false); } /** @@ -537,11 +555,13 @@ private AuthorityInfo getAuthorityInfo(String id) * * @param id * The authority name. + * @param includeDescription + * True if description should be loaded * @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) + private AuthorityInfo getAuthorityInfo(String id, boolean includeDescription, boolean defaultDisplayNameIfNull) { if (id == null || id.isEmpty()) { @@ -554,9 +574,20 @@ private AuthorityInfo getAuthorityInfo(String id, boolean defaultDisplayNameIfNu throw new EntityNotFoundException(id); } - String authorityDisplayName = getAuthorityDisplayName(id, defaultDisplayNameIfNull); + String authorityDisplayName; + String description = null; - return new AuthorityInfo(null, authorityDisplayName, id); + if (includeDescription) + { + Pair displayNameAndDescription = getAuthorityDisplayNameAndDescription(id, defaultDisplayNameIfNull); + authorityDisplayName = displayNameAndDescription.getFirst(); + description = displayNameAndDescription.getSecond(); + } + else + { + authorityDisplayName = getAuthorityDisplayName(id, defaultDisplayNameIfNull); + } + return new AuthorityInfo(null, authorityDisplayName, id, description); } private String getAuthorityDisplayName(String id, boolean defaultDisplayNameIfNull) @@ -564,6 +595,11 @@ private String getAuthorityDisplayName(String id, boolean defaultDisplayNameIfNu return defaultDisplayNameIfNull ? authorityService.getAuthorityDisplayName(id) : authorityDAO.getAuthorityDisplayName(id); } + private Pair getAuthorityDisplayNameAndDescription(String id, boolean defaultDisplayNameIfNull) + { + return defaultDisplayNameIfNull ? authorityService.getAuthorityDisplayNameAndDescription(id) : authorityDAO.getAuthorityDisplayNameAndDescription(id); + } + private Group getGroup(AuthorityInfo authorityInfo, List includeParam, Set rootAuthorities) { if (authorityInfo == null) @@ -576,13 +612,23 @@ private Group getGroup(AuthorityInfo authorityInfo, List includeParam, S // REPO-1743 String authorityDisplayName = authorityInfo.getAuthorityDisplayName(); + String description = authorityInfo.getDescription(); if (authorityDisplayName == null || authorityDisplayName.isEmpty()) { - authorityDisplayName = authorityService.getAuthorityDisplayName(authorityInfo.getAuthorityName()); + if (includeParam != null && includeParam.contains(PARAM_INCLUDE_DESCRIPTION)) + { + Pair displayNameAndDescription = authorityService.getAuthorityDisplayNameAndDescription(authorityInfo.getAuthorityName()); + authorityDisplayName = displayNameAndDescription.getFirst(); + description = displayNameAndDescription.getSecond(); + } + else + { + authorityDisplayName = authorityService.getAuthorityDisplayName(authorityInfo.getAuthorityName()); + } } group.setDisplayName(authorityDisplayName); - + group.setDescription(description); group.setIsRoot(isRootAuthority(rootAuthorities, authorityInfo.getAuthorityName())); // Optionally include @@ -606,6 +652,19 @@ private Group getGroup(AuthorityInfo authorityInfo, List includeParam, S Set authorityZones = authorityService.getAuthorityZones(authorityInfo.getAuthorityName()); group.setZones(authorityZones); } + + if (includeParam.contains(PARAM_INCLUDE_HAS_SUBGROUPS)) + { + Set containedAuthorities; + try + { + containedAuthorities = authorityService.getContainedAuthorities(AuthorityType.GROUP, authorityInfo.getAuthorityName(), true); + } catch (UnknownAuthorityException e) + { + containedAuthorities = Collections.emptySet(); + } + group.setHasSubgroups(CollectionUtils.isNotEmpty(containedAuthorities)); + } } return group; @@ -621,7 +680,7 @@ private Pair getGroupsSortProp(Parameters parameters) Pair sortProp; List sortCols = parameters.getSorting(); - if ((sortCols != null) && (sortCols.size() > 0)) + if (sortCols != null && !sortCols.isEmpty()) { if (sortCols.size() > 1) { @@ -636,7 +695,7 @@ private Pair getGroupsSortProp(Parameters parameters) throw new InvalidArgumentException("Invalid sort field: " + sortCol.column); } - sortProp = new Pair<>(sortPropName, (sortCol.asc ? Boolean.TRUE : Boolean.FALSE)); + sortProp = new Pair<>(sortPropName, sortCol.asc ? Boolean.TRUE : Boolean.FALSE); } else { @@ -851,7 +910,6 @@ public void deleteGroupMembership(String groupId, String groupMemberId) validateGroupMemberId(groupMemberId); // Verify if groupMemberId is member of groupId - AuthorityType authorityType = AuthorityType.getAuthorityType(groupMemberId); Set parents = authorityService.getContainingAuthorities(AuthorityType.GROUP, groupMemberId, true); if (!parents.contains(groupId)) { @@ -894,7 +952,7 @@ private PagingResults getAuthoritiesInfo(AuthorityType authorityT } List authorityInfoList = new ArrayList<>(authorities.size()); - authorityInfoList.addAll(authorities.stream().map(this::getAuthorityInfo).collect(Collectors.toList())); + authorityInfoList.addAll(authorities.stream().map(auth -> getAuthorityInfo(auth, false)).collect(Collectors.toList())); // Post process sorting - this should be moved to service // layer. It is done here because sorting is not supported at @@ -943,7 +1001,7 @@ private GroupMember getGroupMember(AuthorityInfo authorityInfo) private GroupMember getGroupMember(String authorityId) { - AuthorityInfo authorityInfo = getAuthorityInfo(authorityId); + AuthorityInfo authorityInfo = getAuthorityInfo(authorityId, false); return getGroupMember(authorityInfo); } @@ -1014,6 +1072,10 @@ private void validateGroup(Group group, boolean isUpdate) { throw new InvalidArgumentException("Group update does not support field: zones"); } + if (group.wasSet(Group.HAS_SUBGROUPS)) + { + throw new InvalidArgumentException("Group update does not support field: hasSubgroups"); + } } } @@ -1054,7 +1116,7 @@ private boolean authorityExists(AuthorityType authorityType, String authorityNam { String name = inferPrefix ? authorityService.getName(authorityType, authorityName) : authorityName; - return (name != null && authorityService.authorityExists(name)); + return name != null && authorityService.authorityExists(name); } private boolean isGroupAuthority(String authorityName) diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/Group.java b/remote-api/src/main/java/org/alfresco/rest/api/model/Group.java index 6ef826229cf..87ae0095645 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/Group.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/Group.java @@ -42,7 +42,9 @@ public class Group implements Comparable protected String id; // group id (aka authority name) protected String displayName; + protected String description; protected Boolean isRoot; + protected Boolean hasSubgroups; protected Set parentIds; protected Set zones; @@ -50,7 +52,9 @@ public class Group implements Comparable public static final String ID = "id"; public static final String DISPLAY_NAME = "displayName"; + public static final String DESCRIPTION = "description"; public static final String IS_ROOT = "isRoot"; + public static final String HAS_SUBGROUPS = "hasSubgroups"; public static final String PARENT_IDS = "parentIds"; public static final String ZONES = "zones"; @@ -81,6 +85,14 @@ public void setDisplayName(String displayName) setFields.put(DISPLAY_NAME, true); } + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + public Boolean getIsRoot() { return isRoot; @@ -92,6 +104,14 @@ public void setIsRoot(Boolean isRoot) setFields.put(IS_ROOT, true); } + public Boolean getHasSubgroups() { + return hasSubgroups; + } + + public void setHasSubgroups(Boolean hasSubgroups) { + this.hasSubgroups = hasSubgroups; + } + public Set getParentIds() { return parentIds; @@ -154,12 +174,13 @@ public int hashCode() @Override public String toString() { - return "Group [id=" + id + ", displayName=" + displayName + ", isRoot=" + isRoot + "]"; + return "Group [id=" + id + ", displayName=" + displayName + ", description=" + description + + ", isRoot=" + isRoot + ", hasSubgroups=" + hasSubgroups + "]"; } public boolean wasSet(String fieldName) { Boolean b = setFields.get(fieldName); - return (b != null ? b : false); + return b != null && b; } } \ No newline at end of file diff --git a/remote-api/src/test/java/org/alfresco/rest/api/tests/GroupsTest.java b/remote-api/src/test/java/org/alfresco/rest/api/tests/GroupsTest.java index df0e8f45ed2..1b09ca88c39 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/tests/GroupsTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/tests/GroupsTest.java @@ -43,17 +43,20 @@ import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.util.GUID; -import org.alfresco.util.testing.category.LuceneTests; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.experimental.categories.Category; import org.mockito.Mock; import jakarta.servlet.http.HttpServletResponse; + import java.util.*; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; /** @@ -69,13 +72,13 @@ public class GroupsTest extends AbstractSingleNetworkSiteTest protected AuthorityService authorityService; - private String rootGroupName = null; - private Group rootGroup = null; - private Group groupA = null; - private Group groupB = null; - private GroupMember groupMemberA = null; - private GroupMember groupMemberB = null; - private GroupMember personMember = null; + private String rootGroupName; + private Group rootGroup; + private Group groupA; + private Group groupB; + private GroupMember groupMemberA; + private GroupMember groupMemberB; + private GroupMember personMember; @Mock private ResultSetRow groupAResultSetRow; @Mock @@ -670,6 +673,7 @@ private void validateGroupDefaultFields(Group group, boolean ignoreOptionallyInc // Optionally included. assertNull(group.getParentIds()); assertNull(group.getZones()); + assertNull(group.getHasSubgroups()); } } @@ -956,7 +960,7 @@ private void canGetGroupsForUserId() throws Exception expected.retainAll(respPostProcess.getList()); // If this assertion fails, then the tests aren't providing any value - change them! - assertTrue("List doesn't contain enough items for test to be conclusive.", expected.size() > 0); + assertTrue("List doesn't contain enough items for test to be conclusive.", !expected.isEmpty()); checkList(expected, respPostProcess.getPaging(), respPostProcess); } @@ -977,7 +981,7 @@ private void canGetGroupsForUserId() throws Exception expected.retainAll(respPostProcess.getList()); // If this assertion fails, then the tests aren't providing any value - change them! - assertTrue("List doesn't contain enough items for test to be conclusive.", expected.size() > 0); + assertTrue("List doesn't contain enough items for test to be conclusive.", !expected.isEmpty()); checkList(expected, respPostProcess.getPaging(), respPostProcess); } @@ -1154,7 +1158,6 @@ private void canGetGroupsForUserId() throws Exception // -ve test: invalid zones clause { - Paging paging = getPaging(0, Integer.MAX_VALUE); Map otherParams = new HashMap<>(); otherParams.put("include", org.alfresco.rest.api.Groups.PARAM_INCLUDE_ZONES); @@ -1418,16 +1421,17 @@ public void testCreateGroup() throws Exception setRequestContext(networkOne.getId(), networkAdmin, DEFAULT_ADMIN_PWD); Map otherParams = new HashMap<>(); - otherParams.put("include", org.alfresco.rest.api.Groups.PARAM_INCLUDE_PARENT_IDS); + otherParams.put("include", org.alfresco.rest.api.Groups.PARAM_INCLUDE_HAS_SUBGROUPS); Group group = generateGroup(); - Group createdGroup01 = groupsProxy.createGroup(group, null, HttpServletResponse.SC_CREATED); + Group createdGroup01 = groupsProxy.createGroup(group, otherParams, HttpServletResponse.SC_CREATED); assertNotNull(createdGroup01); assertNotNull(createdGroup01.getId()); assertTrue(createdGroup01.getIsRoot()); assertNull(createdGroup01.getParentIds()); + assertFalse(createdGroup01.getHasSubgroups()); Set subGroup01Parents = new HashSet<>(); subGroup01Parents.add(createdGroup01.getId()); @@ -1435,12 +1439,18 @@ public void testCreateGroup() throws Exception Group subGroup01 = generateGroup(); subGroup01.setParentIds(subGroup01Parents); + otherParams.put("include", org.alfresco.rest.api.Groups.PARAM_INCLUDE_PARENT_IDS + "," + org.alfresco.rest.api.Groups.PARAM_INCLUDE_HAS_SUBGROUPS); Group createdSubGroup01 = groupsProxy.createGroup(subGroup01, otherParams, HttpServletResponse.SC_CREATED); assertNotNull(createdSubGroup01); assertNotNull(createdSubGroup01.getId()); assertFalse(createdSubGroup01.getIsRoot()); assertNotNull(createdSubGroup01.getParentIds()); assertEquals(subGroup01Parents, createdSubGroup01.getParentIds()); + assertFalse(createdSubGroup01.getHasSubgroups()); + + //validate if parent group now has any subgroup + Group group01 = groupsProxy.getGroup(createdGroup01.getId(), otherParams, HttpServletResponse.SC_OK); + assertTrue(group01.getHasSubgroups()); } // Group id is missing. diff --git a/remote-api/src/test/java/org/alfresco/rest/api/tests/client/data/Group.java b/remote-api/src/test/java/org/alfresco/rest/api/tests/client/data/Group.java index f8109d4f75d..ec530ca244d 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/tests/client/data/Group.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/tests/client/data/Group.java @@ -58,7 +58,9 @@ public void expected(Object o) AssertUtil.assertEquals("id", getId(), other.getId()); AssertUtil.assertEquals("displayName", getDisplayName(), other.getDisplayName()); + AssertUtil.assertEquals("description", getDescription(), other.getDescription()); AssertUtil.assertEquals("isRoot", getIsRoot(), other.getIsRoot()); + AssertUtil.assertEquals("hasSubgroups", getHasSubgroups(), other.getHasSubgroups()); AssertUtil.assertEquals("parentIds", getParentIds(), other.getParentIds()); AssertUtil.assertEquals("zones", getZones(), other.getZones()); } @@ -73,11 +75,21 @@ public JSONObject toJSON() groupJson.put("displayName", getDisplayName()); + if (getDescription() != null) + { + groupJson.put("description", getDescription()); + } + if (getIsRoot() != null) { groupJson.put("isRoot", getIsRoot()); } + if (getHasSubgroups() != null) + { + groupJson.put("hasSubgroups", getHasSubgroups()); + } + if (getParentIds() != null) { groupJson.put("parentIds", new ArrayList(getParentIds())); @@ -95,16 +107,19 @@ public static Group parseGroup(JSONObject jsonObject) { String id = (String) jsonObject.get("id"); String displayName = (String) jsonObject.get("displayName"); + String description = (String) jsonObject.get("description"); Boolean isRoot = (Boolean) jsonObject.get("isRoot"); + Boolean hasSubgroups = (Boolean) jsonObject.get("hasSubgroups"); List parentIds = (List) jsonObject.get("parentIds"); List zones = (List) jsonObject.get("zones"); - Group group = new Group(); group.setId(id); group.setDisplayName(displayName); + group.setDescription(description); group.setIsRoot(isRoot); - group.setParentIds(parentIds != null ? new HashSet(parentIds) : null); - group.setZones(zones != null ? new HashSet(zones) : null); + group.setHasSubgroups(hasSubgroups); + group.setParentIds(parentIds != null ? new HashSet<>(parentIds) : null); + group.setZones(zones != null ? new HashSet<>(zones) : null); return group; } diff --git a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAO.java b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAO.java index 6404f6c255c..993a93b3a71 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAO.java +++ b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAO.java @@ -1,31 +1,33 @@ -/* - * #%L - * Alfresco Repository - * %% - * 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% - */ +/* + * #%L + * Alfresco Repository + * %% + * 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.repo.security.authority; +import java.io.Serializable; import java.util.Collection; +import java.util.Map; import java.util.Set; import org.alfresco.model.ContentModel; @@ -34,6 +36,8 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.AuthorityService.AuthorityFilter; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; public interface AuthorityDAO { @@ -61,6 +65,11 @@ public interface AuthorityDAO */ void createAuthority(String name, String authorityDisplayName, Set authorityZones); + /** + * Create an authority with properties. + */ + void createAuthority(String name, String authorityDisplayName, Set authorityZones, Map properties); + /** * Delete an authority. */ @@ -142,7 +151,19 @@ public interface AuthorityDAO * Set the display name for an authority */ void setAuthorityDisplayName(String authorityName, String authorityDisplayName); - + + /** + * Get the display name and description for an authority + * + * @return the display name and description + */ + Pair getAuthorityDisplayNameAndDescription(String authorityName); + + /** + * Set the display name and description for an authority + */ + void setAuthorityDisplayNameAndDescription(String authorityName, String authorityDisplayName, String description); + /** * Get root authorities */ diff --git a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java index f72f4b5177b..4b7b7c81257 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java +++ b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java @@ -92,6 +92,7 @@ import org.alfresco.util.SearchLanguageConversion; import org.alfresco.util.registry.NamedObjectRegistry; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; @@ -378,27 +379,38 @@ public void addAuthority(Collection parentNames, String childName) } } - public void createAuthority(String name, String authorityDisplayName, Set authorityZones) + @Override + public void createAuthority(String name, String authorityDisplayName, Set authorityZones) { + createAuthority(name, authorityDisplayName, authorityZones, null); + } + + @Override + public void createAuthority(String name, String authorityDisplayName, Set authorityZones, Map properties) { - HashMap props = new HashMap(); + Map props = new HashMap<>(); /* MNT-11749 : Alfresco allows to create authorities with different char cases, but disallow duplicates */ props.put(ContentModel.PROP_NAME, DigestUtils.md5Hex(name)); props.put(ContentModel.PROP_AUTHORITY_NAME, name); props.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, authorityDisplayName); + if (properties != null) + { + props.putAll(properties); + } NodeRef childRef; NodeRef authorityContainerRef = getAuthorityContainer(); + logger.info("AuthorityDAO before create node"); childRef = nodeService.createNode(authorityContainerRef, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name, namespacePrefixResolver), ContentModel.TYPE_AUTHORITY_CONTAINER, props).getChildRef(); if (authorityZones != null) { - Set zoneRefs = new HashSet(authorityZones.size() * 2); + Set zoneRefs = new HashSet<>(authorityZones.size() * 2); String currentUserDomain = tenantService.getCurrentUserDomain(); for (String authorityZone : authorityZones) { zoneRefs.add(getOrCreateZone(authorityZone)); - zoneAuthorityCache.remove(new Pair(currentUserDomain, authorityZone)); + zoneAuthorityCache.remove(new Pair<>(currentUserDomain, authorityZone)); } - zoneAuthorityCache.remove(new Pair(currentUserDomain, null)); + zoneAuthorityCache.remove(new Pair<>(currentUserDomain, null)); nodeService.addChild(zoneRefs, childRef, ContentModel.ASSOC_IN_ZONE, QName.createQName("cm", name, namespacePrefixResolver)); } authorityLookupCache.put(cacheKey(name), childRef); @@ -1431,7 +1443,33 @@ public void setAuthorityDisplayName(String authorityName, String authorityDispla return; } nodeService.setProperty(ref, ContentModel.PROP_AUTHORITY_DISPLAY_NAME, authorityDisplayName); + } + + @Override + public Pair getAuthorityDisplayNameAndDescription(String authorityName) + { + NodeRef ref = getAuthorityOrNull(authorityName); + if (ref == null) + { + return Pair.nullPair(); + } + String displayName = getAuthorityDisplayName(authorityName); + Serializable description = nodeService.getProperty(ref, ContentModel.PROP_DESCRIPTION); + return new Pair<>(displayName, DefaultTypeConverter.INSTANCE.convert(String.class, description)); + } + @Override + public void setAuthorityDisplayNameAndDescription(String authorityName, String authorityDisplayName, String description) + { + NodeRef ref = getAuthorityOrNull(authorityName); + if (ref == null) + { + return; + } + Map properties = nodeService.getProperties(ref); + properties.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, authorityDisplayName); + properties.put(ContentModel.PROP_DESCRIPTION, description); + nodeService.setProperties(ref, properties); } public NodeRef getOrCreateZone(String zoneName) diff --git a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityInfo.java b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityInfo.java index 9d6729acc1d..cce5aa326b9 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityInfo.java +++ b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityInfo.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Repository - * %% - * 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% - */ +/* + * #%L + * Alfresco Repository + * %% + * 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.repo.security.authority; import org.alfresco.api.AlfrescoPublicApi; @@ -39,15 +39,24 @@ public class AuthorityInfo { private Long nodeId; - private String authorityDisplayName; // eg. My Group, My Role private String authorityName; // eg. GROUP_my1, ROLE_myA + private String description; + public AuthorityInfo(Long nodeId, String authorityDisplayName, String authorityName, String description) + { + this.nodeId = nodeId; + this.authorityDisplayName = authorityDisplayName; + this.authorityName = authorityName; + this.description = description; + } + public AuthorityInfo(Long nodeId, String authorityDisplayName, String authorityName) { this.nodeId = nodeId; this.authorityDisplayName = authorityDisplayName; this.authorityName = authorityName; + this.description = null; } public Long getNodeId() @@ -65,6 +74,10 @@ public String getAuthorityName() return authorityName; } + public String getDescription() { + return description; + } + public String getShortName() { AuthorityType type = AuthorityType.getAuthorityType(authorityName); diff --git a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java index 0d4ecf8e2ab..13aa81f9479 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java @@ -25,6 +25,7 @@ */ package org.alfresco.repo.security.authority; +import java.io.Serializable; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; @@ -32,6 +33,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -53,6 +55,7 @@ import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; import org.springframework.beans.factory.InitializingBean; import org.springframework.extensions.surf.util.ParameterCheck; @@ -65,7 +68,6 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean { public static final String GROUP_ALFRESCO_SYSTEM_ADMINISTRATORS_AUTHORITY = PermissionService.GROUP_PREFIX + "ALFRESCO_SYSTEM_ADMINISTRATORS"; - private static Set DEFAULT_ZONES = new HashSet(); static @@ -543,6 +545,15 @@ public String createAuthority(AuthorityType type, String shortName) { return createAuthority(type, shortName, shortName, getDefaultZones()); } + + /** + * {@inheritDoc} + */ + @Override + public String createAuthority(AuthorityType type, String shortName, Map properties) + { + return createAuthority(type, shortName, shortName, getDefaultZones(), properties); + } /** * {@inheritDoc} @@ -643,12 +654,21 @@ public boolean authorityExists(String name) */ public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, Set authorityZones) + { + return createAuthority(type, shortName, authorityDisplayName, authorityZones, null); + } + + /** + * {@inheritDoc} + */ + @Override + public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, + Set authorityZones, Map properties) { checkTypeIsMutable(type); String name = getName(type, shortName); + authorityDAO.createAuthority(name, authorityDisplayName, authorityZones, properties); - authorityDAO.createAuthority(name, authorityDisplayName, authorityZones); - return name; } @@ -674,6 +694,31 @@ public void setAuthorityDisplayName(String authorityName, String authorityDispla checkTypeIsMutable(type); authorityDAO.setAuthorityDisplayName(authorityName, authorityDisplayName); } + + /** + * {@inheritDoc} + */ + @Override + public Pair getAuthorityDisplayNameAndDescription(String name) + { + Pair displayNameAndDescription = authorityDAO.getAuthorityDisplayNameAndDescription(name); + if(displayNameAndDescription.getFirst() == null) + { + displayNameAndDescription.setFirst(getShortName(name)); + } + return displayNameAndDescription; + } + + /** + * {@inheritDoc} + */ + @Override + public void setAuthorityDisplayNameAndDescription(String authorityName, String authorityDisplayName, String description) + { + AuthorityType type = AuthorityType.getAuthorityType(authorityName); + checkTypeIsMutable(type); + authorityDAO.setAuthorityDisplayNameAndDescription(authorityName, authorityDisplayName, description); + } /** * {@inheritDoc} diff --git a/repository/src/main/java/org/alfresco/service/cmr/security/AuthorityService.java b/repository/src/main/java/org/alfresco/service/cmr/security/AuthorityService.java index 50943025394..65835cc45e8 100644 --- a/repository/src/main/java/org/alfresco/service/cmr/security/AuthorityService.java +++ b/repository/src/main/java/org/alfresco/service/cmr/security/AuthorityService.java @@ -25,7 +25,9 @@ */ package org.alfresco.service.cmr.security; +import java.io.Serializable; import java.util.Collection; +import java.util.Map; import java.util.Set; import org.alfresco.api.AlfrescoPublicApi; @@ -35,6 +37,8 @@ import org.alfresco.service.Auditable; import org.alfresco.service.NotAuditable; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; /** * The service that encapsulates authorities granted to users. @@ -225,6 +229,24 @@ public interface AuthorityService @Auditable(parameters = {"type", "shortName"}) public String createAuthority(AuthorityType type, String shortName); + /** + * Create an authority with properties. + * + * @param type - + * the type of the authority + * @param shortName - + * the short name of the authority to create + * this will also be set as the default display name for the authority + * + * @param properties - + * properties that will be added to authority + * + * @return the name of the authority (this will be the prefix, if any + * associated with the type appended with the short name) + */ + @Auditable(parameters = {"type", "shortName"}) + String createAuthority(AuthorityType type, String shortName, Map properties); + /** * Create an authority with a display name and zone. * @@ -242,6 +264,27 @@ public interface AuthorityService @Auditable(parameters = {"type", "shortName", "authorityDisplayName", "authorityZones"}) public String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, Set authorityZones); + /** + * Create an authority with a display name and zone. + * + * @param type + * the type of the authority + * @param shortName + * the short name of the authority to create + * @param authorityDisplayName + * the display name for the authority + * @param authorityZones + * identifier for external user registry owning the authority or null if not applicable + * + * @param properties - + * properties that will be added to authority + * + * @return the full name of the authority (this will be the prefix, if any associated with the type appended with + * the short name) + */ + @Auditable(parameters = {"type", "shortName", "authorityDisplayName", "authorityZones"}) + String createAuthority(AuthorityType type, String shortName, String authorityDisplayName, Set authorityZones, Map properties); + /** * Set an authority to include another authority. For example, adding a * group to a group or adding a user to a group. @@ -399,7 +442,16 @@ public interface AuthorityFilter * @return - the display name */ @Auditable(parameters = {"name"}) - public String getAuthorityDisplayName(String name); + String getAuthorityDisplayName(String name); + + /** + * Get the display name and description for the given authority. + * + * @param name - the full authority string including any prefix (e.g. GROUP_woof) + * @return - pair containing display name and description + */ + @Auditable(parameters = {"name"}) + Pair getAuthorityDisplayNameAndDescription(String name); /** * Set the display name for the given authority. @@ -409,7 +461,18 @@ public interface AuthorityFilter * @param authorityDisplayName String */ @Auditable(parameters = {"authorityName", "authorityDisplayName"}) - public void setAuthorityDisplayName(String authorityName, String authorityDisplayName); + void setAuthorityDisplayName(String authorityName, String authorityDisplayName); + + /** + * Set the display name and description for the given authority. + * Setting the display name is only supported for authorities of type group + * + * @param authorityName String + * @param authorityDisplayName String + * @param description String + */ + @Auditable(parameters = {"authorityName", "authorityDisplayName", "description"}) + void setAuthorityDisplayNameAndDescription(String authorityName, String authorityDisplayName, String description); /** * Gets the authority node for the specified name diff --git a/repository/src/main/resources/alfresco/public-services-security-context.xml b/repository/src/main/resources/alfresco/public-services-security-context.xml index 7295be35047..51e2bab8df9 100644 --- a/repository/src/main/resources/alfresco/public-services-security-context.xml +++ b/repository/src/main/resources/alfresco/public-services-security-context.xml @@ -821,6 +821,8 @@ org.alfresco.service.cmr.security.AuthorityService.authorityExists=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.setAuthorityDisplayName=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.security.AuthorityService.getAuthorityDisplayName=ACL_ALLOW + org.alfresco.service.cmr.security.AuthorityService.setAuthorityDisplayNameAndDescription=ACL_METHOD.ROLE_ADMINISTRATOR + org.alfresco.service.cmr.security.AuthorityService.getAuthorityDisplayNameAndDescription=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.getOrCreateZone=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.security.AuthorityService.getZone=ACL_ALLOW org.alfresco.service.cmr.security.AuthorityService.getAuthorityZones=ACL_ALLOW diff --git a/repository/src/test/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java b/repository/src/test/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java index 8447461b9b4..246135f6a4a 100644 --- a/repository/src/test/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java +++ b/repository/src/test/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java @@ -83,9 +83,11 @@ import org.alfresco.service.transaction.TransactionService; import org.alfresco.test_category.OwnJVMTestsCategory; import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.Pair; import org.alfresco.util.testing.category.LuceneTests; import org.alfresco.util.testing.category.RedundantTests; import org.junit.FixMethodOrder; +import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runners.MethodSorters; import org.springframework.context.ApplicationContext; @@ -581,7 +583,40 @@ public void testCreateGroupAuth() // Ignore since we where expecting this } } - + + @Test + public void testCreateGroupAuthWithProperties() + { + String auth; + String groupName = "TESTGROUP"; + String prefixedGroupName = "GROUP_TESTGROUP"; + String description = "testDesc"; + String title = "testTitle"; + Map props = new HashMap<>(); + props.put(ContentModel.PROP_DESCRIPTION, description); + props.put(ContentModel.PROP_TITLE, title); + + // create authority with properties and default zones + auth = pubAuthorityService.createAuthority(AuthorityType.GROUP, groupName, props); + assertTrue(pubAuthorityService.authorityExists(prefixedGroupName)); + NodeRef nodeRef = pubAuthorityService.getAuthorityNodeRef(auth); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION), description); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE), title); + pubAuthorityService.deleteAuthority(auth); + + // create authority with zones and properties + Set zones = new HashSet<>(); + zones.add("Test1"); + zones.add("Test2"); + auth = pubAuthorityService.createAuthority(AuthorityType.GROUP, groupName, prefixedGroupName, zones, props); + assertTrue(pubAuthorityService.authorityExists(prefixedGroupName)); + nodeRef = pubAuthorityService.getAuthorityNodeRef(auth); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION), description); + assertEquals(nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE), title); + assertEquals(2, pubAuthorityService.getAuthorityZones(auth).size()); + pubAuthorityService.deleteAuthority(auth); + } + public void testCreateOwnerAuth() { try @@ -1373,7 +1408,6 @@ private Map createDefaultProperties(String userName, String properties.put(ContentModel.PROP_ORGID, orgId); return properties; } - public void testAuthorityDisplayNames() { String authOne = pubAuthorityService.createAuthority(AuthorityType.GROUP, "One");