Compare commits

..

40 Commits

Author SHA1 Message Date
Damian.Ujma@hyland.com
cd8ef77b3e Increase sleep to 4 minutes 2022-09-06 12:27:56 +02:00
Damian.Ujma@hyland.com
8622e0e102 Init 2022-09-06 11:10:46 +02:00
Travis CI User
69170dde35 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-04 00:10:18 +00:00
Travis CI User
c848024130 [maven-release-plugin][skip ci] prepare release 17.101 2022-09-04 00:10:15 +00:00
Alfresco CI User
553f78bb1e [force] Force release for 2022-09-04. 2022-09-04 00:03:36 +00:00
Travis CI User
9a3ceb21a8 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-03 17:43:30 +00:00
Travis CI User
57d0ff62dc [maven-release-plugin][skip ci] prepare release 17.100 2022-09-03 17:43:27 +00:00
mstrankowski
42bd94c1da ACS-3461: Update ATS reference to released 1.5.4-A3 2022-09-03 18:58:02 +02:00
Travis CI User
c5dd6538f8 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-01 05:40:58 +00:00
Travis CI User
152c036d86 [maven-release-plugin][skip ci] prepare release 17.99 2022-09-01 05:40:55 +00:00
rrajoria
f2055f91dc Reverting googledrive changes 2022-09-01 10:27:18 +05:30
Travis CI User
a1d7f0d479 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-31 14:01:04 +00:00
Travis CI User
8476f01b35 [maven-release-plugin][skip ci] prepare release 17.98 2022-08-31 14:01:01 +00:00
Maciej Pichura
6c4b9e458a ACS-3431 rule set links TAS REST tests (#1342)
* ACS-3431: Initial TAS REST tests for link to rule set.

* ACS-3431: Fixing assertions.

* ACS-3431: Adding rule set assertions, fixing TAS RESTAPI dependency version.

* ACS-3431: Small test refactorings.

* ACS-3431: Small test refactorings.

* ACS-3431: Adding more tests and refactorings.

* ACS-3431: Fixing a TYPO.
2022-08-31 15:25:25 +02:00
Marcin Strankowski
0f99dec012 ACS-3463: Updating AIS and ATC versions (#1348) 2022-08-31 14:45:25 +02:00
Travis CI User
06c7836e70 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-31 09:54:21 +00:00
Travis CI User
2ceb7384bf [maven-release-plugin][skip ci] prepare release 17.97 2022-08-31 09:54:19 +00:00
rrajoria
d848c83a57 Updating google drive version
Updating google drive version (Test only for JDK 17changes)
2022-08-31 14:46:12 +05:30
Kristian Dimitrov
be7572a978 ACS-3352 GET e2es for newly mapped other fields (#1335)
* ACS-3381: GET e2es for newly mapped other fields

* ACS-3381: Fix failing tests after rebase
2022-08-31 09:53:08 +01:00
Jamal Kaabi-Mofrad
ef45aaf9cc Upgraded Keycloak-Client to match the Identity-Service version. (#1344) 2022-08-30 16:47:37 +01:00
Travis CI User
6f834909f6 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-28 00:10:34 +00:00
Travis CI User
b928598bd7 [maven-release-plugin][skip ci] prepare release 17.96 2022-08-28 00:10:32 +00:00
Alfresco CI User
678eeab278 [force] Force release for 2022-08-28. 2022-08-28 00:04:02 +00:00
Travis CI User
45f9bd6569 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-25 15:41:39 +00:00
Travis CI User
23b8c0e7a6 [maven-release-plugin][skip ci] prepare release 17.95 2022-08-25 15:41:37 +00:00
Antonio Felix
9c98f7b0fb Fix/mnt 23087 export of records failing (#1333)
* MNT-23087 - Split the export list into several smaller list for better performance
2022-08-25 15:36:50 +01:00
Travis CI User
6e1d5c81e2 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-25 11:21:43 +00:00
Travis CI User
092d895f6a [maven-release-plugin][skip ci] prepare release 17.94 2022-08-25 11:21:40 +00:00
Maciej Pichura
a568c87571 ACS-3429, ACS-3336: Rule action mappings (create), validations (update) - part 2 (#1332)
* ACS-3429, ACS-3336: Adding initial TAS tests for create rule with multiple actions, adding action parameters mappings and rule/action validations for rule update.

* ACS-3429: Removing duplicated assertion.

* ACS-3429: Changing NodeRef conversions to use only node id.
2022-08-25 12:46:42 +02:00
Kacper Magdziarz
3aac7be11c MNT-23103 - Downloading a document replaces filename having space with + character (#1327)
* MNT-23103 Change encoder for content disposition filename to be consistent with RFC5987.

Add test covering filename encoding.
2022-08-24 15:59:11 +02:00
Travis CI User
700fbce572 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-24 13:43:15 +00:00
Travis CI User
7be96e788b [maven-release-plugin][skip ci] prepare release 17.93 2022-08-24 13:43:12 +00:00
George Evangelopoulos
0af001be2a Support for linking to a single rule set (#1324)
* Support for linking to a single rule set

* ACS-3435: Small fix to get parent  node for rule set.

* ACS-3435: Revert unnecessary change

* ACS-3435: added tests

* ACS-3435: move test assertions

* ACS-3435: adding tests

Co-authored-by: mpichura <maciej.pichura@hyland.com>
2022-08-24 15:58:04 +03:00
Travis CI User
f38a36910f [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-24 11:57:18 +00:00
Travis CI User
972f81ab8b [maven-release-plugin][skip ci] prepare release 17.92 2022-08-24 11:57:16 +00:00
Domenico Sibilio
1bd0dfd114 ACS-3351 Bump Alfresco JLAN to 7.2 (#1334) 2022-08-24 13:14:03 +02:00
Travis CI User
775de0e94c [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-21 00:10:37 +00:00
Travis CI User
78d2ed247a [maven-release-plugin][skip ci] prepare release 17.91 2022-08-21 00:10:35 +00:00
Alfresco CI User
5ca3630398 [force] Force release for 2022-08-21. 2022-08-21 00:03:38 +00:00
Travis CI User
ee7383dcab [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-19 15:10:22 +00:00
48 changed files with 1162 additions and 233 deletions

11
.github/workflows/hackathon.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
name: Hackathon
on:
push:
jobs:
sleep:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: sleep 240

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<build>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<modules>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<build>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<modules>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<dependencies>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<dependencies>

View File

@@ -9,6 +9,6 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
</project>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<modules>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<modules>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<developers>

View File

@@ -27,12 +27,7 @@ package org.alfresco.rest.rules;
import static java.util.stream.Collectors.toList;
import static org.alfresco.rest.rules.RulesTestsUtils.RULE_NAME_DEFAULT;
import static org.alfresco.rest.rules.RulesTestsUtils.createDefaultActionModel;
import static org.alfresco.rest.rules.RulesTestsUtils.createEmptyConditionModel;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithDefaultName;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithDefaultValues;
import static org.alfresco.rest.rules.RulesTestsUtils.*;
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
import static org.alfresco.utility.constants.UserRole.SiteConsumer;
import static org.alfresco.utility.constants.UserRole.SiteContributor;
@@ -46,10 +41,14 @@ import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleModelsCollection;
import org.alfresco.utility.constants.UserRole;
@@ -89,20 +88,18 @@ public class CreateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void createRule()
{
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
RestRuleModel ruleModel = createRuleModelWithModifiedValues();
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
RestRuleModel expectedRuleModel = createRuleModelWithModifiedValues();
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
expectedRuleModel.setConditions(createEmptyConditionModel());
restClient.assertStatusCodeIs(CREATED);
// TODO fix actions mapping and remove it from ignored fields, actual issue - difference:
// actual: actions=[RestActionBodyExecTemplateModel{actionDefinitionId='add-features', params={actionContext=rule, aspect-name={http://www.alfresco.org/model/audio/1.0}audio}}]
// expected: actions=[RestActionBodyExecTemplateModel{actionDefinitionId='set-property-value', params={aspect-name={http://www.alfresco.org/model/audio/1.0}audio, actionContext=rule}}]
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED, "actions")
.assertThat().field("id").isNotNull()
.assertThat().field("isShared").isNull();
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
.assertThat().field("id").isNotNull()
.assertThat().field("isShared").isNull();
}
/** Check creating a rule in a non-existent folder returns an error. */
@@ -274,7 +271,7 @@ public class CreateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithoutDescription()
{
RestRuleModel ruleModel = createRuleModelWithDefaultName();
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
@@ -290,7 +287,7 @@ public class CreateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithoutTriggers()
{
RestRuleModel ruleModel = createRuleModelWithDefaultName();
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
@@ -306,7 +303,7 @@ public class CreateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithoutErrorScript()
{
RestRuleModel ruleModel = createRuleModelWithDefaultName();
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
@@ -322,7 +319,7 @@ public class CreateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithSharedFlag()
{
RestRuleModel ruleModel = createRuleModelWithDefaultName();
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
ruleModel.setIsShared(true);
UserModel admin = dataUser.getAdminUser();
@@ -362,4 +359,37 @@ public class CreateRulesTests extends RestTest
return restClient.authenticateUser(userWithRole).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
}
/**
* Check we can create a rule with several actions.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithActions()
{
final Map<String, Serializable> copyParams =
Map.of("destination-folder", "dummy-folder-node", "deep-copy", true);
final RestActionBodyExecTemplateModel copyAction = createCustomActionModel("copy", copyParams);
final Map<String, Serializable> checkOutParams =
Map.of("destination-folder", "dummy-folder-node", "assoc-name", "cm:checkout", "assoc-type",
"cm:contains");
final RestActionBodyExecTemplateModel checkOutAction = createCustomActionModel("check-out", checkOutParams);
final Map<String, Serializable> scriptParams = Map.of("script-ref", "dummy-script-node-id");
final RestActionBodyExecTemplateModel scriptAction = createCustomActionModel("script", scriptParams);
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
ruleModel.setActions(Arrays.asList(copyAction, checkOutAction, scriptAction));
final UserModel admin = dataUser.getAdminUser();
final RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
final RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
expectedRuleModel.setActions(addActionContextParams(Arrays.asList(copyAction, checkOutAction, scriptAction)));
expectedRuleModel.setConditions(createEmptyConditionModel());
expectedRuleModel.setTriggers(List.of("inbound"));
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
.assertThat().field("isShared").isNull();
}
}

View File

@@ -27,13 +27,14 @@ package org.alfresco.rest.rules;
import static java.util.stream.Collectors.toList;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
import static org.alfresco.rest.rules.RulesTestsUtils.*;
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.HttpStatus.CREATED;
import java.util.List;
import java.util.stream.IntStream;
@@ -60,6 +61,8 @@ public class GetRulesTests extends RestTest
private FolderModel ruleFolder;
private List<RestRuleModel> createdRules;
private RestRuleModel createdRuleA;
private static final String IGNORE_ID = "id";
private static final String IGNORE_IS_SHARED = "isShared";
@BeforeClass(alwaysRun = true)
public void dataPreparation()
@@ -133,7 +136,7 @@ public class GetRulesTests extends RestTest
restClient.assertStatusCodeIs(NOT_FOUND);
}
/** Check we can get all the rules for a folder along with the extra "include" fields. */
/** Check we can get all the rules for a folder along with the extra "include" and "other" fields. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getRulesListWithIncludedFields()
{
@@ -145,7 +148,14 @@ public class GetRulesTests extends RestTest
rules.assertThat().entriesListCountIs(createdRules.size());
IntStream.range(0, createdRules.size()).forEach(i ->
rules.getEntries().get(i).onModel()
.assertThat().field("isShared").isNotNull());
.assertThat().field("isShared").isNotNull()
.assertThat().field("description").isNull()
.assertThat().field("enabled").is(false)
.assertThat().field("cascade").is(false)
.assertThat().field("asynchronous").is(false)
.assertThat().field("errorScript").isNull()
.assertThat().field("shared").isNull()
.assertThat().field("triggers").is("[inbound]"));
}
/**
@@ -166,6 +176,54 @@ public class GetRulesTests extends RestTest
.assertThat().field("isShared").isNull();
}
/** Check we can get rule's other fields */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getRulesOtherFieldsModified()
{
STEP("Create a rule with all other fields default values modified");
RestRuleModel ruleModel = createRuleModelWithModifiedValues();
ruleModel.setTriggers(List.of("update"));
UserModel admin = dataUser.getAdminUser();
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(folder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = createRuleModelWithModifiedValues();
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
expectedRuleModel.setTriggers(List.of("update"));
expectedRuleModel.setConditions(createEmptyConditionModel());
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
.assertThat().field("id").isNotNull()
.assertThat().field("isShared").isNull();
}
/** Check we can get rule's "other" fields */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getRulesDefaultFields()
{
STEP("Create a rule with all other fields default values");
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(folder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
expectedRuleModel.setTriggers(List.of("inbound"));
expectedRuleModel.setConditions(createEmptyConditionModel());
restClient.assertStatusCodeIs(CREATED);
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
.assertThat().field("id").isNotNull()
.assertThat().field("isShared").isNull();
}
/** Check we get a 404 if trying to load a rule from a folder that doesn't exist. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getSingleRuleFromNonExistentFolder()

View File

@@ -0,0 +1,313 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 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.createRuleModel;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import org.alfresco.dataprep.CMISUtil;
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.FileModel;
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 /nodes/{nodeId}/rule-set-links.
*/
@Test(groups = {TestGroup.RULES})
public class RuleSetLinksTests 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 link to folder containing a rule set.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToFolderContainingRules()
{
STEP("Create folders in existing site");
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create a rule in the rule folder.");
RestRuleModel ruleModel = createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Get the rule sets for the folder and find the rule set id");
final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
.getListOfRuleSets();
ruleSets.assertThat().entriesListCountIs(1);
final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
STEP("Link to a rule folder");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(ruleFolder.getNodeRef());
final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
STEP("Assert link result");
restClient.assertStatusCodeIs(CREATED);
final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
expectedLink.setId(ruleSetId);
ruleLink.assertThat().isEqualTo(expectedLink);
STEP("Check if folder returns same rules");
final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder)
.usingDefaultRuleSet()
.getListOfRules();
linkedRules.assertThat().entriesListCountIs(1);
linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
STEP("Check if folder returns rule set with linked inclusionType");
final RestRuleSetModelsCollection linkedRuleSets = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder)
.include("inclusionType")
.getListOfRuleSets();
linkedRuleSets.assertThat().entriesListCountIs(1);
final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
expectedRuleSet.setId(ruleSetId);
expectedRuleSet.setInclusionType("linked");
linkedRuleSets.getEntries()
.get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
}
/**
* Check we can link to a rule set.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToRuleSet()
{
STEP("Create folders in existing site");
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create a rule in the rule folder.");
RestRuleModel ruleModel = createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Get the rule sets for the folder and find the rule set id");
final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
.getListOfRuleSets();
ruleSets.assertThat().entriesListCountIs(1);
final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
STEP("Link to a rule set");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(ruleSetId);
final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
STEP("Assert link result");
restClient.assertStatusCodeIs(CREATED);
final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
expectedLink.setId(ruleSetId);
ruleLink.assertThat().isEqualTo(expectedLink);
STEP("Check if folder returns same rules");
final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder)
.usingDefaultRuleSet()
.getListOfRules();
linkedRules.assertThat().entriesListCountIs(1);
linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
STEP("Check if folder returns rule set with linked inclusionType");
final RestRuleSetModelsCollection likedRuleSets = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder)
.include("inclusionType")
.getListOfRuleSets();
likedRuleSets.assertThat().entriesListCountIs(1);
final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
expectedRuleSet.setId(ruleSetId);
expectedRuleSet.setInclusionType("linked");
likedRuleSets.getEntries()
.get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
}
/**
* Check we get 404 when linking to a non-existing rule set/folder.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToNonExistingRuleSet()
{
STEP("Create a folder in existing site");
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Link to non-existing rule set");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId("dummy-rule-set-id");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
STEP("Assert link result is 404");
restClient.assertStatusCodeIs(NOT_FOUND);
}
/**
* Check we get bad request error when linking to a folder without rules.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToFolderWithoutRules()
{
STEP("Create 2 folders without rules in existing site");
final FolderModel folder1 = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel folder2 = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Link to a folder without rules");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(folder2.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).createRuleLink(request);
STEP("Assert link result is 400");
restClient.assertStatusCodeIs(BAD_REQUEST)
.assertLastError().containsSummary("The target node has no rules to link.");
}
/**
* Check we get bad request error when linking from a folder which already has rules.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkFromFolderWithRules()
{
STEP("Create folders in existing site");
final FolderModel folder1 = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel folder2 = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create rules in both folders.");
RestRuleModel ruleModel1 = createRuleModel("ruleName1");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).usingDefaultRuleSet()
.createSingleRule(ruleModel1);
RestRuleModel ruleModel2 = createRuleModel("ruleName2");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder2).usingDefaultRuleSet()
.createSingleRule(ruleModel2);
STEP("Link from a folder with rules");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(folder2.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).createRuleLink(request);
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.");
}
/**
* Check we get bad request error when linking to a file node.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToFileNode()
{
STEP("Create a folder in existing site");
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
final FileModel fileContent = dataContent.usingUser(user).usingSite(site).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Link to a file node");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(fileContent.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
STEP("Assert link result is 400");
restClient.assertStatusCodeIs(BAD_REQUEST)
.assertLastError().containsSummary("NodeId of a folder is expected!");
}
/**
* Check we can link to a parent folder with rules.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToParentNodeWithRules()
{
STEP("Create parent/child folders in existing site");
final FolderModel parentFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel childFolder = dataContent.usingUser(user).usingSite(site).usingResource(parentFolder).createFolder();
STEP("Create a rule in the parent folder.");
RestRuleModel ruleModel = createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(parentFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Get the rule sets for the folder and find the rule set id");
final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(parentFolder)
.getListOfRuleSets();
ruleSets.assertThat().entriesListCountIs(1);
final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
STEP("Link to the parent folder");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(parentFolder.getNodeRef());
final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolder).createRuleLink(request);
STEP("Assert link result");
restClient.assertStatusCodeIs(CREATED);
final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
expectedLink.setId(ruleSetId);
ruleLink.assertThat().isEqualTo(expectedLink);
STEP("Check if child folder returns same rules");
final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
.usingNode(childFolder)
.usingDefaultRuleSet()
.getListOfRules();
linkedRules.assertThat().entriesListCountIs(1);
linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
STEP("Check if child folder returns rule set with linked inclusionType");
final RestRuleSetModelsCollection linkedRuleSets = restClient.authenticateUser(user).withCoreAPI()
.usingNode(childFolder)
.include("inclusionType")
.getListOfRuleSets();
linkedRuleSets.assertThat().entriesListCountIs(1);
final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
expectedRuleSet.setId(ruleSetId);
expectedRuleSet.setInclusionType("linked");
linkedRuleSets.getEntries()
.get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
}
}

View File

@@ -25,6 +25,8 @@
*/
package org.alfresco.rest.rules;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -48,9 +50,9 @@ public class RulesTestsUtils
*
* @return The created rule model.
*/
public static RestRuleModel createRuleModelWithDefaultValues()
public static RestRuleModel createRuleModelWithModifiedValues()
{
RestRuleModel ruleModel = createRuleModelWithDefaultName();
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
ruleModel.setDescription(RULE_DESCRIPTION_DEFAULT);
ruleModel.setEnabled(RULE_ENABLED_DEFAULT);
ruleModel.setCascade(RULE_CASCADE_DEFAULT);
@@ -62,7 +64,7 @@ public class RulesTestsUtils
return ruleModel;
}
public static RestRuleModel createRuleModelWithDefaultName()
public static RestRuleModel createRuleModelWithDefaultValues()
{
return createRuleModel(RULE_NAME_DEFAULT, List.of(createDefaultActionModel()));
}
@@ -95,11 +97,29 @@ public class RulesTestsUtils
public static RestActionBodyExecTemplateModel createDefaultActionModel()
{
RestActionBodyExecTemplateModel restActionModel = new RestActionBodyExecTemplateModel();
restActionModel.setActionDefinitionId("add-features");
restActionModel.setActionDefinitionId("set-property-value");
restActionModel.setParams(Map.of("aspect-name", "cm:audio"));
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();
restActionModel.setActionDefinitionId(actionDefinitionId);
restActionModel.setParams(params);
return restActionModel;
}
public static RestCompositeConditionDefinitionModel createEmptyConditionModel()
{
RestCompositeConditionDefinitionModel conditions = new RestCompositeConditionDefinitionModel();

View File

@@ -161,8 +161,7 @@ public class UpdateRulesTests extends RestTest
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule to have no name.");
RestRuleModel updatedRuleModel = new RestRuleModel();
updatedRuleModel.setName("");
RestRuleModel updatedRuleModel = createRuleModel("");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().updateRule(rule.getId(), updatedRuleModel);
restClient.assertLastError().statusCodeIs(BAD_REQUEST)

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<developers>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<properties>

14
pom.xml
View File

@@ -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.90</version>
<version>17.102-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -45,14 +45,14 @@
<dependency.alfresco-hb-data-sender.version>1.0.12</dependency.alfresco-hb-data-sender.version>
<dependency.alfresco-trashcan-cleaner.version>2.4.1</dependency.alfresco-trashcan-cleaner.version>
<dependency.alfresco-jlan.version>7.1</dependency.alfresco-jlan.version>
<dependency.alfresco-jlan.version>7.2</dependency.alfresco-jlan.version>
<dependency.alfresco-server-root.version>6.0.1</dependency.alfresco-server-root.version>
<dependency.alfresco-messaging-repo.version>1.2.20</dependency.alfresco-messaging-repo.version>
<dependency.alfresco-log-sanitizer.version>0.2</dependency.alfresco-log-sanitizer.version>
<dependency.activiti-engine.version>5.23.0</dependency.activiti-engine.version>
<dependency.activiti.version>5.23.0</dependency.activiti.version>
<dependency.alfresco-transform-service.version>1.5.3</dependency.alfresco-transform-service.version>
<dependency.alfresco-transform-core.version>2.6.0</dependency.alfresco-transform-core.version>
<dependency.alfresco-transform-service.version>1.5.4-A3</dependency.alfresco-transform-service.version>
<dependency.alfresco-transform-core.version>2.7.0-A1</dependency.alfresco-transform-core.version>
<dependency.alfresco-greenmail.version>6.4</dependency.alfresco-greenmail.version>
<dependency.acs-event-model.version>0.0.16</dependency.acs-event-model.version>
@@ -82,7 +82,7 @@
<dependency.truezip.version>7.7.10</dependency.truezip.version>
<dependency.poi.version>5.2.2</dependency.poi.version>
<dependency.ooxml-schemas.version>1.4</dependency.ooxml-schemas.version>
<dependency.keycloak.version>15.0.2</dependency.keycloak.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.activemq.version>5.17.1</dependency.activemq.version>
@@ -120,7 +120,7 @@
<dependency.mariadb.version>2.7.4</dependency.mariadb.version>
<dependency.tas-utility.version>3.0.49</dependency.tas-utility.version>
<dependency.rest-assured.version>5.1.1</dependency.rest-assured.version>
<dependency.tas-restapi.version>1.114</dependency.tas-restapi.version>
<dependency.tas-restapi.version>1.115</dependency.tas-restapi.version>
<dependency.tas-cmis.version>1.32</dependency.tas-cmis.version>
<dependency.tas-email.version>1.9</dependency.tas-email.version>
<dependency.tas-webdav.version>1.7</dependency.tas-webdav.version>
@@ -148,7 +148,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>17.90</tag>
<tag>HEAD</tag>
</scm>
<distributionManagement>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<dependencies>

View File

@@ -30,6 +30,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@@ -59,6 +60,7 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.attachment.Rfc5987Util;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
import org.springframework.extensions.webscripts.Cache;
@@ -472,7 +474,7 @@ public class ContentStreamer implements ResourceLoaderAware
if (req == null)
{
headerValue += "; filename*=UTF-8''" + URLEncoder.encode(attachFileName, StandardCharsets.UTF_8)
headerValue += "; filename*=UTF-8''" + encodeFilename(attachFileName)
+ "; filename=\"" + filterNameForQuotedString(attachFileName) + "\"";
}
else
@@ -481,12 +483,12 @@ public class ContentStreamer implements ResourceLoaderAware
boolean isLegacy = (null != userAgent) && (userAgent.contains("MSIE 8") || userAgent.contains("MSIE 7"));
if (isLegacy)
{
headerValue += "; filename=\"" + URLEncoder.encode(attachFileName, StandardCharsets.UTF_8);
headerValue += "; filename=\"" + encodeFilename(attachFileName);
}
else
{
headerValue += "; filename=\"" + filterNameForQuotedString(attachFileName) + "\"; filename*=UTF-8''"
+ URLEncoder.encode(attachFileName, StandardCharsets.UTF_8);
+ encodeFilename(attachFileName);
}
}
}
@@ -496,6 +498,21 @@ public class ContentStreamer implements ResourceLoaderAware
res.setHeader("Content-Disposition", headerValue);
}
}
private String encodeFilename(String attachFileName)
{
try
{
return Rfc5987Util.encode(attachFileName);
}
catch (UnsupportedEncodingException e)
{
if (logger.isInfoEnabled())
logger.info(e.getMessage() + " Changing encoder from Rfc5987Util to java.net.URLEncoder.");
return URLEncoder.encode(attachFileName, StandardCharsets.UTF_8);
}
}
protected String filterNameForQuotedString(String s)
{

View File

@@ -41,6 +41,8 @@ import org.alfresco.service.cmr.action.ParameterizedItemDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryException;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
@@ -62,7 +64,8 @@ public class ActionParameterConverter
this.namespaceService = namespaceService;
}
Map<String, Serializable> getConvertedParams(Map<String, Serializable> params, String name) {
Map<String, Serializable> getConvertedParams(Map<String, Serializable> params, String name)
{
final Map<String, Serializable> parameters = new HashMap<>(params.size());
final ParameterizedItemDefinition definition = actionService.getActionDefinition(name);
if (definition == null)
@@ -89,6 +92,21 @@ public class ActionParameterConverter
return parameters;
}
public Serializable convertParamFromServiceModel(Serializable param)
{
if (param instanceof QName)
{
return ((QName) param).toPrefixString(namespaceService);
}
else if (param instanceof NodeRef) {
return ((NodeRef) param).getId();
}
else
{
return param;
}
}
private Serializable convertValue(QName typeQName, Object propertyValue) throws JSONException
{
Serializable value;
@@ -117,12 +135,18 @@ public class ActionParameterConverter
list.add(convertValue(typeQName, ((JSONArray) propertyValue).get(i)));
}
value = (Serializable) list;
} else
}
else
{
if (typeQName.equals(DataTypeDefinition.QNAME) && typeQName.toString().contains(":"))
{
value = QName.createQName(propertyValue.toString(), namespaceService);
} else
}
else if (typeQName.isMatch(DataTypeDefinition.NODE_REF))
{
value = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, propertyValue.toString());
}
else
{
value = (Serializable) DefaultTypeConverter.INSTANCE.convert(dictionaryService.getDataType(typeQName), propertyValue);
}

View File

@@ -33,12 +33,15 @@ import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
@@ -52,6 +55,7 @@ public class NodeValidator
private Nodes nodes;
private RuleService ruleService;
private PermissionService permissionService;
private NodeService nodeService;
/**
* Validates if folder node exists and the user has permission to use it.
@@ -65,20 +69,7 @@ public class NodeValidator
public NodeRef validateFolderNode(final String folderNodeId, boolean requireChangePermission)
{
final NodeRef nodeRef = nodes.validateOrLookupNode(folderNodeId, null);
if (requireChangePermission)
{
if (permissionService.hasPermission(nodeRef, CHANGE_PERMISSIONS) != ALLOWED)
{
throw new PermissionDeniedException("Insufficient permissions to manage rules.");
}
}
else
{
if (permissionService.hasReadPermission(nodeRef) != ALLOWED)
{
throw new PermissionDeniedException("Cannot read from this node!");
}
}
validatePermission(requireChangePermission, nodeRef);
verifyNodeType(nodeRef, ContentModel.TYPE_FOLDER, null);
return nodeRef;
@@ -114,6 +105,15 @@ public class NodeValidator
return ruleSetNodeRef;
}
public NodeRef validateRuleSetNode(String linkToNodeId, boolean requireChangePermission)
{
final Node ruleSetNode = nodes.getNode(linkToNodeId);
final ChildAssociationRef primaryParent = nodeService.getPrimaryParent(ruleSetNode.getNodeRef());
final NodeRef parentNode = primaryParent.getParentRef();
validatePermission(requireChangePermission, parentNode);
return parentNode;
}
/**
* Validates if rule node exists and associated rule set node matches.
@@ -142,6 +142,24 @@ public class NodeValidator
return nodeRef;
}
private void validatePermission(boolean requireChangePermission, NodeRef nodeRef)
{
if (requireChangePermission)
{
if (permissionService.hasPermission(nodeRef, CHANGE_PERMISSIONS) != ALLOWED)
{
throw new PermissionDeniedException("Insufficient permissions to manage rules.");
}
}
else
{
if (permissionService.hasReadPermission(nodeRef) != ALLOWED)
{
throw new PermissionDeniedException("Cannot read from this node!");
}
}
}
private void verifyNodeType(final NodeRef nodeRef, final QName expectedType, final String expectedTypeName)
{
final Set<QName> expectedTypes = Set.of(expectedType);
@@ -152,6 +170,16 @@ public class NodeValidator
}
}
public boolean isRuleSetNode(String nodeId) {
try
{
validateNode(nodeId, ContentModel.TYPE_SYSTEM_FOLDER, RULE_SET_EXPECTED_TYPE_NAME);
return true;
} catch (InvalidArgumentException e) {
return false;
}
}
public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
{
if (ruleSetNodeRef == null && folderNodeRef != null)
@@ -184,4 +212,9 @@ public class NodeValidator
{
this.nodes = nodes;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
}

View File

@@ -81,7 +81,10 @@ public class RuleSetsImpl implements RuleSets
{
final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId,true);
final NodeRef linkToNodeRef = validator.validateFolderNode(linkToNodeId, true);
final boolean isRuleSetNode = validator.isRuleSetNode(linkToNodeId);
final NodeRef linkToNodeRef = isRuleSetNode
? validator.validateRuleSetNode(linkToNodeId, true)
: validator.validateFolderNode(linkToNodeId, true);
//The target node should have pre-existing rules to link to
if (!ruleService.hasRules(linkToNodeRef)) {

View File

@@ -27,6 +27,7 @@
package org.alfresco.rest.api.impl.rules;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.alfresco.rest.api.Nodes;
@@ -65,7 +66,7 @@ public class RulesImpl implements Rules
validator.validateRuleSetNode(ruleSetId, folderNodeRef);
final List<Rule> rules = ruleService.getRules(folderNodeRef).stream()
.map(ruleModel -> ruleLoader.loadRule(ruleModel, includes))
.map(ruleModel -> loadRuleAndConvertActionParams(ruleModel, includes))
.collect(Collectors.toList());
return ListPage.of(rules, paging);
@@ -78,7 +79,7 @@ public class RulesImpl implements Rules
final NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
final NodeRef ruleNodeRef = validator.validateRuleNode(ruleId, ruleSetNodeRef);
return ruleLoader.loadRule(ruleService.getRule(ruleNodeRef), includes);
return loadRuleAndConvertActionParams(ruleService.getRule(ruleNodeRef), includes);
}
@Override
@@ -94,7 +95,7 @@ public class RulesImpl implements Rules
return rules.stream()
.map(this::mapToServiceModelAndValidateActions)
.map(rule -> ruleService.saveRule(folderNodeRef, rule))
.map(rule -> ruleLoader.loadRule(rule, includes))
.map(rule -> loadRuleAndConvertActionParams(rule, includes))
.collect(Collectors.toList());
}
@@ -107,7 +108,7 @@ public class RulesImpl implements Rules
NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
validator.validateRuleNode(ruleId, ruleSetNodeRef);
return ruleLoader.loadRule(ruleService.saveRule(folderNodeRef, rule.toServiceModel(nodes)), includes);
return ruleLoader.loadRule(ruleService.saveRule(folderNodeRef, mapToServiceModelAndValidateActions(rule)), includes);
}
@Override
@@ -130,6 +131,20 @@ public class RulesImpl implements Rules
return actionPermissionValidator.validateRulePermissions(serviceModelRule);
}
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()
.stream()
.collect(Collectors
.toMap(Map.Entry::getKey, e -> actionParameterConverter.convertParamFromServiceModel(e.getValue())))
)
);
return rule;
}
public void setNodes(Nodes nodes)
{
this.nodes = nodes;

View File

@@ -854,6 +854,7 @@
<property name="nodes" ref="Nodes" />
<property name="permissionService" ref="PermissionService" />
<property name="ruleService" ref="RuleService" />
<property name="nodeService" ref="NodeService"/>
</bean>
<bean class="org.alfresco.rest.api.nodes.NodeRulesRelation">

View File

@@ -36,6 +36,7 @@ import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.times;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.action.executer.AddFeaturesActionExecuter;
@@ -79,10 +80,7 @@ public class ActionParameterConverterTest
private static final String IDENTIFIER_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + IDENTIFIER;
private static final String DUMMY_FOLDER_NODE_ID = "dummy-folder-node";
private static final String DUMMY_FOLDER_NODE_REF = STORE_REF_WORKSPACE_SPACESSTORE + "/" + DUMMY_FOLDER_NODE_ID;
private static final String DUMMY_SCRIPT_NODE_ID = "dummy-script-ref";
private static final String DUMMY_SCRIPT_NODE_REF = STORE_REF_WORKSPACE_SPACESSTORE + "/" + DUMMY_SCRIPT_NODE_ID;
@Mock
private DictionaryService dictionaryService;
@@ -148,7 +146,7 @@ public class ActionParameterConverterTest
final String name = CopyActionExecuter.NAME;
final String destinationFolderKey = CopyActionExecuter.PARAM_DESTINATION_FOLDER;
final String deepCopyKey = CopyActionExecuter.PARAM_DEEP_COPY;
final Map<String, Serializable> params = Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_REF, deepCopyKey, true);
final Map<String, Serializable> params = Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID, deepCopyKey, true);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
@@ -159,7 +157,6 @@ public class ActionParameterConverterTest
given(actionDefinitionParam2.getType()).willReturn(bool);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dataTypeDefinition1.getJavaClassName()).willReturn(NodeRef.class.getName());
given(dictionaryService.getDataType(bool)).willReturn(dataTypeDefinition2);
given(dataTypeDefinition2.getJavaClassName()).willReturn(Boolean.class.getName());
@@ -172,7 +169,7 @@ public class ActionParameterConverterTest
then(actionDefinition).should().getParameterDefintion(deepCopyKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(2)).getDataType(bool);
then(dictionaryService).should(times(2)).getDataType(nodeRef);
then(dictionaryService).should().getDataType(nodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
@@ -190,7 +187,7 @@ public class ActionParameterConverterTest
{
final String name = ScriptActionExecuter.NAME;
final String executeScriptKey = ScriptActionExecuter.PARAM_SCRIPTREF;
final Map<String, Serializable> params = Map.of(executeScriptKey, DUMMY_SCRIPT_NODE_REF);
final Map<String, Serializable> params = Map.of(executeScriptKey, DUMMY_SCRIPT_NODE_ID);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(executeScriptKey)).willReturn(actionDefinitionParam1);
@@ -198,7 +195,6 @@ public class ActionParameterConverterTest
given(actionDefinitionParam1.getType()).willReturn(scriptNodeRef);
given(dictionaryService.getDataType(scriptNodeRef)).willReturn(dataTypeDefinition1);
given(dataTypeDefinition1.getJavaClassName()).willReturn(NodeRef.class.getName());
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
@@ -207,7 +203,7 @@ public class ActionParameterConverterTest
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(executeScriptKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(2)).getDataType(scriptNodeRef);
then(dictionaryService).should().getDataType(scriptNodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
@@ -222,7 +218,7 @@ public class ActionParameterConverterTest
{
final String name = MoveActionExecuter.NAME;
final String destinationFolderKey = MoveActionExecuter.PARAM_DESTINATION_FOLDER;
final Map<String, Serializable> params = Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_REF);
final Map<String, Serializable> params = Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
@@ -230,7 +226,6 @@ public class ActionParameterConverterTest
given(actionDefinitionParam1.getType()).willReturn(nodeRef);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dataTypeDefinition1.getJavaClassName()).willReturn(NodeRef.class.getName());
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
@@ -239,7 +234,7 @@ public class ActionParameterConverterTest
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(destinationFolderKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(2)).getDataType(nodeRef);
then(dictionaryService).should().getDataType(nodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
@@ -300,7 +295,7 @@ public class ActionParameterConverterTest
final String assocNameKey = CheckOutActionExecuter.PARAM_ASSOC_QNAME;
final String assocTypeKey = CheckOutActionExecuter.PARAM_ASSOC_TYPE_QNAME;
final Map<String, Serializable> params =
Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_REF, assocNameKey, CHECKOUT_ASPECT, assocTypeKey, CONTAINS_ASPECT);
Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID, assocNameKey, CHECKOUT_ASPECT, assocTypeKey, CONTAINS_ASPECT);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
@@ -313,7 +308,6 @@ public class ActionParameterConverterTest
given(actionDefinitionParam3.getType()).willReturn(qname);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dataTypeDefinition1.getJavaClassName()).willReturn(NodeRef.class.getName());
given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition2);
given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
@@ -327,7 +321,7 @@ public class ActionParameterConverterTest
then(actionDefinition).should().getParameterDefintion(assocTypeKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(2)).getDataType(qname);
then(dictionaryService).should(times(2)).getDataType(nodeRef);
then(dictionaryService).should().getDataType(nodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).should(times(2)).getNamespaceURI(any());
then(namespaceService).shouldHaveNoMoreInteractions();
@@ -354,7 +348,7 @@ public class ActionParameterConverterTest
final String name = LinkCategoryActionExecuter.NAME;
final String categoryAspectKey = LinkCategoryActionExecuter.PARAM_CATEGORY_ASPECT;
final String categoryValueKey = LinkCategoryActionExecuter.PARAM_CATEGORY_VALUE;
final Map<String, Serializable> params = Map.of(categoryAspectKey, CLASSIFIABLE_ASPECT, categoryValueKey, DUMMY_FOLDER_NODE_REF);
final Map<String, Serializable> params = Map.of(categoryAspectKey, CLASSIFIABLE_ASPECT, categoryValueKey, DUMMY_FOLDER_NODE_ID);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(categoryAspectKey)).willReturn(actionDefinitionParam1);
@@ -365,7 +359,6 @@ public class ActionParameterConverterTest
given(actionDefinitionParam2.getType()).willReturn(nodeRef);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dataTypeDefinition1.getJavaClassName()).willReturn(NodeRef.class.getName());
given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition2);
given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
@@ -378,7 +371,7 @@ public class ActionParameterConverterTest
then(actionDefinition).should().getParameterDefintion(categoryValueKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should().getDataType(qname);
then(dictionaryService).should(times(2)).getDataType(nodeRef);
then(dictionaryService).should().getDataType(nodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).should().getNamespaceURI(any());
then(namespaceService).shouldHaveNoMoreInteractions();
@@ -440,8 +433,8 @@ public class ActionParameterConverterTest
final String approve = "Approve";
final String reject = "Reject";
final Map<String, Serializable> params =
Map.of(approveStepKey, approve, approveFolderKey, DUMMY_FOLDER_NODE_REF, approveMoveKey, true,
rejectStepKey, reject, rejectFolderKey, DUMMY_FOLDER_NODE_REF, rejectMoveKey, true);
Map.of(approveStepKey, approve, approveFolderKey, DUMMY_FOLDER_NODE_ID, approveMoveKey, true,
rejectStepKey, reject, rejectFolderKey, DUMMY_FOLDER_NODE_ID, rejectMoveKey, true);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(rejectStepKey)).willReturn(actionDefinitionParam1);
@@ -458,7 +451,6 @@ public class ActionParameterConverterTest
given(actionDefinitionParam3.getType()).willReturn(bool, bool);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dataTypeDefinition1.getJavaClassName()).willReturn(NodeRef.class.getName());
given(dictionaryService.getDataType(text)).willReturn(dataTypeDefinition2);
given(dataTypeDefinition2.getJavaClassName()).willReturn(String.class.getName());
given(dictionaryService.getDataType(bool)).willReturn(dataTypeDefinition3);
@@ -477,7 +469,7 @@ public class ActionParameterConverterTest
then(actionDefinition).should().getParameterDefintion(rejectMoveKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(4)).getDataType(text);
then(dictionaryService).should(times(4)).getDataType(nodeRef);
then(dictionaryService).should(times(2)).getDataType(nodeRef);
then(dictionaryService).should(times(4)).getDataType(bool);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
@@ -560,4 +552,41 @@ public class ActionParameterConverterTest
assertTrue(convertedPropTypeParam instanceof String);
assertEquals(propType, convertedPropTypeParam);
}
@Test
public void testQnameServiceModelParamConversion() {
given(namespaceService.getPrefixes(any())).willReturn(List.of("cm"));
final String qname = "{cm-dummy-prefix}audio";
final Serializable qnameParam = QName.createQName(qname);
//when
final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(qnameParam);
then(namespaceService).should().getPrefixes(any());
then(namespaceService).shouldHaveNoMoreInteractions();
assertEquals("cm:audio", convertedParam);
}
@Test
public void testNodeRefServiceModelParamConversion() {
//given
final Serializable nodeRefParam = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_FOLDER_NODE_ID);
//when
final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(nodeRefParam);
then(namespaceService).shouldHaveNoInteractions();
assertEquals(DUMMY_FOLDER_NODE_ID, convertedParam);
}
@Test
public void testOtherServiceModelParamConversion() {
//given
final Serializable dummyStringParam = "dummy-param";
//when
final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(dummyStringParam);
then(namespaceService).shouldHaveNoInteractions();
assertEquals(dummyStringParam, convertedParam);
}
}

View File

@@ -26,15 +26,20 @@
package org.alfresco.rest.api.impl.rules;
import static org.alfresco.service.cmr.rule.RuleType.INBOUND;
import static org.alfresco.service.cmr.rule.RuleType.OUTBOUND;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.BDDMockito.then;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.CompositeActionImpl;
import org.alfresco.repo.action.RuntimeActionService;
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
import org.alfresco.repo.action.executer.CopyActionExecuter;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -59,15 +64,20 @@ public class ActionPermissionValidatorTest extends TestCase
private ActionPermissionValidator objectUnderTest;
@Test
public void testPositiveRulePermissionValidation() {
public void testPositiveRulePermissionValidation()
{
//given
final CompositeActionImpl compositeAction = new CompositeActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "composite-id");
final Action action1 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-1", "actionDef-1");
final CompositeActionImpl compositeAction =
new CompositeActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "composite-id");
final Action action1 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-1",
CopyActionExecuter.NAME);
compositeAction.addAction(action1);
final Action action2 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-2", "actionDef-2");
final Action action2 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-2",
CheckOutActionExecuter.NAME);
compositeAction.addAction(action2);
final Rule inputRule = new Rule();
inputRule.setAction(compositeAction);
inputRule.setRuleTypes(List.of(INBOUND));
//when
final Rule validatedRule = objectUnderTest.validateRulePermissions(inputRule);
@@ -80,5 +90,28 @@ public class ActionPermissionValidatorTest extends TestCase
.forEach(action -> Assertions.assertThat(action.getParameterValue("actionContext")).isEqualTo("rule"));
}
//TODO: when Rule mappings are done - we need to add negative test(s) here
@Test
public void testNegativeRulePermissionValidation()
{
//given
final CompositeActionImpl compositeAction =
new CompositeActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "composite-id");
final Action action1 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-1",
CopyActionExecuter.NAME);
compositeAction.addAction(action1);
final Action action2 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-2",
CheckOutActionExecuter.NAME);
compositeAction.addAction(action2);
final Rule inputRule = new Rule();
inputRule.setAction(compositeAction);
inputRule.setRuleTypes(List.of(OUTBOUND));
//when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.validateRulePermissions(inputRule));
then(runtimeActionService).should().verifyActionAccessRestrictions(action1);
then(runtimeActionService).should().verifyActionAccessRestrictions(action2);
then(runtimeActionService).shouldHaveNoMoreInteractions();
}
}

View File

@@ -39,18 +39,24 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.reset;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.security.PermissionService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
@@ -61,21 +67,33 @@ public class NodeValidatorTest
{
private static final String FOLDER_NODE_ID = "dummy-folder-node-id";
private static final String LINK_TO_NODE_ID = "dummy-link-to-node-id";
private static final String RULE_SET_ID = "dummy-rule-set-id";
private static final String RULE_ID = "dummy-rule-id";
private static final String PARENT_NODE_ID = "dummy-parent-node-id";
private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID);
private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
private static final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_NODE_ID);
@Mock
private Nodes nodesMock;
@Mock
private Node ruleSetNodeMock;
@Mock
private PermissionService permissionServiceMock;
@Mock
private RuleService ruleServiceMock;
@Mock
private NodeService nodeServiceMock;
@Mock
private ChildAssociationRef primaryParentMock;
@InjectMocks
private NodeValidator nodeValidator;
@@ -182,6 +200,20 @@ public class NodeValidatorTest
assertThat(nodeRef).isNotNull().isEqualTo(ruleSetNodeRef);
}
@Test
public void testValidateRuleSetNodeNoParentId()
{
given(nodesMock.getNode(any())).willReturn(ruleSetNodeMock);
given(nodeServiceMock.getPrimaryParent(any())).willReturn(primaryParentMock);
given(primaryParentMock.getParentRef()).willReturn(parentNodeRef);
//when
final NodeRef nodeRef = nodeValidator.validateRuleSetNode(LINK_TO_NODE_ID,true);
assertThat(nodeRef).isNotNull().isEqualTo(parentNodeRef);
}
@Test
public void validateRuleSetNode_defaultId()
{
@@ -329,6 +361,28 @@ public class NodeValidatorTest
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testIsRuleSetNode()
{
//resetting mock to bypass setup method
resetNodesMock();
boolean actual = nodeValidator.isRuleSetNode(RULE_SET_ID);
Assert.assertTrue(actual);
}
@Test
public void testIsNotRuleSetNode()
{
//resetting mock to bypass setup method
resetNodesMock();
//using an id that doesn't belong to a ruleset node
boolean actual = nodeValidator.isRuleSetNode(FOLDER_NODE_ID);
Assert.assertFalse(actual);
}
@Test
public void testIsRuleSetNotNullAndShared()
{
@@ -376,4 +430,12 @@ public class NodeValidatorTest
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
private void resetNodesMock() {
reset(nodesMock);
given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef);
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
given(nodesMock.nodeMatches(ruleSetNodeRef, Set.of(ContentModel.TYPE_SYSTEM_FOLDER), null)).willReturn(true);
}
}

View File

@@ -96,6 +96,7 @@ public class RuleSetsImplTest extends TestCase
MockitoAnnotations.openMocks(this);
given(nodeValidatorMock.validateFolderNode(eq(LINK_TO_NODE_ID), anyBoolean())).willReturn(LINK_TO_NODE);
given(nodeValidatorMock.validateRuleSetNode(LINK_TO_NODE_ID,true)).willReturn(LINK_TO_NODE);
given(nodeValidatorMock.validateFolderNode(eq(FOLDER_ID), anyBoolean())).willReturn(FOLDER_NODE);
given(nodeValidatorMock.validateRuleSetNode(RULE_SET_ID, FOLDER_NODE)).willReturn(RULE_SET_NODE);
@@ -153,7 +154,7 @@ public class RuleSetsImplTest extends TestCase
}
@Test
public void testLinkingToRuleSet()
public void testLinkToFolderRuleSet()
{
NodeRef childNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "dummy-child-id");
@@ -162,7 +163,7 @@ public class RuleSetsImplTest extends TestCase
given(assocRef.getChildRef()).willReturn(childNodeRef);
//when
assertEquals(ruleSets.linkToRuleSet(FOLDER_ID,LINK_TO_NODE_ID).getId(), childNodeRef.getId());
String actual = ruleSets.linkToRuleSet(FOLDER_ID,LINK_TO_NODE_ID).getId();
then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
then(ruleServiceMock).should().hasRules(FOLDER_NODE);
@@ -170,6 +171,35 @@ public class RuleSetsImplTest extends TestCase
then(runtimeRuleServiceMock).shouldHaveNoMoreInteractions();
then(nodeServiceMock).should().addChild(FOLDER_NODE, childNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
then(nodeServiceMock).shouldHaveNoMoreInteractions();
assertEquals(childNodeRef.getId(),actual);
}
@Test
public void testLinkToRuleSet()
{
NodeRef childNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "dummy-child-id");
given(nodeValidatorMock.isRuleSetNode(any())).willReturn(true);
given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true, false);
given(runtimeRuleServiceMock.getSavedRuleFolderAssoc(any(NodeRef.class))).willReturn(assocRef);
given(assocRef.getChildRef()).willReturn(childNodeRef);
//when
String actual = ruleSets.linkToRuleSet(FOLDER_ID,LINK_TO_NODE_ID).getId();
then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID,true);
then(nodeValidatorMock).should().isRuleSetNode(LINK_TO_NODE_ID);
then(nodeValidatorMock).should().validateRuleSetNode(LINK_TO_NODE_ID,true);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
then(ruleServiceMock).should().hasRules(FOLDER_NODE);
then(runtimeRuleServiceMock).should().getSavedRuleFolderAssoc(LINK_TO_NODE);
then(runtimeRuleServiceMock).shouldHaveNoMoreInteractions();
then(nodeServiceMock).should().addChild(FOLDER_NODE, childNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
then(nodeServiceMock).shouldHaveNoMoreInteractions();
assertEquals(childNodeRef.getId(),actual);
}
@Test

View File

@@ -125,6 +125,7 @@ public class RulesImplTest extends TestCase
@Test
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);
@@ -133,6 +134,8 @@ public class RulesImplTest extends TestCase
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(ruleLoaderMock).should().loadRule(ruleModel, emptyList());
then(ruleLoaderMock).shouldHaveNoMoreInteractions();
assertThat(rulesPage)
.isNotNull()
.extracting(CollectionWithPagingInfo::getCollection)
@@ -428,22 +431,25 @@ public class RulesImplTest extends TestCase
@Test
public void testUpdateRuleById()
{
Rule ruleBody = mock(Rule.class);
org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody);
org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleBody)).willReturn(serviceRule);
given(ruleLoaderMock.loadRule(serviceRule, INCLUDE)).willReturn(ruleMock);
given(ruleMock.toServiceModel(nodesMock)).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);
given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
// when
Rule updatedRule = rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, ruleBody, INCLUDE);
Rule updatedRule = rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, ruleMock, INCLUDE);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, serviceRuleBody);
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, serviceRuleMock);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(actionParameterConverterMock).should().getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
assertThat(updatedRule).isEqualTo(ruleMock);
}

View File

@@ -3721,6 +3721,50 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
getSingle(getNodeContentUrl(contentNodeId), null, null, headers, 304);
}
/**
* Tests download of file/content name.
* <p>GET:</p>
* {@literal <host>:<port>/alfresco/api/-default-/public/alfresco/versions/1/nodes/<nodeId>/content}
*/
@Test
public void testDownloadFileContentName() throws Exception
{
setRequestContext(user1);
//
// Test plain text
//
String fileName = "Test Download (1).txt";
File file = getResourceFile(fileName);
MultiPartBuilder multiPartBuilder = MultiPartBuilder.create()
.setFileData(new FileData(fileName, file));
MultiPartRequest reqBody = multiPartBuilder.build();
// Upload text content
HttpResponse response = post(getNodeChildrenUrl(Nodes.PATH_MY), reqBody.getBody(), null, reqBody.getContentType(), 201);
Document document = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class);
String contentNodeId = document.getId();
// Check the upload response
assertEquals(fileName, document.getName());
ContentInfo contentInfo = document.getContent();
assertNotNull(contentInfo);
assertEquals(MimetypeMap.MIMETYPE_TEXT_PLAIN, contentInfo.getMimeType());
// Download text content - by default with Content-Disposition header
response = getSingle(NodesEntityResource.class, contentNodeId + "/content", null, 200);
String textContent = response.getResponse();
assertEquals("The quick brown fox jumps over the lazy dog", textContent);
Map<String, String> responseHeaders = response.getHeaders();
assertNotNull(responseHeaders);
assertEquals("attachment; filename=\"Test Download (1).txt\"; filename*=UTF-8''Test%20Download%20%281%29.txt", responseHeaders.get("Content-Disposition"));
}
/**
* Tests download of file/content using backed temp file for streaming.
* <p>

View File

@@ -0,0 +1 @@
The quick brown fox jumps over the lazy dog

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.90</version>
<version>17.102-SNAPSHOT</version>
</parent>
<dependencies>

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2022 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.exporter;
import java.io.IOException;
@@ -39,6 +39,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Arrays;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.MLPropertyInterceptor;
@@ -77,6 +78,7 @@ import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.lang3.math.NumberUtils;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.extensions.surf.util.ParameterCheck;
@@ -99,6 +101,8 @@ public class ExporterComponent
private DescriptorService descriptorService;
private AuthenticationService authenticationService;
private PermissionService permissionService;
private String exportChunkSize;
/** Indent Size */
@@ -178,6 +182,14 @@ public class ExporterComponent
{
this.exportSecondaryNodes = exportSecondaryNodes;
}
/**
* @param exportChunkSize the exportChunkSize
*/
public void setExportChunkSize(String exportChunkSize)
{
this.exportChunkSize = exportChunkSize;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ExporterService#exportView(java.io.OutputStream, org.alfresco.service.cmr.view.ExporterCrawlerParameters, org.alfresco.service.cmr.view.Exporter)
@@ -943,28 +955,23 @@ public class ExporterComponent
try
{
// Current strategy is to determine if node is a child of the root exported node
for (NodeRef exportRoot : context.getExportList())
if (context.getExportMap() != null)
{
if (nodeRef.equals(exportRoot) && parameters.isCrawlSelf() == true)
for (NodeRef[] listNodeRef : context.getExportMap().values())
{
// node to export is the root export node (and root is to be exported)
isWithin = true;
}
else
{
// locate export root in primary parent path of node
Path nodePath = nodeService.getPath(nodeRef);
for (int i = nodePath.size() - 1; i >= 0; i--)
for (NodeRef exportRoot : listNodeRef)
{
Path.ChildAssocElement pathElement = (Path.ChildAssocElement) nodePath.get(i);
if (pathElement.getRef().getChildRef().equals(exportRoot))
{
isWithin = true;
break;
}
isWithin = checkIsWithin(nodeRef, exportRoot, parameters);
}
}
}
else
{
for (NodeRef exportRoot : context.getExportList())
{
isWithin = checkIsWithin(nodeRef, exportRoot, parameters);
}
}
}
catch (AccessDeniedException accessErr)
{
@@ -979,6 +986,28 @@ public class ExporterComponent
}
}
private boolean checkIsWithin(NodeRef nodeRef, NodeRef exportRoot, ExporterCrawlerParameters parameters){
if (nodeRef.equals(exportRoot) && parameters.isCrawlSelf() == true)
{
// node to export is the root export node (and root is to be exported)
return true;
}
else
{
// locate export root in primary parent path of node
Path nodePath = nodeService.getPath(nodeRef);
for (int i = nodePath.size() - 1; i >= 0; i--)
{
Path.ChildAssocElement pathElement = (Path.ChildAssocElement) nodePath.get(i);
if (pathElement.getRef().getChildRef().equals(exportRoot))
{
return true;
}
}
}
return false;
}
/**
* Exporter Context
@@ -986,7 +1015,9 @@ public class ExporterComponent
private class ExporterContextImpl implements ExporterContext
{
private NodeRef[] exportList;
private Map<Integer,NodeRef[]> exportListMap;
private NodeRef[] parentList;
private Map<Integer,NodeRef[]> parentListMap;
private String exportedBy;
private Date exportedDate;
private String exporterVersion;
@@ -995,8 +1026,10 @@ public class ExporterComponent
private Map<Integer, Set<NodeRef>> nodesWithAssociations = new HashMap<Integer, Set<NodeRef>>();
private int index;
private int indexSubList;
private int chunkSize;
/**
* Construct
*
@@ -1005,7 +1038,17 @@ public class ExporterComponent
public ExporterContextImpl(ExporterCrawlerParameters parameters)
{
index = 0;
indexSubList = 0;
if(!NumberUtils.isParsable(exportChunkSize)){
chunkSize = 10;
}
else
{
chunkSize = Integer.parseInt(exportChunkSize);
}
// get current user performing export
String currentUserName = authenticationService.getCurrentUserName();
exportedBy = (currentUserName == null) ? "unknown" : currentUserName;
@@ -1022,24 +1065,80 @@ public class ExporterComponent
NodeRef exportOf = getNodeRef(parameters.getExportFrom());
exportList[0] = exportOf;
}
parentList = new NodeRef[exportList.length];
for (int i = 0; i < exportList.length; i++)
if(exportList.length > chunkSize)
{
parentList[i] = getParent(exportList[i], parameters.isCrawlSelf());
exportListMap = splitArray(exportList);
parentListMap = new HashMap<>();
for(Map.Entry<Integer, NodeRef[]> exportEntrySet : exportListMap.entrySet())
{
parentList= new NodeRef[exportEntrySet.getValue().length];
for (int i = 0; i < exportEntrySet.getValue().length; i++)
{
parentList[i] = getParent(exportEntrySet.getValue()[i], parameters.isCrawlSelf());
}
parentListMap.put(exportEntrySet.getKey(), parentList);
}
}
else{
parentList = new NodeRef[exportList.length];
for (int i = 0; i < exportList.length; i++)
{
parentList[i] = getParent(exportList[i], parameters.isCrawlSelf());
}
}
// get exporter version
exporterVersion = descriptorService.getServerDescriptor().getVersion();
}
public Map<Integer, NodeRef[]> splitArray(NodeRef[] arrayToSplit){
if(chunkSize <= 0){
return null;
}
int rest = arrayToSplit.length % chunkSize;
int chunks = arrayToSplit.length / chunkSize + (rest > 0 ? 1 : 0);
Map<Integer, NodeRef[]> arrays = new HashMap<>() ;
for(Integer i = 0; i < (rest > 0 ? chunks - 1 : chunks); i++){
arrays.put(i, Arrays.copyOfRange(arrayToSplit, i * chunkSize, i * chunkSize + chunkSize));
}
if(rest > 0){
arrays.put(chunks - 1, Arrays.copyOfRange(arrayToSplit, (chunks - 1) * chunkSize, (chunks - 1) * chunkSize + rest));
}
return arrays;
}
public boolean canRetrieve()
{
return index < exportList.length;
if(exportListMap != null)
{
if (exportListMap.containsKey(indexSubList))
{
return index < exportListMap.get(indexSubList).length;
}
else
{
return false;
}
}
else {
return index < exportList.length;
}
}
public int setNextValue()
{
return ++index;
if(exportListMap != null && (index == exportListMap.get(indexSubList).length-1)){
resetContext();
if(indexSubList <= exportListMap.size())
{
++indexSubList;
}
}
else{
++index;
}
return index;
}
public void resetContext()
@@ -1078,7 +1177,13 @@ public class ExporterComponent
{
if (canRetrieve())
{
return exportList[index];
if(exportListMap!=null)
{
return exportListMap.get(indexSubList)[index];
}
else {
return exportList[index];
}
}
return null;
}
@@ -1091,7 +1196,13 @@ public class ExporterComponent
{
if (canRetrieve())
{
return parentList[index];
if(parentListMap!=null)
{
return parentListMap.get(indexSubList)[index];
}
else {
return parentList[index];
}
}
return null;
}
@@ -1105,6 +1216,11 @@ public class ExporterComponent
return exportList;
}
public Map<Integer, NodeRef[]> getExportMap()
{
return exportListMap;
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ExporterContext#getExportParentList()

View File

@@ -1,31 +1,32 @@
/*
* #%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 - 2022 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.service.cmr.view;
import java.util.Date;
import java.util.Map;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -73,6 +74,8 @@ public interface ExporterContext
* @return NodeRef[]
*/
public NodeRef[] getExportList();
public Map<Integer, NodeRef[]> getExportMap();
/**
* Gets list of parents for exporting nodes

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2022 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.service.cmr.view;
import java.io.OutputStream;
@@ -75,5 +75,6 @@ public interface ExporterService
*/
@Auditable(parameters = {"exporter", "parameters", "progress"})
public void exportView(Exporter exporter, ExporterCrawlerParameters parameters, Exporter progress);
public void setExportChunkSize(String exportChunkSize);
}

View File

@@ -130,6 +130,9 @@
<property name="permissionService">
<ref bean="PermissionService" />
</property>
<property name="exportChunkSize">
<value>${rm.export.chunk.size}</value>
</property>
</bean>
<bean id="repositoryExporterComponent" class="org.alfresco.repo.exporter.RepositoryExporterComponent">

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -33,7 +33,10 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -41,6 +44,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.importer.ACPImportPackageHandler;
@@ -50,12 +55,7 @@ import org.alfresco.repo.security.permissions.PermissionServiceSPI;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.*;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
@@ -68,6 +68,7 @@ import org.alfresco.service.cmr.view.ExporterService;
import org.alfresco.service.cmr.view.ImportPackageHandler;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.test_category.OwnJVMTestsCategory;
@@ -82,6 +83,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.surf.util.InputStreamContent;
import org.springframework.transaction.annotation.Transactional;
@Category({OwnJVMTestsCategory.class, LuceneTests.class})
@@ -95,6 +97,7 @@ public class ExporterComponentTest extends BaseSpringTest
private FileFolderService fileFolderService;
private CategoryService categoryService;
private TransactionService transactionService;
private ContentService contentService;
private StoreRef storeRef;
private AuthenticationComponent authenticationComponent;
private PermissionServiceSPI permissionService;
@@ -112,6 +115,7 @@ public class ExporterComponentTest extends BaseSpringTest
categoryService = (CategoryService) applicationContext.getBean("categoryService");
transactionService = (TransactionService) applicationContext.getBean("transactionService");
permissionService = (PermissionServiceSPI) applicationContext.getBean("permissionService");
contentService = (ContentService) applicationContext.getBean("contentService");
this.authenticationService = (MutableAuthenticationService) applicationContext.getBean("AuthenticationService");
this.authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent");
@@ -151,9 +155,7 @@ public class ExporterComponentTest extends BaseSpringTest
OutputStream output = new FileOutputStream(tempFile);
ExporterCrawlerParameters parameters = new ExporterCrawlerParameters();
parameters.setExportFrom(location);
// parameters.setExcludeAspects(new QName[] { ContentModel.ASPECT_AUDITABLE });
// parameters.setExcludeChildAssocs(new QName[] { ContentModel.ASSOC_CONTAINS });
File acpFile = TempFileProvider.createTempFile("alf", ACPExportPackageHandler.ACP_EXTENSION);
File dataFile = new File("test");
File contentDir = new File("test");
@@ -162,6 +164,81 @@ public class ExporterComponentTest extends BaseSpringTest
acpHandler.setExportAsFolders(true);
exporterService.exportView(acpHandler, parameters, testProgress);
output.close();
}
@Test
public void testExportWithChunkedList()
throws Exception
{
TestProgress testProgress = new TestProgress();
Location location = new Location(storeRef);
String testFile = "_testFile";
int numberOfNodesToExport = 20;
// now export
location.setPath("/system");
File tempFile = TempFileProvider.createTempFile("xmlexporttest", ".xml");
OutputStream output = new FileOutputStream(tempFile);
ExporterCrawlerParameters parameters = new ExporterCrawlerParameters();
parameters.setExportFrom(location);
File acpFile = TempFileProvider.createTempFile("alf", ACPExportPackageHandler.ACP_EXTENSION);
File dataFile = new File("test");
File contentDir = new File("test");
ACPExportPackageHandler acpHandler = new ACPExportPackageHandler(new FileOutputStream(acpFile), dataFile, contentDir, null);
acpHandler.setNodeService(nodeService);
acpHandler.setExportAsFolders(true);
NodeRef nodeRef = (location == null) ? null : location.getNodeRef();
if (nodeRef == null)
{
// If a specific node has not been provided, default to the root
nodeRef = nodeService.getRootNode(location.getStoreRef());
}
NodeRef[] childRefs = new NodeRef[numberOfNodesToExport];
for (int i = 0; i < numberOfNodesToExport; i++)
{
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(ContentModel.PROP_NAME, this.getClass() + testFile + i);
childRefs[i] = nodeService.createNode(nodeRef, ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS, ContentModel.TYPE_CONTENT, props).getChildRef();
}
parameters.getExportFrom().setNodeRefs(childRefs);
parameters.setCrawlSelf(true);
exporterService.setExportChunkSize("3");
exporterService.exportView(acpHandler, parameters, testProgress);
output.close();
ZipFile zipFile = new ZipFile(acpFile.getAbsolutePath());
Enumeration<? extends ZipEntry> entries = zipFile.entries();
int numberOfExportedNodes = 0;
while(entries.hasMoreElements()){
ZipEntry entry = entries.nextElement();
InputStream stream = zipFile.getInputStream(entry);
try (BufferedReader br = new BufferedReader(new InputStreamReader(
stream, StandardCharsets.UTF_8));) {
String line;
while ((line = br.readLine()) != null) {
if(line.contains(testFile)){
numberOfExportedNodes++;
}
}
}
stream.close();
}
zipFile.close();
assertEquals(numberOfNodesToExport, numberOfExportedNodes);
parameters.getExportFrom().setNodeRefs(null);
for (int i = 0; i < numberOfNodesToExport; i++)
{
nodeService.deleteNode(childRefs[i]);
}
}
/**