mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
ACS-4025: Support include count and orderBy count for GET /tags (#1806)
* ACS-4025: Support include count and orderBy count for GET /tags * ACS-4025: add E2Es
This commit is contained in:
committed by
GitHub
parent
05df8a7582
commit
d39401a7ec
@@ -16,6 +16,11 @@ import org.alfresco.utility.testrail.annotation.TestRail;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import static org.alfresco.utility.report.log.Step.STEP;
|
||||||
|
|
||||||
@Test(groups = {TestGroup.REQUIRE_SOLR})
|
@Test(groups = {TestGroup.REQUIRE_SOLR})
|
||||||
public class GetTagsTests extends TagsDataPrep
|
public class GetTagsTests extends TagsDataPrep
|
||||||
{
|
{
|
||||||
@@ -72,6 +77,130 @@ public class GetTagsTests extends TagsDataPrep
|
|||||||
.and().entriesListContains("tag", documentTagValue2);
|
.and().entriesListContains("tag", documentTagValue2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include count in the query parameters and ensure count is as expected for returned tags.
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||||
|
public void testGetTags_withIncludeCount()
|
||||||
|
{
|
||||||
|
STEP("Get tags including count filter and ensure count is as expected for returned tags");
|
||||||
|
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||||
|
.withParams("include=count")
|
||||||
|
.withCoreAPI()
|
||||||
|
.getTags();
|
||||||
|
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||||
|
|
||||||
|
returnedCollection.getEntries().stream()
|
||||||
|
.filter(e -> e.onModel().getTag().equals(folderTagValue) || e.onModel().getTag().equals(documentTagValue))
|
||||||
|
.forEach(e -> e.onModel().assertThat().field("count").is(2));
|
||||||
|
|
||||||
|
returnedCollection.getEntries().stream()
|
||||||
|
.filter(e -> e.onModel().getTag().equals(documentTagValue2))
|
||||||
|
.forEach(e -> e.onModel().assertThat().field("count").is(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tags and order results by count. Default sort order should be ascending
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||||
|
public void testGetTags_withOrderByCountDefaultOrderShouldBeAsc()
|
||||||
|
{
|
||||||
|
|
||||||
|
STEP("Get tags and order results by count. Default sort order should be ascending");
|
||||||
|
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||||
|
.withParams("include=count&orderBy=count")
|
||||||
|
.withCoreAPI()
|
||||||
|
.getTags();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||||
|
returnedCollection.assertThat().entriesListIsSortedAscBy("count");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tags and order results by count in ascending order
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||||
|
public void testGetTags_withOrderByCountAsc()
|
||||||
|
{
|
||||||
|
|
||||||
|
STEP("Get tags and order results by count in ascending order");
|
||||||
|
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||||
|
.withParams("include=count&orderBy=count ASC")
|
||||||
|
.withCoreAPI()
|
||||||
|
.getTags();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||||
|
returnedCollection.assertThat().entriesListIsSortedAscBy("count");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tags and order results by count in descending order
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||||
|
public void testGetTags_withOrderByCountDesc()
|
||||||
|
{
|
||||||
|
|
||||||
|
STEP("Get tags and order results by count in descending order");
|
||||||
|
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||||
|
.withParams("include=count&orderBy=count DESC")
|
||||||
|
.withCoreAPI()
|
||||||
|
.getTags();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||||
|
returnedCollection.assertThat().entriesListIsSortedDescBy("count");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tags and order results by tag name. Default sort order should be ascending
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||||
|
public void testGetTags_withOrderByTagDefaultOrderShouldBeAsc()
|
||||||
|
{
|
||||||
|
|
||||||
|
STEP("Get tags and order results by tag name. Default sort order should be ascending");
|
||||||
|
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||||
|
.withParams("orderBy=tag")
|
||||||
|
.withCoreAPI()
|
||||||
|
.getTags();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||||
|
returnedCollection.assertThat().entriesListIsSortedAscBy("tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tags and order results by tag name in ascending order
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||||
|
public void testGetTags_withOrderByTagAsc()
|
||||||
|
{
|
||||||
|
|
||||||
|
STEP("Get tags and order results by tag name in ascending order");
|
||||||
|
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||||
|
.withParams("orderBy=tag ASC")
|
||||||
|
.withCoreAPI()
|
||||||
|
.getTags();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||||
|
returnedCollection.assertThat().entriesListIsSortedAscBy("tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tags and order results by tag name in descending order
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||||
|
public void testGetTags_withOrderByTagDesc()
|
||||||
|
{
|
||||||
|
|
||||||
|
STEP("Get tags and order results by tag name in descending order");
|
||||||
|
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||||
|
.withParams("orderBy=tag DESC")
|
||||||
|
.withCoreAPI()
|
||||||
|
.getTags();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||||
|
returnedCollection.assertThat().entriesListIsSortedDescBy("tag");
|
||||||
|
}
|
||||||
|
|
||||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.SANITY, description = "Failed authentication get tags call returns status code 401 with Manager role")
|
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.SANITY, description = "Failed authentication get tags call returns status code 401 with Manager role")
|
||||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.SANITY })
|
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.SANITY })
|
||||||
// @Bug(id="MNT-16904", description = "It fails only on environment with tenants")
|
// @Bug(id="MNT-16904", description = "It fails only on environment with tenants")
|
||||||
@@ -193,8 +322,7 @@ public class GetTagsTests extends TagsDataPrep
|
|||||||
.getPagination().assertThat().field("maxItems").is(100)
|
.getPagination().assertThat().field("maxItems").is(100)
|
||||||
.and().field("hasMoreItems").is("false")
|
.and().field("hasMoreItems").is("false")
|
||||||
.and().field("count").is("0")
|
.and().field("count").is("0")
|
||||||
.and().field("skipCount").is(20000)
|
.and().field("skipCount").is(20000);
|
||||||
.and().field("totalItems").is(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
|
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
|
||||||
|
@@ -22,7 +22,8 @@ public class TagsDataPrep extends RestTest
|
|||||||
protected static ListUserWithRoles usersWithRoles;
|
protected static ListUserWithRoles usersWithRoles;
|
||||||
protected static SiteModel siteModel;
|
protected static SiteModel siteModel;
|
||||||
protected static FileModel document;
|
protected static FileModel document;
|
||||||
protected static FolderModel folder;
|
protected static FolderModel folder, folder2;
|
||||||
|
protected static RestTagModelsCollection folder2tags;
|
||||||
protected static String documentTagValue, documentTagValue2, folderTagValue;
|
protected static String documentTagValue, documentTagValue2, folderTagValue;
|
||||||
protected static RestTagModel documentTag, documentTag2, folderTag, orphanTag, returnedModel;
|
protected static RestTagModel documentTag, documentTag2, folderTag, orphanTag, returnedModel;
|
||||||
protected static RestTagModelsCollection returnedCollection;
|
protected static RestTagModelsCollection returnedCollection;
|
||||||
@@ -38,6 +39,7 @@ public class TagsDataPrep extends RestTest
|
|||||||
usersWithRoles = dataUser.usingAdmin().addUsersWithRolesToSite(siteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer, UserRole.SiteContributor);
|
usersWithRoles = dataUser.usingAdmin().addUsersWithRolesToSite(siteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer, UserRole.SiteContributor);
|
||||||
document = dataContent.usingUser(adminUserModel).usingSite(siteModel).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
|
document = dataContent.usingUser(adminUserModel).usingSite(siteModel).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
|
||||||
folder = dataContent.usingUser(adminUserModel).usingSite(siteModel).createFolder();
|
folder = dataContent.usingUser(adminUserModel).usingSite(siteModel).createFolder();
|
||||||
|
folder2 = dataContent.usingUser(adminUserModel).usingSite(siteModel).createFolder();
|
||||||
|
|
||||||
documentTagValue = RandomData.getRandomName("tag").toLowerCase();
|
documentTagValue = RandomData.getRandomName("tag").toLowerCase();
|
||||||
documentTagValue2 = RandomData.getRandomName("tag").toLowerCase();
|
documentTagValue2 = RandomData.getRandomName("tag").toLowerCase();
|
||||||
@@ -48,6 +50,7 @@ public class TagsDataPrep extends RestTest
|
|||||||
documentTag2 = restClient.withCoreAPI().usingResource(document).addTag(documentTagValue2);
|
documentTag2 = restClient.withCoreAPI().usingResource(document).addTag(documentTagValue2);
|
||||||
folderTag = restClient.withCoreAPI().usingResource(folder).addTag(folderTagValue);
|
folderTag = restClient.withCoreAPI().usingResource(folder).addTag(folderTagValue);
|
||||||
orphanTag = restClient.withCoreAPI().createSingleTag(RestTagModel.builder().tag(RandomData.getRandomName("orphan-tag").toLowerCase()).create());
|
orphanTag = restClient.withCoreAPI().createSingleTag(RestTagModel.builder().tag(RandomData.getRandomName("orphan-tag").toLowerCase()).create());
|
||||||
|
folder2tags = restClient.withCoreAPI().usingResource(folder2).addTags(folderTagValue, documentTagValue);
|
||||||
|
|
||||||
// Allow indexing to complete.
|
// Allow indexing to complete.
|
||||||
Utility.sleep(500, 60000, () ->
|
Utility.sleep(500, 60000, () ->
|
||||||
|
@@ -36,6 +36,7 @@ import static org.alfresco.service.cmr.tagging.TaggingService.TAG_ROOT_NODE_REF;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -44,6 +45,8 @@ import java.util.Objects;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.query.ListBackedPagingResults;
|
||||||
import org.alfresco.query.PagingResults;
|
import org.alfresco.query.PagingResults;
|
||||||
import org.alfresco.repo.tagging.NonExistentTagException;
|
import org.alfresco.repo.tagging.NonExistentTagException;
|
||||||
import org.alfresco.repo.tagging.TagExistsException;
|
import org.alfresco.repo.tagging.TagExistsException;
|
||||||
@@ -60,10 +63,12 @@ import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationE
|
|||||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||||
import org.alfresco.rest.framework.resource.parameters.Paging;
|
import org.alfresco.rest.framework.resource.parameters.Paging;
|
||||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
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.Query;
|
||||||
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
|
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
|
||||||
import org.alfresco.rest.framework.resource.parameters.where.QueryImpl;
|
import org.alfresco.rest.framework.resource.parameters.where.QueryImpl;
|
||||||
import org.alfresco.service.Experimental;
|
import org.alfresco.service.Experimental;
|
||||||
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
@@ -166,36 +171,25 @@ public class TagsImpl implements Tags
|
|||||||
taggingService.deleteTag(storeRef, tagValue);
|
taggingService.deleteTag(storeRef, tagValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionWithPagingInfo<Tag> getTags(StoreRef storeRef, Parameters params)
|
public CollectionWithPagingInfo<Tag> getTags(StoreRef storeRef, Parameters params)
|
||||||
{
|
{
|
||||||
Paging paging = params.getPaging();
|
Paging paging = params.getPaging();
|
||||||
Map<Integer, Collection<String>> namesFilters = resolveTagNamesQuery(params.getQuery());
|
Pair<String, Boolean> sorting = !params.getSorting().isEmpty() ? new Pair<>(params.getSorting().get(0).column, params.getSorting().get(0).asc) : null;
|
||||||
PagingResults<Pair<NodeRef, String>> results = taggingService.getTags(storeRef, Util.getPagingRequest(paging), namesFilters.get(EQUALS), namesFilters.get(MATCHES));
|
Map<Integer, Collection<String>> namesFilters = resolveTagNamesQuery(params.getQuery());
|
||||||
|
|
||||||
Integer totalItems = results.getTotalResultCount().getFirst();
|
Map<NodeRef, Long> results = taggingService.getTags(storeRef, params.getInclude(), sorting, namesFilters.get(EQUALS), namesFilters.get(MATCHES));
|
||||||
List<Pair<NodeRef, String>> page = results.getPage();
|
|
||||||
List<Tag> tags = new ArrayList<>(page.size());
|
|
||||||
for (Pair<NodeRef, String> pair : page)
|
|
||||||
{
|
|
||||||
Tag selectedTag = new Tag(pair.getFirst(), pair.getSecond());
|
|
||||||
tags.add(selectedTag);
|
|
||||||
}
|
|
||||||
if (params.getInclude().contains(PARAM_INCLUDE_COUNT))
|
|
||||||
{
|
|
||||||
List<Pair<String, Integer>> tagsByCount = taggingService.findTaggedNodesAndCountByTagName(storeRef);
|
|
||||||
Map<String, Long> tagsByCountMap = new HashMap<>();
|
|
||||||
if (tagsByCount != null)
|
|
||||||
{
|
|
||||||
for (Pair<String, Integer> tagByCountElem : tagsByCount)
|
|
||||||
{
|
|
||||||
tagsByCountMap.put(tagByCountElem.getFirst(), Long.valueOf(tagByCountElem.getSecond()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tags.forEach(tag -> tag.setCount(Optional.ofNullable(tagsByCountMap.get(tag.getTag())).orElse(0L)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return CollectionWithPagingInfo.asPaged(paging, tags, results.hasMoreItems(), totalItems);
|
List<Tag> tagsList = results.entrySet().stream().map(entry -> new Tag(entry.getKey(), (String)nodeService.getProperty(entry.getKey(), ContentModel.PROP_NAME))).collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (params.getInclude().contains(PARAM_INCLUDE_COUNT))
|
||||||
|
{
|
||||||
|
tagsList.forEach(tag -> tag.setCount(results.get(tag.getNodeRef())));
|
||||||
|
}
|
||||||
|
|
||||||
|
ListBackedPagingResults listBackedPagingResults = new ListBackedPagingResults(tagsList, Util.getPagingRequest(params.getPaging()));
|
||||||
|
|
||||||
|
return CollectionWithPagingInfo.asPaged(paging, listBackedPagingResults.getPage(), listBackedPagingResults.hasMoreItems(), (Integer) listBackedPagingResults.getTotalResultCount().getFirst());
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeRef validateTag(String tagId)
|
public NodeRef validateTag(String tagId)
|
||||||
|
@@ -29,7 +29,6 @@ import static java.util.stream.Collectors.toList;
|
|||||||
|
|
||||||
import static org.alfresco.rest.api.impl.TagsImpl.NOT_A_VALID_TAG;
|
import static org.alfresco.rest.api.impl.TagsImpl.NOT_A_VALID_TAG;
|
||||||
import static org.alfresco.rest.api.impl.TagsImpl.NO_PERMISSION_TO_MANAGE_A_TAG;
|
import static org.alfresco.rest.api.impl.TagsImpl.NO_PERMISSION_TO_MANAGE_A_TAG;
|
||||||
import static org.alfresco.rest.api.impl.TagsImpl.PARAM_INCLUDE_COUNT;
|
|
||||||
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
|
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||||
@@ -41,10 +40,14 @@ import static org.mockito.ArgumentMatchers.isNull;
|
|||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.mockito.BDDMockito.then;
|
import static org.mockito.BDDMockito.then;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.query.PagingRequest;
|
import org.alfresco.query.PagingRequest;
|
||||||
import org.alfresco.query.PagingResults;
|
import org.alfresco.query.PagingResults;
|
||||||
import org.alfresco.rest.api.Nodes;
|
import org.alfresco.rest.api.Nodes;
|
||||||
@@ -56,6 +59,7 @@ import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationE
|
|||||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||||
import org.alfresco.rest.framework.resource.parameters.Paging;
|
import org.alfresco.rest.framework.resource.parameters.Paging;
|
||||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||||
|
import org.alfresco.rest.framework.resource.parameters.SortColumn;
|
||||||
import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryException;
|
import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryException;
|
||||||
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
|
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
@@ -84,6 +88,8 @@ public class TagsImplTest
|
|||||||
private static final NodeRef TAG_PARENT_NODE_REF = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, PARENT_NODE_ID);
|
private static final NodeRef TAG_PARENT_NODE_REF = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, PARENT_NODE_ID);
|
||||||
private static final String CONTENT_NODE_ID = "content-node-id";
|
private static final String CONTENT_NODE_ID = "content-node-id";
|
||||||
private static final NodeRef CONTENT_NODE_REF = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, CONTENT_NODE_ID);
|
private static final NodeRef CONTENT_NODE_REF = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, CONTENT_NODE_ID);
|
||||||
|
private static final String PARAM_INCLUDE_COUNT = "count";
|
||||||
|
|
||||||
|
|
||||||
private final RecognizedParamsExtractor queryExtractor = new RecognizedParamsExtractor() {};
|
private final RecognizedParamsExtractor queryExtractor = new RecognizedParamsExtractor() {};
|
||||||
|
|
||||||
@@ -123,13 +129,16 @@ public class TagsImplTest
|
|||||||
public void testGetTags()
|
public void testGetTags()
|
||||||
{
|
{
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
given(parametersMock.getInclude()).willReturn(new ArrayList<>());
|
||||||
given(pagingResultsMock.getPage()).willReturn(List.of(new Pair<>(TAG_NODE_REF, TAG_NAME)));
|
|
||||||
|
//given(taggingServiceMock.getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(), any(), isNull(), isNull())).willReturn(List.of(new Pair<>(TAG_NODE_REF, null)));
|
||||||
|
given(taggingServiceMock.getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(), any(), isNull(), isNull())).willReturn(Map.of(TAG_NODE_REF, 0L));
|
||||||
|
given(nodeServiceMock.getProperty(any(NodeRef.class), eq(ContentModel.PROP_NAME))).willReturn("tag-dummy-name");
|
||||||
|
|
||||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(PagingRequest.class), isNull(), isNull());
|
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(), any(), isNull(), isNull());
|
||||||
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
||||||
final List<Tag> expectedTags = createTagsWithNodeRefs(List.of(TAG_NAME));
|
final List<Tag> expectedTags = createTagsWithNodeRefs(List.of(TAG_NAME));
|
||||||
assertEquals(expectedTags, actualTags.getCollection());
|
assertEquals(expectedTags, actualTags.getCollection());
|
||||||
@@ -139,14 +148,15 @@ public class TagsImplTest
|
|||||||
public void testGetTags_verifyIfCountIsZero()
|
public void testGetTags_verifyIfCountIsZero()
|
||||||
{
|
{
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
given(parametersMock.getInclude()).willReturn(List.of(PARAM_INCLUDE_COUNT));
|
||||||
given(pagingResultsMock.getPage()).willReturn(List.of(new Pair<>(TAG_NODE_REF, TAG_NAME)));
|
given(taggingServiceMock.getTags(any(StoreRef.class), any(), any(), any(), any())).willReturn(Map.of(TAG_NODE_REF, 0L));
|
||||||
|
|
||||||
|
given(nodeServiceMock.getProperty(any(NodeRef.class), eq(ContentModel.PROP_NAME))).willReturn("tag-dummy-name");
|
||||||
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
||||||
|
|
||||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
then(taggingServiceMock).should().findTaggedNodesAndCountByTagName(STORE_REF_WORKSPACE_SPACESSTORE);
|
|
||||||
final List<Tag> expectedTags = createTagsWithNodeRefs(List.of(TAG_NAME)).stream()
|
final List<Tag> expectedTags = createTagsWithNodeRefs(List.of(TAG_NAME)).stream()
|
||||||
.peek(tag -> tag.setCount(0L))
|
.peek(tag -> tag.setCount(0L))
|
||||||
.collect(toList());
|
.collect(toList());
|
||||||
@@ -159,36 +169,157 @@ public class TagsImplTest
|
|||||||
{
|
{
|
||||||
NodeRef tagNodeA = new NodeRef("tag://A/");
|
NodeRef tagNodeA = new NodeRef("tag://A/");
|
||||||
NodeRef tagNodeB = new NodeRef("tag://B/");
|
NodeRef tagNodeB = new NodeRef("tag://B/");
|
||||||
List<Pair<NodeRef, String>> tagPairs = List.of(new Pair<>(tagNodeA, "taga"), new Pair<>(tagNodeB, "tagb"));
|
|
||||||
|
|
||||||
|
given(parametersMock.getSorting()).willReturn(Collections.emptyList());
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
|
||||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
|
||||||
given(pagingResultsMock.getPage()).willReturn(tagPairs);
|
|
||||||
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
||||||
// Only taga is included in the returned list since tagb is not in use.
|
|
||||||
given(taggingServiceMock.findTaggedNodesAndCountByTagName(STORE_REF_WORKSPACE_SPACESSTORE)).willReturn(List.of(new Pair<>("taga", 5)));
|
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||||
|
results.put(tagNodeA, 5L);
|
||||||
|
results.put(tagNodeB, 0L);
|
||||||
|
|
||||||
|
given(taggingServiceMock.getTags(any(StoreRef.class), eq(List.of(PARAM_INCLUDE_COUNT)), isNull(), any(), any())).willReturn(results);
|
||||||
|
given(nodeServiceMock.getProperty(any(NodeRef.class), eq(ContentModel.PROP_NAME))).willReturn("taga", "tagb");
|
||||||
|
|
||||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
then(taggingServiceMock).should().findTaggedNodesAndCountByTagName(STORE_REF_WORKSPACE_SPACESSTORE);
|
final List<Tag> expectedTags = List.of(Tag.builder().tag("tagA").nodeRef(tagNodeA).count(5L).create(),
|
||||||
|
Tag.builder().tag("tagB").nodeRef(tagNodeB).count(0L).create());
|
||||||
|
assertEquals(expectedTags, actualTags.getCollection());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTags_orderByCountAscendingOrder()
|
||||||
|
{
|
||||||
|
NodeRef tagNodeA = new NodeRef("tag://A/");
|
||||||
|
NodeRef tagNodeB = new NodeRef("tag://B/");
|
||||||
|
NodeRef tagNodeC = new NodeRef("tag://C/");
|
||||||
|
|
||||||
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
|
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
||||||
|
given(parametersMock.getSorting()).willReturn(List.of(new SortColumn("count", true)));
|
||||||
|
|
||||||
|
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||||
|
results.put(tagNodeB, 0L);
|
||||||
|
results.put(tagNodeC, 2L);
|
||||||
|
results.put(tagNodeA, 5L);
|
||||||
|
|
||||||
|
given(taggingServiceMock.getTags(any(StoreRef.class), eq(List.of(PARAM_INCLUDE_COUNT)), eq(new Pair<>("count", true)), any(), any())).willReturn(results);
|
||||||
|
given(nodeServiceMock.getProperty(tagNodeA, ContentModel.PROP_NAME)).willReturn("taga");
|
||||||
|
given(nodeServiceMock.getProperty(tagNodeB, ContentModel.PROP_NAME)).willReturn("tagb");
|
||||||
|
given(nodeServiceMock.getProperty(tagNodeC, ContentModel.PROP_NAME)).willReturn("tagc");
|
||||||
|
|
||||||
|
//when
|
||||||
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
|
final List<Tag> expectedTags = List.of(Tag.builder().tag("tagb").nodeRef(tagNodeB).count(0L).create(),
|
||||||
|
Tag.builder().tag("tagc").nodeRef(tagNodeC).count(2L).create(),
|
||||||
|
Tag.builder().tag("taga").nodeRef(tagNodeA).count(5L).create());
|
||||||
|
assertEquals(expectedTags, actualTags.getCollection());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTags_orderByCountDescendingOrder()
|
||||||
|
{
|
||||||
|
NodeRef tagNodeA = new NodeRef("tag://A/");
|
||||||
|
NodeRef tagNodeB = new NodeRef("tag://B/");
|
||||||
|
NodeRef tagNodeC = new NodeRef("tag://C/");
|
||||||
|
|
||||||
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
|
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
||||||
|
given(parametersMock.getSorting()).willReturn(List.of(new SortColumn("count", false)));
|
||||||
|
|
||||||
|
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||||
|
results.put(tagNodeA, 5L);
|
||||||
|
results.put(tagNodeC, 2L);
|
||||||
|
results.put(tagNodeB, 0L);
|
||||||
|
|
||||||
|
given(taggingServiceMock.getTags(any(StoreRef.class), eq(List.of(PARAM_INCLUDE_COUNT)), eq(new Pair<>("count", false)), any(), any())).willReturn(results);
|
||||||
|
given(nodeServiceMock.getProperty(tagNodeA, ContentModel.PROP_NAME)).willReturn("taga");
|
||||||
|
given(nodeServiceMock.getProperty(tagNodeB, ContentModel.PROP_NAME)).willReturn("tagb");
|
||||||
|
given(nodeServiceMock.getProperty(tagNodeC, ContentModel.PROP_NAME)).willReturn("tagc");
|
||||||
|
|
||||||
|
//when
|
||||||
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
final List<Tag> expectedTags = List.of(Tag.builder().tag("taga").nodeRef(tagNodeA).count(5L).create(),
|
final List<Tag> expectedTags = List.of(Tag.builder().tag("taga").nodeRef(tagNodeA).count(5L).create(),
|
||||||
|
Tag.builder().tag("tagc").nodeRef(tagNodeC).count(2L).create(),
|
||||||
Tag.builder().tag("tagb").nodeRef(tagNodeB).count(0L).create());
|
Tag.builder().tag("tagb").nodeRef(tagNodeB).count(0L).create());
|
||||||
assertEquals(expectedTags, actualTags.getCollection());
|
assertEquals(expectedTags, actualTags.getCollection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTags_orderByTagAscendingOrder()
|
||||||
|
{
|
||||||
|
NodeRef tagApple = new NodeRef("tag://apple/");
|
||||||
|
NodeRef tagBanana = new NodeRef("tag://banana/");
|
||||||
|
NodeRef tagCoconut = new NodeRef("tag://coconut/");
|
||||||
|
|
||||||
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
|
given(parametersMock.getInclude()).willReturn(Collections.emptyList());
|
||||||
|
given(parametersMock.getSorting()).willReturn(List.of(new SortColumn("tag", true)));
|
||||||
|
|
||||||
|
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||||
|
results.put(tagApple, 0L);
|
||||||
|
results.put(tagBanana, 0L);
|
||||||
|
results.put(tagCoconut, 0L);
|
||||||
|
|
||||||
|
given(taggingServiceMock.getTags(any(StoreRef.class), any(), eq(new Pair<>("tag", true)), any(), any())).willReturn(results);
|
||||||
|
given(nodeServiceMock.getProperty(tagApple, ContentModel.PROP_NAME)).willReturn("apple");
|
||||||
|
given(nodeServiceMock.getProperty(tagBanana, ContentModel.PROP_NAME)).willReturn("banana");
|
||||||
|
given(nodeServiceMock.getProperty(tagCoconut, ContentModel.PROP_NAME)).willReturn("coconut");
|
||||||
|
|
||||||
|
//when
|
||||||
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
|
final List<Tag> expectedTags = List.of(Tag.builder().tag("apple").nodeRef(tagApple).create(),
|
||||||
|
Tag.builder().tag("banana").nodeRef(tagBanana).create(),
|
||||||
|
Tag.builder().tag("coconut").nodeRef(tagCoconut).create());
|
||||||
|
assertEquals(expectedTags, actualTags.getCollection());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTags_orderByTagDescendingOrder()
|
||||||
|
{
|
||||||
|
NodeRef tagApple = new NodeRef("tag://apple/");
|
||||||
|
NodeRef tagBanana = new NodeRef("tag://banana/");
|
||||||
|
NodeRef tagCoconut = new NodeRef("tag://coconut/");
|
||||||
|
|
||||||
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
|
given(parametersMock.getInclude()).willReturn(Collections.emptyList());
|
||||||
|
given(parametersMock.getSorting()).willReturn(List.of(new SortColumn("tag", false)));
|
||||||
|
|
||||||
|
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||||
|
results.put(tagCoconut, 0L);
|
||||||
|
results.put(tagBanana, 0L);
|
||||||
|
results.put(tagApple, 0L);
|
||||||
|
|
||||||
|
given(taggingServiceMock.getTags(any(StoreRef.class), any(), eq(new Pair<>("tag", false)), any(), any())).willReturn(results);
|
||||||
|
given(nodeServiceMock.getProperty(tagApple, ContentModel.PROP_NAME)).willReturn("apple");
|
||||||
|
given(nodeServiceMock.getProperty(tagBanana, ContentModel.PROP_NAME)).willReturn("banana");
|
||||||
|
given(nodeServiceMock.getProperty(tagCoconut, ContentModel.PROP_NAME)).willReturn("coconut");
|
||||||
|
|
||||||
|
//when
|
||||||
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
|
final List<Tag> expectedTags = List.of(Tag.builder().tag("coconut").nodeRef(tagCoconut).create(),
|
||||||
|
Tag.builder().tag("banana").nodeRef(tagBanana).create(),
|
||||||
|
Tag.builder().tag("apple").nodeRef(tagApple).create());
|
||||||
|
assertEquals(expectedTags, actualTags.getCollection());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetTags_withEqualsClauseWhereQuery()
|
public void testGetTags_withEqualsClauseWhereQuery()
|
||||||
{
|
{
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag=expectedName)"));
|
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag=expectedName)"));
|
||||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
given(parametersMock.getInclude()).willReturn(new ArrayList<>());
|
||||||
|
|
||||||
//when
|
//when
|
||||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(PagingRequest.class), eq(Set.of("expectedname")), isNull());
|
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), eq(new ArrayList<>()), any(), eq(Set.of("expectedname")), isNull());
|
||||||
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
||||||
assertThat(actualTags).isNotNull();
|
assertThat(actualTags).isNotNull();
|
||||||
}
|
}
|
||||||
@@ -198,13 +329,13 @@ public class TagsImplTest
|
|||||||
{
|
{
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag IN (expectedName1, expectedName2))"));
|
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag IN (expectedName1, expectedName2))"));
|
||||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
given(parametersMock.getInclude()).willReturn(new ArrayList<>());
|
||||||
|
|
||||||
//when
|
//when
|
||||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(PagingRequest.class), eq(Set.of("expectedname1", "expectedname2")), isNull());
|
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE),any(), any(), eq(Set.of("expectedname1", "expectedname2")), isNull());
|
||||||
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
||||||
assertThat(actualTags).isNotNull();
|
assertThat(actualTags).isNotNull();
|
||||||
}
|
}
|
||||||
@@ -214,13 +345,13 @@ public class TagsImplTest
|
|||||||
{
|
{
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag MATCHES ('expectedName*'))"));
|
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag MATCHES ('expectedName*'))"));
|
||||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
given(parametersMock.getInclude()).willReturn(new ArrayList<>());
|
||||||
|
|
||||||
//when
|
//when
|
||||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||||
|
|
||||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(PagingRequest.class), isNull(), eq(Set.of("expectedname*")));
|
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(), any(), isNull(), eq(Set.of("expectedname*")));
|
||||||
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
||||||
assertThat(actualTags).isNotNull();
|
assertThat(actualTags).isNotNull();
|
||||||
}
|
}
|
||||||
@@ -230,6 +361,7 @@ public class TagsImplTest
|
|||||||
{
|
{
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag=expectedName AND tag IN (expectedName1, expectedName2))"));
|
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag=expectedName AND tag IN (expectedName1, expectedName2))"));
|
||||||
|
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||||
|
|
||||||
//when
|
//when
|
||||||
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
||||||
@@ -243,6 +375,7 @@ public class TagsImplTest
|
|||||||
{
|
{
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag BETWEEN ('expectedName', 'expectedName2'))"));
|
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag BETWEEN ('expectedName', 'expectedName2'))"));
|
||||||
|
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||||
|
|
||||||
//when
|
//when
|
||||||
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
||||||
@@ -256,6 +389,7 @@ public class TagsImplTest
|
|||||||
{
|
{
|
||||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(NOT tag=expectedName)"));
|
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(NOT tag=expectedName)"));
|
||||||
|
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||||
|
|
||||||
//when
|
//when
|
||||||
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
||||||
|
@@ -23,225 +23,225 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
package org.alfresco.repo.jscript;
|
package org.alfresco.repo.jscript;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.query.PagingRequest;
|
import org.alfresco.query.PagingRequest;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.cmr.search.CategoryService;
|
import org.alfresco.service.cmr.search.CategoryService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.util.Pair;
|
import org.alfresco.util.Pair;
|
||||||
import org.mozilla.javascript.Context;
|
import org.mozilla.javascript.Context;
|
||||||
import org.mozilla.javascript.Scriptable;
|
import org.mozilla.javascript.Scriptable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support class for finding categories, finding root nodes for categories and creating root categories.
|
* Support class for finding categories, finding root nodes for categories and creating root categories.
|
||||||
*
|
*
|
||||||
* @author Andy Hind
|
* @author Andy Hind
|
||||||
*/
|
*/
|
||||||
public final class Classification extends BaseScopableProcessorExtension
|
public final class Classification extends BaseScopableProcessorExtension
|
||||||
{
|
{
|
||||||
private ServiceRegistry services;
|
private ServiceRegistry services;
|
||||||
|
|
||||||
private StoreRef storeRef;
|
private StoreRef storeRef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the default store reference
|
* Set the default store reference
|
||||||
*
|
*
|
||||||
* @param storeRef the default store reference
|
* @param storeRef the default store reference
|
||||||
*/
|
*/
|
||||||
public void setStoreUrl(String storeRef)
|
public void setStoreUrl(String storeRef)
|
||||||
{
|
{
|
||||||
this.storeRef = new StoreRef(storeRef);
|
this.storeRef = new StoreRef(storeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the service registry
|
* Set the service registry
|
||||||
*
|
*
|
||||||
* @param services the service registry
|
* @param services the service registry
|
||||||
*/
|
*/
|
||||||
public void setServiceRegistry(ServiceRegistry services)
|
public void setServiceRegistry(ServiceRegistry services)
|
||||||
{
|
{
|
||||||
this.services = services;
|
this.services = services;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all the category nodes in a given classification.
|
* Find all the category nodes in a given classification.
|
||||||
*
|
*
|
||||||
* @param aspect String
|
* @param aspect String
|
||||||
* @return Scriptable
|
* @return Scriptable
|
||||||
*/
|
*/
|
||||||
public Scriptable getAllCategoryNodes(String aspect)
|
public Scriptable getAllCategoryNodes(String aspect)
|
||||||
{
|
{
|
||||||
Object[] cats = buildCategoryNodes(services.getCategoryService().getCategories(
|
Object[] cats = buildCategoryNodes(services.getCategoryService().getCategories(
|
||||||
storeRef, createQName(aspect), CategoryService.Depth.ANY));
|
storeRef, createQName(aspect), CategoryService.Depth.ANY));
|
||||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the aspects that define a classification.
|
* Get all the aspects that define a classification.
|
||||||
*
|
*
|
||||||
* @return String[]
|
* @return String[]
|
||||||
*/
|
*/
|
||||||
public String[] getAllClassificationAspects()
|
public String[] getAllClassificationAspects()
|
||||||
{
|
{
|
||||||
Collection<QName> aspects = services.getCategoryService().getClassificationAspects();
|
Collection<QName> aspects = services.getCategoryService().getClassificationAspects();
|
||||||
String[] answer = new String[aspects.size()];
|
String[] answer = new String[aspects.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (QName qname : aspects)
|
for (QName qname : aspects)
|
||||||
{
|
{
|
||||||
answer[i++] = qname.toPrefixString(this.services.getNamespaceService());
|
answer[i++] = qname.toPrefixString(this.services.getNamespaceService());
|
||||||
}
|
}
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a root category in a classification.
|
* Create a root category in a classification.
|
||||||
*
|
*
|
||||||
* @param aspect String
|
* @param aspect String
|
||||||
* @param name String
|
* @param name String
|
||||||
*/
|
*/
|
||||||
public CategoryNode createRootCategory(String aspect, String name)
|
public CategoryNode createRootCategory(String aspect, String name)
|
||||||
{
|
{
|
||||||
NodeRef categoryNodeRef = services.getCategoryService().createRootCategory(storeRef, createQName(aspect), name);
|
NodeRef categoryNodeRef = services.getCategoryService().createRootCategory(storeRef, createQName(aspect), name);
|
||||||
CategoryNode categoryNode = new CategoryNode(categoryNodeRef, this.services, getScope());
|
CategoryNode categoryNode = new CategoryNode(categoryNodeRef, this.services, getScope());
|
||||||
|
|
||||||
return categoryNode;
|
return categoryNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the category node from the category node reference.
|
* Get the category node from the category node reference.
|
||||||
*
|
*
|
||||||
* @param categoryRef category node reference
|
* @param categoryRef category node reference
|
||||||
* @return {@link CategoryNode} category node
|
* @return {@link CategoryNode} category node
|
||||||
*/
|
*/
|
||||||
public CategoryNode getCategory(String categoryRef)
|
public CategoryNode getCategory(String categoryRef)
|
||||||
{
|
{
|
||||||
CategoryNode result = null;
|
CategoryNode result = null;
|
||||||
NodeRef categoryNodeRef = new NodeRef(categoryRef);
|
NodeRef categoryNodeRef = new NodeRef(categoryRef);
|
||||||
if (services.getNodeService().exists(categoryNodeRef) == true &&
|
if (services.getNodeService().exists(categoryNodeRef) == true &&
|
||||||
services.getDictionaryService().isSubClass(ContentModel.TYPE_CATEGORY, services.getNodeService().getType(categoryNodeRef)) == true)
|
services.getDictionaryService().isSubClass(ContentModel.TYPE_CATEGORY, services.getNodeService().getType(categoryNodeRef)) == true)
|
||||||
{
|
{
|
||||||
result = new CategoryNode(categoryNodeRef, this.services, getScope());
|
result = new CategoryNode(categoryNodeRef, this.services, getScope());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the root categories in a classification.
|
* Get the root categories in a classification.
|
||||||
*
|
*
|
||||||
* @param aspect String
|
* @param aspect String
|
||||||
* @return Scriptable
|
* @return Scriptable
|
||||||
*/
|
*/
|
||||||
public Scriptable getRootCategories(String aspect)
|
public Scriptable getRootCategories(String aspect)
|
||||||
{
|
{
|
||||||
Object[] cats = buildCategoryNodes(services.getCategoryService().getRootCategories(
|
Object[] cats = buildCategoryNodes(services.getCategoryService().getRootCategories(
|
||||||
storeRef, createQName(aspect)));
|
storeRef, createQName(aspect)));
|
||||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get ordered, filtered and paged root categories in a classification.
|
* Get ordered, filtered and paged root categories in a classification.
|
||||||
*
|
*
|
||||||
* @param aspect
|
* @param aspect
|
||||||
* @param filter
|
* @param filter
|
||||||
* @param maxItems
|
* @param maxItems
|
||||||
* @param skipCount (offset)
|
* @param skipCount (offset)
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Scriptable getRootCategories(String aspect, String filter, int maxItems, int skipCount)
|
public Scriptable getRootCategories(String aspect, String filter, int maxItems, int skipCount)
|
||||||
{
|
{
|
||||||
PagingRequest pagingRequest = new PagingRequest(skipCount, maxItems);
|
PagingRequest pagingRequest = new PagingRequest(skipCount, maxItems);
|
||||||
List<ChildAssociationRef> rootCategories = services.getCategoryService().getRootCategories(storeRef, createQName(aspect), pagingRequest, true, filter).getPage();
|
List<ChildAssociationRef> rootCategories = services.getCategoryService().getRootCategories(storeRef, createQName(aspect), pagingRequest, true, filter).getPage();
|
||||||
Object[] cats = buildCategoryNodes(rootCategories);
|
Object[] cats = buildCategoryNodes(rootCategories);
|
||||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the category usage count.
|
* Get the category usage count.
|
||||||
*
|
*
|
||||||
* @param aspect String
|
* @param aspect String
|
||||||
* @param maxCount int
|
* @param maxCount int
|
||||||
* @return Scriptable
|
* @return Scriptable
|
||||||
*/
|
*/
|
||||||
public Scriptable getCategoryUsage(String aspect, int maxCount)
|
public Scriptable getCategoryUsage(String aspect, int maxCount)
|
||||||
{
|
{
|
||||||
List<Pair<NodeRef, Integer>> topCats = services.getCategoryService().getTopCategories(storeRef, createQName(aspect), maxCount);
|
List<Pair<NodeRef, Integer>> topCats = services.getCategoryService().getTopCategories(storeRef, createQName(aspect), maxCount);
|
||||||
Object[] tags = new Object[topCats.size()];
|
Object[] tags = new Object[topCats.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Pair<NodeRef, Integer> topCat : topCats)
|
for (Pair<NodeRef, Integer> topCat : topCats)
|
||||||
{
|
{
|
||||||
tags[i++] = new Tag(new CategoryNode(topCat.getFirst(), this.services, getScope()), topCat.getSecond());
|
tags[i++] = new Tag(new CategoryNode(topCat.getFirst(), this.services, getScope()), topCat.getSecond());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Context.getCurrentContext().newArray(getScope(), tags);
|
return Context.getCurrentContext().newArray(getScope(), tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build category nodes.
|
* Build category nodes.
|
||||||
*
|
*
|
||||||
* @param cars list of associations to category nodes
|
* @param cars list of associations to category nodes
|
||||||
* @return {@link Object}[] array of category nodes
|
* @return {@link Object}[] array of category nodes
|
||||||
*/
|
*/
|
||||||
private Object[] buildCategoryNodes(Collection<ChildAssociationRef> cars)
|
private Object[] buildCategoryNodes(Collection<ChildAssociationRef> cars)
|
||||||
{
|
{
|
||||||
Object[] categoryNodes = new Object[cars.size()];
|
Object[] categoryNodes = new Object[cars.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (ChildAssociationRef car : cars)
|
for (ChildAssociationRef car : cars)
|
||||||
{
|
{
|
||||||
categoryNodes[i++] = new CategoryNode(car.getChildRef(), this.services, getScope());
|
categoryNodes[i++] = new CategoryNode(car.getChildRef(), this.services, getScope());
|
||||||
}
|
}
|
||||||
return categoryNodes;
|
return categoryNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create QName from string
|
* Create QName from string
|
||||||
*
|
*
|
||||||
* @param s QName string value
|
* @param s QName string value
|
||||||
* @return {@link QName} qualified name object
|
* @return {@link QName} qualified name object
|
||||||
*/
|
*/
|
||||||
private QName createQName(String s)
|
private QName createQName(String s)
|
||||||
{
|
{
|
||||||
QName qname;
|
QName qname;
|
||||||
if (s.indexOf(QName.NAMESPACE_BEGIN) != -1)
|
if (s.indexOf(QName.NAMESPACE_BEGIN) != -1)
|
||||||
{
|
{
|
||||||
qname = QName.createQName(s);
|
qname = QName.createQName(s);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qname = QName.createQName(s, this.services.getNamespaceService());
|
qname = QName.createQName(s, this.services.getNamespaceService());
|
||||||
}
|
}
|
||||||
return qname;
|
return qname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag class returned from getCategoryUsage().
|
* Tag class returned from getCategoryUsage().
|
||||||
*/
|
*/
|
||||||
public final class Tag
|
public final class Tag
|
||||||
{
|
{
|
||||||
private CategoryNode categoryNode;
|
private CategoryNode categoryNode;
|
||||||
private int frequency = 0;
|
private int frequency = 0;
|
||||||
|
|
||||||
public Tag(CategoryNode categoryNode, int frequency)
|
public Tag(CategoryNode categoryNode, int frequency)
|
||||||
{
|
{
|
||||||
this.categoryNode = categoryNode;
|
this.categoryNode = categoryNode;
|
||||||
this.frequency = frequency;
|
this.frequency = frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CategoryNode getCategory()
|
public CategoryNode getCategory()
|
||||||
{
|
{
|
||||||
return categoryNode;
|
return categoryNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFrequency()
|
public int getFrequency()
|
||||||
{
|
{
|
||||||
return frequency;
|
return frequency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -414,34 +414,7 @@ public abstract class AbstractCategoryServiceImpl implements CategoryService
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
boolean moreItems = false;
|
boolean moreItems = false;
|
||||||
|
|
||||||
final Function<NodeRef, Collection<ChildAssociationRef>> childNodesSupplier = (nodeRef) -> {
|
final Function<NodeRef, Collection<ChildAssociationRef>> childNodesSupplier = getNodeRefCollectionFunction(sortByName, exactNamesFilter, alikeNamesFilter, skipCount, maxItems);
|
||||||
final Set<ChildAssociationRef> childNodes = new HashSet<>();
|
|
||||||
if (CollectionUtils.isEmpty(exactNamesFilter) && CollectionUtils.isEmpty(alikeNamesFilter))
|
|
||||||
{
|
|
||||||
// lookup in DB without filtering
|
|
||||||
childNodes.addAll(nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_SUBCATEGORIES, RegexQNamePattern.MATCH_ALL));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (CollectionUtils.isNotEmpty(exactNamesFilter))
|
|
||||||
{
|
|
||||||
// lookup in DB filtering by name
|
|
||||||
childNodes.addAll(nodeService.getChildrenByName(nodeRef, ContentModel.ASSOC_SUBCATEGORIES, exactNamesFilter));
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isNotEmpty(alikeNamesFilter))
|
|
||||||
{
|
|
||||||
// lookup using search engin filtering by name
|
|
||||||
childNodes.addAll(getChildren(nodeRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE, sortByName, alikeNamesFilter, skipCount + maxItems + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream<ChildAssociationRef> childNodesStream = childNodes.stream();
|
|
||||||
if (sortByName)
|
|
||||||
{
|
|
||||||
childNodesStream = childNodesStream.sorted(Comparator.comparing(tag -> tag.getQName().getLocalName()));
|
|
||||||
}
|
|
||||||
return childNodesStream.collect(Collectors.toList());
|
|
||||||
};
|
|
||||||
|
|
||||||
OUTER_LOOP: for(NodeRef nodeRef : nodeRefs)
|
OUTER_LOOP: for(NodeRef nodeRef : nodeRefs)
|
||||||
{
|
{
|
||||||
@@ -468,6 +441,55 @@ public abstract class AbstractCategoryServiceImpl implements CategoryService
|
|||||||
return new ListBackedPagingResults<>(associations, moreItems);
|
return new ListBackedPagingResults<>(associations, moreItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||||
|
{
|
||||||
|
final Set<NodeRef> nodeRefs = getClassificationNodes(storeRef, aspectName);
|
||||||
|
final List<ChildAssociationRef> associations = new LinkedList<>();
|
||||||
|
|
||||||
|
final Function<NodeRef, Collection<ChildAssociationRef>> childNodesSupplier = getNodeRefCollectionFunction(false, exactNamesFilter, alikeNamesFilter, 0, 10000);
|
||||||
|
|
||||||
|
for (NodeRef nodeRef : nodeRefs)
|
||||||
|
{
|
||||||
|
Collection<ChildAssociationRef> children = childNodesSupplier.apply(nodeRef);
|
||||||
|
associations.addAll(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return associations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Function<NodeRef, Collection<ChildAssociationRef>> getNodeRefCollectionFunction(boolean sortByName, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter, int skipCount, int maxItems)
|
||||||
|
{
|
||||||
|
final Function<NodeRef, Collection<ChildAssociationRef>> childNodesSupplier = (nodeRef) -> {
|
||||||
|
final Set<ChildAssociationRef> childNodes = new HashSet<>();
|
||||||
|
if (CollectionUtils.isEmpty(exactNamesFilter) && CollectionUtils.isEmpty(alikeNamesFilter))
|
||||||
|
{
|
||||||
|
// lookup in DB without filtering
|
||||||
|
childNodes.addAll(nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_SUBCATEGORIES, RegexQNamePattern.MATCH_ALL));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CollectionUtils.isNotEmpty(exactNamesFilter))
|
||||||
|
{
|
||||||
|
// lookup in DB filtering by name
|
||||||
|
childNodes.addAll(nodeService.getChildrenByName(nodeRef, ContentModel.ASSOC_SUBCATEGORIES, exactNamesFilter));
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(alikeNamesFilter))
|
||||||
|
{
|
||||||
|
// lookup using search engine filtering by name
|
||||||
|
childNodes.addAll(getChildren(nodeRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE, sortByName, alikeNamesFilter, skipCount + maxItems + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<ChildAssociationRef> childNodesStream = childNodes.stream();
|
||||||
|
if (sortByName)
|
||||||
|
{
|
||||||
|
childNodesStream = childNodesStream.sorted(Comparator.comparing(tag -> tag.getQName().getLocalName()));
|
||||||
|
}
|
||||||
|
return childNodesStream.collect(Collectors.toList());
|
||||||
|
};
|
||||||
|
return childNodesSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName)
|
public Collection<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName)
|
||||||
{
|
{
|
||||||
return getRootCategories(storeRef, aspectName, null);
|
return getRootCategories(storeRef, aspectName, null);
|
||||||
|
@@ -46,12 +46,16 @@ import java.util.Comparator;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.query.EmptyPagingResults;
|
import org.alfresco.query.EmptyPagingResults;
|
||||||
@@ -61,6 +65,7 @@ import org.alfresco.repo.audit.AuditComponent;
|
|||||||
import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckOut;
|
import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckOut;
|
||||||
import org.alfresco.repo.copy.CopyServicePolicies.BeforeCopyPolicy;
|
import org.alfresco.repo.copy.CopyServicePolicies.BeforeCopyPolicy;
|
||||||
import org.alfresco.repo.copy.CopyServicePolicies.OnCopyCompletePolicy;
|
import org.alfresco.repo.copy.CopyServicePolicies.OnCopyCompletePolicy;
|
||||||
|
import org.alfresco.repo.domain.query.QueryException;
|
||||||
import org.alfresco.repo.event2.EventGenerator;
|
import org.alfresco.repo.event2.EventGenerator;
|
||||||
import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy;
|
import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy;
|
||||||
import org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy;
|
import org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy;
|
||||||
@@ -138,6 +143,9 @@ public class TaggingServiceImpl implements TaggingService,
|
|||||||
private static final String TAG_DETAILS_DELIMITER = "|";
|
private static final String TAG_DETAILS_DELIMITER = "|";
|
||||||
/** Next tag delimiter */
|
/** Next tag delimiter */
|
||||||
private static final String NEXT_TAG_DELIMITER = "\n";
|
private static final String NEXT_TAG_DELIMITER = "\n";
|
||||||
|
/** Parameters Include count */
|
||||||
|
private static final String PARAM_INCLUDE_COUNT = "count";
|
||||||
|
|
||||||
|
|
||||||
private static Set<String> FORBIDDEN_TAGS_SEQUENCES = new HashSet<String>(Arrays.asList(new String[] {NEXT_TAG_DELIMITER, TAG_DETAILS_DELIMITER}));
|
private static Set<String> FORBIDDEN_TAGS_SEQUENCES = new HashSet<String>(Arrays.asList(new String[] {NEXT_TAG_DELIMITER, TAG_DETAILS_DELIMITER}));
|
||||||
|
|
||||||
@@ -680,6 +688,21 @@ public class TaggingServiceImpl implements TaggingService,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Long> calculateCount(StoreRef storeRef)
|
||||||
|
{
|
||||||
|
List<Pair<String, Integer>> tagsByCount = findTaggedNodesAndCountByTagName(storeRef);
|
||||||
|
Map<String, Long> tagsByCountMap = new HashMap<>();
|
||||||
|
if (tagsByCount != null)
|
||||||
|
{
|
||||||
|
for (Pair<String, Integer> tagByCountElem : tagsByCount)
|
||||||
|
{
|
||||||
|
tagsByCountMap.put(tagByCountElem.getFirst(), Long.valueOf(tagByCountElem.getSecond()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tagsByCountMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see TaggingService#hasTag(NodeRef, String)
|
* @see TaggingService#hasTag(NodeRef, String)
|
||||||
*/
|
*/
|
||||||
@@ -956,7 +979,83 @@ public class TaggingServiceImpl implements TaggingService,
|
|||||||
exactNamesFilter, alikeNamesFilter);
|
exactNamesFilter, alikeNamesFilter);
|
||||||
|
|
||||||
return mapPagingResult(rootCategories,
|
return mapPagingResult(rootCategories,
|
||||||
(childAssociation) -> new Pair<>(childAssociation.getChildRef(), childAssociation.getQName().getLocalName()));
|
(childAssociation) -> new Pair<>(childAssociation.getChildRef(), childAssociation.getQName().getLocalName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<NodeRef, Long> getTags(StoreRef storeRef, List<String> parameterIncludes, Pair<String, Boolean> sorting, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||||
|
{
|
||||||
|
ParameterCheck.mandatory("storeRef", storeRef);
|
||||||
|
Collection<ChildAssociationRef> rootCategories = categoryService.getRootCategories(storeRef, ContentModel.ASPECT_TAGGABLE, exactNamesFilter, alikeNamesFilter);
|
||||||
|
|
||||||
|
Map<String, Long> tagsMap = new TreeMap<>();
|
||||||
|
for (ChildAssociationRef childAssociation : rootCategories)
|
||||||
|
{
|
||||||
|
tagsMap.put(childAssociation.getQName().getLocalName(), 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Long> tagsByCountMap = new HashMap<>();
|
||||||
|
|
||||||
|
if(parameterIncludes.contains(PARAM_INCLUDE_COUNT))
|
||||||
|
{
|
||||||
|
tagsByCountMap = calculateCount(storeRef);
|
||||||
|
|
||||||
|
for (Map.Entry<String, Long> entry : tagsMap.entrySet()) {
|
||||||
|
entry.setValue(Optional.ofNullable(tagsByCountMap.get(entry.getKey())).orElse(0L));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if we should sort results. Can only sort by one parameter, default order is ascending
|
||||||
|
if (sorting != null)
|
||||||
|
{
|
||||||
|
if (sorting.getFirst().equals("tag"))
|
||||||
|
{
|
||||||
|
if (!sorting.getSecond())
|
||||||
|
{
|
||||||
|
Stream<Map.Entry<String,Long>> sortedTags =
|
||||||
|
tagsMap.entrySet().stream()
|
||||||
|
.sorted(Collections.reverseOrder(Map.Entry.comparingByKey()));
|
||||||
|
tagsMap = sortedTags.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Stream<Map.Entry<String,Long>> sortedTags =
|
||||||
|
tagsMap.entrySet().stream()
|
||||||
|
.sorted(Map.Entry.comparingByKey());
|
||||||
|
tagsMap = sortedTags.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sorting.getFirst().equals(PARAM_INCLUDE_COUNT))
|
||||||
|
{
|
||||||
|
if (tagsByCountMap.isEmpty())
|
||||||
|
{
|
||||||
|
throw new QueryException("Tag count should be included when ordering by count");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sorting.getSecond())
|
||||||
|
{
|
||||||
|
Stream<Map.Entry<String, Long>> sortedTags =
|
||||||
|
tagsMap.entrySet().stream()
|
||||||
|
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
|
||||||
|
tagsMap = sortedTags.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Stream<Map.Entry<String,Long>> sortedTags =
|
||||||
|
tagsMap.entrySet().stream()
|
||||||
|
.sorted(Map.Entry.comparingByValue());
|
||||||
|
tagsMap = sortedTags.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<NodeRef, Long> tagNodeRefMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, Long> entry : tagsMap.entrySet())
|
||||||
|
{
|
||||||
|
tagNodeRefMap.put(getTagNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, entry.getKey()), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return tagNodeRefMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
package org.alfresco.service.cmr.search;
|
package org.alfresco.service.cmr.search;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -150,11 +151,21 @@ public interface CategoryService
|
|||||||
*/
|
*/
|
||||||
@Auditable(parameters = {"storeRef", "aspectName", "pagingRequest", "sortByName", "exactNamesFilter", "alikeNamesFilter"})
|
@Auditable(parameters = {"storeRef", "aspectName", "pagingRequest", "sortByName", "exactNamesFilter", "alikeNamesFilter"})
|
||||||
default PagingResults<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName, PagingRequest pagingRequest, boolean sortByName,
|
default PagingResults<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName, PagingRequest pagingRequest, boolean sortByName,
|
||||||
Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||||
{
|
{
|
||||||
return new EmptyPagingResults<>();
|
return new EmptyPagingResults<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a collection of the root categories for an aspect/classification supporting multiple name filters.
|
||||||
|
*/
|
||||||
|
@Auditable(parameters = {"storeRef", "aspectName", "exactNamesFilter", "alikeNamesFilter"})
|
||||||
|
default Collection<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||||
|
{
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the root categories for an aspect/classification with names that start with filter
|
* Get the root categories for an aspect/classification with names that start with filter
|
||||||
*
|
*
|
||||||
|
@@ -28,6 +28,7 @@ package org.alfresco.service.cmr.tagging;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.api.AlfrescoPublicApi;
|
import org.alfresco.api.AlfrescoPublicApi;
|
||||||
import org.alfresco.query.EmptyPagingResults;
|
import org.alfresco.query.EmptyPagingResults;
|
||||||
@@ -94,6 +95,18 @@ public interface TaggingService
|
|||||||
{
|
{
|
||||||
return new EmptyPagingResults<>();
|
return new EmptyPagingResults<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a map of tag NodeRefs and their respective usage count filtered by name and sorted by tag name or count
|
||||||
|
*
|
||||||
|
* @param storeRef
|
||||||
|
* @param parameterIncludes
|
||||||
|
* @param sorting
|
||||||
|
* @param exactNamesFilter
|
||||||
|
* @param alikeNamesFilter
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Map<NodeRef, Long> getTags(StoreRef storeRef, List<String>parameterIncludes, Pair<String, Boolean> sorting, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the tags currently available that match the provided filter.
|
* Get all the tags currently available that match the provided filter.
|
||||||
@@ -327,8 +340,7 @@ public interface TaggingService
|
|||||||
*/
|
*/
|
||||||
@NotAuditable
|
@NotAuditable
|
||||||
Pair<List<String>, Integer> getPagedTags(StoreRef storeRef, String filter, int fromTag, int pageSize);
|
Pair<List<String>, Integer> getPagedTags(StoreRef storeRef, String filter, int fromTag, int pageSize);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get tagged nodes and count of nodes group by tag name
|
* Get tagged nodes and count of nodes group by tag name
|
||||||
*
|
*
|
||||||
@@ -362,6 +374,13 @@ public interface TaggingService
|
|||||||
{
|
{
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param storeRef
|
||||||
|
* @return a map with each tag name and its usage count
|
||||||
|
*/
|
||||||
|
Map<String, Long> calculateCount(StoreRef storeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user