mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-10 14:11:58 +00:00
Compare commits
39 Commits
hack/hacka
...
17.113
Author | SHA1 | Date | |
---|---|---|---|
|
b22595058e | ||
|
742a4c89dd | ||
|
09db0fcad3 | ||
|
313823eb8c | ||
|
b7d2d3bae9 | ||
|
e265bb0a5d | ||
|
6da0d7cc7b | ||
|
430d15f32d | ||
|
3fc0100bb5 | ||
|
7ccd9640ee | ||
|
bea34483b5 | ||
|
e0867a099f | ||
|
172d6c2185 | ||
|
4692d471a3 | ||
|
3c55c1a9a0 | ||
|
400b33c7eb | ||
|
bc9c23503b | ||
|
7ed021fb77 | ||
|
0e73bc1572 | ||
|
7eb063e923 | ||
|
a5a34c05c1 | ||
|
9f4371eb9c | ||
|
5846a1fd11 | ||
|
ffef5f875a | ||
|
fa04a7264f | ||
|
6e5d37067d | ||
|
0bbc63fb20 | ||
|
2819e0590b | ||
|
2a84afe2f0 | ||
|
80ccf64df8 | ||
|
5cf7c1934a | ||
|
25d6b428aa | ||
|
829393b602 | ||
|
18d2dfc84d | ||
|
8cdff26342 | ||
|
8bc3b357cf | ||
|
d2a71d0c9f | ||
|
0eb5a4b806 | ||
|
b8ac41ac0d |
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
- name: "Source Clear Scan (SCA)"
|
||||
stage: test
|
||||
if: branch = master OR branch =~ /release\/.*/
|
||||
if: (branch = master OR branch =~ /release\/.*/) AND type != pull_request
|
||||
# Run Veracode
|
||||
install: skip
|
||||
script: travis_wait 30 bash scripts/travis/source_clear.sh
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -11,7 +11,7 @@ function main()
|
||||
var params =
|
||||
{
|
||||
type: "people",
|
||||
term: args.t,
|
||||
term: args.t + " [hint:useCQ]",
|
||||
maxResults: (args.maxResults !== null) ? parseInt(args.maxResults, 10) : DEFAULT_MAX_RESULTS,
|
||||
startIndex: (args.startIndex !== null) ? parseInt(args.startIndex, 10) : 0
|
||||
};
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -25,6 +25,9 @@ package org.alfresco.error;
|
||||
*/
|
||||
public class ExceptionStackUtil
|
||||
{
|
||||
private static final String JAVASCRIPT_EXCEPTION = "org.mozilla.javascript.JavaScriptException";
|
||||
private static final String EXCEPTION_DELIMITER = ":";
|
||||
|
||||
/**
|
||||
* Searches through the exception stack of the given throwable to find any instance
|
||||
* of the possible cause. The top-level throwable will also be tested.
|
||||
@@ -38,10 +41,17 @@ public class ExceptionStackUtil
|
||||
{
|
||||
while (throwable != null)
|
||||
{
|
||||
Class<?> throwableClass = throwable.getClass();
|
||||
|
||||
boolean isJavaScriptException = throwableClass.getName().contains(JAVASCRIPT_EXCEPTION);
|
||||
String throwableMsg = throwable.getMessage() != null ? throwable.getMessage() : "";
|
||||
|
||||
for (Class<?> possibleCauseClass : possibleCauses)
|
||||
{
|
||||
Class<?> throwableClass = throwable.getClass();
|
||||
if (possibleCauseClass.isAssignableFrom(throwableClass))
|
||||
String possibleCauseClassName = possibleCauseClass.getName();
|
||||
|
||||
if (possibleCauseClass.isAssignableFrom(throwableClass)
|
||||
|| (isJavaScriptException && throwableMsg.contains(possibleCauseClassName + EXCEPTION_DELIMITER)))
|
||||
{
|
||||
// We have a match
|
||||
return throwable;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -9,6 +9,6 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -49,6 +49,7 @@ import java.util.stream.IntStream;
|
||||
|
||||
import org.alfresco.rest.RestTest;
|
||||
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
|
||||
import org.alfresco.rest.model.RestCompositeConditionDefinitionModel;
|
||||
import org.alfresco.rest.model.RestRuleModel;
|
||||
import org.alfresco.rest.model.RestRuleModelsCollection;
|
||||
import org.alfresco.utility.constants.UserRole;
|
||||
@@ -94,7 +95,6 @@ public class CreateRulesTests extends RestTest
|
||||
.createSingleRule(ruleModel);
|
||||
|
||||
RestRuleModel expectedRuleModel = createRuleModelWithModifiedValues();
|
||||
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
|
||||
expectedRuleModel.setConditions(createEmptyConditionModel());
|
||||
restClient.assertStatusCodeIs(CREATED);
|
||||
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
|
||||
@@ -384,7 +384,7 @@ public class CreateRulesTests extends RestTest
|
||||
.createSingleRule(ruleModel);
|
||||
|
||||
final RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
|
||||
expectedRuleModel.setActions(addActionContextParams(Arrays.asList(copyAction, checkOutAction, scriptAction)));
|
||||
expectedRuleModel.setActions(Arrays.asList(copyAction, checkOutAction, scriptAction));
|
||||
expectedRuleModel.setConditions(createEmptyConditionModel());
|
||||
expectedRuleModel.setTriggers(List.of("inbound"));
|
||||
|
||||
@@ -392,4 +392,64 @@ public class CreateRulesTests extends RestTest
|
||||
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
|
||||
.assertThat().field("isShared").isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we can create a rule with multiple conditions
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
public void createRuleWithConditions()
|
||||
{
|
||||
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
||||
ruleModel.setConditions(createVariousConditions());
|
||||
|
||||
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||
.createSingleRule(ruleModel);
|
||||
|
||||
RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
|
||||
expectedRuleModel.setConditions(createVariousConditions());
|
||||
expectedRuleModel.setTriggers(List.of("inbound"));
|
||||
restClient.assertStatusCodeIs(CREATED);
|
||||
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we can create a rule with empty list as conditions
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
public void createRuleWithConditions_emptyConditionList()
|
||||
{
|
||||
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
||||
ruleModel.setConditions(createCompositeCondition(null));
|
||||
|
||||
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||
.createSingleRule(ruleModel);
|
||||
|
||||
RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
|
||||
expectedRuleModel.setConditions(createCompositeCondition(null));
|
||||
expectedRuleModel.setTriggers(List.of("inbound"));
|
||||
restClient.assertStatusCodeIs(CREATED);
|
||||
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we can NOT create a rule when category ID in condition is invalid, HTTP status code 400 is expected
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
public void createRuleWithConditions_invalidCategory()
|
||||
{
|
||||
STEP("Try to create a rule with non existing category in conditions.");
|
||||
String fakeCategoryId = "bdba5f9f-fake-id22-803b-349bcfd06fd1";
|
||||
RestCompositeConditionDefinitionModel conditions = createCompositeCondition(List.of(
|
||||
createCompositeCondition(!INVERTED, List.of(
|
||||
createSimpleCondition("category", "equals", fakeCategoryId)
|
||||
))
|
||||
));
|
||||
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
||||
ruleModel.setConditions(conditions);
|
||||
|
||||
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
|
||||
|
||||
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||
restClient.assertLastError().containsSummary("Category in condition is invalid");
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* #%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 <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.rest.rules;
|
||||
|
||||
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithModifiedValues;
|
||||
import static org.alfresco.utility.report.log.Step.STEP;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.alfresco.rest.RestTest;
|
||||
import org.alfresco.rest.model.RestRuleModel;
|
||||
import org.alfresco.rest.model.RestRuleModelsCollection;
|
||||
import org.alfresco.rest.model.RestRuleSetLinkModel;
|
||||
import org.alfresco.rest.model.RestRuleSetModel;
|
||||
import org.alfresco.rest.model.RestRuleSetModelsCollection;
|
||||
import org.alfresco.utility.model.FolderModel;
|
||||
import org.alfresco.utility.model.SiteModel;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for GET /nodes/{nodeId}/rule-sets/{ruleSetId}/rules with rule inheritance.
|
||||
*/
|
||||
@Test(groups = {TestGroup.RULES})
|
||||
public class GetInheritedRulesTests extends RestTest
|
||||
{
|
||||
private UserModel user;
|
||||
private SiteModel site;
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void dataPreparation()
|
||||
{
|
||||
STEP("Create a user and site");
|
||||
user = dataUser.createRandomTestUser();
|
||||
site = dataSite.usingUser(user).createPublicRandomSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we can get all the rules for the folder by providing the different rule set ids.
|
||||
*/
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
|
||||
public void getInheritedRules()
|
||||
{
|
||||
STEP("Create a parent and child folder, each with inheriting rules");
|
||||
FolderModel parent = dataContent.usingUser(user).usingSite(site).createFolder();
|
||||
FolderModel child = dataContent.usingUser(user).usingResource(parent).createFolder();
|
||||
RestRuleModel parentRule = createRuleModelWithModifiedValues();
|
||||
parentRule = restClient.authenticateUser(user).withCoreAPI().usingNode(parent).usingDefaultRuleSet().createSingleRule(parentRule);
|
||||
RestRuleModel childRule = createRuleModelWithModifiedValues();
|
||||
childRule = restClient.authenticateUser(user).withCoreAPI().usingNode(child).usingDefaultRuleSet().createSingleRule(childRule);
|
||||
|
||||
STEP("Get the rules in the default rule set for the child folder");
|
||||
RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(child).usingDefaultRuleSet().getListOfRules();
|
||||
rules.assertThat().entriesListContains("id", childRule.getId())
|
||||
.and().entriesListCountIs(1);
|
||||
|
||||
STEP("Get the rules in the inherited rule set for the child folder");
|
||||
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(child).include("inclusionType").getListOfRuleSets();
|
||||
String inheritedRuleSetId = ruleSets.getEntries().stream()
|
||||
.filter(ruleSet -> ruleSet.onModel().getInclusionType().equals("inherited"))
|
||||
.findFirst().get().onModel().getId();
|
||||
RestRuleModelsCollection inheritedRules = restClient.authenticateUser(user).withCoreAPI().usingNode(child).usingRuleSet(inheritedRuleSetId).getListOfRules();
|
||||
inheritedRules.assertThat().entriesListContains("id", parentRule.getId())
|
||||
.and().entriesListCountIs(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that we only get each rule once with linking and inheritance, and the order is correct.
|
||||
* <p>
|
||||
* The folder structure for this test is as follows:
|
||||
* <pre>
|
||||
* A --[links]-> DRuleSet
|
||||
* +-B --[owns]-> BRuleSet
|
||||
* +-C --[owns]-> CRuleSet
|
||||
* +-D --[owns]--> DRuleSet
|
||||
* </pre>
|
||||
*/
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
|
||||
public void rulesReturnedAreUnique()
|
||||
{
|
||||
STEP("Create four folders with rules");
|
||||
FolderModel folderA = dataContent.usingUser(user).usingSite(site).createFolder();
|
||||
FolderModel folderB = dataContent.usingUser(user).usingResource(folderA).createFolder();
|
||||
FolderModel folderC = dataContent.usingUser(user).usingResource(folderB).createFolder();
|
||||
FolderModel folderD = dataContent.usingUser(user).usingResource(folderC).createFolder();
|
||||
RestRuleModel ruleB = restClient.authenticateUser(user).withCoreAPI().usingNode(folderB).usingDefaultRuleSet().createSingleRule(createRuleModelWithModifiedValues());
|
||||
RestRuleModel ruleC = restClient.authenticateUser(user).withCoreAPI().usingNode(folderC).usingDefaultRuleSet().createSingleRule(createRuleModelWithModifiedValues());
|
||||
RestRuleModel ruleD = restClient.authenticateUser(user).withCoreAPI().usingNode(folderD).usingDefaultRuleSet().createSingleRule(createRuleModelWithModifiedValues());
|
||||
STEP("Link folderA to ruleSetD");
|
||||
RestRuleSetLinkModel linkModel = new RestRuleSetLinkModel();
|
||||
linkModel.setId(folderD.getNodeRef());
|
||||
restClient.authenticateUser(user).withCoreAPI().usingNode(folderA).createRuleLink(linkModel);
|
||||
|
||||
STEP("Get the rule sets for the folderD");
|
||||
List<RestRuleSetModel> ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(folderD).getListOfRuleSets().getEntries();
|
||||
|
||||
STEP("Check the rules for each rule set are as expected");
|
||||
List<RestRuleModel> expectedRuleIds = List.of(ruleD, ruleB, ruleC);
|
||||
IntStream.range(0, 2).forEach(index -> {
|
||||
String ruleSetId = ruleSets.get(index).onModel().getId();
|
||||
List<RestRuleModel> rules = restClient.authenticateUser(user)
|
||||
.withCoreAPI()
|
||||
.usingNode(folderD)
|
||||
.usingRuleSet(ruleSetId)
|
||||
.getListOfRules()
|
||||
.getEntries()
|
||||
.stream()
|
||||
.map(RestRuleModel::onModel)
|
||||
.collect(Collectors.toList());
|
||||
assertEquals(rules, List.of(expectedRuleIds.get(index)), "Unexpected rules found for rule set " + ruleSetId);
|
||||
});
|
||||
assertEquals(ruleSets.size(), 3, "Expected three unique rule sets to be returned but got " + ruleSets);
|
||||
}
|
||||
}
|
@@ -35,6 +35,7 @@ import org.alfresco.rest.RestTest;
|
||||
import org.alfresco.rest.model.RestRuleModel;
|
||||
import org.alfresco.rest.model.RestRuleSetModel;
|
||||
import org.alfresco.rest.model.RestRuleSetModelsCollection;
|
||||
import org.alfresco.rest.model.RestRuleSettingsModel;
|
||||
import org.alfresco.utility.model.FolderModel;
|
||||
import org.alfresco.utility.model.SiteModel;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
@@ -51,6 +52,8 @@ public class GetRuleSetsTests extends RestTest
|
||||
private UserModel user;
|
||||
private SiteModel site;
|
||||
private FolderModel ruleFolder;
|
||||
private FolderModel inheritingChildFolder;
|
||||
private FolderModel notInheritingChildFolder;
|
||||
private RestRuleModel rule;
|
||||
private String ruleSetId;
|
||||
|
||||
@@ -62,6 +65,14 @@ public class GetRuleSetsTests extends RestTest
|
||||
site = dataSite.usingUser(user).createPublicRandomSite();
|
||||
ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
|
||||
|
||||
STEP("Create two children of the folder - one that inherits rules and one that doesn't");
|
||||
inheritingChildFolder = dataContent.usingUser(user).usingResource(ruleFolder).createFolder();
|
||||
notInheritingChildFolder = dataContent.usingUser(user).usingResource(ruleFolder).createFolder();
|
||||
RestRuleSettingsModel doesntInherit = new RestRuleSettingsModel();
|
||||
doesntInherit.setValue(false);
|
||||
restClient.authenticateUser(user).withCoreAPI().usingNode(notInheritingChildFolder)
|
||||
.usingIsInheritanceEnabledRuleSetting().updateSetting(doesntInherit);
|
||||
|
||||
STEP("Create a rule in the folder.");
|
||||
RestRuleModel ruleModel = createRuleModel("ruleName");
|
||||
rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||
@@ -133,7 +144,7 @@ public class GetRuleSetsTests extends RestTest
|
||||
|
||||
/** Check we can get the reason that a rule set is included in the list. */
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void getRuleSetsAndInclusionType()
|
||||
public void getRuleSetsAndOwnedInclusionType()
|
||||
{
|
||||
STEP("Get the rule sets and inclusion type");
|
||||
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
|
||||
@@ -148,6 +159,36 @@ public class GetRuleSetsTests extends RestTest
|
||||
ruleSets.assertThat().entriesListCountIs(1);
|
||||
}
|
||||
|
||||
/** Check we can tell that a rule set has been inherited. */
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void getRuleSetsAndInheritedInclusionType()
|
||||
{
|
||||
STEP("Get the rule sets and inclusion type");
|
||||
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
|
||||
.usingNode(inheritingChildFolder)
|
||||
.include("inclusionType")
|
||||
.getListOfRuleSets();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
ruleSets.getEntries().get(0).onModel()
|
||||
.assertThat().field("inclusionType").is("inherited")
|
||||
.assertThat().field("id").is(ruleSetId);
|
||||
ruleSets.assertThat().entriesListCountIs(1);
|
||||
}
|
||||
|
||||
/** Check that a rule set is not inherited if inheriting is disabled. */
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void getRuleSetsWithoutInheriting()
|
||||
{
|
||||
STEP("Get the rule sets and inclusion type");
|
||||
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
|
||||
.usingNode(notInheritingChildFolder)
|
||||
.getListOfRuleSets();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
ruleSets.assertThat().entriesListCountIs(0);
|
||||
}
|
||||
|
||||
/** Check we can get a rule set by its id. */
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
|
||||
public void getRuleSetById()
|
||||
|
@@ -189,7 +189,6 @@ public class GetRulesTests extends RestTest
|
||||
.createSingleRule(ruleModel);
|
||||
|
||||
RestRuleModel expectedRuleModel = createRuleModelWithModifiedValues();
|
||||
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
|
||||
expectedRuleModel.setTriggers(List.of("update"));
|
||||
expectedRuleModel.setConditions(createEmptyConditionModel());
|
||||
|
||||
@@ -212,7 +211,6 @@ public class GetRulesTests extends RestTest
|
||||
.createSingleRule(ruleModel);
|
||||
|
||||
RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
|
||||
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
|
||||
expectedRuleModel.setTriggers(List.of("inbound"));
|
||||
expectedRuleModel.setConditions(createEmptyConditionModel());
|
||||
|
||||
|
@@ -234,7 +234,7 @@ public class RuleSetLinksTests extends RestTest
|
||||
STEP("Assert link result is 400");
|
||||
restClient.assertStatusCodeIs(BAD_REQUEST)
|
||||
.assertLastError().containsSummary(
|
||||
"Unable to link to a ruleset because the folder has pre-existing rules or is already linked to a ruleset.");
|
||||
"Unable to link to a rule set because the folder has pre-existing rules or is already linked to a rule set.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -26,13 +26,13 @@
|
||||
package org.alfresco.rest.rules;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
|
||||
import org.alfresco.rest.model.RestCompositeConditionDefinitionModel;
|
||||
import org.alfresco.rest.model.RestRuleModel;
|
||||
import org.alfresco.rest.model.RestSimpleConditionDefinitionModel;
|
||||
|
||||
public class RulesTestsUtils
|
||||
{
|
||||
@@ -44,6 +44,8 @@ public class RulesTestsUtils
|
||||
static final boolean RULE_SHARED_DEFAULT = false;
|
||||
static final String RULE_ERROR_SCRIPT_DEFAULT = "error-script";
|
||||
static final List<String> ruleTriggersDefault = List.of("inbound", "update", "outbound");
|
||||
static final boolean INVERTED = true;
|
||||
static final String AND = "and";
|
||||
|
||||
/**
|
||||
* Create a rule model filled with default values.
|
||||
@@ -102,16 +104,6 @@ public class RulesTestsUtils
|
||||
return restActionModel;
|
||||
}
|
||||
|
||||
public static List<RestActionBodyExecTemplateModel> addActionContextParams(List<RestActionBodyExecTemplateModel> inputActions)
|
||||
{
|
||||
inputActions.forEach(inputAction -> {
|
||||
final Map<String, Serializable> params = new HashMap<>((Map<String, Serializable>) inputAction.getParams());
|
||||
params.put("actionContext", "rule");
|
||||
inputAction.setParams(params);
|
||||
});
|
||||
return inputActions;
|
||||
}
|
||||
|
||||
public static RestActionBodyExecTemplateModel createCustomActionModel(String actionDefinitionId, Map<String, Serializable> params)
|
||||
{
|
||||
RestActionBodyExecTemplateModel restActionModel = new RestActionBodyExecTemplateModel();
|
||||
@@ -123,8 +115,59 @@ public class RulesTestsUtils
|
||||
public static RestCompositeConditionDefinitionModel createEmptyConditionModel()
|
||||
{
|
||||
RestCompositeConditionDefinitionModel conditions = new RestCompositeConditionDefinitionModel();
|
||||
conditions.setInverted(false);
|
||||
conditions.setBooleanMode("and");
|
||||
conditions.setInverted(!INVERTED);
|
||||
conditions.setBooleanMode(AND);
|
||||
return conditions;
|
||||
}
|
||||
|
||||
public static RestCompositeConditionDefinitionModel createVariousConditions()
|
||||
{
|
||||
return createCompositeCondition(List.of(
|
||||
createCompositeCondition(!INVERTED, List.of(
|
||||
createSimpleCondition("cm:created", "less_than", "2022-09-01T12:59:00.000+02:00"),
|
||||
createSimpleCondition("cm:creator", "ends", "ski"),
|
||||
createSimpleCondition("size", "greater_than", "90000000"),
|
||||
createSimpleCondition("mimetype", "equals", "video/3gpp"),
|
||||
createSimpleCondition("encoding", "equals", "utf-8"),
|
||||
createSimpleCondition("type", "equals", "cm:folder"),
|
||||
createSimpleCondition("tag", "equals", "uat")
|
||||
)),
|
||||
createCompositeCondition(INVERTED, List.of(
|
||||
createSimpleCondition("aspect", "equals", "audio:audio"),
|
||||
createSimpleCondition("cm:modelVersion", "begins", "1.")
|
||||
))
|
||||
));
|
||||
}
|
||||
|
||||
public static RestSimpleConditionDefinitionModel createSimpleCondition(String field, String comparator, String parameter)
|
||||
{
|
||||
RestSimpleConditionDefinitionModel simpleCondition = new RestSimpleConditionDefinitionModel();
|
||||
simpleCondition.setField(field);
|
||||
simpleCondition.setComparator(comparator);
|
||||
simpleCondition.setParameter(parameter);
|
||||
return simpleCondition;
|
||||
}
|
||||
|
||||
public static RestCompositeConditionDefinitionModel createCompositeCondition(List<RestCompositeConditionDefinitionModel> compositeConditions)
|
||||
{
|
||||
return createCompositeCondition(AND, !INVERTED, compositeConditions, null);
|
||||
}
|
||||
|
||||
public static RestCompositeConditionDefinitionModel createCompositeCondition(boolean inverted,
|
||||
List<RestSimpleConditionDefinitionModel> simpleConditions)
|
||||
{
|
||||
return createCompositeCondition(AND, inverted, null, simpleConditions);
|
||||
}
|
||||
|
||||
private static RestCompositeConditionDefinitionModel createCompositeCondition(String booleanMode, boolean inverted,
|
||||
List<RestCompositeConditionDefinitionModel> compositeConditions, List<RestSimpleConditionDefinitionModel> simpleConditions)
|
||||
{
|
||||
RestCompositeConditionDefinitionModel compositeCondition = new RestCompositeConditionDefinitionModel();
|
||||
compositeCondition.setBooleanMode(booleanMode);
|
||||
compositeCondition.setInverted(inverted);
|
||||
compositeCondition.setCompositeConditions(compositeConditions);
|
||||
compositeCondition.setSimpleConditions(simpleConditions);
|
||||
|
||||
return compositeCondition;
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,8 @@ import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import org.alfresco.rest.RestTest;
|
||||
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
|
||||
import org.alfresco.rest.model.RestRuleModel;
|
||||
@@ -198,6 +200,29 @@ public class UpdateRulesTests extends RestTest
|
||||
updatedRule.assertThat().field("isShared").isNotNull();
|
||||
}
|
||||
|
||||
/** Check we can use the POST response to create the new rule. */
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
|
||||
public void updateCopyRuleWithResponseFromPOST()
|
||||
{
|
||||
FolderModel destination = dataContent.usingUser(user).usingSite(site).createFolder();
|
||||
|
||||
RestActionBodyExecTemplateModel copyAction = new RestActionBodyExecTemplateModel();
|
||||
copyAction.setActionDefinitionId("copy");
|
||||
copyAction.setParams(ImmutableMap.of("destination-folder", destination.getNodeRef()));
|
||||
RestRuleModel rule = createAndSaveRule("Rule name", List.of(copyAction));
|
||||
|
||||
STEP("Try to update the rule.");
|
||||
rule.setName("Updated rule name");
|
||||
RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||
.include("isShared")
|
||||
.updateRule(rule.getId(), rule);
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
updatedRule.assertThat().field("name").is("Updated rule name")
|
||||
.assertThat().field("actions.actionDefinitionId").is(List.of("copy"))
|
||||
.assertThat().field("actions.params").is(List.of(ImmutableMap.of("destination-folder", destination.getNodeRef())));
|
||||
}
|
||||
|
||||
private RestRuleModel createAndSaveRule(String name)
|
||||
{
|
||||
return createAndSaveRule(name, List.of(createDefaultActionModel()));
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
25
pom.xml
25
pom.xml
@@ -2,7 +2,7 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Alfresco Community Repo Parent</name>
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
<dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version>
|
||||
<dependency.xercesImpl.version>2.12.2</dependency.xercesImpl.version>
|
||||
<dependency.slf4j.version>1.7.36</dependency.slf4j.version>
|
||||
<dependency.gytheio.version>0.16</dependency.gytheio.version>
|
||||
<dependency.gytheio.version>0.17</dependency.gytheio.version>
|
||||
<dependency.groovy.version>3.0.12</dependency.groovy.version>
|
||||
<dependency.tika.version>2.4.1</dependency.tika.version>
|
||||
<dependency.spring-security.version>5.7.2</dependency.spring-security.version>
|
||||
@@ -84,7 +84,10 @@
|
||||
<dependency.ooxml-schemas.version>1.4</dependency.ooxml-schemas.version>
|
||||
<dependency.keycloak.version>18.0.0</dependency.keycloak.version>
|
||||
<dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
|
||||
<dependency.camel.version>3.15.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies (can cause dependency conflicts)-->
|
||||
<dependency.camel.version>3.18.2</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
|
||||
<dependency.netty.version>4.1.79.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
|
||||
<dependency.netty.qpid.version>4.1.72.Final</dependency.netty.qpid.version> <!-- must be in sync with camels transitive dependencies: native-unix-common/native-epoll/native-kqueue -->
|
||||
<dependency.netty-tcnative.version>2.0.53.Final</dependency.netty-tcnative.version> <!-- must be in sync with camels transitive dependencies -->
|
||||
<dependency.activemq.version>5.17.1</dependency.activemq.version>
|
||||
<dependency.apache-compress.version>1.21</dependency.apache-compress.version>
|
||||
<dependency.apache.taglibs.version>1.2.5</dependency.apache.taglibs.version>
|
||||
@@ -107,7 +110,7 @@
|
||||
<dependency.jakarta-json-path.version>2.7.0</dependency.jakarta-json-path.version>
|
||||
<dependency.jakarta-rpc-api.version>1.1.4</dependency.jakarta-rpc-api.version>
|
||||
|
||||
<alfresco.googledrive.version>3.2.2</alfresco.googledrive.version>
|
||||
<alfresco.googledrive.version>3.2.3-A2</alfresco.googledrive.version>
|
||||
<alfresco.aos-module.version>1.4.1</alfresco.aos-module.version>
|
||||
<alfresco.api-explorer.version>7.2.1</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
|
||||
|
||||
@@ -148,7 +151,7 @@
|
||||
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
|
||||
<url>https://github.com/Alfresco/alfresco-community-repo</url>
|
||||
<tag>HEAD</tag>
|
||||
<tag>17.113</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -851,6 +854,18 @@
|
||||
<artifactId>camel-mock</artifactId>
|
||||
<version>${dependency.camel.version}</version>
|
||||
</dependency>
|
||||
<!-- Netty non-transitive dependencies declared for depending projects usage in conjunction with Camel's other transitive netty dependencies -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-handler-proxy</artifactId>
|
||||
<version>${dependency.netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-tcnative-classes</artifactId>
|
||||
<version>${dependency.netty-tcnative.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.taglibs</groupId>
|
||||
<artifactId>taglibs-standard-spec</artifactId>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -180,6 +180,12 @@ public class NodeValidator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if rule set node or folder node's default rule set is shared
|
||||
* @param ruleSetNodeRef
|
||||
* @param folderNodeRef
|
||||
* @return
|
||||
*/
|
||||
public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
|
||||
{
|
||||
if (ruleSetNodeRef == null && folderNodeRef != null)
|
||||
|
@@ -31,6 +31,7 @@ import org.alfresco.rest.api.model.rules.Rule;
|
||||
import org.alfresco.service.Experimental;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.rule.RuleService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
|
||||
/** Responsible for creating {@link Rule} objects. */
|
||||
@Experimental
|
||||
@@ -39,10 +40,11 @@ public class RuleLoader
|
||||
public static final String IS_SHARED = "isShared";
|
||||
private RuleService ruleService;
|
||||
private NodeValidator nodeValidator;
|
||||
private NamespaceService namespaceService;
|
||||
|
||||
public Rule loadRule(org.alfresco.service.cmr.rule.Rule ruleModel, List<String> includes)
|
||||
{
|
||||
Rule rule = Rule.from(ruleModel);
|
||||
Rule rule = Rule.from(ruleModel, namespaceService);
|
||||
if (includes != null && includes.contains(IS_SHARED))
|
||||
{
|
||||
NodeRef ruleSet = ruleService.getRuleSetNode(ruleModel.getNodeRef());
|
||||
@@ -61,4 +63,9 @@ public class RuleLoader
|
||||
{
|
||||
this.nodeValidator = nodeValidator;
|
||||
}
|
||||
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ package org.alfresco.rest.api.impl.rules;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.alfresco.repo.rule.RuleModel;
|
||||
import org.alfresco.repo.rule.RuntimeRuleService;
|
||||
@@ -59,10 +59,13 @@ public class RuleSetsImpl implements RuleSets
|
||||
{
|
||||
NodeRef folderNode = validator.validateFolderNode(folderNodeId, false);
|
||||
|
||||
NodeRef ruleSetNode = ruleService.getRuleSetNode(folderNode);
|
||||
List<RuleSet> ruleSets = Optional.ofNullable(ruleSetNode)
|
||||
.map(nodeRef -> ruleSetLoader.loadRuleSet(nodeRef, folderNode, includes))
|
||||
.stream().collect(toList());
|
||||
List<RuleSet> ruleSets = ruleService.getNodesSupplyingRuleSets(folderNode)
|
||||
.stream()
|
||||
.map(ruleService::getRuleSetNode)
|
||||
.filter(Objects::nonNull)
|
||||
.map(nodeRef -> ruleSetLoader.loadRuleSet(nodeRef, folderNode, includes))
|
||||
.distinct()
|
||||
.collect(toList());
|
||||
|
||||
return ListPage.of(ruleSets, paging);
|
||||
}
|
||||
@@ -93,7 +96,7 @@ public class RuleSetsImpl implements RuleSets
|
||||
|
||||
//The folder shouldn't have any pre-existing rules
|
||||
if (ruleService.hasRules(folderNodeRef)) {
|
||||
throw new InvalidArgumentException("Unable to link to a ruleset because the folder has pre-existing rules or is already linked to a ruleset.");
|
||||
throw new InvalidArgumentException("Unable to link to a rule set because the folder has pre-existing rules or is already linked to a rule set.");
|
||||
}
|
||||
|
||||
// Create the destination folder as a secondary child of the first
|
||||
|
@@ -41,6 +41,7 @@ import org.alfresco.service.Experimental;
|
||||
import org.alfresco.service.cmr.action.CompositeAction;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.rule.RuleService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -55,6 +56,7 @@ public class RulesImpl implements Rules
|
||||
private RuleLoader ruleLoader;
|
||||
private ActionParameterConverter actionParameterConverter;
|
||||
private ActionPermissionValidator actionPermissionValidator;
|
||||
private NamespaceService namespaceService;
|
||||
|
||||
@Override
|
||||
public CollectionWithPagingInfo<Rule> getRules(final String folderNodeId,
|
||||
@@ -63,9 +65,10 @@ public class RulesImpl implements Rules
|
||||
final Paging paging)
|
||||
{
|
||||
final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false);
|
||||
validator.validateRuleSetNode(ruleSetId, folderNodeRef);
|
||||
NodeRef ruleSetNode = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
|
||||
NodeRef owningFolder = ruleService.getOwningNodeRef(ruleSetNode);
|
||||
|
||||
final List<Rule> rules = ruleService.getRules(folderNodeRef).stream()
|
||||
final List<Rule> rules = ruleService.getRules(owningFolder, false).stream()
|
||||
.map(ruleModel -> loadRuleAndConvertActionParams(ruleModel, includes))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -123,7 +126,7 @@ public class RulesImpl implements Rules
|
||||
|
||||
private org.alfresco.service.cmr.rule.Rule mapToServiceModelAndValidateActions(Rule rule)
|
||||
{
|
||||
final org.alfresco.service.cmr.rule.Rule serviceModelRule = rule.toServiceModel(nodes);
|
||||
final org.alfresco.service.cmr.rule.Rule serviceModelRule = rule.toServiceModel(nodes, namespaceService);
|
||||
final CompositeAction compositeAction = (CompositeAction) serviceModelRule.getAction();
|
||||
compositeAction.getActions().forEach(action -> action.setParameterValues(
|
||||
actionParameterConverter.getConvertedParams(action.getParameterValues(), action.getActionDefinitionName())));
|
||||
@@ -133,7 +136,6 @@ public class RulesImpl implements Rules
|
||||
|
||||
private Rule loadRuleAndConvertActionParams(org.alfresco.service.cmr.rule.Rule ruleModel, List<String> includes)
|
||||
{
|
||||
|
||||
final Rule rule = ruleLoader.loadRule(ruleModel, includes);
|
||||
rule.getActions()
|
||||
.forEach(a -> a.setParams(a.getParams().entrySet()
|
||||
@@ -174,4 +176,9 @@ public class RulesImpl implements Rules
|
||||
{
|
||||
this.actionPermissionValidator = actionPermissionValidator;
|
||||
}
|
||||
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,8 @@
|
||||
|
||||
package org.alfresco.rest.api.model.rules;
|
||||
|
||||
import static org.alfresco.repo.action.access.ActionAccessRestriction.ACTION_CONTEXT_PARAM_NAME;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -60,7 +62,9 @@ public class Action
|
||||
final Action.Builder builder = builder().actionDefinitionId(actionModel.getActionDefinitionName());
|
||||
if (actionModel.getParameterValues() != null)
|
||||
{
|
||||
builder.params(new HashMap<>(actionModel.getParameterValues()));
|
||||
Map<String, Serializable> params = new HashMap<>(actionModel.getParameterValues());
|
||||
params.remove(ACTION_CONTEXT_PARAM_NAME);
|
||||
builder.params(params);
|
||||
}
|
||||
|
||||
return builder.create();
|
||||
|
@@ -32,8 +32,10 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.alfresco.rest.api.Nodes;
|
||||
import org.alfresco.service.Experimental;
|
||||
import org.alfresco.service.cmr.action.ActionCondition;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
@Experimental
|
||||
@@ -50,7 +52,7 @@ public class CompositeCondition
|
||||
* @param actionConditions - list of {@link ActionCondition} service POJOs
|
||||
* @return {@link CompositeCondition} REST model
|
||||
*/
|
||||
public static CompositeCondition from(final List<ActionCondition> actionConditions)
|
||||
public static CompositeCondition from(final List<ActionCondition> actionConditions, final NamespaceService namespaceService)
|
||||
{
|
||||
if (actionConditions == null)
|
||||
{
|
||||
@@ -62,7 +64,7 @@ public class CompositeCondition
|
||||
// group action conditions by inversion flag
|
||||
actionConditions.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(ActionCondition::getInvertCondition))
|
||||
// map action condition sub lists
|
||||
.forEach((inverted, actionConditionsPart) -> Optional.ofNullable(CompositeCondition.ofActionConditions(actionConditionsPart, inverted, ConditionOperator.AND))
|
||||
.forEach((inverted, actionConditionsPart) -> Optional.ofNullable(CompositeCondition.ofActionConditions(actionConditionsPart, namespaceService, inverted, ConditionOperator.AND))
|
||||
// if composite condition present add to final list
|
||||
.ifPresent(compositeCondition -> conditions.compositeConditions.add(compositeCondition)));
|
||||
|
||||
@@ -73,14 +75,14 @@ public class CompositeCondition
|
||||
return conditions;
|
||||
}
|
||||
|
||||
private static CompositeCondition ofActionConditions(final List<ActionCondition> actionConditions, final boolean inverted, final ConditionOperator conditionOperator)
|
||||
private static CompositeCondition ofActionConditions(final List<ActionCondition> actionConditions, final NamespaceService namespaceService, final boolean inverted, final ConditionOperator conditionOperator)
|
||||
{
|
||||
if (actionConditions == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ofSimpleConditions(SimpleCondition.listOf(actionConditions), inverted, conditionOperator);
|
||||
return ofSimpleConditions(SimpleCondition.listOf(actionConditions, namespaceService), inverted, conditionOperator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,6 +114,21 @@ public class CompositeCondition
|
||||
.create();
|
||||
}
|
||||
|
||||
public List<ActionCondition> toServiceModels(final Nodes nodes, final NamespaceService namespaceService)
|
||||
{
|
||||
final List<ActionCondition> actionConditions = new ArrayList<>();
|
||||
if (CollectionUtils.isNotEmpty(simpleConditions))
|
||||
{
|
||||
simpleConditions.forEach(simpleCondition -> actionConditions.add(simpleCondition.toServiceModel(inverted, nodes, namespaceService)));
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(compositeConditions))
|
||||
{
|
||||
compositeConditions.forEach(compositeCondition -> actionConditions.addAll(compositeCondition.toServiceModels(nodes, namespaceService)));
|
||||
}
|
||||
|
||||
return actionConditions;
|
||||
}
|
||||
|
||||
public boolean isInverted()
|
||||
{
|
||||
return inverted;
|
||||
@@ -131,6 +148,14 @@ public class CompositeCondition
|
||||
return booleanMode.name().toLowerCase();
|
||||
}
|
||||
|
||||
public void setBooleanMode(String booleanMode)
|
||||
{
|
||||
if (booleanMode != null)
|
||||
{
|
||||
this.booleanMode = ConditionOperator.valueOf(booleanMode.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
public void setBooleanMode(ConditionOperator booleanMode)
|
||||
{
|
||||
this.booleanMode = booleanMode;
|
||||
|
@@ -37,6 +37,7 @@ import org.alfresco.rest.framework.resource.UniqueId;
|
||||
import org.alfresco.service.Experimental;
|
||||
import org.alfresco.service.cmr.action.CompositeAction;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.util.GUID;
|
||||
|
||||
@Experimental
|
||||
@@ -60,7 +61,7 @@ public class Rule
|
||||
* @param ruleModel - {@link org.alfresco.service.cmr.rule.Rule} service POJO
|
||||
* @return {@link Rule} REST model
|
||||
*/
|
||||
public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel)
|
||||
public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel, final NamespaceService namespaceService)
|
||||
{
|
||||
if (ruleModel == null)
|
||||
{
|
||||
@@ -83,7 +84,7 @@ public class Rule
|
||||
}
|
||||
if (ruleModel.getAction() != null)
|
||||
{
|
||||
builder.conditions(CompositeCondition.from(ruleModel.getAction().getActionConditions()));
|
||||
builder.conditions(CompositeCondition.from(ruleModel.getAction().getActionConditions(), namespaceService));
|
||||
if (ruleModel.getAction().getCompensatingAction() != null && ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF) != null)
|
||||
{
|
||||
builder.errorScript(ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF).toString());
|
||||
@@ -103,7 +104,7 @@ public class Rule
|
||||
* @param nodes The nodes API.
|
||||
* @return The rule service POJO.
|
||||
*/
|
||||
public org.alfresco.service.cmr.rule.Rule toServiceModel(Nodes nodes)
|
||||
public org.alfresco.service.cmr.rule.Rule toServiceModel(final Nodes nodes, final NamespaceService namespaceService)
|
||||
{
|
||||
final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule();
|
||||
final NodeRef nodeRef = (id != null) ? nodes.validateOrLookupNode(id, null) : null;
|
||||
@@ -124,6 +125,10 @@ public class Rule
|
||||
compensatingAction.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, errorScript);
|
||||
ruleModel.getAction().setCompensatingAction(compensatingAction);
|
||||
}
|
||||
if (conditions != null)
|
||||
{
|
||||
conditions.toServiceModels(nodes, namespaceService).forEach(condition -> ruleModel.getAction().addActionCondition(condition));
|
||||
}
|
||||
|
||||
return ruleModel;
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ public class RuleSetLink
|
||||
{
|
||||
|
||||
/**
|
||||
* This id is referring to the node id of the linked-to-folder which contains the ruleset(s)
|
||||
* This id is referring to the node id of the linked-to-folder which contains the rule set(s)
|
||||
*/
|
||||
private String id;
|
||||
|
||||
|
@@ -26,27 +26,41 @@
|
||||
|
||||
package org.alfresco.rest.api.model.rules;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionConditionImpl;
|
||||
import org.alfresco.repo.action.evaluator.CompareMimeTypeEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.HasAspectEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.HasChildEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.HasTagEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.HasVersionHistoryEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.InCategoryEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.IsSubTypeEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.NoConditionEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.compare.ComparePropertyValueOperation;
|
||||
import org.alfresco.repo.action.evaluator.compare.ContentPropertyName;
|
||||
import org.alfresco.rest.api.Nodes;
|
||||
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
|
||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
|
||||
import org.alfresco.service.Experimental;
|
||||
import org.alfresco.service.cmr.action.ActionCondition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
@Experimental
|
||||
public class SimpleCondition
|
||||
{
|
||||
private static final String COMPARATOR_EQUALS = "equals";
|
||||
private static final String CATEGORY_INVALID_MSG = "Category in condition is invalid";
|
||||
public static final String PARAM_CATEGORY = "category";
|
||||
public static final String PARAM_MIMETYPE = "mimetype";
|
||||
|
||||
private String field;
|
||||
private String comparator;
|
||||
@@ -58,7 +72,7 @@ public class SimpleCondition
|
||||
* @param actionConditions - list of {@link ActionCondition} service POJOs
|
||||
* @return list of {@link SimpleCondition} REST models
|
||||
*/
|
||||
public static List<SimpleCondition> listOf(final List<ActionCondition> actionConditions)
|
||||
public static List<SimpleCondition> listOf(final List<ActionCondition> actionConditions, final NamespaceService namespaceService)
|
||||
{
|
||||
if (CollectionUtils.isEmpty(actionConditions))
|
||||
{
|
||||
@@ -66,7 +80,7 @@ public class SimpleCondition
|
||||
}
|
||||
|
||||
return actionConditions.stream()
|
||||
.map(SimpleCondition::from)
|
||||
.map(actionCondition -> from(actionCondition, namespaceService))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@@ -77,7 +91,7 @@ public class SimpleCondition
|
||||
* @param actionCondition - {@link ActionCondition} service POJO
|
||||
* @return {@link SimpleCondition} REST model
|
||||
*/
|
||||
public static SimpleCondition from(final ActionCondition actionCondition)
|
||||
public static SimpleCondition from(final ActionCondition actionCondition, final NamespaceService namespaceService)
|
||||
{
|
||||
if (actionCondition == null || actionCondition.getActionConditionDefinitionName() == null || actionCondition.getParameterValues() == null)
|
||||
{
|
||||
@@ -87,27 +101,86 @@ public class SimpleCondition
|
||||
switch (actionCondition.getActionConditionDefinitionName())
|
||||
{
|
||||
case ComparePropertyValueEvaluator.NAME:
|
||||
return createComparePropertyValueCondition(actionCondition);
|
||||
return createComparePropertyValueCondition(actionCondition, namespaceService);
|
||||
case CompareMimeTypeEvaluator.NAME:
|
||||
return createCompareMimeTypeCondition(actionCondition);
|
||||
case HasAspectEvaluator.NAME:
|
||||
return createHasAspectCondition(actionCondition);
|
||||
case HasChildEvaluator.NAME:
|
||||
return createHasChildCondition(actionCondition);
|
||||
return createHasAspectCondition(actionCondition, namespaceService);
|
||||
case HasTagEvaluator.NAME:
|
||||
return createHasTagCondition(actionCondition);
|
||||
case HasVersionHistoryEvaluator.NAME:
|
||||
return createHasVersionHistoryCondition(actionCondition);
|
||||
case InCategoryEvaluator.NAME:
|
||||
return createInCategoryCondition(actionCondition);
|
||||
case IsSubTypeEvaluator.NAME:
|
||||
return createIsSubtypeCondition(actionCondition);
|
||||
return createIsSubtypeCondition(actionCondition, namespaceService);
|
||||
case NoConditionEvaluator.NAME:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ActionCondition toServiceModel(final boolean inverted, final Nodes nodes, final NamespaceService namespaceService)
|
||||
{
|
||||
if (field == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, Serializable> parameterValues = new HashMap<>();
|
||||
String conditionDefinitionId;
|
||||
|
||||
switch (field)
|
||||
{
|
||||
case HasAspectEvaluator.PARAM_ASPECT:
|
||||
conditionDefinitionId = HasAspectEvaluator.NAME;
|
||||
parameterValues.put(HasAspectEvaluator.PARAM_ASPECT, QName.createQName(parameter, namespaceService));
|
||||
break;
|
||||
case HasTagEvaluator.PARAM_TAG:
|
||||
conditionDefinitionId = HasTagEvaluator.NAME;
|
||||
parameterValues.put(HasTagEvaluator.PARAM_TAG, parameter);
|
||||
break;
|
||||
case PARAM_CATEGORY:
|
||||
conditionDefinitionId = InCategoryEvaluator.NAME;
|
||||
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, ContentModel.ASPECT_GEN_CLASSIFIABLE);
|
||||
try
|
||||
{
|
||||
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, nodes.validateOrLookupNode(parameter, null));
|
||||
} catch (EntityNotFoundException e) {
|
||||
throw new InvalidArgumentException(CATEGORY_INVALID_MSG);
|
||||
}
|
||||
break;
|
||||
case IsSubTypeEvaluator.PARAM_TYPE:
|
||||
conditionDefinitionId = IsSubTypeEvaluator.NAME;
|
||||
parameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, QName.createQName(parameter, namespaceService));
|
||||
break;
|
||||
case PARAM_MIMETYPE:
|
||||
conditionDefinitionId = CompareMimeTypeEvaluator.NAME;
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT);
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, parameter);
|
||||
break;
|
||||
default:
|
||||
conditionDefinitionId = ComparePropertyValueEvaluator.NAME;
|
||||
try
|
||||
{
|
||||
// if size or encoding create content property evaluator
|
||||
ContentPropertyName.valueOf(field.toUpperCase());
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY, field.toUpperCase());
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT);
|
||||
}
|
||||
catch (IllegalArgumentException ignore)
|
||||
{
|
||||
// else create common property evaluator
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, QName.createQName(field, namespaceService));
|
||||
}
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, comparator.toUpperCase());
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, parameter);
|
||||
break;
|
||||
}
|
||||
|
||||
final ActionCondition actionCondition = new ActionConditionImpl(UUID.randomUUID().toString(), conditionDefinitionId, parameterValues);
|
||||
actionCondition.setInvertCondition(inverted);
|
||||
return actionCondition;
|
||||
}
|
||||
|
||||
public String getField()
|
||||
{
|
||||
return field;
|
||||
@@ -161,13 +234,14 @@ public class SimpleCondition
|
||||
return Objects.hash(field, comparator, parameter);
|
||||
}
|
||||
|
||||
private static SimpleCondition createComparePropertyValueCondition(final ActionCondition actionCondition) {
|
||||
private static SimpleCondition createComparePropertyValueCondition(final ActionCondition actionCondition, final NamespaceService namespaceService)
|
||||
{
|
||||
final SimpleCondition.Builder builder = builder();
|
||||
if (actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY) != null)
|
||||
{
|
||||
builder.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY).toString().toLowerCase());
|
||||
} else {
|
||||
builder.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase());
|
||||
builder.field(((QName) actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY)).toPrefixString(namespaceService));
|
||||
}
|
||||
return builder
|
||||
.comparator(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_OPERATION).toString().toLowerCase())
|
||||
@@ -175,65 +249,48 @@ public class SimpleCondition
|
||||
.create();
|
||||
}
|
||||
|
||||
private static SimpleCondition createCompareMimeTypeCondition(final ActionCondition actionCondition) {
|
||||
private static SimpleCondition createCompareMimeTypeCondition(final ActionCondition actionCondition)
|
||||
{
|
||||
return builder()
|
||||
.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase())
|
||||
.comparator(COMPARATOR_EQUALS)
|
||||
.field(PARAM_MIMETYPE)
|
||||
.comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase())
|
||||
.parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
|
||||
.create();
|
||||
}
|
||||
|
||||
private static SimpleCondition createHasAspectCondition(final ActionCondition actionCondition) {
|
||||
private static SimpleCondition createHasAspectCondition(final ActionCondition actionCondition, final NamespaceService namespaceService)
|
||||
{
|
||||
return builder()
|
||||
.field(HasAspectEvaluator.PARAM_ASPECT)
|
||||
.comparator(COMPARATOR_EQUALS)
|
||||
.parameter(actionCondition.getParameterValues().get(HasAspectEvaluator.PARAM_ASPECT).toString())
|
||||
.comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase())
|
||||
.parameter(((QName) actionCondition.getParameterValues().get(HasAspectEvaluator.PARAM_ASPECT)).toPrefixString(namespaceService))
|
||||
.create();
|
||||
}
|
||||
|
||||
private static SimpleCondition createHasChildCondition(final ActionCondition actionCondition) {
|
||||
final SimpleCondition.Builder builder = builder();
|
||||
if (actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_TYPE) != null)
|
||||
{
|
||||
builder.field(actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_TYPE).toString().toLowerCase());
|
||||
} else {
|
||||
builder.field(actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_NAME).toString().toLowerCase());
|
||||
}
|
||||
return builder
|
||||
.comparator(COMPARATOR_EQUALS)
|
||||
.parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
|
||||
.create();
|
||||
}
|
||||
|
||||
private static SimpleCondition createHasTagCondition(final ActionCondition actionCondition) {
|
||||
private static SimpleCondition createHasTagCondition(final ActionCondition actionCondition)
|
||||
{
|
||||
return builder()
|
||||
.field(HasTagEvaluator.PARAM_TAG)
|
||||
.comparator(COMPARATOR_EQUALS)
|
||||
.comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase())
|
||||
.parameter(actionCondition.getParameterValues().get(HasTagEvaluator.PARAM_TAG).toString())
|
||||
.create();
|
||||
}
|
||||
|
||||
private static SimpleCondition createHasVersionHistoryCondition(final ActionCondition actionCondition) {
|
||||
private static SimpleCondition createInCategoryCondition(final ActionCondition actionCondition)
|
||||
{
|
||||
return builder()
|
||||
.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase())
|
||||
.comparator(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_OPERATION).toString().toLowerCase())
|
||||
.parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
|
||||
.field(PARAM_CATEGORY)
|
||||
.comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase())
|
||||
.parameter(((NodeRef) actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_VALUE)).getId())
|
||||
.create();
|
||||
}
|
||||
|
||||
private static SimpleCondition createInCategoryCondition(final ActionCondition actionCondition) {
|
||||
return builder()
|
||||
.field(actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_ASPECT).toString().toLowerCase())
|
||||
.comparator(COMPARATOR_EQUALS)
|
||||
.parameter(actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_VALUE).toString())
|
||||
.create();
|
||||
}
|
||||
|
||||
private static SimpleCondition createIsSubtypeCondition(final ActionCondition actionCondition) {
|
||||
private static SimpleCondition createIsSubtypeCondition(final ActionCondition actionCondition, final NamespaceService namespaceService)
|
||||
{
|
||||
return builder()
|
||||
.field(IsSubTypeEvaluator.PARAM_TYPE)
|
||||
.comparator(COMPARATOR_EQUALS)
|
||||
.parameter(actionCondition.getParameterValues().get(IsSubTypeEvaluator.PARAM_TYPE).toString())
|
||||
.comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase())
|
||||
.parameter(((QName) actionCondition.getParameterValues().get(IsSubTypeEvaluator.PARAM_TYPE)).toPrefixString(namespaceService))
|
||||
.create();
|
||||
}
|
||||
|
||||
|
@@ -65,7 +65,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
|
||||
|
||||
/**
|
||||
* List folder rules for given folder node's and rule set's IDs as a page.
|
||||
*
|
||||
* <p>
|
||||
* - GET /nodes/{folderNodeId}/rule-sets/{ruleSetId}/rules
|
||||
*
|
||||
* @param folderNodeId - entity resource context for this relationship
|
||||
@@ -87,7 +87,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
|
||||
|
||||
/**
|
||||
* Get single folder rule for given node's, rule set's and rule's IDs.
|
||||
*
|
||||
* <p>
|
||||
* - GET /nodes/{folderNodeId}/rule-sets/{ruleSetId}/rules/{ruleId}
|
||||
*
|
||||
* @param folderNodeId - entity resource context for this relationship
|
||||
@@ -158,7 +158,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
|
||||
|
||||
/**
|
||||
* Delete single folder rule for given node's, rule set's and rule's IDs.
|
||||
*
|
||||
* <p>
|
||||
* - DELETE /nodes/{folderNodeId}/rule-sets/{ruleSetId}/rules/{ruleId}
|
||||
*
|
||||
* @param folderNodeId - entity resource context for this relationship
|
||||
|
@@ -886,6 +886,7 @@
|
||||
<bean id="ruleLoader" class="org.alfresco.rest.api.impl.rules.RuleLoader">
|
||||
<property name="ruleService" ref="RuleService" />
|
||||
<property name="nodeValidator" ref="nodeValidator" />
|
||||
<property name="namespaceService" ref="NamespaceService"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.alfresco.rest.api.nodes.NodeRuleSetsRelation">
|
||||
@@ -909,6 +910,7 @@
|
||||
<property name="ruleLoader" ref="ruleLoader"/>
|
||||
<property name="actionParameterConverter" ref="actionParameterConverter"/>
|
||||
<property name="actionPermissionValidator" ref="actionPermissionValidator"/>
|
||||
<property name="namespaceService" ref="NamespaceService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="Rules" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
|
@@ -309,7 +309,7 @@ function sortByName(a, b)
|
||||
|
||||
function findUsers(searchTerm, maxResults, results)
|
||||
{
|
||||
var personRefs = people.getPeople(searchTerm, maxResults, "lastName", true);
|
||||
var personRefs = people.getPeople(searchTerm+ " [hint:useCQ]", maxResults, "lastName", true);
|
||||
|
||||
// create person object for each result
|
||||
for each(var personRef in personRefs)
|
||||
|
@@ -55,10 +55,14 @@ public class PreferenceServiceTest extends BaseWebScriptTest
|
||||
private PersonService personService;
|
||||
|
||||
private static final String USER_ONE = "PreferenceTestOne" + System.currentTimeMillis();
|
||||
|
||||
private static final String USER_TWO = "PreferenceTestTwo" + System.currentTimeMillis();
|
||||
private static final String USER_BAD = "PreferenceTestBad" + System.currentTimeMillis();
|
||||
|
||||
private static final String URL = "/api/people/" + USER_ONE + "/preferences";;
|
||||
private static final String URL = "/api/people/" + USER_ONE + "/preferences";
|
||||
private static final String URL2 = "/api/people/" + USER_TWO + "/preferences";
|
||||
|
||||
private static final int NUM_THREADS = 3;
|
||||
private static Integer THREADS_FINISHED = 0;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception
|
||||
@@ -75,6 +79,7 @@ public class PreferenceServiceTest extends BaseWebScriptTest
|
||||
|
||||
// Create users
|
||||
createUser(USER_ONE);
|
||||
createUser(USER_TWO);
|
||||
createUser(USER_BAD);
|
||||
|
||||
// Do tests as user one
|
||||
@@ -103,7 +108,6 @@ public class PreferenceServiceTest extends BaseWebScriptTest
|
||||
{
|
||||
super.tearDown();
|
||||
this.authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
}
|
||||
|
||||
public void testPreferences() throws Exception
|
||||
@@ -193,6 +197,64 @@ public class PreferenceServiceTest extends BaseWebScriptTest
|
||||
sendRequest(new GetRequest("/api/people/noExistUser/preferences"), 404);
|
||||
}
|
||||
|
||||
public void testPreferencesMNT21901() throws Exception
|
||||
{
|
||||
String[] body = {
|
||||
"{\"org\":{\"alfresco\":{\"share\":{\"forum\":{\"summary\":{\"dashlet\":{\"component-1-5\":{\"topics\":\"mine\"}}}}}}}}",
|
||||
"{\"org\":{\"alfresco\":{\"share\":{\"forum\":{\"summary\":{\"dashlet\":{\"component-2-5\":{\"topics\":\"mine\"}}}}}}}}",
|
||||
"{\"org\":{\"alfresco\":{\"share\":{\"forum\":{\"summary\":{\"dashlet\":{\"component-2-5\":{\"history\":\"1\"}}}}}}}}"
|
||||
};
|
||||
|
||||
Thread[] threads = new Thread[NUM_THREADS];
|
||||
|
||||
for (int i = 0; i < NUM_THREADS; i++)
|
||||
{
|
||||
UpdatePreferencesThread t = new UpdatePreferencesThread(i, body[i]);
|
||||
threads[i] = t;
|
||||
t.start();
|
||||
}
|
||||
|
||||
for (int i = 0; i < threads.length; i++)
|
||||
{
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
authenticationComponent.setCurrentUser(USER_ONE);
|
||||
|
||||
if (THREADS_FINISHED != NUM_THREADS)
|
||||
{
|
||||
fail("An error has occurred when updating preferences in concurrency context");
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdatePreferencesThread extends Thread
|
||||
{
|
||||
private String body;
|
||||
|
||||
UpdatePreferencesThread(int threadNum, String body)
|
||||
{
|
||||
super(UpdatePreferencesThread.class.getSimpleName() + "-" + threadNum);
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
authenticationComponent.setCurrentUser(USER_TWO);
|
||||
|
||||
try
|
||||
{
|
||||
Response resp = sendRequest(new PostRequest(URL2, body, "application/json"), 200);
|
||||
assertEquals(0, resp.getContentLength());
|
||||
THREADS_FINISHED++;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject getPreferenceObj() throws JSONException
|
||||
{
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
@@ -208,5 +270,4 @@ public class PreferenceServiceTest extends BaseWebScriptTest
|
||||
assertEquals(10, jsonObject.get("numberValue"));
|
||||
assertEquals(BigDecimal.valueOf(3.142), jsonObject.get("numberValue2"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -101,6 +102,8 @@ public class RuleSetsImplTest extends TestCase
|
||||
given(nodeValidatorMock.validateRuleSetNode(RULE_SET_ID, FOLDER_NODE)).willReturn(RULE_SET_NODE);
|
||||
|
||||
given(ruleServiceMock.getRuleSetNode(FOLDER_NODE)).willReturn(RULE_SET_NODE);
|
||||
given(ruleServiceMock.getNodesSupplyingRuleSets(FOLDER_NODE)).willReturn(List.of(FOLDER_NODE));
|
||||
|
||||
given(ruleSetLoaderMock.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, INCLUDES)).willReturn(ruleSetMock);
|
||||
}
|
||||
|
||||
@@ -113,6 +116,7 @@ public class RuleSetsImplTest extends TestCase
|
||||
then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
|
||||
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
|
||||
|
||||
then(ruleServiceMock).should().getNodesSupplyingRuleSets(FOLDER_NODE);
|
||||
then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE);
|
||||
then(ruleServiceMock).shouldHaveNoMoreInteractions();
|
||||
|
||||
@@ -133,6 +137,7 @@ public class RuleSetsImplTest extends TestCase
|
||||
then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
|
||||
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
|
||||
|
||||
then(ruleServiceMock).should().getNodesSupplyingRuleSets(FOLDER_NODE);
|
||||
then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE);
|
||||
then(ruleServiceMock).shouldHaveNoMoreInteractions();
|
||||
|
||||
@@ -140,6 +145,62 @@ public class RuleSetsImplTest extends TestCase
|
||||
assertEquals(PAGING, actual.getPaging());
|
||||
}
|
||||
|
||||
/** Check that a folder with a parent and grandparent can inherit rule sets from the grandparent, even if the parent has no rules. */
|
||||
@Test
|
||||
public void testGetInheritedRuleSets()
|
||||
{
|
||||
// Simulate a parent node without a rule set.
|
||||
NodeRef parentNode = new NodeRef("parent://node/");
|
||||
// Simulate a grandparent node providing a rule set.
|
||||
NodeRef grandparentNode = new NodeRef("grandparent://node/");
|
||||
RuleSet grandparentRuleSet = mock(RuleSet.class);
|
||||
NodeRef grandparentRuleSetNode = new NodeRef("grandparent://rule-set/");
|
||||
given(ruleServiceMock.getRuleSetNode(grandparentNode)).willReturn(grandparentRuleSetNode);
|
||||
given(ruleSetLoaderMock.loadRuleSet(grandparentRuleSetNode, FOLDER_NODE, INCLUDES)).willReturn(grandparentRuleSet);
|
||||
// These should be returned with the highest in hierarchy first.
|
||||
given(ruleServiceMock.getNodesSupplyingRuleSets(FOLDER_NODE)).willReturn(List.of(grandparentNode, parentNode, FOLDER_NODE));
|
||||
|
||||
// Call the method under test.
|
||||
CollectionWithPagingInfo<RuleSet> actual = ruleSets.getRuleSets(FOLDER_ID, INCLUDES, PAGING);
|
||||
|
||||
then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
|
||||
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
|
||||
|
||||
then(ruleServiceMock).should().getNodesSupplyingRuleSets(FOLDER_NODE);
|
||||
then(ruleServiceMock).should().getRuleSetNode(grandparentNode);
|
||||
then(ruleServiceMock).should().getRuleSetNode(parentNode);
|
||||
then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE);
|
||||
then(ruleServiceMock).shouldHaveNoMoreInteractions();
|
||||
|
||||
Collection<RuleSet> expected = List.of(grandparentRuleSet, ruleSetMock);
|
||||
assertEquals(expected, actual.getCollection());
|
||||
assertEquals(PAGING, actual.getPaging());
|
||||
}
|
||||
|
||||
/** When getting rule sets then only the first instance of each rule set should be included (ancestor first). */
|
||||
@Test
|
||||
public void testGetDuplicateRuleSets()
|
||||
{
|
||||
// Simulate a grandparent, parent and child with the grandparent linking to the child's rule set.
|
||||
NodeRef grandparentNode = new NodeRef("grandparent://node/");
|
||||
given(ruleServiceMock.getRuleSetNode(grandparentNode)).willReturn(RULE_SET_NODE);
|
||||
NodeRef parentNode = new NodeRef("parent://node/");
|
||||
RuleSet parentRuleSet = mock(RuleSet.class);
|
||||
NodeRef parentRuleSetNode = new NodeRef("parent://rule-set/");
|
||||
given(ruleServiceMock.getRuleSetNode(parentNode)).willReturn(parentRuleSetNode);
|
||||
given(ruleSetLoaderMock.loadRuleSet(parentRuleSetNode, FOLDER_NODE, INCLUDES)).willReturn(parentRuleSet);
|
||||
// These should be returned with the highest in hierarchy first.
|
||||
given(ruleServiceMock.getNodesSupplyingRuleSets(FOLDER_NODE)).willReturn(List.of(grandparentNode, parentNode, FOLDER_NODE));
|
||||
|
||||
// Call the method under test.
|
||||
CollectionWithPagingInfo<RuleSet> actual = ruleSets.getRuleSets(FOLDER_ID, INCLUDES, PAGING);
|
||||
|
||||
// The grandparent's linked rule set should be first and only appear once.
|
||||
Collection<RuleSet> expected = List.of(ruleSetMock, parentRuleSet);
|
||||
assertEquals(expected, actual.getCollection());
|
||||
assertEquals(PAGING, actual.getPaging());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuleSetById()
|
||||
{
|
||||
|
@@ -61,6 +61,7 @@ import org.alfresco.service.cmr.action.CompositeAction;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.rule.RuleService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -87,6 +88,8 @@ public class RulesImplTest extends TestCase
|
||||
@Mock
|
||||
private Nodes nodesMock;
|
||||
@Mock
|
||||
private NamespaceService namespaceService;
|
||||
@Mock
|
||||
private NodeValidator nodeValidatorMock;
|
||||
@Mock
|
||||
private RuleService ruleServiceMock;
|
||||
@@ -115,7 +118,8 @@ public class RulesImplTest extends TestCase
|
||||
given(nodeValidatorMock.validateRuleNode(any(), any())).willReturn(RULE_NODE_REF);
|
||||
|
||||
given(ruleServiceMock.getRule(RULE_NODE_REF)).willReturn(ruleModel);
|
||||
given(ruleServiceMock.getRules(FOLDER_NODE_REF)).willReturn(List.of(ruleModel));
|
||||
given(ruleServiceMock.getRules(FOLDER_NODE_REF, false)).willReturn(List.of(ruleModel));
|
||||
given(ruleServiceMock.getOwningNodeRef(RULE_SET_NODE_REF)).willReturn(FOLDER_NODE_REF);
|
||||
|
||||
given(ruleLoaderMock.loadRule(ruleModel, INCLUDE)).willReturn(ruleMock);
|
||||
|
||||
@@ -126,13 +130,15 @@ public class RulesImplTest extends TestCase
|
||||
public void testGetRules()
|
||||
{
|
||||
given(ruleLoaderMock.loadRule(ruleModel, emptyList())).willReturn(ruleMock);
|
||||
|
||||
// when
|
||||
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING);
|
||||
|
||||
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
|
||||
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
|
||||
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
|
||||
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF);
|
||||
then(ruleServiceMock).should().getOwningNodeRef(RULE_SET_NODE_REF);
|
||||
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF, false);
|
||||
then(ruleServiceMock).shouldHaveNoMoreInteractions();
|
||||
then(ruleLoaderMock).should().loadRule(ruleModel, emptyList());
|
||||
then(ruleLoaderMock).shouldHaveNoMoreInteractions();
|
||||
@@ -148,12 +154,13 @@ public class RulesImplTest extends TestCase
|
||||
@Test
|
||||
public void testGetRules_emptyResult()
|
||||
{
|
||||
given(ruleServiceMock.getRules(any())).willReturn(emptyList());
|
||||
given(ruleServiceMock.getRules(FOLDER_NODE_REF, false)).willReturn(emptyList());
|
||||
|
||||
// when
|
||||
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING);
|
||||
|
||||
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF);
|
||||
then(ruleServiceMock).should().getOwningNodeRef(RULE_SET_NODE_REF);
|
||||
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF, false);
|
||||
then(ruleServiceMock).shouldHaveNoMoreInteractions();
|
||||
assertThat(rulesPage)
|
||||
.isNotNull()
|
||||
@@ -284,7 +291,7 @@ public class RulesImplTest extends TestCase
|
||||
public void testCreateRules()
|
||||
{
|
||||
List<Rule> ruleList = List.of(ruleMock);
|
||||
given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
|
||||
given(ruleMock.toServiceModel(nodesMock, namespaceService)).willReturn(serviceRuleMock);
|
||||
given(serviceRuleMock.getAction()).willReturn(compositeAction);
|
||||
given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(arg -> arg.getArguments()[1]);
|
||||
given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
|
||||
@@ -300,7 +307,7 @@ public class RulesImplTest extends TestCase
|
||||
then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
|
||||
then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
|
||||
then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
|
||||
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock));
|
||||
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock, namespaceService));
|
||||
then(ruleServiceMock).shouldHaveNoMoreInteractions();
|
||||
List<Rule> expected = List.of(ruleMock);
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
@@ -313,7 +320,7 @@ public class RulesImplTest extends TestCase
|
||||
public void testCreateRules_defaultRuleSet()
|
||||
{
|
||||
List<Rule> ruleList = List.of(ruleMock);
|
||||
given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
|
||||
given(ruleMock.toServiceModel(nodesMock, namespaceService)).willReturn(serviceRuleMock);
|
||||
given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(arg -> arg.getArguments()[1]);
|
||||
given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
|
||||
given(serviceRuleMock.getAction()).willReturn(compositeAction);
|
||||
@@ -328,7 +335,7 @@ public class RulesImplTest extends TestCase
|
||||
then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
|
||||
then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
|
||||
then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
|
||||
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock));
|
||||
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock, namespaceService));
|
||||
then(ruleServiceMock).shouldHaveNoMoreInteractions();
|
||||
List<Rule> expected = List.of(ruleMock);
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
@@ -358,7 +365,7 @@ public class RulesImplTest extends TestCase
|
||||
Rule ruleBodyMock = mock(Rule.class);
|
||||
ruleBodyList.add(ruleBodyMock);
|
||||
org.alfresco.service.cmr.rule.Rule serviceRuleMockInner = mock(org.alfresco.service.cmr.rule.Rule.class);
|
||||
given(ruleBodyMock.toServiceModel(nodesMock)).willReturn(serviceRuleMockInner);
|
||||
given(ruleBodyMock.toServiceModel(nodesMock, namespaceService)).willReturn(serviceRuleMockInner);
|
||||
final CompositeAction compositeActionInner = new CompositeActionImpl(RULE_NODE_REF, "compositeActionInnerId");
|
||||
compositeActionInner.addAction(new ActionImpl(FOLDER_NODE_REF, "actionInnerId", ACTION_DEFINITION_NAME, DUMMY_PARAMS));
|
||||
given(serviceRuleMockInner.getAction()).willReturn(compositeActionInner);
|
||||
@@ -377,8 +384,8 @@ public class RulesImplTest extends TestCase
|
||||
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
|
||||
for (Rule ruleBody : ruleBodyList)
|
||||
{
|
||||
then(actionPermissionValidatorMock).should().validateRulePermissions(ruleBody.toServiceModel(nodesMock));
|
||||
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleBody.toServiceModel(nodesMock));
|
||||
then(actionPermissionValidatorMock).should().validateRulePermissions(ruleBody.toServiceModel(nodesMock, namespaceService));
|
||||
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleBody.toServiceModel(nodesMock, namespaceService));
|
||||
}
|
||||
then(actionParameterConverterMock).should(times(3)).getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
|
||||
then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
|
||||
@@ -431,7 +438,7 @@ public class RulesImplTest extends TestCase
|
||||
@Test
|
||||
public void testUpdateRuleById()
|
||||
{
|
||||
given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
|
||||
given(ruleMock.toServiceModel(nodesMock, namespaceService)).willReturn(serviceRuleMock);
|
||||
given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(a -> a.getArguments()[1]);
|
||||
given(serviceRuleMock.getAction()).willReturn(compositeAction);
|
||||
given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
|
||||
|
@@ -27,6 +27,7 @@
|
||||
package org.alfresco.rest.api.model.rules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
@@ -39,12 +40,18 @@ import org.alfresco.repo.action.ActionConditionImpl;
|
||||
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
|
||||
import org.alfresco.service.Experimental;
|
||||
import org.alfresco.service.cmr.action.ActionCondition;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@Experimental
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CompositeConditionTest
|
||||
{
|
||||
|
||||
private final NamespaceService namespaceService = mock(NamespaceService.class);
|
||||
|
||||
@Test
|
||||
public void testFrom()
|
||||
{
|
||||
@@ -64,7 +71,7 @@ public class CompositeConditionTest
|
||||
));
|
||||
|
||||
// when
|
||||
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions);
|
||||
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions, namespaceService);
|
||||
|
||||
assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition);
|
||||
}
|
||||
@@ -76,7 +83,7 @@ public class CompositeConditionTest
|
||||
final CompositeCondition expectedCompositeCondition = CompositeCondition.builder().create();
|
||||
|
||||
// when
|
||||
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions);
|
||||
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions, namespaceService);
|
||||
|
||||
assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition);
|
||||
}
|
||||
@@ -85,7 +92,7 @@ public class CompositeConditionTest
|
||||
public void testFromNullValue()
|
||||
{
|
||||
// when
|
||||
final CompositeCondition actualCompositeCondition = CompositeCondition.from(null);
|
||||
final CompositeCondition actualCompositeCondition = CompositeCondition.from(null, namespaceService);
|
||||
|
||||
assertThat(actualCompositeCondition).isNull();
|
||||
}
|
||||
@@ -98,7 +105,7 @@ public class CompositeConditionTest
|
||||
final CompositeCondition expectedCompositeCondition = CompositeCondition.builder().create();
|
||||
|
||||
// when
|
||||
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions);
|
||||
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions, namespaceService);
|
||||
|
||||
assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition);
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ import org.alfresco.service.cmr.action.ActionCondition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.rule.RuleType;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
@@ -60,6 +61,8 @@ public class RuleTest
|
||||
private static final String ACTION_DEFINITION_NAME = "action-def-name";
|
||||
private static final String ERROR_SCRIPT = "error-script-ref";
|
||||
|
||||
private final NamespaceService namespaceService = mock(NamespaceService.class);
|
||||
|
||||
@Test
|
||||
public void testFrom()
|
||||
{
|
||||
@@ -67,7 +70,7 @@ public class RuleTest
|
||||
final Rule expectedRule = createRuleWithDefaultValues();
|
||||
|
||||
// when
|
||||
final Rule actualRule = Rule.from(ruleModel);
|
||||
final Rule actualRule = Rule.from(ruleModel, namespaceService);
|
||||
|
||||
assertThat(actualRule).isNotNull().usingRecursiveComparison().isEqualTo(expectedRule);
|
||||
|
||||
@@ -80,7 +83,7 @@ public class RuleTest
|
||||
final Rule expectedRule = Rule.builder().enabled(true).create();
|
||||
|
||||
// when
|
||||
final Rule actualRule = Rule.from(ruleModel);
|
||||
final Rule actualRule = Rule.from(ruleModel, namespaceService);
|
||||
|
||||
assertThat(actualRule).isNotNull().usingRecursiveComparison().isEqualTo(expectedRule);
|
||||
|
||||
@@ -96,7 +99,7 @@ public class RuleTest
|
||||
final org.alfresco.service.cmr.action.Action expectedCompensatingActionModel = createCompensatingActionModel();
|
||||
|
||||
// when
|
||||
final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock);
|
||||
final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock, namespaceService);
|
||||
|
||||
then(nodesMock).should().validateOrLookupNode(RULE_ID, null);
|
||||
then(nodesMock).shouldHaveNoMoreInteractions();
|
||||
@@ -121,7 +124,7 @@ public class RuleTest
|
||||
expectedRuleModel.setRuleDisabled(true);
|
||||
|
||||
// when
|
||||
final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock);
|
||||
final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock, namespaceService);
|
||||
|
||||
then(nodesMock).shouldHaveNoInteractions();
|
||||
assertThat(actualRuleModel)
|
||||
@@ -131,6 +134,20 @@ public class RuleTest
|
||||
.isEqualTo(expectedRuleModel);
|
||||
}
|
||||
|
||||
private Rule createRuleWithDefaultValues() {
|
||||
return Rule.builder()
|
||||
.id(RULE_ID)
|
||||
.name(RULE_NAME)
|
||||
.description(RULE_DESCRIPTION)
|
||||
.enabled(RULE_ENABLED)
|
||||
.cascade(RULE_CASCADE)
|
||||
.asynchronous(RULE_ASYNC)
|
||||
.triggers(List.of(RuleTrigger.INBOUND, RuleTrigger.UPDATE))
|
||||
.errorScript(ERROR_SCRIPT)
|
||||
.conditions(CompositeCondition.from(Collections.emptyList(), namespaceService))
|
||||
.create();
|
||||
}
|
||||
|
||||
private static org.alfresco.service.cmr.rule.Rule createRuleModel() {
|
||||
final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
|
||||
final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule(nodeRef);
|
||||
@@ -160,18 +177,4 @@ public class RuleTest
|
||||
|
||||
return compensatingActionModel;
|
||||
}
|
||||
|
||||
private static Rule createRuleWithDefaultValues() {
|
||||
return Rule.builder()
|
||||
.id(RULE_ID)
|
||||
.name(RULE_NAME)
|
||||
.description(RULE_DESCRIPTION)
|
||||
.enabled(RULE_ENABLED)
|
||||
.cascade(RULE_CASCADE)
|
||||
.asynchronous(RULE_ASYNC)
|
||||
.triggers(List.of(RuleTrigger.INBOUND, RuleTrigger.UPDATE))
|
||||
.errorScript(ERROR_SCRIPT)
|
||||
.conditions(CompositeCondition.from(Collections.emptyList()))
|
||||
.create();
|
||||
}
|
||||
}
|
@@ -27,6 +27,8 @@
|
||||
package org.alfresco.rest.api.model.rules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
@@ -36,6 +38,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionConditionImpl;
|
||||
import org.alfresco.repo.action.evaluator.CompareMimeTypeEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
|
||||
@@ -46,28 +49,54 @@ import org.alfresco.repo.action.evaluator.HasVersionHistoryEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.InCategoryEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.IsSubTypeEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.NoConditionEvaluator;
|
||||
import org.alfresco.repo.action.evaluator.compare.ComparePropertyValueOperation;
|
||||
import org.alfresco.repo.action.evaluator.compare.ContentPropertyName;
|
||||
import org.alfresco.rest.api.Nodes;
|
||||
import org.alfresco.service.Experimental;
|
||||
import org.alfresco.service.cmr.action.ActionCondition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@Experimental
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SimpleConditionTest
|
||||
{
|
||||
private static final boolean NULL_RESULT = true;
|
||||
private static final boolean NOT_INVERTED = false;
|
||||
private static final String PARAMETER_DEFAULT = "value";
|
||||
|
||||
private final Nodes nodes = mock(Nodes.class);
|
||||
private final NamespaceService namespaceService = mock(NamespaceService.class);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
given(namespaceService.getPrefixes(NamespaceService.CONTENT_MODEL_1_0_URI)).willReturn(List.of(NamespaceService.CONTENT_MODEL_PREFIX));
|
||||
given(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).willReturn(NamespaceService.CONTENT_MODEL_1_0_URI);
|
||||
given(namespaceService.getPrefixes(NamespaceService.AUDIO_MODEL_1_0_URI)).willReturn(List.of(NamespaceService.AUDIO_MODEL_PREFIX));
|
||||
given(namespaceService.getNamespaceURI(NamespaceService.AUDIO_MODEL_PREFIX)).willReturn(NamespaceService.AUDIO_MODEL_1_0_URI);
|
||||
}
|
||||
|
||||
private static List<TestData> getTestData() {
|
||||
return List.of(
|
||||
TestData.of(ComparePropertyValueEvaluator.NAME),
|
||||
TestData.of(CompareMimeTypeEvaluator.NAME),
|
||||
TestData.of(HasAspectEvaluator.NAME),
|
||||
TestData.of(HasChildEvaluator.NAME),
|
||||
TestData.of(HasChildEvaluator.NAME, NULL_RESULT),
|
||||
TestData.of(HasTagEvaluator.NAME),
|
||||
TestData.of(HasVersionHistoryEvaluator.NAME),
|
||||
TestData.of(HasVersionHistoryEvaluator.NAME, NULL_RESULT),
|
||||
TestData.of(InCategoryEvaluator.NAME),
|
||||
TestData.of(IsSubTypeEvaluator.NAME),
|
||||
TestData.of(NoConditionEvaluator.NAME, true),
|
||||
TestData.of("fake-definition-name", true),
|
||||
TestData.of("", true),
|
||||
TestData.of(null, true)
|
||||
TestData.of(NoConditionEvaluator.NAME, NULL_RESULT),
|
||||
TestData.of("fake-definition-name", NULL_RESULT),
|
||||
TestData.of("", NULL_RESULT),
|
||||
TestData.of(null, NULL_RESULT)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,10 +105,10 @@ public class SimpleConditionTest
|
||||
{
|
||||
for (TestData testData : getTestData())
|
||||
{
|
||||
final ActionCondition actionCondition = createActionCondition(testData.actionDefinitionName);
|
||||
final ActionCondition actionCondition = createActionCondition(testData.conditionDefinitionName);
|
||||
|
||||
// when
|
||||
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition);
|
||||
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition, namespaceService);
|
||||
|
||||
assertThat(Objects.isNull(actualSimpleCondition)).isEqualTo(testData.isNullResult);
|
||||
if (!testData.isNullResult)
|
||||
@@ -95,7 +124,7 @@ public class SimpleConditionTest
|
||||
public void testFromNullValue()
|
||||
{
|
||||
// when
|
||||
final SimpleCondition actualSimpleCondition = SimpleCondition.from(null);
|
||||
final SimpleCondition actualSimpleCondition = SimpleCondition.from(null, namespaceService);
|
||||
|
||||
assertThat(actualSimpleCondition).isNull();
|
||||
}
|
||||
@@ -106,7 +135,7 @@ public class SimpleConditionTest
|
||||
final ActionCondition actionCondition = new ActionConditionImpl("fake-id", null, createParameterValues());
|
||||
|
||||
// when
|
||||
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition);
|
||||
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition, namespaceService);
|
||||
|
||||
assertThat(actualSimpleCondition).isNull();
|
||||
}
|
||||
@@ -117,7 +146,7 @@ public class SimpleConditionTest
|
||||
final ActionCondition actionCondition = new ActionConditionImpl("fake-id", "fake-def-name", null);
|
||||
|
||||
// when
|
||||
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition);
|
||||
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition, namespaceService);
|
||||
|
||||
assertThat(actualSimpleCondition).isNull();
|
||||
}
|
||||
@@ -129,14 +158,22 @@ public class SimpleConditionTest
|
||||
createActionCondition(ComparePropertyValueEvaluator.NAME),
|
||||
createActionCondition(CompareMimeTypeEvaluator.NAME)
|
||||
);
|
||||
final List<SimpleCondition> expectedSimpleConditions = List.of(
|
||||
SimpleCondition.builder().field("content-property").comparator("operation").parameter("value").create(),
|
||||
SimpleCondition.builder().field("property").comparator("equals").parameter("value").create()
|
||||
);
|
||||
|
||||
// when
|
||||
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(actionConditions);
|
||||
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(actionConditions, namespaceService);
|
||||
|
||||
final List<SimpleCondition> expectedSimpleConditions = List.of(
|
||||
SimpleCondition.builder()
|
||||
.field("content-property")
|
||||
.comparator("operation")
|
||||
.parameter("value")
|
||||
.create(),
|
||||
SimpleCondition.builder()
|
||||
.field(SimpleCondition.PARAM_MIMETYPE)
|
||||
.comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase())
|
||||
.parameter("value")
|
||||
.create()
|
||||
);
|
||||
assertThat(actualSimpleConditions)
|
||||
.isNotNull()
|
||||
.containsExactlyElementsOf(expectedSimpleConditions);
|
||||
@@ -145,7 +182,8 @@ public class SimpleConditionTest
|
||||
@Test
|
||||
public void testListOfEmptyActionConditions()
|
||||
{
|
||||
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(Collections.emptyList());
|
||||
// when
|
||||
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(Collections.emptyList(), namespaceService);
|
||||
|
||||
assertThat(actualSimpleConditions).isNull();
|
||||
}
|
||||
@@ -153,7 +191,8 @@ public class SimpleConditionTest
|
||||
@Test
|
||||
public void testListOfNullActionConditions()
|
||||
{
|
||||
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(null);
|
||||
// when
|
||||
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(null, namespaceService);
|
||||
|
||||
assertThat(actualSimpleConditions).isNull();
|
||||
}
|
||||
@@ -164,50 +203,207 @@ public class SimpleConditionTest
|
||||
final List<ActionCondition> actionConditions = new ArrayList<>();
|
||||
actionConditions.add(null);
|
||||
|
||||
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(actionConditions);
|
||||
// when
|
||||
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(actionConditions, namespaceService);
|
||||
|
||||
assertThat(actualSimpleConditions).isNotNull().isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToServiceModel_withSizeContentProperty()
|
||||
{
|
||||
final SimpleCondition simpleCondition = createSimpleCondition(ContentPropertyName.SIZE.toString().toLowerCase());
|
||||
|
||||
// when
|
||||
final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService);
|
||||
|
||||
final Map<String, Serializable> expectedParameterValues = new HashMap<>();
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY, ContentPropertyName.SIZE.toString());
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT);
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.EQUALS.toString());
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, PARAMETER_DEFAULT);
|
||||
ActionCondition expectedActionCondition = new ActionConditionImpl(null, ComparePropertyValueEvaluator.NAME, expectedParameterValues);
|
||||
assertThat(actualActionCondition)
|
||||
.isNotNull().usingRecursiveComparison().ignoringFields("id")
|
||||
.isEqualTo(expectedActionCondition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToServiceModel_withoutContentProperty()
|
||||
{
|
||||
final SimpleCondition simpleCondition = createSimpleCondition(ContentModel.PROP_DESCRIPTION.toPrefixString(namespaceService));
|
||||
|
||||
// when
|
||||
final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService);
|
||||
|
||||
final Map<String, Serializable> expectedParameterValues = new HashMap<>();
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.PROP_DESCRIPTION);
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.EQUALS.toString());
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, PARAMETER_DEFAULT);
|
||||
final ActionCondition expectedActionCondition = new ActionConditionImpl(null, ComparePropertyValueEvaluator.NAME, expectedParameterValues);
|
||||
assertThat(actualActionCondition)
|
||||
.isNotNull().usingRecursiveComparison().ignoringFields("id", "parameterValues.property.prefix")
|
||||
.isEqualTo(expectedActionCondition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToServiceModel_compareMimetype()
|
||||
{
|
||||
final SimpleCondition simpleCondition = createSimpleCondition(SimpleCondition.PARAM_MIMETYPE);
|
||||
|
||||
// when
|
||||
final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService);
|
||||
|
||||
final Map<String, Serializable> expectedParameterValues = new HashMap<>();
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT);
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, PARAMETER_DEFAULT);
|
||||
final ActionCondition expectedActionCondition = new ActionConditionImpl(null, CompareMimeTypeEvaluator.NAME, expectedParameterValues);
|
||||
assertThat(actualActionCondition)
|
||||
.isNotNull().usingRecursiveComparison().ignoringFields("id")
|
||||
.isEqualTo(expectedActionCondition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToServiceModel_hasAspect()
|
||||
{
|
||||
final QName audioAspect = QName.createQName(NamespaceService.AUDIO_MODEL_1_0_URI, NamespaceService.AUDIO_MODEL_PREFIX);
|
||||
final SimpleCondition simpleCondition = createSimpleCondition(HasAspectEvaluator.PARAM_ASPECT, audioAspect.toPrefixString(namespaceService));
|
||||
|
||||
// when
|
||||
final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService);
|
||||
|
||||
final Map<String, Serializable> expectedParameterValues = new HashMap<>();
|
||||
expectedParameterValues.put(HasAspectEvaluator.PARAM_ASPECT, audioAspect);
|
||||
final ActionCondition expectedActionCondition = new ActionConditionImpl(null, HasAspectEvaluator.NAME, expectedParameterValues);
|
||||
assertThat(actualActionCondition)
|
||||
.isNotNull().usingRecursiveComparison().ignoringFields("id", "parameterValues.aspect.prefix")
|
||||
.isEqualTo(expectedActionCondition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToServiceModel_hasTag()
|
||||
{
|
||||
final String tag = "some tag";
|
||||
final SimpleCondition simpleCondition = createSimpleCondition(HasTagEvaluator.PARAM_TAG, tag);
|
||||
|
||||
// when
|
||||
final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService);
|
||||
|
||||
final Map<String, Serializable> expectedParameterValues = new HashMap<>();
|
||||
expectedParameterValues.put(HasTagEvaluator.PARAM_TAG, tag);
|
||||
final ActionCondition expectedActionCondition = new ActionConditionImpl(null, HasTagEvaluator.NAME, expectedParameterValues);
|
||||
assertThat(actualActionCondition)
|
||||
.isNotNull().usingRecursiveComparison().ignoringFields("id")
|
||||
.isEqualTo(expectedActionCondition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToServiceModel_inCategory()
|
||||
{
|
||||
final SimpleCondition simpleCondition = createSimpleCondition(SimpleCondition.PARAM_CATEGORY);
|
||||
final NodeRef defaultNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARAMETER_DEFAULT);
|
||||
given(nodes.validateOrLookupNode(PARAMETER_DEFAULT, null)).willReturn(defaultNodeRef);
|
||||
|
||||
// when
|
||||
final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService);
|
||||
|
||||
final Map<String, Serializable> expectedParameterValues = new HashMap<>();
|
||||
expectedParameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, ContentModel.ASPECT_GEN_CLASSIFIABLE);
|
||||
expectedParameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, defaultNodeRef);
|
||||
final ActionCondition expectedActionCondition = new ActionConditionImpl(null, InCategoryEvaluator.NAME, expectedParameterValues);
|
||||
assertThat(actualActionCondition)
|
||||
.isNotNull().usingRecursiveComparison().ignoringFields("id")
|
||||
.isEqualTo(expectedActionCondition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToServiceModel_isSubType()
|
||||
{
|
||||
final SimpleCondition simpleCondition = createSimpleCondition(IsSubTypeEvaluator.PARAM_TYPE, ContentModel.TYPE_FOLDER.toPrefixString(namespaceService));
|
||||
|
||||
// when
|
||||
final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService);
|
||||
|
||||
final Map<String, Serializable> expectedParameterValues = new HashMap<>();
|
||||
expectedParameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, ContentModel.TYPE_FOLDER);
|
||||
final ActionCondition expectedActionCondition = new ActionConditionImpl(null, IsSubTypeEvaluator.NAME, expectedParameterValues);
|
||||
assertThat(actualActionCondition)
|
||||
.isNotNull().usingRecursiveComparison().ignoringFields("id", "parameterValues.type.prefix")
|
||||
.isEqualTo(expectedActionCondition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToServiceModel_inverted()
|
||||
{
|
||||
final SimpleCondition simpleCondition = createSimpleCondition(ContentModel.PROP_DESCRIPTION.toPrefixString(namespaceService));
|
||||
|
||||
// when
|
||||
final ActionCondition actualActionCondition = simpleCondition.toServiceModel(!NOT_INVERTED, nodes, namespaceService);
|
||||
|
||||
final Map<String, Serializable> expectedParameterValues = new HashMap<>();
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.PROP_DESCRIPTION);
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.EQUALS.toString());
|
||||
expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, PARAMETER_DEFAULT);
|
||||
final ActionCondition expectedActionCondition = new ActionConditionImpl(null, ComparePropertyValueEvaluator.NAME, expectedParameterValues);
|
||||
expectedActionCondition.setInvertCondition(!NOT_INVERTED);
|
||||
assertThat(actualActionCondition)
|
||||
.isNotNull().usingRecursiveComparison().ignoringFields("id", "parameterValues.property.prefix")
|
||||
.isEqualTo(expectedActionCondition);
|
||||
}
|
||||
|
||||
private static SimpleCondition createSimpleCondition(final String field)
|
||||
{
|
||||
return createSimpleCondition(field, PARAMETER_DEFAULT);
|
||||
}
|
||||
|
||||
private static SimpleCondition createSimpleCondition(final String field, final String parameter)
|
||||
{
|
||||
return SimpleCondition.builder()
|
||||
.field(field)
|
||||
.comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase())
|
||||
.parameter(parameter)
|
||||
.create();
|
||||
}
|
||||
|
||||
private static ActionCondition createActionCondition(final String actionDefinitionName)
|
||||
{
|
||||
return new ActionConditionImpl("fake-id", actionDefinitionName, createParameterValues());
|
||||
}
|
||||
|
||||
private static Map<String, Serializable> createParameterValues() {
|
||||
final QName audioAspect = QName.createQName(NamespaceService.AUDIO_MODEL_1_0_URI, NamespaceService.AUDIO_MODEL_PREFIX);
|
||||
final NodeRef defaultNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARAMETER_DEFAULT);
|
||||
final Map<String, Serializable> parameterValues = new HashMap<>();
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY, "content-property");
|
||||
parameterValues.put(HasChildEvaluator.PARAM_ASSOC_TYPE, "assoc-type");
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, "property");
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT);
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, "operation");
|
||||
parameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, "value");
|
||||
parameterValues.put(HasAspectEvaluator.PARAM_ASPECT, "aspect");
|
||||
parameterValues.put(HasChildEvaluator.PARAM_ASSOC_NAME, "assoc-name");
|
||||
parameterValues.put(HasAspectEvaluator.PARAM_ASPECT, audioAspect);
|
||||
parameterValues.put(HasTagEvaluator.PARAM_TAG, "tag");
|
||||
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, "category-aspect");
|
||||
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, "category-value");
|
||||
parameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, "type");
|
||||
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, defaultNodeRef);
|
||||
parameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, ContentModel.TYPE_FOLDER);
|
||||
|
||||
return parameterValues;
|
||||
}
|
||||
|
||||
private static class TestData
|
||||
{
|
||||
String actionDefinitionName;
|
||||
String conditionDefinitionName;
|
||||
boolean isNullResult;
|
||||
|
||||
public TestData(String actionDefinitionName, boolean isNullResult)
|
||||
public TestData(String conditionDefinitionName, boolean isNullResult)
|
||||
{
|
||||
this.actionDefinitionName = actionDefinitionName;
|
||||
this.conditionDefinitionName = conditionDefinitionName;
|
||||
this.isNullResult = isNullResult;
|
||||
}
|
||||
|
||||
public static TestData of(String actionDefinitionName) {
|
||||
return new TestData(actionDefinitionName, false);
|
||||
public static TestData of(String conditionDefinitionName) {
|
||||
return new TestData(conditionDefinitionName, false);
|
||||
}
|
||||
|
||||
public static TestData of(String actionDefinitionName, boolean isNullResult) {
|
||||
return new TestData(actionDefinitionName, isNullResult);
|
||||
public static TestData of(String conditionDefinitionName, boolean isNullResult) {
|
||||
return new TestData(conditionDefinitionName, isNullResult);
|
||||
}
|
||||
}
|
||||
}
|
@@ -106,6 +106,7 @@ import org.apache.commons.collections.map.MultiValueMap;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
@@ -3611,6 +3612,7 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
|
||||
* {@literal <host>:<port>/alfresco/api/-default-/public/alfresco/versions/1/nodes/<nodeId>/content}
|
||||
*/
|
||||
@Test
|
||||
@Ignore("ACS-3531 Frequent intermittent failure")
|
||||
public void testDownloadFileContent() throws Exception
|
||||
{
|
||||
setRequestContext(user1);
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>17.102-SNAPSHOT</version>
|
||||
<version>17.113</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
@@ -691,6 +691,16 @@
|
||||
<artifactId>camel-mock</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Netty non-transitive dependencies declared for depending projects usage in conjunction with Camel's other transitive netty dependencies -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-handler-proxy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-tcnative-classes</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-client</artifactId>
|
||||
|
@@ -1,33 +1,34 @@
|
||||
/*
|
||||
* #%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 <http://www.gnu.org/licenses/>.
|
||||
* #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 <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.action;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.alfresco.service.cmr.action.ParameterizedItem;
|
||||
|
||||
@@ -38,8 +39,8 @@ import org.alfresco.service.cmr.action.ParameterizedItem;
|
||||
*/
|
||||
public abstract class ParameterizedItemImpl implements ParameterizedItem, Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 3578052215076397741L;
|
||||
|
||||
private static final long serialVersionUID = 3578052215076397741L;
|
||||
|
||||
/**
|
||||
* The id
|
||||
*/
|
||||
@@ -50,23 +51,23 @@ public abstract class ParameterizedItemImpl implements ParameterizedItem, Serial
|
||||
*/
|
||||
private Map<String, Serializable> parameterValues = new HashMap<String, Serializable>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
public ParameterizedItemImpl(String id)
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
public ParameterizedItemImpl(String id)
|
||||
{
|
||||
this(id, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param id the rule item
|
||||
* @param parameterValues the parameter values
|
||||
*/
|
||||
public ParameterizedItemImpl(String id, Map<String, Serializable> parameterValues)
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param id the rule item
|
||||
* @param parameterValues the parameter values
|
||||
*/
|
||||
public ParameterizedItemImpl(String id, Map<String, Serializable> parameterValues)
|
||||
{
|
||||
// Set the action id
|
||||
this.id = id;
|
||||
@@ -135,7 +136,7 @@ public abstract class ParameterizedItemImpl implements ParameterizedItem, Serial
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return this.id.hashCode();
|
||||
return Objects.hashCode(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -220,6 +220,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
|
||||
{
|
||||
// Process batch
|
||||
primaryId = processPrimaryTableResultSet(primaryPrepStmt, secondaryPrepStmts, deletePrepStmt, deleteIds, primaryTableName, primaryColumnName, tableColumn);
|
||||
connection.commit();
|
||||
|
||||
if (primaryId == null)
|
||||
{
|
||||
@@ -298,7 +299,6 @@ public class DeleteNotExistsExecutor implements StatementExecutor
|
||||
if (deleteIds.size() == deleteBatchSize)
|
||||
{
|
||||
deleteFromPrimaryTable(deletePrepStmt, deleteIds, primaryTableName);
|
||||
connection.commit();
|
||||
}
|
||||
|
||||
if (!resultSet.next())
|
||||
|
@@ -117,6 +117,7 @@ public class MySQLDeleteNotExistsExecutor extends DeleteNotExistsExecutor
|
||||
{
|
||||
// Process batch
|
||||
primaryId = processPrimaryTableResultSet(primaryPrepStmt, secondaryPrepStmts, deletePrepStmt, deleteIds, primaryTableName, primaryColumnName, tableColumn);
|
||||
connection.commit();
|
||||
|
||||
if (primaryId == null)
|
||||
{
|
||||
|
@@ -25,6 +25,9 @@
|
||||
*/
|
||||
package org.alfresco.repo.rule;
|
||||
|
||||
import static org.alfresco.repo.rule.RuleModel.ASPECT_IGNORE_INHERITED_RULES;
|
||||
import static org.alfresco.repo.rule.RuleModel.ASSOC_RULE_FOLDER;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -33,6 +36,9 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionImpl;
|
||||
@@ -255,7 +261,7 @@ public class RuleServiceImpl
|
||||
policyComponent.bindAssociationBehaviour(
|
||||
NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
|
||||
RuleModel.ASPECT_RULES,
|
||||
RuleModel.ASSOC_RULE_FOLDER,
|
||||
ASSOC_RULE_FOLDER,
|
||||
new JavaBehaviour(this, "onCreateChildAssociation"));
|
||||
policyComponent.bindClassBehaviour(
|
||||
NodeServicePolicies.OnAddAspectPolicy.QNAME,
|
||||
@@ -347,8 +353,8 @@ public class RuleServiceImpl
|
||||
|
||||
List<ChildAssociationRef> assocs = this.runtimeNodeService.getChildAssocs(
|
||||
nodeRef,
|
||||
RuleModel.ASSOC_RULE_FOLDER,
|
||||
RuleModel.ASSOC_RULE_FOLDER);
|
||||
ASSOC_RULE_FOLDER,
|
||||
ASSOC_RULE_FOLDER);
|
||||
if (assocs.size() > 1)
|
||||
{
|
||||
throw new ActionServiceException("There is more than one rule folder, which is invalid.");
|
||||
@@ -479,7 +485,7 @@ public class RuleServiceImpl
|
||||
// Node has gone or is not the correct type
|
||||
return rules;
|
||||
}
|
||||
if (includeInherited == true && runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_IGNORE_INHERITED_RULES) == false)
|
||||
if (includeInherited && !runtimeNodeService.hasAspect(nodeRef, ASPECT_IGNORE_INHERITED_RULES))
|
||||
{
|
||||
// Get any inherited rules
|
||||
for (Rule rule : getInheritedRules(nodeRef, ruleTypeName, null))
|
||||
@@ -597,10 +603,53 @@ public class RuleServiceImpl
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
@Experimental
|
||||
public List<NodeRef> getNodesSupplyingRuleSets(NodeRef nodeRef)
|
||||
{
|
||||
return getNodesSupplyingRuleSets(nodeRef, new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse the folder hierarchy find all the folder nodes that could supply rules by inheritance.
|
||||
* <p>
|
||||
* The order of nodes returned by this methods has to match the order used by {@link #getInheritedRules}.
|
||||
*
|
||||
* @param nodeRef The starting node ref.
|
||||
* @param visitedNodeRefs All the visited node refs (will be modified).
|
||||
* @return A list of node refs, starting with the first parent of the first parent of ... and ending with the object generated by the
|
||||
* given node ref.
|
||||
*/
|
||||
private List<NodeRef> getNodesSupplyingRuleSets(NodeRef nodeRef, List<NodeRef> visitedNodeRefs)
|
||||
{
|
||||
List<NodeRef> returnList = new ArrayList<>();
|
||||
// This check prevents stack over flow when we have a cyclic node graph
|
||||
if (!visitedNodeRefs.contains(nodeRef))
|
||||
{
|
||||
visitedNodeRefs.add(nodeRef);
|
||||
if (!runtimeNodeService.hasAspect(nodeRef, ASPECT_IGNORE_INHERITED_RULES))
|
||||
{
|
||||
List<ChildAssociationRef> parents = runtimeNodeService.getParentAssocs(nodeRef);
|
||||
for (ChildAssociationRef parent : parents)
|
||||
{
|
||||
// We are not interested in following potentially massive person group membership trees!
|
||||
if (!IGNORE_PARENT_ASSOC_TYPES.contains(parent.getTypeQName()))
|
||||
{
|
||||
// Update visitedNodeRefs with all the ancestors.
|
||||
returnList.addAll(getNodesSupplyingRuleSets(parent.getParentRef(), visitedNodeRefs));
|
||||
}
|
||||
}
|
||||
}
|
||||
returnList.add(nodeRef);
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the inherited rules for a given node reference
|
||||
*
|
||||
*
|
||||
* @param nodeRef the nodeRef
|
||||
* @param ruleTypeName the rule type (null if all applicable)
|
||||
* @return a list of inherited rules (empty if none)
|
||||
@@ -608,20 +657,20 @@ public class RuleServiceImpl
|
||||
private List<Rule> getInheritedRules(NodeRef nodeRef, String ruleTypeName, Set<NodeRef> visitedNodeRefs)
|
||||
{
|
||||
List<Rule> inheritedRules = new ArrayList<Rule>();
|
||||
|
||||
|
||||
if (this.runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_IGNORE_INHERITED_RULES) == false)
|
||||
{
|
||||
{
|
||||
// Create the visited nodes set if it has not already been created
|
||||
if (visitedNodeRefs == null)
|
||||
{
|
||||
visitedNodeRefs = new HashSet<NodeRef>();
|
||||
}
|
||||
|
||||
|
||||
// This check prevents stack over flow when we have a cyclic node graph
|
||||
if (visitedNodeRefs.contains(nodeRef) == false)
|
||||
{
|
||||
visitedNodeRefs.add(nodeRef);
|
||||
|
||||
|
||||
List<Rule> allInheritedRules = new ArrayList<Rule>();
|
||||
List<ChildAssociationRef> parents = this.runtimeNodeService.getParentAssocs(nodeRef);
|
||||
for (ChildAssociationRef parent : parents)
|
||||
@@ -641,7 +690,7 @@ public class RuleServiceImpl
|
||||
allInheritedRules.add(rule);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<Rule> rules = getRules(parent.getParentRef(), false);
|
||||
for (Rule rule : rules)
|
||||
{
|
||||
@@ -652,7 +701,7 @@ public class RuleServiceImpl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ruleTypeName == null)
|
||||
{
|
||||
inheritedRules = allInheritedRules;
|
||||
@@ -670,7 +719,7 @@ public class RuleServiceImpl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return inheritedRules;
|
||||
}
|
||||
|
||||
@@ -1523,6 +1572,12 @@ public class RuleServiceImpl
|
||||
return this.nodeService.getPrimaryParent(systemFolder).getParentRef();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeRef getOwningNodeRef(NodeRef ruleSet)
|
||||
{
|
||||
return nodeService.getPrimaryParent(ruleSet).getParentRef();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeRef getOwningNodeRef(final Action action)
|
||||
{
|
||||
@@ -1615,7 +1670,7 @@ public class RuleServiceImpl
|
||||
@Experimental
|
||||
public NodeRef getRuleSetNode(final NodeRef folderNodeRef)
|
||||
{
|
||||
return runtimeNodeService.getChildAssocs(folderNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER).stream()
|
||||
return runtimeNodeService.getChildAssocs(folderNodeRef, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER).stream()
|
||||
.map(ChildAssociationRef::getChildRef)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
@@ -1625,7 +1680,10 @@ public class RuleServiceImpl
|
||||
@Experimental
|
||||
public boolean isRuleSetAssociatedWithFolder(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
|
||||
{
|
||||
return isChildOf(ruleSetNodeRef, RuleModel.ASSOC_RULE_FOLDER, folderNodeRef);
|
||||
List<ChildAssociationRef> associations = runtimeNodeService.getParentAssocs(ruleSetNodeRef, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
|
||||
Set<NodeRef> associatedFolders = associations.stream().map(ChildAssociationRef::getParentRef).collect(Collectors.toSet());
|
||||
Set<NodeRef> supplyingFolders = new HashSet<>(getNodesSupplyingRuleSets(folderNodeRef));
|
||||
return !Sets.intersection(associatedFolders, supplyingFolders).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -25,54 +25,54 @@
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication.ldap;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.AuthenticationNotSupportedException;
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.ldap.InitialLdapContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
import javax.naming.ldap.PagedResultsControl;
|
||||
import javax.naming.ldap.PagedResultsResponseControl;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.security.authentication.AlfrescoSSLSocketFactory;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationDiagnostic;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.AuthenticationNotSupportedException;
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.ldap.InitialLdapContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
import javax.naming.ldap.PagedResultsControl;
|
||||
import javax.naming.ldap.PagedResultsResponseControl;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.repo.security.authentication.AlfrescoSSLSocketFactory;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationDiagnostic;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFactory, InitializingBean
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(LDAPInitialDirContextFactoryImpl.class);
|
||||
|
||||
private static Set<Map<String, String>> checkedEnvs = Collections.synchronizedSet(new HashSet<Map<String, String>>(
|
||||
11));
|
||||
private SimpleCache<String, Set<Map<String, String>>> ldapInitialDirContextCache;
|
||||
|
||||
private Map<String, String> defaultEnvironment = Collections.<String, String> emptyMap();
|
||||
private Map<String, String> authenticatedEnvironment = Collections.<String, String> emptyMap();
|
||||
@@ -80,6 +80,13 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
private String trustStorePath;
|
||||
private String trustStoreType;
|
||||
private String trustStorePassPhrase;
|
||||
|
||||
private boolean initialChecksEnabled = true;
|
||||
|
||||
private final String ANONYMOUS_CHECK = "anonymous_check";
|
||||
private final String SIMPLE_DN_CHECK = "simple_dn_check";
|
||||
private final String DN_CHECK = "dn_check";
|
||||
private final String PRINCIPAL_CHECK = "principal_check";
|
||||
|
||||
public String getTrustStorePath()
|
||||
{
|
||||
@@ -475,159 +482,202 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
logger.debug("after Properties Set");
|
||||
// Check Anonymous bind
|
||||
|
||||
Hashtable<String, String> env = new Hashtable<String, String>(authenticatedEnvironment.size());
|
||||
env.putAll(authenticatedEnvironment);
|
||||
env.remove(Context.SECURITY_PRINCIPAL);
|
||||
env.remove(Context.SECURITY_CREDENTIALS);
|
||||
if (isSSLSocketFactoryRequired())
|
||||
{
|
||||
KeyStore trustStore = initTrustStore();
|
||||
AlfrescoSSLSocketFactory.initTrustedSSLSocketFactory(trustStore);
|
||||
env.put("java.naming.ldap.factory.socket", AlfrescoSSLSocketFactory.class.getName());
|
||||
}
|
||||
try
|
||||
{
|
||||
new InitialDirContext(env);
|
||||
|
||||
logger.warn("LDAP server supports anonymous bind " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (javax.naming.AuthenticationException ax)
|
||||
{
|
||||
|
||||
}
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
logger.error("Unable to connect to LDAP Server; check LDAP configuration", nx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Simple DN and password
|
||||
|
||||
env = new Hashtable<String, String>(authenticatedEnvironment.size());
|
||||
env.putAll(authenticatedEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, "daftAsABrush");
|
||||
env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush");
|
||||
if (isSSLSocketFactoryRequired())
|
||||
{
|
||||
KeyStore trustStore = initTrustStore();
|
||||
AlfrescoSSLSocketFactory.initTrustedSSLSocketFactory(trustStore);
|
||||
env.put("java.naming.ldap.factory.socket", AlfrescoSSLSocketFactory.class.getName());
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
new InitialDirContext(env);
|
||||
|
||||
throw new AuthenticationException(
|
||||
"The ldap server at "
|
||||
+ env.get(Context.PROVIDER_URL)
|
||||
+ " falls back to use anonymous bind if invalid security credentials are presented. This is not supported.");
|
||||
}
|
||||
catch (javax.naming.AuthenticationException ax)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
logger.info("LDAP server does not support simple string user ids and invalid credentials at "+ env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
|
||||
// DN and password
|
||||
|
||||
env = new Hashtable<String, String>(authenticatedEnvironment.size());
|
||||
env.putAll(authenticatedEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, "cn=daftAsABrush,dc=woof");
|
||||
env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush");
|
||||
if (isSSLSocketFactoryRequired())
|
||||
{
|
||||
KeyStore trustStore = initTrustStore();
|
||||
AlfrescoSSLSocketFactory.initTrustedSSLSocketFactory(trustStore);
|
||||
env.put("java.naming.ldap.factory.socket", AlfrescoSSLSocketFactory.class.getName());
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
new InitialDirContext(env);
|
||||
|
||||
throw new AuthenticationException(
|
||||
"The ldap server at "
|
||||
+ env.get(Context.PROVIDER_URL)
|
||||
+ " falls back to use anonymous bind if invalid security credentials are presented. This is not supported.");
|
||||
}
|
||||
catch (javax.naming.AuthenticationException ax)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
logger.info("LDAP server does not support simple DN and invalid password at "+ env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
|
||||
// Check more if we have a real principal we expect to work
|
||||
|
||||
String principal = defaultEnvironment.get(Context.SECURITY_PRINCIPAL);
|
||||
if (principal != null)
|
||||
{
|
||||
// Correct principal invalid password
|
||||
|
||||
env = new Hashtable<String, String>(authenticatedEnvironment.size());
|
||||
env.putAll(authenticatedEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, principal);
|
||||
env.put(Context.SECURITY_CREDENTIALS, "sdasdasdasdasd123123123");
|
||||
if (isSSLSocketFactoryRequired())
|
||||
{
|
||||
KeyStore trustStore = initTrustStore();
|
||||
AlfrescoSSLSocketFactory.initTrustedSSLSocketFactory(trustStore);
|
||||
env.put("java.naming.ldap.factory.socket", AlfrescoSSLSocketFactory.class.getName());
|
||||
}
|
||||
if (!checkedEnvs.contains(env))
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
new InitialDirContext(env);
|
||||
|
||||
throw new AuthenticationException(
|
||||
"The ldap server at "
|
||||
+ env.get(Context.PROVIDER_URL)
|
||||
+ " falls back to use anonymous bind for a known principal if invalid security credentials are presented. This is not supported.");
|
||||
}
|
||||
catch (javax.naming.AuthenticationException ax)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for known principal and invalid credentials at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not support the required authentication mechanism");
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
// already done
|
||||
}
|
||||
// Record this environment as checked so that we don't check it again on further restarts / other subsystem
|
||||
// instances
|
||||
checkedEnvs.add(env);
|
||||
}
|
||||
}
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
logger.debug("after Properties Set");
|
||||
|
||||
if (initialChecksEnabled)
|
||||
{
|
||||
checkAnonymousBind();
|
||||
checkSimpleDnAndPassword();
|
||||
checkDnAndPassword();
|
||||
checkPrincipal();
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("LDAP checks are disabled");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Anonymous bind
|
||||
*/
|
||||
private void checkAnonymousBind()
|
||||
{
|
||||
Hashtable<String, String> env = new Hashtable<String, String>(authenticatedEnvironment.size());
|
||||
env.putAll(authenticatedEnvironment);
|
||||
env.remove(Context.SECURITY_PRINCIPAL);
|
||||
env.remove(Context.SECURITY_CREDENTIALS);
|
||||
|
||||
if (isSSLSocketFactoryRequired())
|
||||
{
|
||||
KeyStore trustStore = initTrustStore();
|
||||
AlfrescoSSLSocketFactory.initTrustedSSLSocketFactory(trustStore);
|
||||
env.put("java.naming.ldap.factory.socket", AlfrescoSSLSocketFactory.class.getName());
|
||||
}
|
||||
|
||||
if (!isCached(ANONYMOUS_CHECK, env))
|
||||
{
|
||||
logger.debug("Starting check: Anonymous bind");
|
||||
|
||||
try
|
||||
{
|
||||
new InitialDirContext(env);
|
||||
|
||||
logger.warn("LDAP server supports anonymous bind " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (javax.naming.AuthenticationException | AuthenticationNotSupportedException e)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
logger.error("Unable to connect to LDAP Server; check LDAP configuration", nx);
|
||||
}
|
||||
|
||||
addToCache(ANONYMOUS_CHECK, env);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check simple DN and password
|
||||
*/
|
||||
private void checkSimpleDnAndPassword()
|
||||
{
|
||||
Hashtable<String, String> env = new Hashtable<String, String>(authenticatedEnvironment.size());
|
||||
env.putAll(authenticatedEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, "daftAsABrush");
|
||||
env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush");
|
||||
|
||||
if (isSSLSocketFactoryRequired())
|
||||
{
|
||||
KeyStore trustStore = initTrustStore();
|
||||
AlfrescoSSLSocketFactory.initTrustedSSLSocketFactory(trustStore);
|
||||
env.put("java.naming.ldap.factory.socket", AlfrescoSSLSocketFactory.class.getName());
|
||||
}
|
||||
|
||||
if (!isCached(SIMPLE_DN_CHECK, env))
|
||||
{
|
||||
logger.debug("Starting check: Simple DN and Password");
|
||||
|
||||
try
|
||||
{
|
||||
new InitialDirContext(env);
|
||||
|
||||
throw new AuthenticationException("The ldap server at " + env.get(Context.PROVIDER_URL)
|
||||
+ " falls back to use anonymous bind if invalid security credentials are presented. This is not supported.");
|
||||
}
|
||||
catch (javax.naming.AuthenticationException | AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at "
|
||||
+ env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
logger.info("LDAP server does not support simple string user ids and invalid credentials at "
|
||||
+ env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
|
||||
addToCache(SIMPLE_DN_CHECK, env);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check DN and Password
|
||||
*/
|
||||
private void checkDnAndPassword()
|
||||
{
|
||||
Hashtable<String, String> env = new Hashtable<String, String>(authenticatedEnvironment.size());
|
||||
env.putAll(authenticatedEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, "cn=daftAsABrush,dc=woof");
|
||||
env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush");
|
||||
|
||||
if (isSSLSocketFactoryRequired())
|
||||
{
|
||||
KeyStore trustStore = initTrustStore();
|
||||
AlfrescoSSLSocketFactory.initTrustedSSLSocketFactory(trustStore);
|
||||
env.put("java.naming.ldap.factory.socket", AlfrescoSSLSocketFactory.class.getName());
|
||||
}
|
||||
|
||||
if (!isCached(DN_CHECK, env))
|
||||
{
|
||||
logger.debug("Starting check: DN and Password");
|
||||
|
||||
try
|
||||
{
|
||||
new InitialDirContext(env);
|
||||
|
||||
throw new AuthenticationException("The ldap server at " + env.get(Context.PROVIDER_URL)
|
||||
+ " falls back to use anonymous bind if invalid security credentials are presented. This is not supported.");
|
||||
}
|
||||
catch (javax.naming.AuthenticationException | AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at "
|
||||
+ env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
logger.info("LDAP server does not support simple DN and invalid password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
|
||||
addToCache(DN_CHECK, env);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check more if we have a real principal we expect to work
|
||||
*/
|
||||
private void checkPrincipal()
|
||||
{
|
||||
String principal = defaultEnvironment.get(Context.SECURITY_PRINCIPAL);
|
||||
|
||||
if (principal != null)
|
||||
{
|
||||
// Correct principal invalid password
|
||||
|
||||
Hashtable<String, String> env = new Hashtable<String, String>(authenticatedEnvironment.size());
|
||||
env.putAll(authenticatedEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, principal);
|
||||
env.put(Context.SECURITY_CREDENTIALS, "sdasdasdasdasd123123123");
|
||||
|
||||
if (isSSLSocketFactoryRequired())
|
||||
{
|
||||
KeyStore trustStore = initTrustStore();
|
||||
AlfrescoSSLSocketFactory.initTrustedSSLSocketFactory(trustStore);
|
||||
env.put("java.naming.ldap.factory.socket", AlfrescoSSLSocketFactory.class.getName());
|
||||
}
|
||||
|
||||
if (!isCached(PRINCIPAL_CHECK, env))
|
||||
{
|
||||
logger.debug("Starting check: Principal");
|
||||
|
||||
try
|
||||
{
|
||||
new InitialDirContext(env);
|
||||
|
||||
throw new AuthenticationException("The ldap server at " + env.get(Context.PROVIDER_URL)
|
||||
+ " falls back to use anonymous bind for a known principal if invalid security credentials are presented. This is not supported.");
|
||||
}
|
||||
catch (javax.naming.AuthenticationException ax)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for known principal and invalid credentials at "
|
||||
+ env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not support the required authentication mechanism");
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
// already done
|
||||
}
|
||||
|
||||
// Record this environment as checked so that we don't check it again on further restarts / other
|
||||
// subsystem instances
|
||||
addToCache(PRINCIPAL_CHECK, env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it required to use custom SSL socket factory with custom trustStore.
|
||||
@@ -704,5 +754,69 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
throw new AlfrescoRuntimeException("The certificates cannot be loaded from truststore.", ce);
|
||||
}
|
||||
return ks;
|
||||
}
|
||||
}
|
||||
|
||||
private void addToCache(String key, Map<String, String> value)
|
||||
{
|
||||
Set<Map<String, String>> envs = ldapInitialDirContextCache.get(key);
|
||||
|
||||
if (envs == null)
|
||||
{
|
||||
envs = Collections.synchronizedSet(new HashSet<Map<String, String>>(11));
|
||||
}
|
||||
|
||||
if (!envs.contains(value))
|
||||
{
|
||||
envs.add(value);
|
||||
}
|
||||
|
||||
if (!ldapInitialDirContextCache.contains(key))
|
||||
{
|
||||
ldapInitialDirContextCache.put(key, envs);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeFromCache(String key, Map<String, String> value)
|
||||
{
|
||||
if (ldapInitialDirContextCache != null && ldapInitialDirContextCache.contains(key))
|
||||
{
|
||||
Set<Map<String, String>> envs = ldapInitialDirContextCache.get(key);
|
||||
if (envs != null && envs.contains(value))
|
||||
{
|
||||
envs.remove(value);
|
||||
if (envs.isEmpty())
|
||||
{
|
||||
ldapInitialDirContextCache.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCached(String key, Map<String, String> value)
|
||||
{
|
||||
boolean isCached = false;
|
||||
|
||||
if (ldapInitialDirContextCache != null && ldapInitialDirContextCache.contains(key))
|
||||
{
|
||||
Set<Map<String, String>> envs = ldapInitialDirContextCache.get(key);
|
||||
if (envs != null && envs.contains(value))
|
||||
{
|
||||
isCached = true;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("LDAP check: " + key + " / isCached: " + (isCached ? "yes" : "no"));
|
||||
|
||||
return isCached;
|
||||
}
|
||||
|
||||
public void setLdapInitialDirContextCache(SimpleCache<String, Set<Map<String, String>>> cache)
|
||||
{
|
||||
this.ldapInitialDirContextCache = cache;
|
||||
}
|
||||
|
||||
public void setInitialChecksEnabled(boolean initialChecksEnabled)
|
||||
{
|
||||
this.initialChecksEnabled = initialChecksEnabled;
|
||||
}
|
||||
}
|
||||
|
@@ -51,6 +51,7 @@ import org.alfresco.service.license.LicenseIntegrityException;
|
||||
import org.alfresco.util.LockHelper.LockTryException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.ibatis.exceptions.PersistenceException;
|
||||
import org.apache.ibatis.exceptions.TooManyResultsException;
|
||||
import org.springframework.aop.MethodBeforeAdvice;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
@@ -105,7 +106,8 @@ public class RetryingTransactionHelper
|
||||
DataIntegrityViolationException.class,
|
||||
LicenseIntegrityException.class,
|
||||
TooManyResultsException.class, // Expected one result but found multiple (bad key alert)
|
||||
LockTryException.class
|
||||
LockTryException.class,
|
||||
PersistenceException.class
|
||||
};
|
||||
|
||||
List<Class<?>> retryExceptions = new ArrayList<Class<?>>();
|
||||
|
@@ -215,7 +215,18 @@ public interface RuleService
|
||||
*/
|
||||
@Auditable(parameters = {"nodeRef"})
|
||||
public int countRules(NodeRef nodeRef);
|
||||
|
||||
|
||||
/**
|
||||
* Traverse the folder hierarchy find all the folder nodes that could supply rules by inheritance.
|
||||
*
|
||||
* @param nodeRef The starting node ref.
|
||||
* @return A list of node refs, starting with the first parent of the first parent of ... and ending with the object generated by the
|
||||
* given node ref.
|
||||
*/
|
||||
@Auditable (parameters = { "nodeRef" })
|
||||
@Experimental
|
||||
List<NodeRef> getNodesSupplyingRuleSets(NodeRef nodeRef);
|
||||
|
||||
/**
|
||||
* Get the rule given its node reference
|
||||
*
|
||||
@@ -300,7 +311,17 @@ public interface RuleService
|
||||
*/
|
||||
@Auditable(parameters = {"action"})
|
||||
public NodeRef getOwningNodeRef(Action action);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the owning node reference for a rule.
|
||||
*
|
||||
* @param ruleSet The rule set node.
|
||||
* @return the owning node reference
|
||||
*/
|
||||
@Auditable (parameters = { "ruleSet" })
|
||||
@Experimental
|
||||
NodeRef getOwningNodeRef(NodeRef ruleSet);
|
||||
|
||||
/**
|
||||
* Indicates whether the passed rule node reference is linked to another
|
||||
* rule node.
|
||||
@@ -342,7 +363,7 @@ public interface RuleService
|
||||
NodeRef getRuleSetNode(final NodeRef folderNodeRef);
|
||||
|
||||
/**
|
||||
* Check if rule set's associated parent matches folder node.
|
||||
* Check if rule set is associated (owned/linked/inherited) with the given folder node.
|
||||
*
|
||||
* @param ruleSetNodeRef - node reference of a rule set
|
||||
* @param folderNodeRef - node reference of a folder
|
||||
@@ -364,7 +385,7 @@ public interface RuleService
|
||||
boolean isRuleAssociatedWithRuleSet(final NodeRef ruleNodeRef, final NodeRef ruleSetNodeRef);
|
||||
|
||||
/**
|
||||
* Check if others folders are linked to rule set.
|
||||
* Check if other folders are linked to rule set.
|
||||
*
|
||||
* @param ruleSetNodeRef - node reference of a rule set
|
||||
* @return true if others folders are linked to rule set
|
||||
|
@@ -506,4 +506,12 @@
|
||||
<bean name="queryAcceleratorCache" factory-bean="cacheFactory" factory-method="createCache">
|
||||
<constructor-arg value="cache.queryAcceleratorCache"/>
|
||||
</bean>
|
||||
|
||||
<!-- ===================================== -->
|
||||
<!-- LDAP Initial Dir Context cache -->
|
||||
<!-- ===================================== -->
|
||||
|
||||
<bean name="ldapInitialDirContextCache" factory-bean="cacheFactory" factory-method="createCache">
|
||||
<constructor-arg value="cache.ldapInitialDirContextCache"/>
|
||||
</bean>
|
||||
</beans>
|
||||
|
@@ -699,3 +699,15 @@ cache.queryAcceleratorCache.backup-count=1
|
||||
cache.queryAcceleratorCache.eviction-policy=NONE
|
||||
cache.queryAcceleratorCache.merge-policy=com.hazelcast.map.merge.LatestUpdateMapMergePolicy
|
||||
cache.queryAcceleratorCache.readBackupData=false
|
||||
|
||||
#
|
||||
# LDAP initial dir context checks cluster cache
|
||||
#
|
||||
cache.ldapInitialDirContextCache.maxItems=100
|
||||
cache.ldapInitialDirContextCache.timeToLiveSeconds=0
|
||||
cache.ldapInitialDirContextCache.maxIdleSeconds=0
|
||||
cache.ldapInitialDirContextCache.cluster.type=fully-distributed
|
||||
cache.ldapInitialDirContextCache.backup-count=1
|
||||
cache.ldapInitialDirContextCache.eviction-policy=NONE
|
||||
cache.ldapInitialDirContextCache.merge-policy=com.hazelcast.map.merge.LatestUpdateMapMergePolicy
|
||||
cache.ldapInitialDirContextCache.readBackupData=false
|
@@ -119,7 +119,12 @@
|
||||
-->
|
||||
|
||||
<bean id="ldapInitialDirContextFactory" class="org.alfresco.repo.security.authentication.ldap.LDAPInitialDirContextFactoryImpl">
|
||||
|
||||
<property name="ldapInitialDirContextCache">
|
||||
<ref bean="ldapInitialDirContextCache" />
|
||||
</property>
|
||||
<property name="initialChecksEnabled">
|
||||
<value>${ldap.authentication.initial.checks.enabled}</value>
|
||||
</property>
|
||||
<property name="trustStorePath">
|
||||
<value>${ldap.authentication.truststore.path}</value>
|
||||
</property>
|
||||
|
@@ -175,3 +175,6 @@ ldap.synchronization.userAccountStatusProperty=userAccountControl
|
||||
|
||||
# The Account Status Interpreter bean name
|
||||
ldap.synchronization.userAccountStatusInterpreter=ldapadUserAccountStatusInterpreter
|
||||
|
||||
# Allows to enable or disable LDAP-AD initial checks (anonymous bind, simple dn, dn and principal)
|
||||
ldap.authentication.initial.checks.enabled=true
|
@@ -192,3 +192,6 @@ ldap.synchronization.disabledAccountPropertyValueCanBeNull=true
|
||||
|
||||
# The Account Status Interpreter bean name
|
||||
ldap.synchronization.userAccountStatusInterpreter=ldapUserAccountStatusInterpreter
|
||||
|
||||
# Allows to enable or disable LDAP initial checks (anonymous bind, simple dn, dn and principal)
|
||||
ldap.authentication.initial.checks.enabled=true
|
@@ -25,7 +25,12 @@
|
||||
*/
|
||||
package org.alfresco.repo.rule;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
|
||||
import static org.alfresco.model.ContentModel.ASSOC_MEMBER;
|
||||
import static org.alfresco.repo.rule.RuleModel.ASPECT_IGNORE_INHERITED_RULES;
|
||||
import static org.alfresco.repo.rule.RuleModel.ASSOC_ACTION;
|
||||
import static org.alfresco.repo.rule.RuleModel.ASSOC_RULE_FOLDER;
|
||||
import static org.alfresco.repo.rule.RuleModel.TYPE_RULE;
|
||||
@@ -33,6 +38,7 @@ import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED;
|
||||
import static org.alfresco.service.cmr.security.AccessStatus.DENIED;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
@@ -47,8 +53,13 @@ import static org.mockito.MockitoAnnotations.openMocks;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.RuntimeActionService;
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
@@ -61,6 +72,7 @@ import org.alfresco.service.cmr.rule.RuleService;
|
||||
import org.alfresco.service.cmr.rule.RuleServiceException;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
@@ -242,6 +254,8 @@ public class RuleServiceImplUnitTest
|
||||
boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE);
|
||||
|
||||
then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
|
||||
then(runtimeNodeService).should().hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
|
||||
then(runtimeNodeService).should().getParentAssocs(FOLDER_NODE);
|
||||
then(runtimeNodeService).shouldHaveNoMoreInteractions();
|
||||
then(nodeService).shouldHaveNoInteractions();
|
||||
assertThat(associated).isTrue();
|
||||
@@ -256,6 +270,8 @@ public class RuleServiceImplUnitTest
|
||||
boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE);
|
||||
|
||||
then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
|
||||
then(runtimeNodeService).should().hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
|
||||
then(runtimeNodeService).should().getParentAssocs(FOLDER_NODE);
|
||||
then(runtimeNodeService).shouldHaveNoMoreInteractions();
|
||||
then(nodeService).shouldHaveNoInteractions();
|
||||
assertThat(associated).isFalse();
|
||||
@@ -271,11 +287,45 @@ public class RuleServiceImplUnitTest
|
||||
boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE);
|
||||
|
||||
then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
|
||||
then(runtimeNodeService).should().hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
|
||||
then(runtimeNodeService).should().getParentAssocs(FOLDER_NODE);
|
||||
then(runtimeNodeService).shouldHaveNoMoreInteractions();
|
||||
then(nodeService).shouldHaveNoInteractions();
|
||||
assertThat(associated).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a rule set is associated with the folder in the following case:
|
||||
* <pre>
|
||||
* parent --[link]-> rule set <-[owned]-- owningFolder
|
||||
* +- child
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testIsRuleSetAssociatedWithFolder_inheritedLinkedAssociation()
|
||||
{
|
||||
// The rule is owned by one node.
|
||||
NodeRef owningFolder = new NodeRef("owning://node/");
|
||||
// The rule is linked to by the parent node.
|
||||
NodeRef parent = new NodeRef("parent://node/");
|
||||
List<ChildAssociationRef> ruleAssociations = List.of(createAssociation(owningFolder, RULE_SET_NODE), createAssociation(parent, RULE_SET_NODE));
|
||||
given(runtimeNodeService.getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER)).willReturn(ruleAssociations);
|
||||
// The parent and the child both supply rule sets.
|
||||
given(runtimeNodeService.getParentAssocs(FOLDER_NODE)).willReturn(List.of(createAssociation(parent, FOLDER_NODE)));
|
||||
|
||||
// when
|
||||
boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE);
|
||||
|
||||
then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
|
||||
then(runtimeNodeService).should().hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
|
||||
then(runtimeNodeService).should().getParentAssocs(FOLDER_NODE);
|
||||
then(runtimeNodeService).should().hasAspect(parent, ASPECT_IGNORE_INHERITED_RULES);
|
||||
then(runtimeNodeService).should().getParentAssocs(parent);
|
||||
then(runtimeNodeService).shouldHaveNoMoreInteractions();
|
||||
then(nodeService).shouldHaveNoInteractions();
|
||||
assertThat(associated).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsRuleAssociatedWithRuleSet()
|
||||
{
|
||||
@@ -356,4 +406,174 @@ public class RuleServiceImplUnitTest
|
||||
{
|
||||
return new ChildAssociationRef(null, parentRef, null, childRef, isPrimary, 1);
|
||||
}
|
||||
|
||||
/** Check that a straight chain of nodes is traversed correctly. */
|
||||
@Test
|
||||
public void testGetNodesSupplyingRuleSets_chain()
|
||||
{
|
||||
Map<String, NodeRef> nodes = createParentChildHierarchy("A,B", "B,C", "C,D", "D,E");
|
||||
|
||||
List<NodeRef> actual = ruleService.getNodesSupplyingRuleSets(nodes.get("E"));
|
||||
|
||||
Map<NodeRef, String> invertedMap = MapUtils.invertMap(nodes);
|
||||
String nodeNames = actual.stream().map(invertedMap::get).collect(joining(","));
|
||||
|
||||
assertEquals("A,B,C,D,E", nodeNames);
|
||||
}
|
||||
|
||||
/** Check that ordered parents are returned in the correct order. */
|
||||
@Test
|
||||
public void testGetNodesSupplyingRuleSets_multipleParents()
|
||||
{
|
||||
Map<String, NodeRef> nodes = createParentChildHierarchy("A,E", "B,E", "C,E", "D,E");
|
||||
|
||||
List<NodeRef> actual = ruleService.getNodesSupplyingRuleSets(nodes.get("E"));
|
||||
|
||||
Map<NodeRef, String> invertedMap = MapUtils.invertMap(nodes);
|
||||
String nodeNames = actual.stream().map(invertedMap::get).collect(joining(","));
|
||||
|
||||
assertEquals("A,B,C,D,E", nodeNames);
|
||||
}
|
||||
|
||||
/** Check that the ASPECT_IGNORE_INHERITED_RULES aspect breaks the chain. */
|
||||
@Test
|
||||
public void testGetNodesSupplyingRuleSets_brokenChain()
|
||||
{
|
||||
Map<String, NodeRef> nodes = createParentChildHierarchy("A,B", "B,C", "C,D", "D,E");
|
||||
given(runtimeNodeService.hasAspect(nodes.get("C"), ASPECT_IGNORE_INHERITED_RULES)).willReturn(true);
|
||||
|
||||
List<NodeRef> actual = ruleService.getNodesSupplyingRuleSets(nodes.get("E"));
|
||||
|
||||
Map<NodeRef, String> invertedMap = MapUtils.invertMap(nodes);
|
||||
String nodeNames = actual.stream().map(invertedMap::get).collect(joining(","));
|
||||
|
||||
assertEquals("C,D,E", nodeNames);
|
||||
}
|
||||
|
||||
/** Check that the user group hierarchy is not traversed. */
|
||||
@Test
|
||||
public void testGetNodesSupplyingRuleSets_userGroupHierarchy()
|
||||
{
|
||||
Map<String, NodeRef> nodes = createParentChildHierarchy("A,B", "B,C", "C,D", "D,E");
|
||||
// Replace the B,C association with a user group membership association.
|
||||
ChildAssociationRef memberAssoc = new ChildAssociationRef(ASSOC_MEMBER, nodes.get("B"), ContentModel.TYPE_FOLDER, nodes.get("C"));
|
||||
given(runtimeNodeService.getParentAssocs(nodes.get("C"))).willReturn(List.of(memberAssoc));
|
||||
|
||||
List<NodeRef> actual = ruleService.getNodesSupplyingRuleSets(nodes.get("E"));
|
||||
|
||||
Map<NodeRef, String> invertedMap = MapUtils.invertMap(nodes);
|
||||
String nodeNames = actual.stream().map(invertedMap::get).collect(joining(","));
|
||||
|
||||
assertEquals("C,D,E", nodeNames);
|
||||
}
|
||||
|
||||
/** Check that a cycle doesn't cause a problem. */
|
||||
@Test
|
||||
public void testGetNodesSupplyingRuleSets_infiniteCycle()
|
||||
{
|
||||
Map<String, NodeRef> nodes = createParentChildHierarchy("A,B", "B,C", "C,A");
|
||||
|
||||
List<NodeRef> actual = ruleService.getNodesSupplyingRuleSets(nodes.get("C"));
|
||||
|
||||
Map<NodeRef, String> invertedMap = MapUtils.invertMap(nodes);
|
||||
String nodeNames = actual.stream().map(invertedMap::get).collect(joining(","));
|
||||
|
||||
assertEquals("A,B,C", nodeNames);
|
||||
}
|
||||
|
||||
/** Check that a diamond of nodes is traversed correctly. */
|
||||
@Test
|
||||
public void testGetNodesSupplyingRuleSets_diamond()
|
||||
{
|
||||
Map<String, NodeRef> nodes = createParentChildHierarchy("A,B", "A,C", "B,D", "C,D");
|
||||
|
||||
List<NodeRef> actual = ruleService.getNodesSupplyingRuleSets(nodes.get("D"));
|
||||
|
||||
Map<NodeRef, String> invertedMap = MapUtils.invertMap(nodes);
|
||||
String nodeNames = actual.stream().map(invertedMap::get).collect(joining(","));
|
||||
|
||||
assertEquals("A,B,C,D", nodeNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that hierarchy of nodes is traversed correctly. Parent-child associations are created in alphabetical order.
|
||||
* <pre>
|
||||
* A
|
||||
* /|\
|
||||
* B C D
|
||||
* | |\|
|
||||
* E | F
|
||||
* \|/
|
||||
* G
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testGetNodesSupplyingRuleSets_alphabetical()
|
||||
{
|
||||
Map<String, NodeRef> nodes = createParentChildHierarchy("A,B", "A,C", "A,D", "B,E", "C,F", "C,G", "D,F", "E,G", "F,G");
|
||||
|
||||
List<NodeRef> actual = ruleService.getNodesSupplyingRuleSets(nodes.get("G"));
|
||||
|
||||
Map<NodeRef, String> invertedMap = MapUtils.invertMap(nodes);
|
||||
String nodeNames = actual.stream().map(invertedMap::get).collect(joining(","));
|
||||
|
||||
assertEquals("A,C,B,E,D,F,G", nodeNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that hierarchy of nodes is traversed correctly. Parent-child associations are created in reverse alphabetical order.
|
||||
* <pre>
|
||||
* A
|
||||
* /|\
|
||||
* B C D
|
||||
* | |\|
|
||||
* E | F
|
||||
* \|/
|
||||
* G
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testGetNodesSupplyingRuleSets_reversedAssociationOrder()
|
||||
{
|
||||
Map<String, NodeRef> nodes = createParentChildHierarchy("F,G", "E,G", "D,F", "C,G", "C,F", "B,E", "A,D", "A,C", "A,B");
|
||||
|
||||
List<NodeRef> actual = ruleService.getNodesSupplyingRuleSets(nodes.get("G"));
|
||||
|
||||
Map<NodeRef, String> invertedMap = MapUtils.invertMap(nodes);
|
||||
String nodeNames = actual.stream().map(invertedMap::get).collect(joining(","));
|
||||
|
||||
assertEquals("A,D,C,F,B,E,G", nodeNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock hierarchy of nodes using the supplied parent child associations.
|
||||
*
|
||||
* @param parentChildAssociations A list of strings of the form "Parent,Child". Associations will be created in this order.
|
||||
* @return A map from the node name to the new NodeRef object.
|
||||
*/
|
||||
private Map<String, NodeRef> createParentChildHierarchy(String... parentChildAssociations)
|
||||
{
|
||||
// Find all the node names mentioned.
|
||||
Set<String> nodeNames = new HashSet<>();
|
||||
List.of(parentChildAssociations).forEach(parentChildAssociation -> {
|
||||
String[] parentChildPair = parentChildAssociation.split(",");
|
||||
nodeNames.addAll(List.of(parentChildPair));
|
||||
});
|
||||
// Create the NodeRefs.
|
||||
Map<String, NodeRef> nodeRefMap = nodeNames.stream().collect(
|
||||
Collectors.toMap(nodeName -> nodeName, nodeName -> new NodeRef("node://" + nodeName + "/")));
|
||||
// Mock the associations.
|
||||
nodeNames.forEach(nodeName -> {
|
||||
NodeRef nodeRef = nodeRefMap.get(nodeName);
|
||||
List<ChildAssociationRef> parentAssocs = List.of(parentChildAssociations)
|
||||
.stream()
|
||||
.filter(assoc -> assoc.endsWith(nodeName))
|
||||
.map(assoc -> assoc.split(",")[0])
|
||||
.map(nodeRefMap::get)
|
||||
.map(parentRef -> new ChildAssociationRef(ASSOC_CONTAINS, parentRef, ContentModel.TYPE_FOLDER, nodeRef))
|
||||
.collect(toList());
|
||||
given(runtimeNodeService.getParentAssocs(nodeRef)).willReturn(parentAssocs);
|
||||
});
|
||||
return nodeRefMap;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,11 @@
|
||||
function testPreferences()
|
||||
{
|
||||
var preferences = {
|
||||
"org.alfresco.share.forum.summary.dashlet.component-1-3.history": "1"
|
||||
};
|
||||
|
||||
preferenceService.setPreferences(username, preferences);
|
||||
}
|
||||
|
||||
// Execute tests
|
||||
testPreferences();
|
Reference in New Issue
Block a user