Compare commits

...

484 Commits

Author SHA1 Message Date
Travis CI User
6eb80bf64e [maven-release-plugin][skip ci] prepare release 17.169 2022-10-14 14:05:17 +00:00
rrajoria
2ab1023eb7 Reverting AOS Dependency 2022-10-14 18:59:36 +05:30
rrajoria
fe1233791d Updating GoogleDrive and AOS Dependencies 2022-10-14 18:44:52 +05:30
Travis CI User
d1079890f7 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-14 10:32:32 +00:00
Travis CI User
2660da2dcb [maven-release-plugin][skip ci] prepare release 17.168 2022-10-14 10:32:29 +00:00
mikolajbrzezinski
4f3382fd92 update ooxml schemas to poi-ooxml-lite (#1498) 2022-10-14 11:57:04 +02:00
Tom Page
86a213541f Merge pull request #1497 from Alfresco/feature/ACS-3651_NodeValidation
ACS-3651 Validate node pameters.
2022-10-14 09:25:55 +01:00
Tom Page
fd83b72226 Merge pull request #1496 from Alfresco/feature/ACS-3651_RulesUtilService
ACS-3651 Convert RulesTestsUtils to a service bean.
2022-10-14 09:25:20 +01:00
Tom Page
1d0dcf3e15 ACS-3651 Remove unused reference to node service. 2022-10-13 15:37:56 +01:00
Tom Page
38bff5dc82 ACS-3651 Add unit tests for node exists and read permission. 2022-10-13 15:01:41 +01:00
Travis CI User
7b026de665 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-13 13:14:50 +00:00
Travis CI User
983de15f72 [maven-release-plugin][skip ci] prepare release 17.167 2022-10-13 13:14:47 +00:00
Tom Page
9b8b1bbbe6 ACS-3651 Validate node pameters. 2022-10-13 14:05:12 +01:00
Tom Page
5aeb9c932a Merge branch 'master' into feature/ACS-3651_RulesUtilService 2022-10-13 13:29:40 +01:00
Tom Page
32aa786c3f ACS-3651 Convert RulesTestsUtils to a service bean.
Update a few dummy folder nodes to use real folders.
2022-10-13 11:51:45 +01:00
Maciej Pichura
1759364b50 ACS-3723, ACS-3724, ACS-3725 move rules V1 API to private space (#1495)
* ACS-3723: Moving endpoints to private API path.

* ACS-3723: Fixes to E2E tests and some other parts.

* ACS-3723: Removing unnecessary imports.
2022-10-13 12:38:44 +02:00
Travis CI User
2ecb64628e [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-13 08:19:55 +00:00
Travis CI User
1fb4ab3bb8 [maven-release-plugin][skip ci] prepare release 17.166 2022-10-13 08:19:52 +00:00
Sara
771e4bb88b ACS-2579 Bump freemarker to 2.3.31-alfresco-patched (#1492) 2022-10-13 09:12:12 +02:00
Travis CI User
6cd05f9845 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-13 05:01:11 +00:00
Travis CI User
1bafb3006c [maven-release-plugin][skip ci] prepare release 17.165 2022-10-13 05:01:08 +00:00
MohinishSah
96c185c25f Merge pull request #1486 from Alfresco/fix/PRODSEC-6265_New
Handle XSS
2022-10-13 09:50:51 +05:30
Travis CI User
94f99bf0fa [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-12 16:12:18 +00:00
Travis CI User
fa0e90e267 [maven-release-plugin][skip ci] prepare release 17.164 2022-10-12 16:12:15 +00:00
Piotr Żurek
9c0799b49a ACS-2579 Use vanilla freemarker (#1491) 2022-10-12 17:12:35 +02:00
mstrankowski
1bbaf470a7 Update transform-core to 3.0.0-A6
Update transform-service to 2.0.0-A5
2022-10-12 16:12:01 +03:00
Travis CI User
7fe4c82adb [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-12 05:34:15 +00:00
Travis CI User
aed31a98e3 [maven-release-plugin][skip ci] prepare release 17.163 2022-10-12 05:34:13 +00:00
kcichonczyk
1f7987469b [ACS-3678] updated InsightEngine version to 2.0.5-A2 (#1489) 2022-10-11 22:26:20 +02:00
Travis CI User
96e176b83e [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-11 15:56:15 +00:00
Travis CI User
de14eb97cb [maven-release-plugin][skip ci] prepare release 17.162 2022-10-11 15:56:11 +00:00
krdabrowski
8ff074dfea ACS-3620: E2Es - API for manual triggering rules on a folder (#1482)
- adding "alwaysRun = true" to @BeforeMethod due to failing acs-packaging "REST API TAS tests with AIMS"
2022-10-11 17:14:43 +02:00
Travis CI User
a27a5571bc [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-11 14:31:41 +00:00
Travis CI User
3f9b18d110 [maven-release-plugin][skip ci] prepare release 17.161 2022-10-11 14:31:38 +00:00
Tom Page
623d166a76 Merge pull request #1487 from Alfresco/feature/ACS-3595_ActionParamMap
ACS-3651 Use Serializable for values in action parameters.
2022-10-11 14:53:02 +01:00
Travis CI User
6502924f8e [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-11 13:42:04 +00:00
Travis CI User
918e1cf183 [maven-release-plugin][skip ci] prepare release 17.160 2022-10-11 13:42:01 +00:00
Aleksandra Onych
59ab7e9458 ACS-3635 Alfresco WebDAV CSRF - allowInsecurePOSTMethod flag (#1488) 2022-10-11 15:05:48 +02:00
Tom Page
ccd421871c ACS-3651 Use Serializable for values in action parameters. 2022-10-11 12:00:17 +01:00
Travis CI User
fa1e616c72 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-11 10:40:52 +00:00
Travis CI User
5a34a2b01a [maven-release-plugin][skip ci] prepare release 17.159 2022-10-11 10:40:49 +00:00
Piotr Żurek
aae87ebffd PRODSEC-6550 Fix CSRF in the WebScript console Refresh Scripts form (#1483) 2022-10-11 12:05:35 +02:00
rrajoria
679746c907 Handle XSS 2022-10-11 13:01:09 +05:30
Travis CI User
44947e3d06 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-11 06:22:01 +00:00
Travis CI User
a94e660047 [maven-release-plugin][skip ci] prepare release 17.158 2022-10-11 06:21:59 +00:00
Marcin Strankowski
561d7d2f5a Update transform-core to 3.0.0-A4, transform-service to 2.0.0-A4, remove different version for jackson-databind. Update jackson version to 2.14.0-rc1 (#1484) 2022-10-11 08:44:52 +03:00
Travis CI User
78e69353d4 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-10 19:29:30 +00:00
Travis CI User
71a88870bd [maven-release-plugin][skip ci] prepare release 17.157 2022-10-10 19:29:27 +00:00
George Evangelopoulos
6bcf33d672 ACS-3616: fix exception type for missing node id (#1457)
* ACS-3616: fix exception type for missing node id

* ACS-3616: fix exception handling for missing node id

* ACS-3616: update javadoc, add a constructor for the exception
2022-10-10 21:52:19 +03:00
Travis CI User
81f2bd7018 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-10 16:08:17 +00:00
Travis CI User
b3968bcd9e [maven-release-plugin][skip ci] prepare release 17.156 2022-10-10 16:08:14 +00:00
Maciej Pichura
307eaff896 ACS-3649, ACS-3650 Action validation mechanism + validations against Action Definitions (#1481)
* ACS-3572: Action constraints endpoint + logic + unit tests.

* ACS-3572: Action constraints endpoint + logic + unit tests.

* ACS-3572: Action constraints endpoint fixes.

* ACS-3572: Cleanup after removal of GET all Action constraints.

* ACS-3572: Fixing formatting in tests.

* ACS-3572: Loosening V1 constraints restrictions for aspects, types and properties.

* ACS-3649: Action validators - constraints.

* ACS-3649: Action validators - constraints.

* ACS-3649: Action validators - constraints.

* ACS-3572: Adding validation for extra paramater.

* ACS-3649: Small refactors and fixes.

* ACS-3649: Validations against action definition.

* ACS-3649: Adding @Experimental annotation.

* ACS-3649: Fixes/refactoring after code review.

* ACS-3649: Removing ignored test
2022-10-10 17:13:51 +02:00
Travis CI User
0cfedbc979 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-10 09:13:35 +00:00
Travis CI User
89522ba09d [maven-release-plugin][skip ci] prepare release 17.155 2022-10-10 09:13:32 +00:00
Tom Page
86761bd408 Merge pull request #1478 from Alfresco/feature/ACS-3615_AllowNullParams
ACS-3615 Allow actions in rules without any params.
2022-10-10 09:29:29 +01:00
Maciej Pichura
4d6b4c2ecf ACS-3572 V1 API for action constraints (#1469)
* ACS-3572: Action constraints endpoint + logic + unit tests.

* ACS-3572: Action constraints endpoint + logic + unit tests.

* ACS-3572: Action constraints endpoint fixes.

* ACS-3572: Cleanup after removal of GET all Action constraints.

* ACS-3572: Fixing formatting in tests.

* ACS-3572: Loosening V1 constraints restrictions for aspects, types and properties.

* ACS-3572: Removing unnecessary code.

* ACS-3572: Removing unnecessary field.

* ACS-3572: Removing unnecessary field - fixing the tests.

* ACS-3572: Renaming the endpoint and fixing license headers.

* ACS-3572: Fixing license headers.

* ACS-3572: Fixing tas-restapi dependency version.

* ACS-3649: Bumping tes-restapi version.

* ACS-3649: Bumping tes-restapi version.
2022-10-10 10:14:47 +02:00
Travis CI User
98cb7762c4 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-09 09:44:47 +00:00
Travis CI User
ee01595f31 [maven-release-plugin][skip ci] prepare release 17.154 2022-10-09 09:44:44 +00:00
Elia Porciani
75acf5110e Fix/acs 2699 mandatory modifier (#1472)
[ACS-2699] managed + and - modifiers in fts query parser
2022-10-09 10:47:18 +02:00
Travis CI User
3a5971e267 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-09 00:11:41 +00:00
Travis CI User
99ef570054 [maven-release-plugin][skip ci] prepare release 17.153 2022-10-09 00:11:39 +00:00
Alfresco CI User
9649324d33 [force] Force release for 2022-10-09. 2022-10-09 00:04:36 +00:00
Tom Page
ad96f85251 ACS-3615 Allow actions in rules without any params. 2022-10-07 16:37:08 +01:00
krdabrowski
7ac48f8a99 ACS-3687: Execute rules API: Remove field "isEachInheritedRuleExecuted" (#1476)
* ACS-3620: E2Es - API for manual triggering rules on a folder
2022-10-07 17:01:08 +02:00
Travis CI User
aa38bcf9df [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-07 14:27:33 +00:00
Travis CI User
86d1d36ffe [maven-release-plugin][skip ci] prepare release 17.152 2022-10-07 14:27:31 +00:00
krdabrowski
b557a0d0f1 ACS-3620: E2Es - API for manual triggering rules on a folder (#1471) 2022-10-07 15:51:48 +02:00
Tom Page
1f81a50677 Merge pull request #1474 from Alfresco/feature/ACS-3657_PartialListOfRuleSets
ACS-3657 Allow returning partial list of rule sets.
2022-10-07 14:38:39 +01:00
Tom Page
855e2522f2 ACS-3657 Allow returning partial list of rule sets.
If a user does not have access to a rule set applied to a node then it will be
excluded from the results, but the user will be able to see the list of other
rule sets.

Also add E2E tests for permissions when viewing rule sets.
2022-10-07 13:03:37 +01:00
Travis CI User
f342b27c74 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-07 11:29:09 +00:00
Travis CI User
b00f01d385 [maven-release-plugin][skip ci] prepare release 17.151 2022-10-07 11:29:06 +00:00
rrajoria
ce68c4bf8b Reverting Change 2022-10-07 15:58:52 +05:30
Travis CI User
2544885f5e [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-05 17:02:40 +00:00
Travis CI User
1f7b272e57 [maven-release-plugin][skip ci] prepare release 17.150 2022-10-05 17:02:37 +00:00
Tom Page
df92ff9328 Merge pull request #1466 from Alfresco/feature/ACS-3630_PrivateActionTests
ACS-3630 E2E tests for creating and updating rules with private actions.
2022-10-05 16:24:47 +01:00
Travis CI User
b262c8fb92 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-05 15:19:28 +00:00
Travis CI User
0254323de5 [maven-release-plugin][skip ci] prepare release 17.149 2022-10-05 15:19:26 +00:00
Tom Page
89e8f7ff66 Merge master into ACS-3630_PrivateActionTests. 2022-10-05 16:09:29 +01:00
Tom Page
5735a41a40 Merge pull request #1468 from Alfresco/feature/ACS-3291_LinkUnlinkPermissionChecks
ACS-3291 Permission checks when linking and unlinking to rule sets.
2022-10-05 15:37:25 +01:00
Piotr Żurek
68b9a0e8a6 ACS-3643 Add meaningful message in the Workflow Console when deployment fails (#1467) 2022-10-05 15:53:42 +02:00
Tom Page
39f4a2179e ACS-3630 Use existing features in AccessRestrictionUtil. 2022-10-05 14:33:18 +01:00
Tom Page
440f0568e3 ACS-3291 Permission checks when linking and unlinking to rule sets. 2022-10-05 14:22:37 +01:00
krdabrowski
67f7fff0b7 ACS-3525: API for manual triggering rules on a folder (#1458)
* ACS-3525: API for manual triggering rules on a folder
2022-10-05 12:19:49 +02:00
Tom Page
1a08480f22 ACS-3630 E2E tests for creating and updating rules with private actions.
Ensure that 403 Forbidden is returned rather than 500 Internal Server Error.
2022-10-05 09:13:01 +01:00
Tom Page
8afd06a57f Merge pull request #1465 from Alfresco/feature/ACS-3605_LimitLinkedToBy
ACS-3605 Add limit to maximum size of optional linkedToBy field.
2022-10-05 09:05:21 +01:00
Tom Page
5e82555269 ACS-3605 Fix reference in unit test. 2022-10-04 16:21:23 +01:00
Tom Page
3682ddf652 ACS-3605 Add limit to maximum size of optional linkedToBy field. 2022-10-04 15:54:31 +01:00
Travis CI User
6747e300af [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-04 08:53:26 +00:00
Travis CI User
4bb2f67a48 [maven-release-plugin][skip ci] prepare release 17.148 2022-10-04 08:53:23 +00:00
Tom Page
c5c6b45f17 Merge pull request #1462 from Alfresco/feature/ACS-3377_UpdateRuleOrder
ACS-3377 Update rule order.
2022-10-04 09:16:30 +01:00
Travis CI User
1d9823d2e9 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-03 22:54:33 +00:00
Travis CI User
bfae9dd78d [maven-release-plugin][skip ci] prepare release 17.147 2022-10-03 22:54:30 +00:00
Kristian Dimitrov
86af67a435 ACS-3601: Add unlink e2es (#1461)
* ACS-3601: Add unlink e2es
2022-10-03 23:16:59 +01:00
Travis CI User
7ce6c121ef [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-03 16:00:31 +00:00
Travis CI User
d0061fb530 [maven-release-plugin][skip ci] prepare release 17.146 2022-10-03 16:00:28 +00:00
Tom Page
1c91452ee9 Merge pull request #1456 from Alfresco/feature/ACS-3376_GETRuleIds
ACS-3376 GET rule order within rule set.
2022-10-03 16:24:39 +01:00
Tom Page
f707906943 ACS-3377 Fix review comments. 2022-10-03 15:40:52 +01:00
Tom Page
af7e9f97aa ACS-3376 Simplify method of obtaining rule ids. 2022-10-03 15:28:00 +01:00
Tom Page
e9105f0f0c ACS-3377 Update rule order. 2022-10-03 10:04:07 +01:00
Travis CI User
282186b877 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-03 09:02:38 +00:00
Travis CI User
5ab44f4f35 [maven-release-plugin][skip ci] prepare release 17.145 2022-10-03 09:02:36 +00:00
kavitshah-gl
bf855c5965 Feature/acs-3579 (#1443)
* Fixed DeleteRecordTests-destroyOfRecord

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]
2022-10-03 13:47:59 +05:30
Travis CI User
d02f88eed4 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-02 00:13:36 +00:00
Travis CI User
e487061e96 [maven-release-plugin][skip ci] prepare release 17.144 2022-10-02 00:13:33 +00:00
Alfresco CI User
615406d5a1 [force] Force release for 2022-10-02. 2022-10-02 00:06:17 +00:00
Travis CI User
548fc9e64a [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-30 12:40:26 +00:00
Travis CI User
e7cc9ba008 [maven-release-plugin][skip ci] prepare release 17.143 2022-09-30 12:40:23 +00:00
kavitshah-gl
e10e9fe1c5 Update pom.xml
Updated Google Drive Version.
2022-09-30 16:42:10 +05:30
Travis CI User
d5a33e3f03 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-30 09:54:34 +00:00
Travis CI User
b62dfc1d76 [maven-release-plugin][skip ci] prepare release 17.142 2022-09-30 09:54:32 +00:00
Sara
3711be4e80 Feature/acs 3623 descriptor startup log (#1460)
* Pick up api-explorer 7.3.0-A1

* remove unused import

* ACS-3623 Add customembeddedworkflow to descriptor startup log
2022-09-30 09:33:36 +01:00
Travis CI User
33297757bf [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-29 15:52:20 +00:00
Travis CI User
5f9c8fc499 [maven-release-plugin][skip ci] prepare release 17.141 2022-09-29 15:52:16 +00:00
tiagosalvado10
119ff309ac [MNT-23241] Prevent duplicated default headers if key/value pair is already in the request, otherwise, header is added (#1454)
* [MNT-23241] Prevent duplicated default headers if key/value pair is already in the request, otherwise, header is added
2022-09-29 16:17:23 +01:00
Tom Page
a93dd27674 ACS-3376 GET rule order within rule set. 2022-09-29 15:21:35 +01:00
Travis CI User
609ffdcbf0 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-28 16:29:18 +00:00
Travis CI User
85baa164db [maven-release-plugin][skip ci] prepare release 17.140 2022-09-28 16:29:15 +00:00
Kristian Dimitrov
8776109582 ACS-3427: Add GET e2es for actions and conditions (#1451)
* ACS-3427: Add GET e2es for actions and conditions

* ACS-3427: Remove unnecessary cast
2022-09-28 16:25:47 +01:00
Travis CI User
c8cf52baef [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-28 10:04:35 +00:00
Travis CI User
9d82828959 [maven-release-plugin][skip ci] prepare release 17.139 2022-09-28 10:04:32 +00:00
Piotr Żurek
d475c74707 ACS-3563 Workflow Licence Check (#1422) 2022-09-28 11:31:32 +02:00
Travis CI User
cc3ea3167b [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-28 08:21:39 +00:00
Travis CI User
36f1c7083c [maven-release-plugin][skip ci] prepare release 17.138 2022-09-28 08:21:36 +00:00
Tom Page
22a158a1ee Merge pull request #1446 from Alfresco/feature/ACS-3488_RemoveXMLDataProvider
ACS-3488 Remove xml data provider.
2022-09-28 08:45:54 +01:00
Sara
2a75a304a9 ACS-3560 Bump tas-restapi to 1.124 (#1449) 2022-09-28 08:37:49 +01:00
Domenico Sibilio
472b3d044f ACS-3594 Add mechanism to deprecate modules within the Repo (#1445) 2022-09-28 09:25:57 +02:00
dependabot[bot]
e2db0aab11 Bump alfresco/alfresco-base-tomcat in /packaging/docker-alfresco (#1439) 2022-09-28 07:18:32 +00:00
Travis CI User
031efe67d7 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-27 16:23:09 +00:00
Travis CI User
e22b5fff86 [maven-release-plugin][skip ci] prepare release 17.137 2022-09-27 16:23:06 +00:00
George Evangelopoulos
91e2421d7c ACS-3291: Support for unlinking rule sets (#1421)
* ACS-3291: Support for unlinking rule sets

* ACS-3291: add unit tests and edge case exceptions

* ACS-3291: add support for -default- ruleSetId

Co-authored-by: Tom Page <tpage-alfresco@users.noreply.github.com>
2022-09-27 18:45:55 +03:00
Tom Page
529f6b31e8 Update SearchInFolderTests.java 2022-09-27 16:22:09 +01:00
Maciej Pichura
4bc36ae18d ACS-3510 Rule mappers refactor pt3 (#1438)
* ACS-3510: Rule mappers refactor pt3 (presumably final)

* ACS-3510: Rule mappers refactor pt3 - fixes after master merge.

* ACS-3510: Fixing error script conversion, adding some logging.
2022-09-27 15:24:39 +02:00
Tom Page
47187ee12e ACS-3488 Refactor in-folder tests. 2022-09-27 14:05:49 +01:00
Tom Page
520b9e7fcb ACS-3488 Remove usage of XML data provider.
This broke when we updated TestNG.
2022-09-27 10:38:25 +01:00
Travis CI User
73518a0342 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-27 09:09:54 +00:00
Travis CI User
cc1682c209 [maven-release-plugin][skip ci] prepare release 17.136 2022-09-27 09:09:51 +00:00
Tom Page
c9d7d0993e ACS-3589 Ensure tas-cmis is built before we try to use it in tas-integration. 2022-09-27 09:31:26 +01:00
Tom Page
ec13ac08c4 ACS-3589 Use project version when importing tas-cmis. 2022-09-27 09:03:07 +01:00
Tom Page
e0df4e8831 ACS-3589 Remove legacy reference to tas-cmis. 2022-09-27 08:58:41 +01:00
Tom Page
dffdb59b05 Merge pull request #1435 from Alfresco/feature/ACS-3589_TASCMISMerge
ACS-3589 Merge TAS CMIS into community repo.
2022-09-27 08:17:55 +01:00
Travis CI User
1d03f3aaa6 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-26 18:42:29 +00:00
Travis CI User
21e444da9f [maven-release-plugin][skip ci] prepare release 17.135 2022-09-26 18:42:26 +00:00
evasques
a512c3443c MNT-23174 - RM upgrade from 3.4.1.1 to 11.153 fails (#1434)
* MNT-23174 - RM upgrade from 3.4.1.1 to 11.153 fails
* Added batching capability to process records in hold
* Changed the retrieval of child assocs witout preload to not fill up the caches when we have very big holds
* Added property rm.patch.v35.holdNewChildAssocPatch.batchSize to be able to configure the batchSize
* Adapt mocks on unit test to the new calls
2022-09-26 19:05:03 +01:00
Travis CI User
e4f9c5539b [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-26 15:51:59 +00:00
Travis CI User
2a5df0dd7c [maven-release-plugin][skip ci] prepare release 17.134 2022-09-26 15:51:56 +00:00
tiagosalvado10
be7d4be636 [MNT-23118] Allow import with long paths (#1426)
* [MNT-23118] Allow nodes with long paths to be created during ACP import
2022-09-26 16:16:35 +01:00
Marcin Strankowski
d40ed346a7 Update transform-core to 3.0.0-A3. Update transform-servce to 2.0.0-A3 (#1437) 2022-09-26 16:45:04 +02:00
Tom Page
8c556eeaca ACS-3359 Rename boolean rule fields. (#1436)
* ACS-3359 Rename boolean rule fields.

* ACS-3359 Re-add unused import.

This has started to be used on master now.

* ACS-3359 Fix E2E test.

The isShared field is requested and comes back correctly as false.
2022-09-26 15:43:13 +01:00
Travis CI User
d0eea6835e [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-26 13:00:15 +00:00
Travis CI User
031dde6293 [maven-release-plugin][skip ci] prepare release 17.133 2022-09-26 13:00:12 +00:00
Maciej Pichura
819f0c9921 ACS-3510: Rule Action updates E2E tests. (#1431)
* ACS-3510: Rule Action updates E2E tests.

* ACS-3510: Rule Action updates E2E tests - fixes and enhancements.
2022-09-26 14:26:59 +02:00
Travis CI User
0b2e9e0a97 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-26 11:19:03 +00:00
Travis CI User
09ce322111 [maven-release-plugin][skip ci] prepare release 17.132 2022-09-26 11:19:00 +00:00
evasques
49cedfc40c MNT-23043 - Property Tables Cleaner Job V3 (#1330)
* Implementation of V3

* Correct commit placement. If done while cursors are still open can result lost cursors - see MNT-23127

* Correct formatting

* Unit Test

* Add test to test suite

* Corrections on the unit test

* Correct typo and add documentation

* Fix typos

* Set the default values as constants

* remove initialization of rowsProcessed

* Improve comments

* Optimizations regarding retrieving min and max values

* Fix PostgreSQL sql script for v3
2022-09-26 11:44:01 +01:00
Tom Page
dcc739db76 ACS-3589 Merge alfresco-tas-cmis into master.
Remove files that are not needed in new structure.
2022-09-26 11:26:22 +01:00
Sara
0aa4b5de9c Feature/acs 3555 add custom embedded workflow license code (#1432)
* ACS-3555 Add license code for custom embedded workflow

* ACS-3555 remove unused import

* ACS-3560 Discovery API for custom embedded workflow license

* ACS-3560 fix compilation error

* use default method

* restore discovery api
2022-09-26 11:04:26 +01:00
Travis CI User
f196de23b0 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-25 00:10:59 +00:00
Travis CI User
59901e44fe [maven-release-plugin][skip ci] prepare release 17.131 2022-09-25 00:10:57 +00:00
Alfresco CI User
964cd86e00 [force] Force release for 2022-09-25. 2022-09-25 00:04:06 +00:00
Travis CI User
636ef33cc0 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-23 15:47:19 +00:00
Travis CI User
0d3ab4d921 [maven-release-plugin][skip ci] prepare release 17.130 2022-09-23 15:47:16 +00:00
Sara
02a0454055 Revert "Feature/acs 3555 add custom embedded workflow license code (#1420)" (#1430)
This reverts commit 19a061dc04.
2022-09-23 15:13:33 +01:00
Travis CI User
653f685dc9 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-23 13:01:58 +00:00
Travis CI User
2362ef986b [maven-release-plugin][skip ci] prepare release 17.129 2022-09-23 13:01:55 +00:00
Sara
dc5404b8c2 Revert "Feature/acs 3560 discovery api for custom embedded workflow license (#1423)" (#1429)
This reverts commit 541bf63d80.
2022-09-23 13:27:56 +01:00
tiagosalvado10
125b35e11c [MNT-21638] Script task execution (#1210)
* [MNT-21638] Script task execution based on workflow deloyment category. Javadoc. Unit tests.
2022-09-23 13:24:49 +01:00
brijmohan1
a77584a398 MNT-22233 resolved error while loading subcategory with cutoff. (#1424)
* MNT-22233 resolved error while loading subcategory with cutoff.

* MNT-22233 added log message when action definition is null.

* MNT-22233 updated log message when action definition is null.
2022-09-23 11:49:01 +05:30
Sara
541bf63d80 Feature/acs 3560 discovery api for custom embedded workflow license (#1423)
* ACS-3555 Add license code for custom embedded workflow

* ACS-3555 remove unused import

* ACS-3560 Discovery API for custom embedded workflow license

* ACS-3560 fix compilation error
2022-09-22 11:19:18 +01:00
Sara
19a061dc04 Feature/acs 3555 add custom embedded workflow license code (#1420)
* ACS-3555 Add license code for custom embedded workflow

* ACS-3555 remove unused import
2022-09-22 11:14:46 +01:00
Travis CI User
b1282cba89 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-22 06:49:24 +00:00
Travis CI User
d137dd89ec [maven-release-plugin][skip ci] prepare release 17.128 2022-09-22 06:49:22 +00:00
Maciej Pichura
9c8f98c12f ACS-3509 Rule mappers refactor pt2 (#1428)
* ACS-3509: Fixes and refactors for rule mappers pt 2.

* ACS-3509: Rule Condition mappings refactor + tests.
2022-09-22 08:10:59 +02:00
Tom Page
e0d52f98ae ACS-3366 Add support for isLinkedTo to GET rule sets. (#1427)
* ACS-3364 Add permission handling to linkedToBy.

* ACS-3366 Add support for isLinkedTo to GET rule sets.
2022-09-21 15:18:41 +01:00
Tom Page
c4d432b136 ACS-3364 Add permission handling to linkedToBy. (#1425) 2022-09-21 15:18:30 +01:00
Travis CI User
e0844d72e1 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-21 10:32:38 +00:00
Travis CI User
857771593b [maven-release-plugin][skip ci] prepare release 17.127 2022-09-21 10:32:35 +00:00
Maciej Pichura
a80ac51b5d ACS-3509: Adding E2E TAS REST tests for update rule conditions. (#1411)
* ACS-3509: Adding E2E TAS REST tests for update rule conditions.

* ACS-3509: Clean up after review.

* ACS-3509: Fixes after review, adding some more E2E tests.
2022-09-21 11:56:10 +02:00
Travis CI User
d7d50d0a67 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-21 09:32:31 +00:00
Travis CI User
11dd5307a7 [maven-release-plugin][skip ci] prepare release 17.126 2022-09-21 09:32:28 +00:00
rrajoria
a038f068ab Encoding to handle XSS (#1409) 2022-09-21 14:26:12 +05:30
Travis CI User
cc1c539a4c [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-21 08:45:24 +00:00
Travis CI User
3407899f20 [maven-release-plugin][skip ci] prepare release 17.125 2022-09-21 08:45:22 +00:00
Tom Page
1c69cd2e61 ACS-3365 Add support for GET rule sets isInherited. (#1415) 2022-09-21 09:00:34 +01:00
Travis CI User
02ba54ab3a [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-21 07:43:37 +00:00
Travis CI User
4116cae611 [maven-release-plugin][skip ci] prepare release 17.124 2022-09-21 07:43:34 +00:00
Tom Page
c300affa6d ACS-3578 Ignoring two more tests that are failing. 2022-09-21 07:52:56 +01:00
Tom Page
dba0dc9083 ACS-3578 Ignoring test that depends on ignored tests. 2022-09-20 17:13:07 +01:00
Tom Page
2c43a64fd0 ACS-3578 Ignoring tests that suddenly started failing. 2022-09-20 16:25:46 +01:00
Tom Page
af2b00cc6b ACS-3577 Use reload4j in TAS tests. 2022-09-20 16:06:20 +01:00
Tom Page
767f6a6af2 Revert "Bump dependency.poi.version from 5.2.2 to 5.2.3 (#1414)" (#1416)
This reverts commit 4990a8b316.
2022-09-20 15:28:52 +01:00
dependabot[bot]
4990a8b316 Bump dependency.poi.version from 5.2.2 to 5.2.3 (#1414)
Bumps `dependency.poi.version` from 5.2.2 to 5.2.3.

Updates `poi` from 5.2.2 to 5.2.3

Updates `poi-ooxml` from 5.2.2 to 5.2.3

Updates `poi-scratchpad` from 5.2.2 to 5.2.3

---
updated-dependencies:
- dependency-name: org.apache.poi:poi
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.poi:poi-ooxml
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.poi:poi-scratchpad
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 10:35:39 +01:00
Travis CI User
af348eac49 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-20 09:05:02 +00:00
Travis CI User
e56b97a6fb [maven-release-plugin][skip ci] prepare release 17.123 2022-09-20 09:04:59 +00:00
dependabot[bot]
f32e554eb7 Bump xmlbeans from 5.1.0 to 5.1.1 (#1345)
Bumps xmlbeans from 5.1.0 to 5.1.1.

---
updated-dependencies:
- dependency-name: org.apache.xmlbeans:xmlbeans
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 09:20:31 +01:00
dependabot[bot]
e0cdf1b3fe Bump joda-time from 2.10.14 to 2.11.1 (#1338)
Bumps [joda-time](https://github.com/JodaOrg/joda-time) from 2.10.14 to 2.11.1.
- [Release notes](https://github.com/JodaOrg/joda-time/releases)
- [Changelog](https://github.com/JodaOrg/joda-time/blob/main/RELEASE-NOTES.txt)
- [Commits](https://github.com/JodaOrg/joda-time/compare/v2.10.14...v2.11.1)

---
updated-dependencies:
- dependency-name: joda-time:joda-time
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 09:20:18 +01:00
dependabot[bot]
1517ff6e85 Bump jsoup from 1.15.2 to 1.15.3 (#1337)
Bumps [jsoup](https://github.com/jhy/jsoup) from 1.15.2 to 1.15.3.
- [Release notes](https://github.com/jhy/jsoup/releases)
- [Changelog](https://github.com/jhy/jsoup/blob/master/CHANGES)
- [Commits](https://github.com/jhy/jsoup/compare/jsoup-1.15.2...jsoup-1.15.3)

---
updated-dependencies:
- dependency-name: org.jsoup:jsoup
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 09:20:07 +01:00
dependabot[bot]
ea8481ca98 Bump postgresql from 42.4.1 to 42.5.0 (#1336)
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.1 to 42.5.0.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.1...REL42.5.0)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 09:19:56 +01:00
dependabot[bot]
5a8e73c03e Bump spring-security-core from 5.7.2 to 5.7.3 (#1314)
Bumps [spring-security-core](https://github.com/spring-projects/spring-security) from 5.7.2 to 5.7.3.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Changelog](https://github.com/spring-projects/spring-security/blob/main/RELEASE.adoc)
- [Commits](https://github.com/spring-projects/spring-security/compare/5.7.2...5.7.3)

---
updated-dependencies:
- dependency-name: org.springframework.security:spring-security-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 09:19:46 +01:00
dependabot[bot]
c89969422e Bump woodstox-core from 6.3.0 to 6.3.1 (#1312)
Bumps [woodstox-core](https://github.com/FasterXML/woodstox) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/FasterXML/woodstox/releases)
- [Commits](https://github.com/FasterXML/woodstox/compare/woodstox-core-6.3.0...woodstox-core-6.3.1)

---
updated-dependencies:
- dependency-name: com.fasterxml.woodstox:woodstox-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 09:19:27 +01:00
dependabot[bot]
4e2f8fb8e6 Bump maven-javadoc-plugin from 3.4.0 to 3.4.1 (#1309)
Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.4.0...maven-javadoc-plugin-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 09:19:17 +01:00
dependabot[bot]
e84481d7f3 Bump dependency.antlr.version from 3.5.2 to 3.5.3 (#1061)
Bumps `dependency.antlr.version` from 3.5.2 to 3.5.3.

Updates `gunit` from 3.5.2 to 3.5.3
- [Release notes](https://github.com/antlr/antlr3/releases)
- [Commits](https://github.com/antlr/antlr3/compare/3.5.2...3.5.3)

Updates `antlr` from 3.5.2 to 3.5.3

---
updated-dependencies:
- dependency-name: org.antlr:gunit
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.antlr:antlr
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 09:19:04 +01:00
Travis CI User
6ea0f9b189 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-20 07:45:56 +00:00
Travis CI User
8def39fe6c [maven-release-plugin][skip ci] prepare release 17.122 2022-09-20 07:45:54 +00:00
Tom Page
d290c129bc ACS-3364 Add support for linkedToBy field in GET rule sets. (#1402)
* ACS-3364 Update TAS REST API for linkedTo field.

* ACS-3364 TAS test for linkedToBy field.

* ACS-3364 Implementation for linkedToBy field.
2022-09-20 08:09:29 +01:00
Travis CI User
15ba054b16 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-19 11:21:31 +00:00
Travis CI User
3e54162fcc [maven-release-plugin][skip ci] prepare release 17.121 2022-09-19 11:21:28 +00:00
Maciej Pichura
d24baf9ecd ACS-3354 Rule mappers pt1 (simple condition mapper) (#1388)
* ACS-3363: Add rule simple condition mapping layer - part 1.

* ACS-3363: Add rule simple condition mapping layer - part 1 - fixes and cleanup.

* ACS-3354: Fixes and refactors for rule mappers pt 1.
2022-09-19 12:42:26 +02:00
Travis CI User
2223f845bb [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-18 00:10:34 +00:00
Travis CI User
ee40a2140e [maven-release-plugin][skip ci] prepare release 17.120 2022-09-18 00:10:32 +00:00
Alfresco CI User
c01147f2b7 [force] Force release for 2022-09-18. 2022-09-18 00:03:29 +00:00
Travis CI User
2d69902c25 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-16 15:15:37 +00:00
Travis CI User
ff3da00a40 [maven-release-plugin][skip ci] prepare release 17.119 2022-09-16 15:15:35 +00:00
dependabot[bot]
2cd96b1522 Bump rest-assured from 5.1.1 to 5.2.0 (#1371)
Bumps [rest-assured](https://github.com/rest-assured/rest-assured) from 5.1.1 to 5.2.0.
- [Release notes](https://github.com/rest-assured/rest-assured/releases)
- [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt)
- [Commits](https://github.com/rest-assured/rest-assured/compare/rest-assured-5.1.1...rest-assured-5.2.0)

---
updated-dependencies:
- dependency-name: io.rest-assured:rest-assured
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-16 14:40:46 +01:00
dependabot[bot]
38300fbac3 Bump alfresco/alfresco-base-tomcat in /packaging/docker-alfresco (#1379)
Bumps alfresco/alfresco-base-tomcat from tomcat9-jre17-rockylinux8-202205140719 to tomcat9-jre17-rockylinux8-202209131110.

---
updated-dependencies:
- dependency-name: alfresco/alfresco-base-tomcat
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-16 14:38:34 +01:00
dependabot[bot]
9031ed139f Bump dependency.slf4j.version from 1.7.36 to 2.0.1 (#1385)
Bumps `dependency.slf4j.version` from 1.7.36 to 2.0.1.

Updates `slf4j-api` from 1.7.36 to 2.0.1
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.36...v_2.0.1)

Updates `slf4j-reload4j` from 1.7.36 to 2.0.1
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/compare/v_1.7.36...v_2.0.1)

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-api
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: org.slf4j:slf4j-reload4j
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-16 14:37:51 +01:00
dependabot[bot]
298283cf7a Bump dependency.spring.version from 5.3.22 to 5.3.23 (#1390)
Bumps `dependency.spring.version` from 5.3.22 to 5.3.23.

Updates `spring-aop` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-beans` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-context` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-context-support` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-core` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-expression` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-jdbc` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-jms` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-test` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-orm` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-tx` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-web` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

Updates `spring-webmvc` from 5.3.22 to 5.3.23
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.3.22...v5.3.23)

---
updated-dependencies:
- dependency-name: org.springframework:spring-aop
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-beans
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-context
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-context-support
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-expression
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-jdbc
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-jms
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-test
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-orm
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-tx
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-web
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.springframework:spring-webmvc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-16 14:36:35 +01:00
dependabot[bot]
8026af1706 Bump dependency.webscripts.version from 8.31 to 8.32 (#1393)
Bumps `dependency.webscripts.version` from 8.31 to 8.32.

Updates `spring-surf-core-configservice` from 8.31 to 8.32

Updates `spring-webscripts` from 8.31 to 8.32
- [Release notes](https://github.com/Alfresco/surf-webscripts/releases)
- [Commits](https://github.com/Alfresco/surf-webscripts/compare/spring-surf-webscripts-parent-8.31...spring-surf-webscripts-parent-8.32)

Updates `spring-webscripts` from 8.31 to 8.32
- [Release notes](https://github.com/Alfresco/surf-webscripts/releases)
- [Commits](https://github.com/Alfresco/surf-webscripts/compare/spring-surf-webscripts-parent-8.31...spring-surf-webscripts-parent-8.32)

Updates `spring-webscripts-api` from 8.31 to 8.32

---
updated-dependencies:
- dependency-name: org.alfresco.surf:spring-surf-core-configservice
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.alfresco.surf:spring-webscripts
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.alfresco.surf:spring-webscripts:tests
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.alfresco.surf:spring-webscripts-api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-16 14:36:07 +01:00
Travis CI User
20ec3351b3 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-16 13:34:48 +00:00
Travis CI User
e79b434c54 [maven-release-plugin][skip ci] prepare release v1.34 2022-09-16 13:34:47 +00:00
dependabot-preview[bot]
163add3bfd Bump resteasy-jackson2-provider from 3.6.3.Final to 4.7.1.Final (#60)
Bumps resteasy-jackson2-provider from 3.6.3.Final to 4.7.1.Final.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2022-09-16 14:30:54 +01:00
dependabot-preview[bot]
ba2367bf92 Bump alfresco-super-pom from 10 to 12 (#19)
Bumps [alfresco-super-pom](https://github.com/Alfresco/alfresco-super-pom) from 10 to 12.
- [Release notes](https://github.com/Alfresco/alfresco-super-pom/releases)
- [Commits](https://github.com/Alfresco/alfresco-super-pom/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2022-09-16 14:30:39 +01:00
dependabot-preview[bot]
84857e1a71 Upgrade to GitHub-native Dependabot (#54)
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2022-09-16 14:30:29 +01:00
dependabot-preview[bot]
cda1c682ae Bump maven-project-info-reports-plugin from 2.9 to 3.1.2 (#55)
Bumps [maven-project-info-reports-plugin](https://github.com/apache/maven-project-info-reports-plugin) from 2.9 to 3.1.2.
- [Release notes](https://github.com/apache/maven-project-info-reports-plugin/releases)
- [Commits](https://github.com/apache/maven-project-info-reports-plugin/compare/maven-project-info-reports-plugin-2.9...maven-project-info-reports-plugin-3.1.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2022-09-16 14:30:18 +01:00
George Evangelopoulos
c11b951e57 Update javadoc to clarify variable use (#1397) 2022-09-16 16:12:38 +03:00
Travis CI User
fc5a7f5838 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-16 10:43:06 +00:00
Travis CI User
3fde3cbadb [maven-release-plugin][skip ci] prepare release 17.118 2022-09-16 10:43:04 +00:00
Tom Page
ac1a77156e ACS-3363 Support inheritedBy in GET rule sets. (#1387)
* ACS-3363 E2E test for inheritedBy.

* ACS-3363 Support optional inheritedBy field in GET rule sets.

* ACS-3363 Update to new version of TAS REST API.

* ACS-3363 Remove user from private site before calling method under test.
2022-09-16 11:06:17 +01:00
Tom Page
e66263a5a8 ACS-3363 Output TAS logs for failed tests. (#1396) 2022-09-16 10:21:32 +01:00
Travis CI User
a410dbe538 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-16 07:18:14 +00:00
Travis CI User
48f53d204d [maven-release-plugin][skip ci] prepare release 17.117 2022-09-16 07:18:11 +00:00
MohinishSah
b589d574ea Update pom.xml 2022-09-16 12:11:08 +05:30
Travis CI User
a04f743318 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-15 14:39:33 +00:00
Travis CI User
d4aa429643 [maven-release-plugin][skip ci] prepare release 17.116 2022-09-15 14:39:30 +00:00
Maciej Pichura
ebdc01300d ACS-3354: Adding TAS test for update rule (other) fields. (#1389) 2022-09-15 16:00:37 +02:00
Travis CI User
977681ba9b [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-15 09:12:54 +00:00
Travis CI User
e457a8b7c7 [maven-release-plugin][skip ci] prepare release 17.115 2022-09-15 09:12:51 +00:00
Maciej Pichura
772109d629 ACS-3429: Better fitting exceptions on POST rule with actions (#1376)
* ACS-3429: Better fitting exceptions on POST rule with actions when missing or invalid fields.

* ACS-3429: Fixing and adding tests
2022-09-15 10:35:32 +02:00
Travis CI User
ee8adb45fb [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-15 06:54:29 +00:00
Travis CI User
7daf864168 [maven-release-plugin][skip ci] prepare release 17.114 2022-09-15 06:54:26 +00:00
alandavis
9744b1da4d HXENG-64 dependency snakeyaml 1.30 -> 1.32 2022-09-15 07:00:22 +01:00
kavitshah-gl
033a00075f Feature/apps 1613 (#1284)
* Adding test for the stage AGS Smoke UI Tests for actions in RM site

* pushed the createCategoriesTest in APPS-1550 brach

* pushed the createCategoriesTest in APPS-1550 branch

* pushed the CreateFoldersTests in APPS-1550 branch

* [ags]

* ~ /\[ags\]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* Revert "~ /\[ags\]"

This reverts commit ed9443e5

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* Adding FoldersDispositionScheduleTests

* Added foldersDispositionScheduleWithGhosting

* Added foldersDispositionScheduleWithoutGhosting

* Added RecordsDispositionScheduleTests and other fixes

* Added RecordsDispositionScheduleWithGhostingTests

* [ags api]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* Revert "[ags api]"

This reverts commit 2153eafc0f.

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* DispositionScheduleLinkedRecordsTest class added

* [ags]

* [ags]

* [ags]

* [ags]

* ags

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

* [ags]

Co-authored-by: sbisht <shishuraj.bisht@globallogic.com>
2022-09-15 10:51:52 +05:30
alandavis
2a48160442 Pick up t-core 3.0.0-A2 and t-service 2.0.0-A2 which include snakeyaml 1.32 2022-09-15 00:24:16 +01:00
Alan Davis
64955658fc HXENG-64 refactor ATS
* Pick refactored t-core 3.0.0 and t-service 2.0.0.
* Use new package names from t-model
* Fix up a few test failures due to incomplete t-config which is now checked.
2022-09-14 22:07:07 +01:00
Travis CI User
bec0ac0236 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-14 13:51:26 +00:00
Travis CI User
b22595058e [maven-release-plugin][skip ci] prepare release 17.113 2022-09-14 13:51:22 +00:00
Marcin Strankowski
742a4c89dd ACS-3402: Add actual dependency, not just dependencyManagement, record of non-transitive netty dependencies to be used in AMPs (#1384) 2022-09-14 15:11:09 +02:00
Travis CI User
09db0fcad3 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-14 12:43:24 +00:00
Travis CI User
313823eb8c [maven-release-plugin][skip ci] prepare release 17.112 2022-09-14 12:43:21 +00:00
Tom Page
b7d2d3bae9 ACS-3536 Omit actionContext for rules. (#1383)
* ACS-3536 Omit actionContext for rules.

It will always be set to 'Rule' anyway.

* ACS-3536 Stop setting actionContext in rules E2E tests.

Also add extra assertion for action params in new test.
2022-09-14 12:56:38 +01:00
Travis CI User
e265bb0a5d [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-13 18:58:36 +00:00
Travis CI User
6da0d7cc7b [maven-release-plugin][skip ci] prepare release 17.111 2022-09-13 18:58:34 +00:00
tiagosalvado10
430d15f32d [MNT-21901] Prevent update preferences concurrency errors (#821)
* [MNT-21901] Added PersistenceException to retry exceptions. Added validation to get retry cause

* [MNT-21901] Check exception message only if it is JavaScriptException

* [MNT-21901] Removed unit test from repository. Added new test on remote-api. Changed ExceptionStackUtil validation.

* [MNT-21901] Improved JavascriptException validation. Added exception delimiter to prevent accepting exceptions with the same partial name.
2022-09-13 16:40:23 +01:00
Travis CI User
3fc0100bb5 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-13 13:49:23 +00:00
Travis CI User
7ccd9640ee [maven-release-plugin][skip ci] prepare release 17.110 2022-09-13 13:49:20 +00:00
Marcin Strankowski
bea34483b5 Feature/acs 3402 release gytheio 0.17.0 (#1375)
* Update Gytheio version
2022-09-13 15:01:02 +02:00
Travis CI User
e0867a099f [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-13 11:19:31 +00:00
Travis CI User
172d6c2185 [maven-release-plugin][skip ci] prepare release 17.109 2022-09-13 11:19:28 +00:00
krdabrowski
4692d471a3 ACS-3430: POST support for conditions (#1356) 2022-09-13 11:32:29 +01:00
Marcin Strankowski
3c55c1a9a0 ACS-3402: Camel upgrade (#1322)
* ACS-3402 Camel upgrade

* ACS-3402 Camel upgrade

* ACS-3402 Camel upgrade

* ACS-3402 Camel upgrade

* Revert "ACS-3402 Camel upgrade"

This reverts commit 124e188027.

* Moving all netty dependencies up to community-repo

These dependencies are a re/declaration of transitive/optional camel dependencies used in dependant projects.
They must be in sync with camel version of community repo, hence declaring them in other projects just causes unnecessary confusion.

* Fixing new versions of netty

They were updated through transitive update of camel from .73.Final to .79.Final, along with netty-transport-native-unix-common library that went to .79.Final

* Had extreme collisions on netty-transport-native-unix-common

Moved to approach with just declaring additional non-provided netty libraries and moving version numbers to community-repo.
Even mentioning netty-transport-native-unix-common in pom.xml seems to crash tests no matter which version is taken or if it's a transitive dependency of netty-handler. Since I can't add it either way, then partial additions of libraries make no sense. I've adjusted comments next to version numbers to make it easier to differentiate what they are responsible for and need to keep track of. Version numbers should still be placed in community-repo

* 3.18.2 was released recently, doesn't modify netty versions, so I'll use the latest one

Co-authored-by: pzurek <Piotr.Zurek@hyland.com>
2022-09-13 11:49:56 +02:00
Tom Page
400b33c7eb ACS-3489 Use specified rule set. (#1373)
* ACS-3280 Get inherited rule sets. [tas]

This needs to work the exact same way as get inherited rules.

* ACS-3280 Replace LinkedList with ArrayList.

* ACS-3280 Don't return duplicated rule sets when there are links.

* ACS-3489 E2E test for getting rules with inheritance.

* ACS-3489 Inherited rule sets are also associated with folders.

* ACS-3489 Fix test to contain expected values.

* ACS-3489 Ensure only rules from specified rule set are returned.

Add E2E test case for inherited links and fix unit tests.

* ACS-3489 Fix audit reference in RuleService.
2022-09-13 10:23:16 +01:00
Travis CI User
bc9c23503b [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-13 08:49:18 +00:00
Travis CI User
7ed021fb77 [maven-release-plugin][skip ci] prepare release 17.108 2022-09-13 08:49:16 +00:00
Tom Page
0e73bc1572 ACS-3533 Disabling scan on PR builds. (#1374) 2022-09-13 09:13:38 +01:00
Travis CI User
7eb063e923 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-12 19:00:33 +00:00
Travis CI User
a5a34c05c1 [maven-release-plugin][skip ci] prepare release 17.107 2022-09-12 19:00:31 +00:00
tiagosalvado10
9f4371eb9c [MNT-21377] Prevent LDAP checks from running multiple times (#1369)
* [MNT-23177] Prevent LDAP checks from running multiple times

* [MNT-23177] Removed lock. Added property to disable ldap checks

* [MNT-23177] Changed property name

* [MNT-23177] Removed unused imports
2022-09-12 19:22:01 +01:00
Travis CI User
5846a1fd11 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-12 18:06:59 +00:00
Travis CI User
ffef5f875a [maven-release-plugin][skip ci] prepare release 17.106 2022-09-12 18:06:57 +00:00
George Evangelopoulos
fa04a7264f ACS-3485: Change naming (#1372) 2022-09-12 20:33:24 +03:00
Tom Page
6e5d37067d ACS-3531 Ignore testDownloadFileContent since it fails so frequently. 2022-09-12 18:07:18 +01:00
Travis CI User
0bbc63fb20 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-12 13:10:51 +00:00
Travis CI User
2819e0590b [maven-release-plugin][skip ci] prepare release 17.105 2022-09-12 13:10:49 +00:00
MohinishSah
2a84afe2f0 Update pom.xml 2022-09-12 17:53:41 +05:30
Tom Page
80ccf64df8 ACS-3280 Get inherited rule sets. [tas] (#1323)
* ACS-3280 Get inherited rule sets. [tas]

This needs to work the exact same way as get inherited rules.

* ACS-3280 Replace LinkedList with ArrayList.

* ACS-3280 Don't return duplicated rule sets when there are links.
2022-09-12 11:44:42 +01:00
Travis CI User
5cf7c1934a [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-11 00:10:33 +00:00
Travis CI User
25d6b428aa [maven-release-plugin][skip ci] prepare release 17.104 2022-09-11 00:10:31 +00:00
Alfresco CI User
829393b602 [force] Force release for 2022-09-11. 2022-09-11 00:03:39 +00:00
Travis CI User
18d2dfc84d [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-09 10:50:31 +00:00
Travis CI User
8cdff26342 [maven-release-plugin][skip ci] prepare release 17.103 2022-09-09 10:50:29 +00:00
Antonio Felix
8bc3b357cf Fix/mnt 23190 queries to find users not returning results (#1365)
* MNT-23190 - Added "hint:useCQ" in order for the new users to appear on the results
2022-09-09 11:07:15 +01:00
Travis CI User
d2a71d0c9f [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-07 09:48:51 +00:00
Travis CI User
0eb5a4b806 [maven-release-plugin][skip ci] prepare release 17.102 2022-09-07 09:48:48 +00:00
evasques
b8ac41ac0d Revert "ACS-1600 : Error when running propTablesCleanupJob on an env with 100 million records in alf_prop_value (#473)" (#1358)
This reverts commit 00b0b21668.
2022-09-07 10:10:25 +01: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
9c989c424f [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-01 14:10:33 +00:00
Travis CI User
c338001de2 [maven-release-plugin][skip ci] prepare release v1.33 2022-09-01 14:10:30 +00:00
Tom Page
c6519c2a3f Upgrade tas-utility version to use latest TestNG. 2022-09-01 15:05:38 +01: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
Travis CI User
36b3dc25c0 [maven-release-plugin][skip ci] prepare release 17.90 2022-08-19 15:10:18 +00:00
Maciej Pichura
0b94042b6f ACS-3429 post support for actions (#1305)
* ACS-3429: Initial attemp to add action mappings for create rule.

* ACS-3429: Adding rule action validation (TBC).

* ACS-3429: Adding some basic unit tests.

* ACS-3429: Fixing existing unit tests.

* ACS-3429: Adding some unit tests, small fixes.

* ACS-3429: Fixing existing TAS tests.

* ACS-3429: Fixing test after merge from master.

* ACS-3429: Updating TAS REST dependency.

* ACS-3429: Small fixes after review.

* ACS-3429: Refactoring conversion of action parameters + unit tests adjustments.

* ACS-3429: More unit tests for action parameter conversions.

* ACS-3429: More unit tests for action parameter conversions.

* ACS-3429: Removing unused imports.

* ACS-3429: Adding missing bean definition.
2022-08-19 16:29:37 +02:00
Travis CI User
27d3701c8b [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-18 13:53:38 +00:00
Travis CI User
dc0102001f [maven-release-plugin][skip ci] prepare release 17.89 2022-08-18 13:53:36 +00:00
krdabrowski
12bc363bcd ACS-3353: POST support for "other fields" (#1287) 2022-08-18 14:19:39 +01:00
Tom Page
2ab89f0d79 ACS-3280 Is inheritance enabled rule settings. (#1317)
* ACS-3280 REST tests for -isInheritanceEnabled- setting.

* ACS-3280 Allow setting/getting isInheritanceEnabled for folders.

* ACS-3280 E2E tests for negative cases.

* ACS-3280 Unit tests for RuleSettingsImpl. [tas]

* Update to released TAS REST API. [tas]

* ACS-3280 Code review fixes.

* ACS-3280 Use correct version of TAS. [tas]
2022-08-18 10:53:19 +01:00
Travis CI User
807e509859 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-17 08:57:47 +00:00
Travis CI User
403da286e8 [maven-release-plugin][skip ci] prepare release 17.88 2022-08-17 08:57:45 +00:00
mikolajbrzezinski
cc3f8aaff4 ACS-3316 Fix custom models downloading and XSS (#1304)
* Revert "Revert "ACS-3316 Fix HTML sanitisation bypass (#1266)" (#1294)"

This reverts commit 6c407b1ef5.

* ACS-3316 Set node name for download node

* ACS-3316 Update license

Co-authored-by: Damian.Ujma@hyland.com <Damian.Ujma@hyland.com>
2022-08-17 10:14:40 +02:00
George Evangelopoulos
be925ab67d Change exception type (#1316) 2022-08-16 16:44:29 +03:00
Travis CI User
de4ac000dd [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-15 12:59:40 +00:00
Travis CI User
b2b866e0f9 [maven-release-plugin][skip ci] prepare release 17.87 2022-08-15 12:59:38 +00:00
George Evangelopoulos
984bc151af ACS-3290: V1 REST API endpoint for linking to ruleset (#1269)
* ACS-3290: Endpoint for linking to ruleset

* ACS-3290: Small fixes to REST API endpoint definition.

* ACS-3290: Small fixes in bean initialization.

* ACS-3290: Fix changes after rebasing and add exception message

* ACS-3290: Added unit tests

* ACS-3290: Refactoring and moving logic to RulesImpl interface

* ACS-3290: Remove unused imports and refactoring

* ACS-3290: Formatting

Co-authored-by: mpichura <maciej.pichura@hyland.com>
2022-08-15 15:08:40 +03:00
Travis CI User
b057455cde [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-14 00:10:20 +00:00
Travis CI User
40edaccd1a [maven-release-plugin][skip ci] prepare release 17.86 2022-08-14 00:10:18 +00:00
Alfresco CI User
a802a17d92 [force] Force release for 2022-08-14. 2022-08-14 00:03:42 +00:00
Travis CI User
332626421b [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-12 15:16:34 +00:00
Travis CI User
1baf8d6fae [maven-release-plugin][skip ci] prepare release 17.85 2022-08-12 15:16:32 +00:00
Tom Page
4bae0f2060 ACS-3358 Support isShared field. (#1301)
* Use the new include method.

* ACS-3358 Rename the shared field to isShared.

* ACS-3358 Make isShared an optional field.

* ACS-3358 Add TAS tests for the optional isShared field.

* ACS-3358 Upgrade to release version of TAS REST API. [tas]

* ACS-3358 Update test descriptions.

* ACS-3358 Update toString of Rule.
2022-08-12 15:37:57 +01:00
Travis CI User
0c017ac30c [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-11 15:08:22 +00:00
Travis CI User
cc0940e519 [maven-release-plugin][skip ci] prepare release 17.84 2022-08-11 15:08:19 +00:00
dependabot[bot]
0190b9060a Bump email from 1.8 to 1.9 (#1299) 2022-08-11 14:33:55 +00:00
dependabot[bot]
596e964553 Bump cmis from 1.31 to 1.32 (#1300) 2022-08-11 14:01:09 +00:00
dependabot[bot]
5d22e161d7 Bump webdav from 1.6 to 1.7 (#1296) 2022-08-11 13:59:12 +00:00
dependabot[bot]
bb27430f6a Bump dependency.slf4j.version from 1.7.35 to 1.7.36 (#952) 2022-08-11 13:52:38 +00:00
Travis CI User
1af879a7ed [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-11 11:45:25 +00:00
Travis CI User
c029f5afa3 [maven-release-plugin][skip ci] prepare release 17.83 2022-08-11 11:45:22 +00:00
mstrankowski
3b93814d76 Retry tests 2022-08-11 13:07:19 +02:00
mstrankowski
656ecdc41d [skip tests] Retry release 2022-08-11 13:05:41 +02:00
Travis CI User
8150abf8b7 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-11 10:21:56 +00:00
Travis CI User
cab6fd6d2c [maven-release-plugin][skip ci] prepare release 17.82 2022-08-11 10:21:54 +00:00
dependabot[bot]
e45211ad0f Bump ftp from 1.5 to 1.7 (#1297) 2022-08-11 09:48:29 +00:00
Tom Page
414cba0c1a ACS-3361 Upgrade TAS REST API and check nothing is broken. [tas] (#1295) 2022-08-10 16:42:53 +01:00
Travis CI User
75b74a5d77 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-10 13:25:09 +00:00
Travis CI User
d3efea8873 [maven-release-plugin][skip ci] prepare release 17.81 2022-08-10 13:25:05 +00:00
mikolajbrzezinski
6c407b1ef5 Revert "ACS-3316 Fix HTML sanitisation bypass (#1266)" (#1294)
This reverts commit 885f21ff86.
2022-08-10 14:36:25 +02:00
Travis CI User
f7dcbc6551 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-10 10:31:48 +00:00
Travis CI User
ed1ee00cee [maven-release-plugin][skip ci] prepare release 17.80 2022-08-10 10:31:46 +00:00
Tom Page
bba1664fef ACS-3361 Support for inclusionType. (#1286)
* ACS-3361 Support for inclusionType.

* ACS-3361 Update to released version of TAS Rest API. [tas]

* ACS-3361 Better coverage of different inclusion types. [tas]
2022-08-10 10:58:15 +01:00
Travis CI User
c7559ba8b1 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-10 08:56:35 +00:00
Travis CI User
c5fcce20f1 [maven-release-plugin][skip ci] prepare release v1.32 2022-08-10 08:56:34 +00:00
Damian Ujma
0a97d98271 ACS-3351 Upgrade to Java 17 (#62) 2022-08-10 10:38:48 +02:00
Travis CI User
d675d58929 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-09 12:38:17 +00:00
Travis CI User
4f37b984be [maven-release-plugin][skip ci] prepare release 17.79 2022-08-09 12:38:14 +00:00
Marcin Strankowski
9d228add35 Update rest-assured version to 5.1.1, link to newer tas-restapi arti… (#1285)
Update rest-assured version to 5.1.1, link to newer  tas-restapi artifact containing changes
2022-08-09 14:01:44 +02:00
Travis CI User
58d9d0b093 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-09 09:59:45 +00:00
Travis CI User
83cd90c85e [maven-release-plugin][skip ci] prepare for next development iteration 2021-08-02 22:33:17 +00:00
Travis CI User
6186757322 [maven-release-plugin][skip ci] prepare release v1.31 2021-08-02 22:33:11 +00:00
dependabot-preview[bot]
27344421e0 Bump utility from 3.0.44 to 3.0.45 (#61) 2021-08-02 22:25:05 +00:00
Travis CI User
a8f9d4df81 [maven-release-plugin][skip ci] prepare for next development iteration 2021-05-13 11:12:31 +00:00
Travis CI User
366cea6e33 [maven-release-plugin][skip ci] prepare release v1.30 2021-05-13 11:12:27 +00:00
Denis Ungureanu
eb9792339f REPO-5391 : [cmis webservices] isPrivateWorkingCopy throws NullPointerException (#56)
- Alfresco supports BindingType.WEBSERVICES for CMIS 1.0 and "cmis:isPrivateWorkingCopy" was introduced with CMIS 1.1
 - thus checking if the document is a pwc (private working copy) through CMIS 1.0 method https://chemistry.apache.org/java/javadoc/org/apache/chemistry/opencmis/client/api/Document.html#isVersionSeriesPrivateWorkingCopy--
2021-05-13 14:03:48 +03:00
Travis CI User
fcb7ec339f [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-26 22:21:06 +00:00
Travis CI User
110a21cf27 [maven-release-plugin][skip ci] prepare release v1.29 2021-03-26 22:21:02 +00:00
dependabot-preview[bot]
bfc9fdc802 Bump utility from 3.0.43 to 3.0.44 (#53) 2021-03-26 22:17:50 +00:00
Travis CI User
ff8e95e1cf [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-02 22:20:09 +00:00
Travis CI User
8e5a259204 [maven-release-plugin][skip ci] prepare release v1.28 2021-03-02 22:20:02 +00:00
dependabot-preview[bot]
f993a9c904 Bump utility from 3.0.42 to 3.0.43 (#52) 2021-03-02 22:16:40 +00:00
Travis CI User
4cd63227ae [maven-release-plugin][skip ci] prepare for next development iteration 2021-02-04 22:28:37 +00:00
Travis CI User
f42e8b2e82 [maven-release-plugin][skip ci] prepare release v1.27 2021-02-04 22:28:29 +00:00
dependabot-preview[bot]
fff66fea81 Bump utility from 3.0.41 to 3.0.42 (#51) 2021-02-04 22:20:13 +00:00
Travis CI User
451736a9b4 [maven-release-plugin][skip ci] prepare for next development iteration 2020-12-17 22:21:59 +00:00
Travis CI User
7c2ae622ad [maven-release-plugin][skip ci] prepare release v1.26 2020-12-17 22:21:53 +00:00
dependabot-preview[bot]
2d34b3579b Bump utility from 3.0.40 to 3.0.41 (#49) 2020-12-17 22:18:17 +00:00
Travis CI User
78d98bba49 [maven-release-plugin][skip ci] prepare for next development iteration 2020-11-19 22:20:01 +00:00
Travis CI User
d8085b463f [maven-release-plugin][skip ci] prepare release v1.25 2020-11-19 22:19:55 +00:00
dependabot-preview[bot]
1ff9c13985 Bump utility from 3.0.39 to 3.0.40 (#48) 2020-11-19 22:16:08 +00:00
Travis CI User
f23c013950 [maven-release-plugin][skip ci] prepare for next development iteration 2020-11-18 22:19:50 +00:00
Travis CI User
e7f6d7aa15 [maven-release-plugin][skip ci] prepare release v1.24 2020-11-18 22:19:43 +00:00
dependabot-preview[bot]
7d00b5a965 Bump utility from 3.0.38 to 3.0.39 (#47) 2020-11-18 22:15:34 +00:00
Travis CI User
78df8e8f18 [maven-release-plugin][skip ci] prepare for next development iteration 2020-11-12 22:20:38 +00:00
Travis CI User
56fca4f248 [maven-release-plugin][skip ci] prepare release v1.23 2020-11-12 22:20:31 +00:00
dependabot-preview[bot]
7646714e3a Bump utility from 3.0.37 to 3.0.38 (#46) 2020-11-12 22:16:53 +00:00
Travis CI User
68948a568a [maven-release-plugin][skip ci] prepare for next development iteration 2020-11-11 22:23:36 +00:00
Travis CI User
c10c522a00 [maven-release-plugin][skip ci] prepare release v1.22 2020-11-11 22:23:30 +00:00
dependabot-preview[bot]
a6fb00721c Bump utility from 3.0.36 to 3.0.37 (#45) 2020-11-11 22:16:48 +00:00
Travis CI User
b07a96a289 [maven-release-plugin][skip ci] prepare for next development iteration 2020-11-04 22:19:54 +00:00
Travis CI User
fb58ef512e [maven-release-plugin][skip ci] prepare release v1.21 2020-11-04 22:19:48 +00:00
dependabot-preview[bot]
99d4b52ccb Bump utility from 3.0.35 to 3.0.36 (#44) 2020-11-04 22:15:37 +00:00
Travis CI User
6946969ab9 [maven-release-plugin][skip ci] prepare for next development iteration 2020-11-04 11:07:37 +00:00
Travis CI User
e1dbd1d4fe [maven-release-plugin][skip ci] prepare release v1.20 2020-11-04 11:07:31 +00:00
Adina Parpalita
0723852ac3 correctly throw assert error (#43) 2020-11-04 13:04:36 +02:00
Travis CI User
3dbcbfa535 [maven-release-plugin][skip ci] prepare for next development iteration 2020-10-30 14:24:15 +00:00
Travis CI User
163c938848 [maven-release-plugin][skip ci] prepare release v1.19 2020-10-30 14:24:09 +00:00
Adina Parpalita
e334c60d7a remove RuntimeException from catch (#42) 2020-10-30 16:20:03 +02:00
Travis CI User
f159e66c1b [maven-release-plugin][skip ci] prepare for next development iteration 2020-10-28 22:22:18 +00:00
Travis CI User
83e4ace76f [maven-release-plugin][skip ci] prepare release v1.18 2020-10-28 22:22:11 +00:00
dependabot-preview[bot]
c60f940cc1 Bump utility from 3.0.34 to 3.0.35 (#41) 2020-10-28 22:18:42 +00:00
Travis CI User
81abbf55b4 [maven-release-plugin][skip ci] prepare for next development iteration 2020-10-27 22:21:47 +00:00
Travis CI User
f97a9605f2 [maven-release-plugin][skip ci] prepare release v1.17 2020-10-27 22:21:39 +00:00
dependabot-preview[bot]
0c81885ea0 Bump utility from 3.0.33 to 3.0.34 (#40) 2020-10-27 22:16:32 +00:00
Travis CI User
248830e77f [maven-release-plugin][skip ci] prepare for next development iteration 2020-10-13 21:22:03 +00:00
Travis CI User
9c950f767f [maven-release-plugin][skip ci] prepare release v1.16 2020-10-13 21:21:57 +00:00
dependabot-preview[bot]
13b23ad55f Bump utility from 3.0.32 to 3.0.33 (#39) 2020-10-13 21:18:35 +00:00
Travis CI User
01f19d717b [maven-release-plugin][skip ci] prepare for next development iteration 2020-10-08 21:24:15 +00:00
Travis CI User
4aeffd2647 [maven-release-plugin][skip ci] prepare release v1.15 2020-10-08 21:24:09 +00:00
dependabot-preview[bot]
03f02a7687 Bump utility from 3.0.30 to 3.0.32 (#38) 2020-10-08 21:20:35 +00:00
Travis CI User
d70555e60a [maven-release-plugin][skip ci] prepare for next development iteration 2020-09-30 13:20:42 +00:00
Travis CI User
255c6c8e8a [maven-release-plugin][skip ci] prepare release v1.14 2020-09-30 13:20:36 +00:00
Alexandru-Eusebiu Epure
961b336c11 Add WS support - alfa version. (#37)
* Add support for WS Binding - alfa stage.
2020-09-30 15:57:54 +03:00
dependabot-preview[bot]
ec79172479 Bump utility from 3.0.29 to 3.0.30 (#36) 2020-09-25 21:18:48 +00:00
dependabot-preview[bot]
47de5d9e0a Bump utility from 3.0.28 to 3.0.29 (#32) 2020-08-31 21:20:26 +00:00
dependabot-preview[bot]
4cb843024c Bump utility from 3.0.27 to 3.0.28 (#31) 2020-08-28 21:19:22 +00:00
dependabot-preview[bot]
b8cb5d89a6 Bump utility from 3.0.26 to 3.0.27 (#29) 2020-07-21 21:45:50 +00:00
dependabot-preview[bot]
d61e5826f7 Bump utility from 3.0.25 to 3.0.26 (#28) 2020-07-14 21:31:16 +00:00
dependabot-preview[bot]
8238947ee0 Bump utility from 3.0.24 to 3.0.25 (#27) 2020-07-10 21:33:37 +00:00
dependabot-preview[bot]
129dac1916 Bump utility from 3.0.23 to 3.0.24 (#26) 2020-07-07 21:23:52 +00:00
dependabot-preview[bot]
cb5548914a Bump utility from 3.0.22 to 3.0.23 (#25) 2020-07-02 21:20:47 +00:00
dependabot-preview[bot]
32b66fad2b Bump utility from 3.0.21 to 3.0.22 (#24) 2020-07-01 21:23:03 +00:00
dependabot-preview[bot]
475dd43a32 Bump utility from 3.0.20 to 3.0.21 (#22) 2020-06-15 21:23:58 +00:00
dependabot-preview[bot]
178ae7375a Bump utility from 3.0.19 to 3.0.20 (#16) 2020-02-26 22:18:06 +00:00
dependabot-preview[bot]
d935b7fc2e Bump utility from 3.0.18 to 3.0.19 (#13) 2020-01-23 22:16:28 +00:00
Travis CI User
5bb26afe91 [maven-release-plugin][skip ci] prepare for next development iteration 2020-01-15 22:25:55 +00:00
Travis CI User
8c121889ae [maven-release-plugin][skip ci] prepare release v1.13 2020-01-15 22:25:49 +00:00
dependabot-preview[bot]
e241c2a4ec Bump utility from 3.0.17 to 3.0.18 (#12) 2020-01-15 22:17:05 +00:00
Travis CI User
da1fd787e7 [maven-release-plugin][skip ci] prepare for next development iteration 2019-12-17 23:29:59 +00:00
Travis CI User
0cf76c6d3f [maven-release-plugin][skip ci] prepare release v1.12 2019-12-17 23:29:53 +00:00
dependabot-preview[bot]
347c05c855 Bump utility from 3.0.16 to 3.0.17 (#9) 2019-12-17 22:56:44 +00:00
Travis CI User
440a3640a9 [maven-release-plugin][skip ci] prepare for next development iteration 2019-12-04 23:07:44 +00:00
Travis CI User
9d4c92bedf [maven-release-plugin][skip ci] prepare release v1.11 2019-12-04 23:07:39 +00:00
dependabot-preview[bot]
e5655effee Bump utility from 3.0.15 to 3.0.16 (#8) 2019-12-04 22:29:55 +00:00
Travis CI User
cf6495a22c [maven-release-plugin][skip ci] prepare for next development iteration 2019-11-30 00:00:11 +00:00
Travis CI User
f917f67a00 [maven-release-plugin][skip ci] prepare release v1.10 2019-11-30 00:00:06 +00:00
dependabot-preview[bot]
f33e7b9555 Bump utility from 3.0.14 to 3.0.15 (#7) 2019-11-29 22:34:36 +00:00
Travis CI User
cfec11a246 [maven-release-plugin][skip ci] prepare for next development iteration 2019-11-29 16:34:51 +00:00
Travis CI User
c066e42152 [maven-release-plugin][skip ci] prepare release v1.9 2019-11-29 16:34:45 +00:00
Tom Page
d2ab9a7998 SEARCH-1989 Allow checking ordered values returned in a column. (#6) 2019-11-29 16:27:05 +00:00
Travis CI User
15dea80d0a [maven-release-plugin][skip ci] prepare for next development iteration 2019-11-29 14:53:58 +00:00
Travis CI User
28ef5fa32c [maven-release-plugin][skip ci] prepare release v1.8 2019-11-29 14:53:52 +00:00
Tom Page
7da7544c37 SEARCH-1989 Allow checking values returned in a column. (#1) 2019-11-29 14:50:05 +00:00
Travis CI User
98bc091adc [maven-release-plugin][skip ci] prepare for next development iteration 2019-11-29 14:44:01 +00:00
Travis CI User
8839ed7027 [maven-release-plugin][skip ci] prepare release v1.7 2019-11-29 14:43:55 +00:00
dependabot-preview[bot]
3ee1db50f8 Bump utility from 3.0.8 to 3.0.14 (#3) 2019-11-29 14:35:21 +00:00
dependabot-preview[bot]
3fbbf5a891 Bump chemistry-opencmis-commons-api from 1.0.0 to 1.1.0 (#2) 2019-11-29 14:32:03 +00:00
Travis CI User
fb7e03b02f [maven-release-plugin][skip ci] prepare for next development iteration 2019-08-02 15:58:13 +00:00
Travis CI User
e6e1245a7a [maven-release-plugin][skip ci] prepare release v1.6 2019-08-02 15:58:07 +00:00
Alex Mukha
2e499fb377 Remove source jar config 2019-08-02 16:53:26 +01:00
Alex Mukha
b25dbeb608 Remove test jar 2019-08-02 16:52:58 +01:00
Alex Mukha
8fba004f83 Remove unused properties from pom 2019-08-02 16:49:34 +01:00
Alex Mukha
47b391315b Fix pom formatting 2019-08-02 16:48:22 +01:00
Travis CI User
deade9c64c [maven-release-plugin][skip ci] prepare for next development iteration 2019-08-02 15:13:30 +00:00
Travis CI User
ffe1d0a158 [maven-release-plugin][skip ci] prepare release v1.5 2019-08-02 15:13:24 +00:00
Alex Mukha
1cd2352dc9 Cleanup of resources 2019-08-02 16:09:11 +01:00
Travis CI User
a27871e7a7 [maven-release-plugin][skip ci] prepare for next development iteration 2019-08-02 14:59:03 +00:00
Travis CI User
030363d7c0 [maven-release-plugin][skip ci] prepare release v1.4 2019-08-02 14:58:57 +00:00
Alex Mukha
0af021b469 Release 1.4 2019-08-02 15:53:53 +01:00
Travis CI User
0dc4f3fbf7 [maven-release-plugin][skip ci] prepare for next development iteration 2019-08-02 14:33:56 +00:00
Travis CI User
988846e1df [maven-release-plugin][skip ci] prepare release v1.3 2019-08-02 14:33:50 +00:00
Alex Mukha
67e366def2 Release 1.3 2019-08-02 15:29:05 +01:00
Travis CI User
a673102baf [maven-release-plugin][skip ci] prepare for next development iteration 2019-08-02 14:24:20 +00:00
Travis CI User
652c0784d5 [maven-release-plugin][skip ci] prepare release v1.2 2019-08-02 14:24:14 +00:00
Alex Mukha
5ca5e96b7e Fix javadoc on JDK11 2019-08-02 15:19:08 +01:00
Travis CI User
ed39b9a114 [maven-release-plugin][skip ci] prepare for next development iteration 2019-08-02 14:15:22 +00:00
Travis CI User
35e543f37d [maven-release-plugin][skip ci] prepare release v1.1 2019-08-02 14:15:17 +00:00
Alex Mukha
a8585b55cb Add compiler plugin config to run on JDK11 2019-08-02 15:09:19 +01:00
Travis CI User
3ffb350567 [maven-release-plugin][skip ci] prepare for next development iteration 2019-08-02 14:03:49 +00:00
Travis CI User
4d2073e4c5 [maven-release-plugin][skip ci] prepare release v1.0 2019-08-02 14:03:43 +00:00
Alex Mukha
19ebec0320 Update build agent to xenial 2019-08-01 22:41:13 +01:00
Alex Mukha
0c23a3fa4b Initial version after move 2019-08-01 22:34:53 +01:00
Alex Mukha
3c2269f51c Initial commit 2019-08-01 22:30:29 +01:00
266 changed files with 20322 additions and 2437 deletions

View File

@@ -53,7 +53,7 @@ jobs:
- name: "Source Clear Scan (SCA)"
stage: test
if: branch = master OR branch =~ /release\/.*/
if: (branch = master OR branch =~ /release\/.*/) AND type != pull_request
# Run Veracode
install: skip
script: travis_wait 30 bash scripts/travis/source_clear.sh
@@ -264,6 +264,7 @@ jobs:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 60 mvn -B verify -f packaging/tests/tas-restapi/pom.xml -Pall-tas-tests,run-restapi-part1 -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-restapi"
- name: "REST API TAS tests part2"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
@@ -272,6 +273,7 @@ jobs:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 60 mvn -B verify -f packaging/tests/tas-restapi/pom.xml -Pall-tas-tests,run-restapi-part2 -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-restapi"
- name: "REST API TAS tests part3"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
@@ -280,6 +282,7 @@ jobs:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 60 mvn -B verify -f packaging/tests/tas-restapi/pom.xml -Pall-tas-tests,run-restapi-part3 -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-restapi"
- name: "CMIS TAS tests - BROWSER binding"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
@@ -288,6 +291,7 @@ jobs:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 40 mvn -B verify -f packaging/tests/tas-cmis/pom.xml -Pall-tas-tests,run-cmis-browser -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-cmis"
- name: "CMIS TAS tests - ATOM binding"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
@@ -296,6 +300,7 @@ jobs:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 40 mvn -B verify -f packaging/tests/tas-cmis/pom.xml -Pall-tas-tests,run-cmis-atom -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-cmis"
- name: "CMIS TAS tests - WEBSERVICES binding"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
@@ -304,6 +309,7 @@ jobs:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 40 mvn -B verify -f packaging/tests/tas-cmis/pom.xml -Pall-tas-tests,run-cmis-webservices -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-cmis"
- name: "Email TAS tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
@@ -312,6 +318,7 @@ jobs:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 30 mvn -B verify -f packaging/tests/tas-email/pom.xml -Pall-tas-tests -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-email"
- name: "WebDAV TAS tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
@@ -320,6 +327,7 @@ jobs:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 30 mvn -B verify -f packaging/tests/tas-webdav/pom.xml -Pall-tas-tests -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-webdav"
- name: "Integration TAS tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
@@ -327,7 +335,9 @@ jobs:
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
- travis_retry travis_wait 40 mvn install -pl :alfresco-community-repo-integration-test -am -DskipTests -Pall-tas-tests
script: travis_wait 30 mvn -B verify -f packaging/tests/tas-integration/pom.xml -Pall-tas-tests -Denvironment=default -DrunBugs=false
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-integration"
- name: "Share Services - ShareServicesTestSuite"
if: commit_message !~ /\[skip repo\]/

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<build>
@@ -45,7 +45,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
<version>1.7.35</version>
<version>${dependency.slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@@ -0,0 +1,73 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* 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.v0;
import org.alfresco.rest.core.v0.BaseAPI;
import org.apache.http.HttpResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.List;
/**
* Methods to make API requests using v0 API for Linking Records
*
* @author Kavit Shah
* @since 3.2
*/
@Component
public class LinksAPI extends BaseAPI {
private static final String LINK_API = "{0}doclib/action/rm-link/site/rm/documentLibrary/{1}";
/**
* Creates the Link
*
* @param user The username of the user to use.
* @param password The password of the user.
* @param expectedStatusCode The expected return status code.
* @param sourcePath The Source of link the record. This should be in the format
* "{site}/{container}/{path}", "{site}/{container}", "{store_type}/{store_id}/{id}/{path}",
* "{store_type}/{store_id}/{id}" or "{store_type}/{store_id}".
* @param nodeRefs The Node that needs to be linked.
* @return The HTTP Response.
* @throws AssertionError If the API didn't return the expected status code.
*/
public HttpResponse linkRecord(String user, String password, int expectedStatusCode, String sourcePath, List<String> nodeRefs) throws UnsupportedEncodingException {
JSONObject requestParams = new JSONObject();
requestParams.put("nodeRefs", new JSONArray(nodeRefs));
return doSlingshotPostJsonRequest(user, password, expectedStatusCode, requestParams,
MessageFormat.format(LINK_API, "{0}", sourcePath));
}
}

View File

@@ -52,7 +52,7 @@ public class RecordCategoriesAPI extends BaseAPI
private static final String RM_ACTIONS_API = "{0}rma/actions/ExecutionQueue";
private static final String DISPOSITION_ACTIONS_API = "{0}node/{1}/dispositionschedule/dispositionactiondefinitions";
private static final String DISPOSITION_SCHEDULE_API = "{0}node/{1}/dispositionschedule";
private static final String NEXT_DISPOSITION_ACTIONS_API = "{0}node/{1}/nextdispositionaction";
/**
* Creates a retention schedule for the category given as parameter
@@ -191,4 +191,19 @@ public class RecordCategoriesAPI extends BaseAPI
retentionProperties.put(RETENTION_SCHEDULE.RETENTION_INSTRUCTIONS, instructions);
return retentionProperties;
}
/**
* Get the Next Disposition Action
*
* @param user
* @param password
* @param recordId
* @return the next disposition schedule action
*/
public JSONObject getNextDispositionAction(String user, String password, String recordId)
{
String nodeRef = NODE_PREFIX + recordId;
JSONObject nextDispositionAction = doGetRequest(user, password, MessageFormat.format(NEXT_DISPOSITION_ACTIONS_API, "{0}", nodeRef));
return nextDispositionAction;
}
}

View File

@@ -72,6 +72,7 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
import org.alfresco.utility.model.TestGroup;
@@ -259,6 +260,7 @@ public class DeclareAndFileDocumentAsRecordTests extends BaseRMRestTest
* And the document is not declared as a record
*/
@Test (dataProvider = "invalidDestinationPaths",groups = { TestGroup.NOT_SUPPORTED_ON_SINGLE_PIPELINE })
@Ignore
public void declareAndFileToInvalidLocationUsingActionsAPI(String containerPath, String expectedException) throws Exception
{
STEP("Declare document as record with an invalid location parameter value");

View File

@@ -61,6 +61,7 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
import org.alfresco.utility.model.TestGroup;
@@ -209,6 +210,7 @@ public class FileVersionAsRecordTests extends BaseRMRestTest
* And the document is not declared as a version record
*/
@Test (dataProvider = "invalidDestinationPaths", groups = { TestGroup.NOT_SUPPORTED_ON_SINGLE_PIPELINE })
@Ignore
public void declareVersionAndFileToInvalidLocationUsingActionsAPI(String containerPath, String expectedException) throws Exception
{
STEP("Declare document as record version with an invalid location parameter value");

View File

@@ -0,0 +1,311 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* 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.rm.community.records;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.rules.ActionsOnRule;
import org.alfresco.rest.rm.community.model.rules.RuleDefinition;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainer;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildCollection;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.rest.v0.RulesAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static java.util.Arrays.asList;
import static org.alfresco.rest.core.v0.BaseAPI.NODE_PREFIX;
import static org.alfresco.rest.core.v0.BaseAPI.RM_SITE_ID;
import static org.alfresco.rest.rm.community.base.TestData.DEFAULT_PASSWORD;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.CREATED_DATE;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
import static org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI.PARENT_ID_PARAM;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.HttpStatus.CREATED;
public class DeclareInPlaceRecordsTestLevel2 extends BaseRMRestTest {
private final String TEST_PREFIX = generateTestPrefix(DeclareInPlaceRecordsTestLevel2.class);
private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
private final String RECORDS_CATEGORY_ONE = TEST_PREFIX + "category";
public static final String RECORD_FOLDER_ONE = "record-folder-one";
public static final String RECORD_CATEGORY_TWO = "record-category-two" + System.currentTimeMillis();
public static final String RECORD_FOLDER_TWO = "record-folder-two";
private final String RULE_NAME = TEST_PREFIX + "rule unfiled";
private String unfiledRecordsNodeRef;
private RecordCategory RecordCategoryOne, RecordCategoryTwo;
private RecordCategoryChild recordFolder;
private UnfiledContainer unfiledContainer;
private FolderModel testFolder;
private SiteModel testSite;
private SiteModel privateSite;
private UserModel testUser;
@Autowired
private DispositionScheduleService dispositionScheduleService;
@Autowired
private RulesAPI rulesAPI;
/**
* data prep services
*/
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired
private RecordsAPI recordsAPI;
@BeforeClass(alwaysRun = true)
public void preConditions() {
STEP("Create RM Site");
createRMSiteIfNotExists();
privateSite = dataSite.usingAdmin().createPrivateRandomSite();
}
/**
* Given that a user is the owner of a document
* And that user has been deleted
* When admin tries to declare the document as a record
* Then the document becomes an inplace record
*/
@Test
@AlfrescoTest(jira="RM-2584")
public void DeclareRecordOwnerDeleted() throws Exception {
createTestPrecondition();
// Upload document in a folder in a collaboration site
FileModel uploadedDoc = dataContent.usingSite(testSite)
.usingUser(testUser)
.usingResource(testFolder)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
// delete the test user
dataUser.deleteUser(testUser);
// declare uploadedDocument as record
getRestAPIFactory().getFilesAPI(getDataUser().getAdminUser()).declareAsRecord(uploadedDoc.getNodeRefWithoutVersion());
assertStatusCode(CREATED);
// assert that the document is now a record
assertTrue(hasRecordAspect(uploadedDoc));
}
/**
* Given that a user is the owner of a document
* And that user declare the document as a record
* When admin files the record to a category that has a disposition schedule applied on records and a cut off step
* And admin completes the record so the pending record action is now Cut off
* Then user is still able to see the in place record in original share site location
*/
@Test
@AlfrescoTest(jira="MNT-18558")
public void inPlaceRecordVisibilityAfterFilingToCategoryWithCutOffStep() throws Exception {
// create test precondition
createTestPrecondition(RECORDS_CATEGORY_ONE);
//create a disposition schedule on Records level with a cut off step
dispositionScheduleService.createCategoryRetentionSchedule(RECORDS_CATEGORY_ONE, true);
dispositionScheduleService.addCutOffAfterPeriodStep(RECORDS_CATEGORY_ONE, "day|2", CREATED_DATE);
//create a folder in category
recordFolder = createFolder(getAdminUser(),RecordCategoryOne.getId(),RECORD_FOLDER_ONE);
// create a File to record folder rule applied on Unfiled Records container
fileToRuleAppliedOnUnfiledRecords();
//create a new test user
UserModel testUser = createSiteManager();
// upload a new document as the user and declare the document as record
FileModel uploadedDoc = dataContent.usingSite(privateSite)
.usingUser(testUser)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
Record uploadedRecord = getRestAPIFactory().getFilesAPI(getDataUser().getAdminUser()).declareAsRecord(uploadedDoc.getNodeRefWithoutVersion());
assertStatusCode(CREATED);
//Complete the record as admin to be sure that pending action is now Cut off
recordsAPI.completeRecord(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), uploadedRecord.getName());
// As test user navigate to collaboration site documents library and check that the record is still visible
dataContent.usingAdmin().usingSite(privateSite).assertContentExist();
}
/**
* Create a user called test
* Create a collaboration site
* Add the user to the collaboration site as consumer
* Create an RM site
* In RM, create a new categories under file plan with a cut off step set after an event happens
* Under the previously created category create a folder
* Set READ-ONLY permission for test user for the folder previously created (the user does not have Read
* permissions to the category containing the folder)
* In the collaboration site create two files
* File as record the first file
* Log in with test user and check if he can still see the two files in the collaboration site
*/
@Test
@AlfrescoTest (jira = "MNT-22138")
public void filesVisibilityAfterFilingToCategoryWithCutOffAfterEventStep() throws Exception {
//create a category
RecordCategoryTwo = createRootCategory(RECORD_CATEGORY_TWO);
//create a disposition schedule on Records level with a cut off step
dispositionScheduleService.createCategoryRetentionSchedule(RECORD_CATEGORY_TWO, true);
dispositionScheduleService.addCutOffAfterPeriodStep(RECORD_CATEGORY_TWO, "day|2", CREATED_DATE);
//create a folder in category
recordFolder = createFolder(getAdminUser(),RecordCategoryTwo.getId(),RECORD_FOLDER_TWO);
//create a new test user
UserModel siteConsumer = getDataUser().createRandomTestUser();
getDataUser().addUserToSite(siteConsumer,privateSite,UserRole.SiteConsumer);
// give read permissions to test user
getRestAPIFactory().getRMUserAPI().addUserPermission(recordFolder.getId(), siteConsumer, PERMISSION_READ_RECORDS);
// create two documents
FileModel testFile = dataContent.usingSite(new SiteModel(privateSite.getTitle()))
.usingAdmin()
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
FileModel testFileNotFiled = dataContent.usingSite(new SiteModel(privateSite.getTitle()))
.usingAdmin()
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
// file one of the documents as record
getRestAPIFactory().getFilesAPI()
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, recordFolder.getId()))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
getRestAPIFactory().getRmRestWrapper().assertStatusCodeIs(CREATED);
// As test user navigate to collaboration site documents library and check that both of the documents are
// visible
STEP("Verify the document in collaboration site is now a record");
Assert.assertTrue(hasRecordAspect(testFile), "File should have record aspect");
Assert.assertFalse(hasRecordAspect(testFileNotFiled), "File should not have record aspect");
}
private void createTestPrecondition(String categoryName) {
// create "rm admin" user if it does not exist and assign it to RM Administrator role
rmRolesAndActionsAPI.createUserAndAssignToRole(
getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),
RM_ADMIN, DEFAULT_PASSWORD, "Administrator");
// create category
STEP("Create category");
RecordCategoryOne = createRootCategory(categoryName,"Title");
unfiledContainer = getRestAPIFactory().getUnfiledContainersAPI().getUnfiledContainer(UNFILED_RECORDS_CONTAINER_ALIAS);
unfiledRecordsNodeRef = NODE_PREFIX + unfiledContainer.getId();
}
private void createTestPrecondition() {
STEP("Create collab_user user");
testUser = getDataUser().createRandomTestUser();
testSite = dataSite.usingAdmin().createPublicRandomSite();
// invite collab_user to Collaboration site with Contributor role
getDataUser().addUserToSite(testUser, testSite, UserRole.SiteContributor);
testFolder = dataContent.usingSite(testSite).usingUser(testUser).createFolder();
}
private void fileToRuleAppliedOnUnfiledRecords() {
unfiledRecordsRuleTeardown();
// create a rule
RuleDefinition ruleDefinition = RuleDefinition.createNewRule().title(RULE_NAME)
.description(RULE_NAME)
.createRecordPath(false)
.path("/" + RECORDS_CATEGORY_ONE + "/" + RECORD_FOLDER_ONE)
.runInBackground(true)
.actions(asList(ActionsOnRule.FILE_TO.getActionValue()));
// create a rule on unfiledRecords
rulesAPI.createRule(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), unfiledRecordsNodeRef, ruleDefinition);
}
private void unfiledRecordsRuleTeardown() {
rulesAPI.deleteAllRulesOnContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), unfiledRecordsNodeRef);
}
public UserModel createSiteManager() {
UserModel siteManager = getDataUser().createRandomTestUser();
getDataUser().addUserToSite(siteManager, privateSite, UserRole.SiteManager);
return siteManager;
}
@AfterClass
public void cleanupCategory() {
unfiledRecordsRuleTeardown();
rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, RECORD_FOLDER_ONE);
rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, RecordCategoryOne.getName());
deleteRecordCategory(RecordCategoryOne.getId());
rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, RECORD_FOLDER_TWO);
rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, RecordCategoryTwo.getName());
deleteRecordCategory(RecordCategoryTwo.getId());
dataSite.usingAdmin().deleteSite(privateSite);
dataSite.usingAdmin().deleteSite(testSite);
UnfiledContainerChildCollection unfiledContainerChildCollection = getRestAPIFactory()
.getUnfiledContainersAPI().getUnfiledContainerChildren(unfiledContainer.getId());
unfiledContainerChildCollection.getEntries().forEach(unfiledChild ->
{
if (unfiledChild.getEntry().getIsRecord())
{
getRestAPIFactory().getRecordsAPI().deleteRecord(unfiledChild.getEntry().getId());
}
else
{
getRestAPIFactory().getUnfiledRecordFoldersAPI().deleteUnfiledRecordFolder(unfiledChild.getEntry().getId());
}
});
}
}

View File

@@ -75,6 +75,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
/**
@@ -102,7 +103,7 @@ public class DeleteRecordTests extends BaseRMRestTest
testSite = dataSite.usingAdmin().createPublicRandomSite();
recordFolder = createCategoryFolderInFilePlan();
unfiledRecordFolder = createUnfiledContainerChild(UNFILED_RECORDS_CONTAINER_ALIAS, getRandomName("Unfiled Folder "),
UNFILED_RECORD_FOLDER_TYPE);
UNFILED_RECORD_FOLDER_TYPE);
}
/** Data provider with electronic and non-electronic records to be deleted */
@@ -133,10 +134,10 @@ public class DeleteRecordTests extends BaseRMRestTest
* </pre>
*/
@Test
(
dataProvider = "recordsToBeDeleted",
description = "Admin user can delete records"
)
(
dataProvider = "recordsToBeDeleted",
description = "Admin user can delete records"
)
@AlfrescoTest(jira="RM-4363")
public void adminCanDeleteRecords(String recordId)
{
@@ -154,17 +155,17 @@ public class DeleteRecordTests extends BaseRMRestTest
* </pre>
*/
@Test
(
description = "User without write permissions can't delete a record"
)
(
description = "User without write permissions can't delete a record"
)
@AlfrescoTest(jira="RM-4363")
public void userWithoutWritePermissionsCantDeleteRecord()
{
// Create a non-electronic record in unfiled records
UnfiledContainerChild nonElectronicRecord = UnfiledContainerChild.builder()
.name("Record " + RandomData.getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE)
.build();
.name("Record " + RandomData.getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE)
.build();
UnfiledContainerChild newRecord = getRestAPIFactory().getUnfiledContainersAPI().createUnfiledContainerChild(nonElectronicRecord, UNFILED_RECORDS_CONTAINER_ALIAS);
assertStatusCode(CREATED);
@@ -187,9 +188,9 @@ public class DeleteRecordTests extends BaseRMRestTest
* </pre>
*/
@Test
(
description = "User without delete records capability can't delete a record"
)
(
description = "User without delete records capability can't delete a record"
)
@AlfrescoTest(jira="RM-4363")
public void userWithoutDeleteRecordsCapabilityCantDeleteRecord()
{
@@ -234,7 +235,7 @@ public class DeleteRecordTests extends BaseRMRestTest
STEP("Create a record in first folder and copy it into second folder.");
String recordId = getRestAPIFactory().getRecordFolderAPI()
.createRecord(createElectronicRecordModel(), recordFolder.getId(), getFile(IMAGE_FILE)).getId();
.createRecord(createElectronicRecordModel(), recordFolder.getId(), getFile(IMAGE_FILE)).getId();
String copyId = copyNode(recordId, recordFolderB.getId()).getId();
assertStatusCode(CREATED);
@@ -318,14 +319,14 @@ public class DeleteRecordTests extends BaseRMRestTest
RecordCategoryChild recFolder = createFolder(recordCategory.getId(), getRandomName("recFolder"));
RecordBodyFile recordBodyFile = RecordBodyFile.builder().targetParentId(recFolder.getId()).build();
Record recordFiled = getRestAPIFactory().getRecordsAPI().fileRecord(recordBodyFile, testFile.getNodeRefWithoutVersion());
getRestAPIFactory().getRecordsAPI().completeRecord(recordFiled.getId());
assertStatusCode(CREATED);
completeRecord(recordFiled.getId());
assertStatusCode(OK);
STEP("Execute the disposition schedule steps.");
rmRolesAndActionsAPI.executeAction(getAdminUser().getUsername(), getAdminUser().getUsername(), recordFiled.getName(),
RM_ACTIONS.CUT_OFF);
RM_ACTIONS.CUT_OFF);
rmRolesAndActionsAPI.executeAction(getAdminUser().getUsername(), getAdminUser().getUsername(), recordFiled.getName(),
RM_ACTIONS.DESTROY);
RM_ACTIONS.DESTROY);
STEP("Check that it's possible to load the copy content.");
getNodeContent(copy.getId());
@@ -348,14 +349,14 @@ public class DeleteRecordTests extends BaseRMRestTest
STEP("Declare file version as record.");
recordsAPI.declareDocumentVersionAsRecord(getAdminUser().getUsername(), getAdminUser().getPassword(), testSite.getId(),
testFile.getName());
testFile.getName());
UnfiledContainerChild unfiledContainerChild = getRestAPIFactory().getUnfiledContainersAPI()
.getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
.getEntries().stream()
.filter(child -> child.getEntry().getName()
.startsWith(testFile.getName().substring(0, testFile.getName().indexOf("."))))
.findFirst()
.get().getEntry();
.getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
.getEntries().stream()
.filter(child -> child.getEntry().getName()
.startsWith(testFile.getName().substring(0, testFile.getName().indexOf("."))))
.findFirst()
.get().getEntry();
STEP("Delete the record.");
deleteAndVerify(unfiledContainerChild.getId());

View File

@@ -0,0 +1,128 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* 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.rm.community.records;
import org.alfresco.dataprep.ContentService;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.test.AlfrescoTest;
import org.apache.commons.httpclient.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import static org.alfresco.rest.core.v0.BaseAPI.RM_SITE_ID;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
/**
* Tests to cover share action for records
* @author Kavit Shah
*/
public class ShareRecordsTest extends BaseRMRestTest {
/** data prep services*/
@Autowired
private RecordsAPI service;
@Autowired
private ContentService contentService;
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
/** Constants*/
private final String TEST_PREFIX = generateTestPrefix(ShareRecordsTest.class);
private final String CATEGORY = "CategoryWithSharedRecords" + TEST_PREFIX;
private final String FOLDER = "FolderWithSharedRecords" + TEST_PREFIX;
private final String ELECTRONIC_RECORD = "ELECTRONIC_RECORD" + TEST_PREFIX;
private final String NONELECTRONIC_REC = "NON_ELECTRONIC_RECORD" + TEST_PREFIX;
private RecordCategory category;
private RecordCategoryChild recordCategoryChild;
/**
* Given a record
* When admin tries to share it via API
* Then the record can't be shared
*/
@Test
@AlfrescoTest(jira = "RM-5308")
public void shareRecordViaApi()
{
//create RM Site
createRMSiteIfNotExists();
//create a category
category = createRootCategory(CATEGORY);
//create folder
recordCategoryChild = createFolder(category.getId(),FOLDER);
createNonElectronicRecord(recordCategoryChild.getId(),NONELECTRONIC_REC);
// create record to be shared
createElectronicRecord(recordCategoryChild.getId(),ELECTRONIC_RECORD);
//get the node id for the ELECTRONIC_RECORD created
String nodeRefRec1= contentService.getNodeRefByPath(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),
"/Sites/" + RM_SITE_ID + "/documentLibrary/" + CATEGORY + "/" + FOLDER + "/" + service.getRecordFullName(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), FOLDER, ELECTRONIC_RECORD));
//check record can't be shared
assertFalse("The record has been succesfully shared",
service.shareDocument(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),nodeRefRec1 ).getKey());
//check the error code when trying to share a record
assertEquals("The API response code is not " + HttpStatus.SC_INTERNAL_SERVER_ERROR, service.shareDocument(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), nodeRefRec1).getValue(),
String.valueOf( HttpStatus.SC_INTERNAL_SERVER_ERROR));
//get the node id for NONELECTRONIC_REC created
String nodeRefRec2 = contentService.getNodeRefByPath(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),
"/Sites/" + RM_SITE_ID + "/documentLibrary/" + CATEGORY + "/" + FOLDER + "/" + service.getRecordFullName(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), FOLDER, NONELECTRONIC_REC));
//check record can't be shared
assertFalse("The record has been succesfully shared",
service.shareDocument(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), nodeRefRec2).getKey());
//check the error code when trying to share a record
assertEquals("The API response code is not " + HttpStatus.SC_INTERNAL_SERVER_ERROR, service.shareDocument(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), nodeRefRec2).getValue(),
String.valueOf(HttpStatus.SC_INTERNAL_SERVER_ERROR));
}
@AfterClass
public void cleanupCategory() {
rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, recordCategoryChild.getName());
rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, category.getName());
deleteRecordCategory(category.getId());
}
}

View File

@@ -0,0 +1,121 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* 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.rm.community.smoke;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.RecordFoldersAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.test.AlfrescoTest;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.CREATED_DATE;
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.CUT_OFF_DATE;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.rest.rm.community.utils.CoreUtil.createBodyForMoveCopy;
import static org.alfresco.rest.rm.community.utils.CoreUtil.toContentModel;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.OK;
import static org.testng.AssertJUnit.assertNotNull;
public class DestroyRecordFolderActionsTest extends BaseRMRestTest {
private RecordCategory Category1,CATEGORY_TO_MOVE;
@Autowired
private DispositionScheduleService dispositionScheduleService;
@Autowired
private RecordFoldersAPI recordFoldersAPI;
private final String TEST_PREFIX = generateTestPrefix(DestroyRecordFolderActionsTest.class);
private final String folderDisposition = TEST_PREFIX + "RM-2937 folder ghosting";
@BeforeClass(alwaysRun = true)
private void setUp(){
STEP("Create the RM site if doesn't exist");
createRMSiteIfNotExists();
STEP("Create two record category");
Category1 = createRootCategory(getRandomName("Category1"));
CATEGORY_TO_MOVE = createRootCategory(getRandomName("CATEGORY_TO_MOVE"));
//create retention schedule
dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), false);
// add cut off step
dispositionScheduleService.addCutOffAfterPeriodStep(Category1.getName(), "day|2", CREATED_DATE);
// add destroy step with ghosting
dispositionScheduleService.addDestroyWithGhostingImmediatelyAfterCutOff(Category1.getName());
}
@Test
@AlfrescoTest (jira = "RM-1621")
public void moveOnCutOffDestroyFolders() throws Exception {
//create folders
RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
// edit disposition date
recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),FOLDER_DESTROY.getName());
// cut off the FOLDER_DESTROY
recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),FOLDER_DESTROY.getName());
// Destroy the FOLDER_DESTROY
recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","destroy"),FOLDER_DESTROY.getName());
//Move the FOLDER_DESTROY within the CATEGORY_TO_MOVE.");
getRestAPIFactory().getNodeAPI(toContentModel(FOLDER_DESTROY.getId())).move(createBodyForMoveCopy(CATEGORY_TO_MOVE.getId()));
assertStatusCode(OK);
}
@AfterMethod(alwaysRun = true)
private void deletePreconditions() {
deleteRecordCategory(Category1.getId());
deleteRecordCategory(CATEGORY_TO_MOVE.getId());
}
}

View File

@@ -0,0 +1,425 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* 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.rm.community.smoke;
import org.alfresco.rest.core.v0.RMEvents;
import org.alfresco.rest.model.RestNodeBodyMoveCopyModel;
import org.alfresco.rest.model.RestNodeModel;
import org.alfresco.rest.requests.Node;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.fileplan.FilePlan;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.v0.LinksAPI;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.RecordFoldersAPI;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.UserModel;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.AssertJUnit;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import static org.alfresco.rest.core.v0.BaseAPI.NODE_REF_WORKSPACE_SPACES_STORE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.CUT_OFF_ASPECT;
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.*;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.HttpStatus.NO_CONTENT;
public class DispositionScheduleLinkedRecordsTest extends BaseRMRestTest {
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired
private DispositionScheduleService dispositionScheduleService;
@Autowired
private LinksAPI linksAPI;
@Autowired
private RecordsAPI recordsAPI;
@Autowired
private RecordFoldersAPI recordFoldersAPI;
private final static String TEST_PREFIX = generateTestPrefix(DispositionScheduleLinkedRecordsTest.class);
private RecordCategory Category1,catsameLevel1,catsameLevel2;
private RecordCategoryChild CopyCatFolder,folder1,CatFolder,folder2;
private static final String categoryRM3077 = TEST_PREFIX + "RM-3077_manager_sees_me";
private static final String copyCategoryRM3077 = "Copy_of_" + categoryRM3077;
private static final String folderRM3077 = "RM-3077_folder_"+ categoryRM3077;
private static final String copyFolderRM3077 = "Copy_of_" + folderRM3077;
private final String electronicRecord = "RM-2937 electronic 2 record";
private final String folder = TEST_PREFIX + "RM-2937 folder ghosting";
private static final String categoryRecordsRM2526 = TEST_PREFIX + "RM-2526_category_records_immediately";
private static final String category2RecordsRM2526 = TEST_PREFIX + "RM-2526_category_2_records_1_day";
private static final String firstCategoryRM3060 = TEST_PREFIX + "RM-3060_category_record";
private static final String secondCategoryRM3060 = "Copy_of_" + firstCategoryRM3060;
private static final String firstFolderRM3060 = TEST_PREFIX + "RM-3060_folder";
private static final String secondFolderRM3060 = TEST_PREFIX + "RM-3060_disposition_on_Record_Level";
private static final String electronicRecordRM3060 = TEST_PREFIX + "RM-3060_electronic_1_record";
private static final String nonElectronicRecordRM3060 = TEST_PREFIX + "RM-3060_non-electronic_record";
private static final String TRANSFER_LOCATION = TEST_PREFIX + "RM-3060_transferred_records";
public static final String TRANSFER_TYPE = "rma:transferred";
private FilePlan filePlanModel;
private UserModel rmAdmin, rmManager;
@BeforeClass(alwaysRun = true)
public void setupDispositionScheduleLinkedRecordsTest() {
createRMSiteIfNotExists();
//get file plan
filePlanModel = getRestAPIFactory().getFilePlansAPI().getFilePlan(FILE_PLAN_ALIAS);
// create "rm admin" user if it does not exist and assign it to RM Administrator role
rmAdmin = getDataUser().createRandomTestUser();
rmRolesAndActionsAPI.assignRoleToUser(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),rmAdmin.getUsername(),
UserRoles.ROLE_RM_ADMIN.roleId);
// create "rm Manager" user if it does not exist and assign it to RM Administrator role
rmManager = getDataUser().createRandomTestUser();
rmRolesAndActionsAPI.assignRoleToUser(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),rmManager.getUsername(),
UserRoles.ROLE_RM_MANAGER.roleId);
}
/**
* Disposition Schedule on Record Folder with linked records test
* <p>
* Precondition:
* <p>
* Create rm_manager user that would have RM Managers role, rm_admin that would have RM Administrator role.
* Log in with admin user, create a category "manager sees me", give rm_manager read&file permission over it.
* Create a disposition schedule for it that would cut off folders after 1 day from created date. Copy the category.
* <p>
* <p/> TestRail Test C775<p/>
**/
@Test
@AlfrescoTest(jira = "RM-1622")
public void dispositionScheduleLinkedRecords() throws UnsupportedEncodingException {
STEP("Create record category");
Category1 = createRootCategory(categoryRM3077);
//create retention schedule
dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), false);
// add cut off step
dispositionScheduleService.addCutOffAfterPeriodStep(Category1.getName(), "day|2", CREATED_DATE);
//create a copy of the category recordsCategory
String CopyCategoryId = copyCategory(getAdminUser(),Category1.getId(), copyCategoryRM3077);
// create folders in both categories
CatFolder = createRecordFolder(Category1.getId(), folderRM3077);
CopyCatFolder = createRecordFolder(CopyCategoryId, copyFolderRM3077);
// create record files
String electronicRecord = "RM-2801 electronic record";
Record elRecord = createElectronicRecord(CatFolder.getId(), electronicRecord);
String elRecordFullName = recordsAPI.getRecordFullName(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), CatFolder.getName(), electronicRecord);
String nonElectronicRecord = "RM-2801 non-electronic record";
Record nonElRecord = createNonElectronicRecord(CatFolder.getId(), nonElectronicRecord);
String nonElRecordFullName = recordsAPI.getRecordFullName(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), CatFolder.getName(), nonElectronicRecord);
// link the records to copy folder, then complete them
List<String> recordLists = new ArrayList<>();
recordLists.add(NODE_REF_WORKSPACE_SPACES_STORE + elRecord.getId());
recordLists.add(NODE_REF_WORKSPACE_SPACES_STORE + nonElRecord.getId());
linksAPI.linkRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), HttpStatus.SC_OK,copyCategoryRM3077 + "/" +
copyFolderRM3077, recordLists);
recordsAPI.completeRecord(rmAdmin.getUsername(), rmAdmin.getPassword(), elRecordFullName);
recordsAPI.completeRecord(rmAdmin.getUsername(), rmAdmin.getPassword(), nonElRecordFullName);
// edit disposition date
recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),CatFolder.getName());
// cut off the Folder
recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),CatFolder.getName());
// Verify the Content
Node electronicNode = getNode(elRecord.getId());
assertTrue("The content of " + electronicRecord + " is available",
StringUtils.isEmpty(electronicNode.getNodeContent().getResponse().getBody().asString()));
// verify the Properties
AssertJUnit.assertNull("The properties are present even after cutting off the record.", elRecord.getProperties().getTitle());
// delete precondition
deleteRecordCategory(Category1.getId());
deleteRecordCategory(CopyCategoryId);
}
/**
* Test covering RM-3060
* Check the disposition steps for a record can be executed
* When the record is linked to a folder with the same disposition schedule
* */
@Test
@AlfrescoTest (jira = "RM-3060")
public void sameDispositionScheduleLinkedRecords() throws UnsupportedEncodingException {
// create a category with retention applied on records level
RecordCategory recordCategory = getRestAPIFactory().getFilePlansAPI(rmAdmin)
.createRootRecordCategory(RecordCategory.builder().name(firstCategoryRM3060).build(),
RecordCategory.DEFAULT_FILE_PLAN_ALIAS);
dispositionScheduleService.createCategoryRetentionSchedule(firstCategoryRM3060, true);
dispositionScheduleService.addCutOffAfterPeriodStep(firstCategoryRM3060, "week|1", DATE_FILED);
dispositionScheduleService.addTransferAfterEventStep(firstCategoryRM3060, TRANSFER_LOCATION, RMEvents.CASE_CLOSED.getEventName());
dispositionScheduleService.addDestroyWithoutGhostingAfterPeriodStep(firstCategoryRM3060, "week|1", CUT_OFF_DATE);
// make a copy of the category created
String categorySecondId = copyCategory(getAdminUser(), recordCategory.getId(), secondCategoryRM3060);
// create a folder on the category firstCategoryRM3060 with a complete electronic record
RecordCategoryChild firstFolderRecordCategoryChild = createRecordFolder(recordCategory.getId(),firstFolderRM3060);
Record firstElectronicRecord = createElectronicRecord(firstFolderRecordCategoryChild.getId(),electronicRecordRM3060);
String elRecordFullName = recordsAPI.getRecordFullName(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(),firstFolderRM3060, electronicRecordRM3060);
String elRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordFullName, "/" + firstCategoryRM3060 + "/" + firstFolderRM3060);
recordsAPI.completeRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), elRecordFullName);
// create a folder on the category secondCategoryRM3060 with a non electronic record
RecordCategoryChild secondFolderRecordCategoryChild = createRecordFolder(categorySecondId,secondFolderRM3060);
Record secondNonElectronicRecord = createNonElectronicRecord(secondFolderRecordCategoryChild.getId(),nonElectronicRecordRM3060);
// link the nonElectronicRecordRM3060 to firstFolderRM3060
List<String> recordLists = new ArrayList<>();
recordLists.add(NODE_REF_WORKSPACE_SPACES_STORE + secondNonElectronicRecord.getId());
linksAPI.linkRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), HttpStatus.SC_OK,secondCategoryRM3060 + "/" +
secondFolderRM3060, recordLists);
String nonElRecordFullName = recordsAPI.getRecordFullName(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), secondFolderRM3060, secondNonElectronicRecord.getName());
String nonElRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordFullName, "/" + secondCategoryRM3060 + "/" + secondFolderRM3060);
// complete records and cut them off
recordsAPI.completeRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), nonElRecordFullName);
// edit the disposition date
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),nonElRecordNameNodeRef);
// cut off the record
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),nonElRecordNameNodeRef);
//check the record is cut off
AssertJUnit.assertTrue("The file " + nonElectronicRecordRM3060 + " has not been successfully cut off.", getRestAPIFactory().getRecordsAPI().getRecord(secondNonElectronicRecord.getId()).getAspectNames().contains(CUT_OFF_ASPECT));
// link the electronic record to secondFolderRM3060
recordLists.clear();
recordLists.add(NODE_REF_WORKSPACE_SPACES_STORE + secondNonElectronicRecord.getId());
linksAPI.linkRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), HttpStatus.SC_OK,secondCategoryRM3060 + "/" +
secondFolderRM3060, recordLists);
// edit the disposition date and cut off the record
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),elRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),elRecordNameNodeRef);
AssertJUnit.assertTrue("The file " + electronicRecordRM3060 + " has not been successfully cut off.", getRestAPIFactory().getRecordsAPI().getRecord(firstElectronicRecord.getId()).getAspectNames().contains(CUT_OFF_ASPECT));
// open the record and complete the disposition schedule event
rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
getAdminUser().getPassword(), elRecordFullName, RMEvents.CASE_CLOSED, Instant.now());
rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
getAdminUser().getPassword(), nonElRecordFullName, RMEvents.CASE_CLOSED, Instant.now());
// transfer the files & complete transfers
HttpResponse nonElRecordNameHttpResponse = recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","transfer"),recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordFullName, "/" + secondCategoryRM3060 + "/" + secondFolderRM3060));
String nonElRecordNameTransferId = getTransferId(nonElRecordNameHttpResponse,nonElRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","transferComplete"),nonElRecordNameTransferId);
HttpResponse elRecordNameHttpResponse = recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","transfer"),recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordFullName, "/" + firstCategoryRM3060 + "/" + firstFolderRM3060));
String elRecordNameTransferId = getTransferId(elRecordNameHttpResponse,elRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","transferComplete"),elRecordNameTransferId);
AssertJUnit.assertTrue("The file " + electronicRecordRM3060 + " has not been successfully transferred", getRestAPIFactory().getRecordsAPI().getRecord(firstElectronicRecord.getId()).getAspectNames().contains(TRANSFER_TYPE));
AssertJUnit.assertTrue("The file " + nonElectronicRecordRM3060 + " has not been successfully transferred.", getRestAPIFactory().getRecordsAPI().getRecord(secondNonElectronicRecord.getId()).getAspectNames().contains(TRANSFER_TYPE));
// edit the disposition date for nonElectronicRecordRM3060 & electronicRecordRM3060
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),nonElRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),elRecordNameNodeRef);
// destroy nonElectronicRecordRM3060 & electronicRecordRM3060 records
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","destroy"),nonElRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","destroy"),elRecordNameNodeRef);
// check the file is not displayed
assertNull("The file " + nonElectronicRecordRM3060 + " has not been successfully destroyed.", secondNonElectronicRecord.getContent());
assertNull("The file " + electronicRecordRM3060 + " has not been successfully destroyed.", firstElectronicRecord.getContent());
// delete precondition
deleteRecordCategory(recordCategory.getId());
deleteRecordCategory(categorySecondId);
}
private String copyCategory(UserModel user, String categoryId, String copyName) {
RepoTestModel repoTestModel = new RepoTestModel() {};
repoTestModel.setNodeRef(categoryId);
RestNodeModel restNodeModel;
RestNodeBodyMoveCopyModel copyDestinationInfo = new RestNodeBodyMoveCopyModel();
copyDestinationInfo.setTargetParentId(filePlanModel.getId());
copyDestinationInfo.setName(copyName);
try
{
restNodeModel = getRestAPIFactory().getNodeAPI(user, repoTestModel).copy(copyDestinationInfo);
}
catch (Exception e)
{
throw new RuntimeException("Problem copying category.", e);
}
return restNodeModel.getId();
}
private Node getNode(String recordId)
{
RepoTestModel repoTestModel = new RepoTestModel() {};
repoTestModel.setNodeRef(recordId);
return getRestAPIFactory().getNodeAPI(repoTestModel);
}
private String getTransferId(HttpResponse httpResponse,String nodeRef) {
HttpEntity entity = httpResponse.getEntity();
String responseString = null;
try {
responseString = EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
throw new RuntimeException(e);
}
JSONObject result = new JSONObject(responseString);
return result
.getJSONObject("results")
.get(nodeRef)
.toString();
}
@Test
@AlfrescoTest(jira = "RM-1622")
public void sameLevelDispositionScheduleStepsPeriodsCalculation() throws Exception {
// create a category with retention applied on records level
RecordCategory catsameLevel1 = getRestAPIFactory().getFilePlansAPI(rmAdmin)
.createRootRecordCategory(RecordCategory.builder().name(firstCategoryRM3060).build(),
RecordCategory.DEFAULT_FILE_PLAN_ALIAS);
RecordCategory catsameLevel2 = getRestAPIFactory().getFilePlansAPI(rmAdmin)
.createRootRecordCategory(RecordCategory.builder().name(secondCategoryRM3060).build(),
RecordCategory.DEFAULT_FILE_PLAN_ALIAS);
// create retention schedule applied on records for category 1
dispositionScheduleService.createCategoryRetentionSchedule(firstCategoryRM3060, true);
// with retain immediately after record creation date and cut 1 day after record creation date
dispositionScheduleService.addCutOffAfterPeriodStep(firstCategoryRM3060, "day|1", DATE_FILED);
// create a folder on the category firstCategoryRM3060 with a complete electronic record
RecordCategoryChild firstFolderRecordCategoryChild = createRecordFolder(catsameLevel1.getId(),firstFolderRM3060);
Record firstElectronicRecord = createElectronicRecord(firstFolderRecordCategoryChild.getId(),electronicRecordRM3060);
String elRecordFullName = recordsAPI.getRecordFullName(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(),firstFolderRM3060, electronicRecordRM3060);
String elRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordFullName, "/" + firstCategoryRM3060 + "/" + firstFolderRM3060);
recordsAPI.completeRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), elRecordFullName);
// create a folder on the category secondCategoryRM3060 with a non electronic record
RecordCategoryChild secondFolderRecordCategoryChild = createRecordFolder(catsameLevel2.getId(),secondFolderRM3060);
String elRecordNameNodeRefs = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordFullName, "/" + firstCategoryRM3060 + "/" + firstFolderRM3060);
// link it to the folder in second category through the details page
List<String> recordLists = new ArrayList<>();
recordLists.add(NODE_REF_WORKSPACE_SPACES_STORE + firstElectronicRecord.getId());
linksAPI.linkRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), HttpStatus.SC_OK,secondCategoryRM3060 + "/" +
secondFolderRM3060, recordLists);
// edit disposition date
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),elRecordNameNodeRefs);
}
@Test (dependsOnMethods = {"sameLevelDispositionScheduleStepsPeriodsCalculation" })
public void deleteLongestPeriodTestPrecondition() {
// Delete the RM site
getRestAPIFactory().getRMSiteAPI().deleteRMSite();
// Verify the status code
assertStatusCode(NO_CONTENT);
}
}

View File

@@ -0,0 +1,138 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* 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.rm.community.smoke;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolderCollection;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.rm.community.records.FileUnfiledRecordsTests;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.RecordCategoriesAPI;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.Utility;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.data.DataSite;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FileType;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.concurrent.atomic.AtomicReference;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.test.util.AssertionErrors.assertTrue;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
public class FileVersionAsRecordTests extends BaseRMRestTest {
private UserModel nonRMuser,rmManager;
private SiteModel testSite;
private FileModel document, documentDeclared;
private RecordCategory category_manager, category_admin;
private RecordCategoryChild folder_admin, folder_manager ;
private static final String CATEGORY_MANAGER = "catManager" + generateTestPrefix(FileAsRecordTests.class);
private static final String CATEGORY_ADMIN = "catAdmin" + generateTestPrefix(FileAsRecordTests.class);
private static final String FOLDER_MANAGER = "recordFolder" + generateTestPrefix(FileAsRecordTests.class);
private static final String FOLDER_ADMIN = "recordFolder" + generateTestPrefix(FileAsRecordTests.class);
@Autowired
private DataSite dataSite;
@Autowired
private DataContent dataContent;
@Autowired
private RoleService roleService;
@BeforeClass(alwaysRun = true)
public void preconditionForFileVersionAsRecordTests()
{
STEP("Create the RM site if doesn't exist");
createRMSiteIfNotExists();
STEP("Create a user");
nonRMuser = dataUser.createRandomTestUser("testUser");
STEP("Create a collaboration site");
testSite = dataSite.usingUser(nonRMuser).createPublicRandomSite();
STEP("Create a document with the user without RM role");
document = dataContent.usingSite(testSite)
.usingUser(nonRMuser)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Create two categories with two folders");
category_manager = createRootCategory(CATEGORY_MANAGER);
category_admin = createRootCategory(CATEGORY_ADMIN);
folder_admin = createFolder(category_admin.getId(),FOLDER_ADMIN);
folder_manager = createFolder(category_manager.getId(),FOLDER_MANAGER);
STEP("Create an rm user and give filling permission over CATEGORY_MANAGER record category");
RecordCategory recordCategory = new RecordCategory().builder()
.id(category_manager.getId())
.build();
rmManager = roleService.createCollaboratorWithRMRoleAndPermission(testSite, recordCategory,
UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
}
@Test
@AlfrescoTest (jira = "APPS-1625")
public void fileVersionAsRecordToUnfiledRecordContainer() throws Exception
{
AtomicReference<RecordFolderCollection> apiChildren = new AtomicReference<>();
STEP("Create a document with the user without RM role");
FileModel inplaceRecord = dataContent.usingSite(testSite).usingUser(rmManager)
.createContent(new FileModel("declareAndFileToIntoUnfiledRecordFolder",
FileType.TEXT_PLAIN));
STEP("Click on Declare and file without selecting a record folder");
getRestAPIFactory().getActionsAPI(rmManager).declareAndFile(inplaceRecord,"");
STEP("Check the file is declared in unfiled record folder");
Assert.assertTrue(isMatchingRecordInUnfiledRecords(inplaceRecord), "Record should be filed to Unfiled Records folder");
}
}

View File

@@ -0,0 +1,156 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* 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.rm.community.smoke;
import org.alfresco.rest.core.v0.BaseAPI;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.RecordCategoriesAPI;
import org.alfresco.rest.v0.RecordFoldersAPI;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.test.AlfrescoTest;
import org.apache.commons.lang3.time.DateUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import static org.alfresco.rest.rm.community.base.TestData.DEFAULT_PASSWORD;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.testng.Assert.assertTrue;
public class RecordRetentionAsOfDateTest extends BaseRMRestTest {
/** data prep 6services */
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired
private RecordsAPI recordsAPI;
@Autowired
private RecordFoldersAPI recordFoldersAPI;
@Autowired
private RecordCategoriesAPI recordCategoriesAPI;
@Autowired
private DispositionScheduleService dispositionScheduleService;
private RecordCategory Category1;
private final String TEST_PREFIX = generateTestPrefix(RecordRetentionAsOfDateTest.class);
private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
private final String recordsCategory = TEST_PREFIX + "RM-5733 category";
private final String folderDisposition = TEST_PREFIX + "RM-5733 folder";
private static final String YEAR_MONTH_DAY = "yyyy-MM-dd";
@Test
@AlfrescoTest (jira = "RM-5733,RM-5799")
public void checkRetentionAsOfDateForTransferStepWithRetentionAction() {
// create test precondition
createTestPrecondition(recordsCategory);
// create disposition schedule
dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), true);
// add cut off step
dispositionScheduleService.addCutOffImmediatelyStep(Category1.getName());
// add transfer step
HashMap<BaseAPI.RETENTION_SCHEDULE, String> transferStep = new HashMap<>();
transferStep.put(BaseAPI.RETENTION_SCHEDULE.RETENTION_PERIOD, "day|1");
transferStep.put(BaseAPI.RETENTION_SCHEDULE.NAME, "transfer");
transferStep.put(BaseAPI.RETENTION_SCHEDULE.RETENTION_PERIOD_PROPERTY, "rma:cutOffDate");
transferStep.put(BaseAPI.RETENTION_SCHEDULE.COMBINE_DISPOSITION_STEP_CONDITIONS, "false");
transferStep.put(BaseAPI.RETENTION_SCHEDULE.RETENTION_ELIGIBLE_FIRST_EVENT, "true");
transferStep.put(BaseAPI.RETENTION_SCHEDULE.RETENTION_GHOST, "on");
transferStep.put(BaseAPI.RETENTION_SCHEDULE.DESCRIPTION, "Transfer after 1 day");
recordCategoriesAPI.addDispositionScheduleSteps(getAdminUser().getUsername(),
getAdminUser().getPassword(), Category1.getName(), transferStep);
// create a folder and an electronic and a non-electronic record in it
RecordCategoryChild FOLDER = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
String nonElectronicRecord = TEST_PREFIX + "RM-5733 non-electronic record";
Record nonElRecord = createNonElectronicRecord(FOLDER.getId(), nonElectronicRecord);
// complete records and cut them off
String nonElRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
getAdminUser().getPassword(), folderDisposition, nonElectronicRecord);
// complete records and cut them off
completeRecord(nonElRecord.getId());
String nonElRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordName, "/" + Category1.getName() + "/" + folderDisposition);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),nonElRecordNameNodeRef);
JSONObject nextDispositionActionJson = recordCategoriesAPI.getNextDispositionAction(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),nonElRecord.getId());
assertTrue(getAsOfDate(nextDispositionActionJson).startsWith(getTomorrow()),
"The retention as of date is not set to tomorrow.");
}
@AfterClass(alwaysRun = true)
public void cleanUp() {
// delete category
deleteRecordCategory(Category1.getId());
}
private void createTestPrecondition(String categoryName) {
createRMSiteIfNotExists();
// create "rm admin" user if it does not exist and assign it to RM Administrator role
rmRolesAndActionsAPI.createUserAndAssignToRole(
getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),
RM_ADMIN, DEFAULT_PASSWORD, "Administrator");
// create category
STEP("Create category");
Category1 = createRootCategory(categoryName,"Title");
}
private String getAsOfDate(JSONObject nextDispositionActionJson) {
return nextDispositionActionJson.getJSONObject("data").get("asOf").toString();
}
private static String getTomorrow() {
Date today = new Date();
Date tomorrow = DateUtils.addDays(today, 1);
SimpleDateFormat dateFormat = new SimpleDateFormat(YEAR_MONTH_DAY);
return dateFormat.format(tomorrow);
}
}

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<modules>

View File

@@ -1,3 +1,3 @@
SOLR6_TAG=2.0.3
SOLR6_TAG=2.0.5-A2
POSTGRES_TAG=14.4
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8

View File

@@ -109,6 +109,10 @@ rm.completerecord.mandatorypropertiescheck.enabled=true
#
rm.patch.v22.convertToStandardFilePlan=false
#
# Max Batch size for adding the associations between the frozen nodes and the hold
rm.patch.v35.holdNewChildAssocPatch.batchSize=1000
# Permission mapping
# these take a comma separated string of permissions from org.alfresco.service.cmr.security.PermissionService
# read maps to ReadRecords and write to FileRecords

View File

@@ -17,5 +17,6 @@
<property name="filePlanService" ref="filePlanService" />
<property name="holdService" ref="holdService" />
<property name="nodeService" ref="nodeService" />
<property name="batchSize" value="${rm.patch.v35.holdNewChildAssocPatch.batchSize}" />
</bean>
</beans>

View File

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

View File

@@ -38,9 +38,12 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
import org.alfresco.module.org_alfresco_module_rm.capability.impl.ViewRecordsCapability;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
import org.alfresco.module.org_alfresco_module_rm.event.EventCompletionDetails;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanComponentKind;
@@ -76,6 +79,7 @@ import org.json.simple.JSONObject;
*
* @author Roy Wetherall
*/
@Slf4j
public class JSONConversionComponent extends org.alfresco.repo.jscript.app.JSONConversionComponent
implements NodeServicePolicies.OnDeleteNodePolicy,
NodeServicePolicies.OnCreateNodePolicy
@@ -515,17 +519,25 @@ public class JSONConversionComponent extends org.alfresco.repo.jscript.app.JS
AuthenticationUtil.runAsSystem((RunAsWork<Void>) () -> {
//Add details of the next incomplete event in the disposition schedule
if (dispositionService.getNextDispositionAction(nodeRef) != null)
DispositionAction nextDispositionAction = dispositionService.getNextDispositionAction(nodeRef);
if (nextDispositionAction != null)
{
for (EventCompletionDetails details : dispositionService.getNextDispositionAction(nodeRef).getEventCompletionDetails())
for (EventCompletionDetails details : nextDispositionAction.getEventCompletionDetails())
{
if (!details.isEventComplete())
{
DispositionActionDefinition dispositionActionDefinition = nextDispositionAction.getDispositionActionDefinition();
HashMap properties = (HashMap) rmNodeValues.get("properties");
properties.put("combineDispositionStepConditions", nodeService.getProperty(dispositionService.getNextDispositionAction(nodeRef).getDispositionActionDefinition().getNodeRef(), PROP_COMBINE_DISPOSITION_STEP_CONDITIONS));
properties.put("incompleteDispositionEvent", details.getEventName());
properties.put("dispositionEventCombination", nodeService.getProperty(dispositionService.getNextDispositionAction(nodeRef).getDispositionActionDefinition().getNodeRef(), PROP_DISPOSITION_EVENT_COMBINATION));
if(dispositionActionDefinition == null)
{
log.debug("Disposition action definition for disposition action "+ nextDispositionAction.getName() +" has been removed or never exist");
}
else
{
properties.put("combineDispositionStepConditions", nodeService.getProperty(dispositionActionDefinition.getNodeRef(), PROP_COMBINE_DISPOSITION_STEP_CONDITIONS));
properties.put("dispositionEventCombination", nodeService.getProperty(dispositionActionDefinition.getNodeRef(), PROP_DISPOSITION_EVENT_COMBINATION));
}
break;
}
}

View File

@@ -30,6 +30,9 @@ import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel.RM_CUSTOM_URI;
import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.ASSOC_FROZEN_CONTENT;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.alfresco.model.ContentModel;
@@ -37,11 +40,14 @@ import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.patch.AbstractModulePatch;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
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.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Patch to create new hold child association to link the record to the hold
@@ -52,8 +58,15 @@ import org.alfresco.service.namespace.RegexQNamePattern;
*/
public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
{
/** logger */
protected static final Logger LOGGER = LoggerFactory.getLogger(RMv35HoldNewChildAssocPatch.class);
/** A name for the associations created by this patch. */
protected static final QName PATCH_ASSOC_NAME = QName.createQName(RM_CUSTOM_URI, RMv35HoldNewChildAssocPatch.class.getSimpleName());
protected static final QName PATCH_ASSOC_NAME = QName.createQName(RM_CUSTOM_URI,
RMv35HoldNewChildAssocPatch.class.getSimpleName());
/** The batch size for processing frozen nodes. */
private int batchSize = 1000;
/**
* File plan service interface
@@ -75,7 +88,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/**
* Setter for fileplanservice
*
* @param filePlanService File plan service interface
* @param filePlanService
* File plan service interface
*/
public void setFilePlanService(FilePlanService filePlanService)
{
@@ -85,7 +99,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/**
* Setter for hold service
*
* @param holdService Hold service interface.
* @param holdService
* Hold service interface.
*/
public void setHoldService(HoldService holdService)
{
@@ -95,7 +110,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/**
* Setter for node service
*
* @param nodeService Interface for public and internal node and store operations.
* @param nodeService
* Interface for public and internal node and store operations.
*/
public void setNodeService(NodeService nodeService)
{
@@ -112,33 +128,49 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
this.behaviourFilter = behaviourFilter;
}
/**
* Setter for maximum batch size
*
* @param maxBatchSize
* The max amount of associations to be created between the frozen nodes and the hold in a transaction
*/
public void setBatchSize(int batchSize)
{
this.batchSize = batchSize;
}
@Override
public void applyInternal()
{
behaviourFilter.disableBehaviour(ContentModel.ASPECT_AUDITABLE);
behaviourFilter.disableBehaviour(ContentModel.ASPECT_VERSIONABLE);
try
{
int patchedNodesCounter = 0;
for (NodeRef filePlan : filePlanService.getFilePlans())
{
for (NodeRef hold : holdService.getHolds(filePlan))
{
List<ChildAssociationRef> frozenAssoc = nodeService.getChildAssocs(hold, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : frozenAssoc)
LOGGER.debug("Analyzing hold {}", hold.getId());
BatchWorker batchWorker = new BatchWorker(hold);
LOGGER.debug("Hold has {} items to be analyzed", batchWorker.getWorkSize());
while (batchWorker.hasMoreResults())
{
NodeRef childNodeRef = ref.getChildRef();
// In testing we found that this was returning more than just "contains" associations.
// Possibly this is due to the code in Node2ServiceImpl.getParentAssocs not using the second parameter.
List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(childNodeRef, ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
boolean childContainedByHold =
parentAssocs.stream().anyMatch(entry -> entry.getParentRef().equals(hold) && entry.getTypeQName().equals(ASSOC_CONTAINS));
if (!childContainedByHold)
{
nodeService.addChild(hold, childNodeRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME);
}
processBatch(hold, batchWorker);
}
LOGGER.debug("Patched {} items in hold", batchWorker.getTotalPatchedNodes());
patchedNodesCounter += batchWorker.getTotalPatchedNodes();
}
}
LOGGER.debug("Patch applied to {} children across all holds", patchedNodesCounter);
}
finally
{
@@ -146,4 +178,92 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
behaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE);
}
}
private void processBatch(NodeRef hold, BatchWorker batch)
{
transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
Collection<ChildAssociationRef> childRefs = batch.getNextWork();
LOGGER.debug("Processing batch of {} children in hold", childRefs.size());
for (ChildAssociationRef child : childRefs)
{
NodeRef childNodeRef = child.getChildRef();
if (!isChildContainedByHold(hold, childNodeRef))
{
nodeService.addChild(hold, childNodeRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME);
batch.countPatchedNode();
}
}
return null;
}, false, true);
}
private boolean isChildContainedByHold(NodeRef hold, NodeRef child)
{
// In testing we found that this was returning more than just "contains" associations.
// Possibly this is due to the code in Node2ServiceImpl.getParentAssocs not using the second
// parameter.
List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(child, ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
return parentAssocs.stream()
.anyMatch(entry -> entry.getParentRef().equals(hold) && entry.getTypeQName().equals(ASSOC_CONTAINS));
}
private class BatchWorker
{
NodeRef hold;
int totalPatchedNodes = 0;
int workSize;
Iterator<ChildAssociationRef> iterator;
public BatchWorker(NodeRef hold)
{
this.hold = hold;
setupHold();
}
public boolean hasMoreResults()
{
return iterator == null ? true : iterator.hasNext();
}
public void countPatchedNode()
{
this.totalPatchedNodes += 1;
}
public int getTotalPatchedNodes()
{
return totalPatchedNodes;
}
public int getWorkSize()
{
return workSize;
}
public void setupHold()
{
// Get child assocs without preloading
List<ChildAssociationRef> holdChildren = nodeService.getChildAssocs(hold, ASSOC_FROZEN_CONTENT,
RegexQNamePattern.MATCH_ALL, Integer.MAX_VALUE, false);
this.iterator = holdChildren.listIterator();
this.workSize = holdChildren.size();
}
public Collection<ChildAssociationRef> getNextWork()
{
List<ChildAssociationRef> frozenNodes = new ArrayList<ChildAssociationRef>(batchSize);
while (iterator.hasNext() && frozenNodes.size() < batchSize)
{
frozenNodes.add(iterator.next());
}
return frozenNodes;
}
}
}

View File

@@ -34,7 +34,9 @@ import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.ASSOC_FROZEN_CONTENT;
import static org.alfresco.module.org_alfresco_module_rm.patch.v35.RMv35HoldNewChildAssocPatch.PATCH_ASSOC_NAME;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -51,16 +53,21 @@ import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
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.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/**
* RM V3.5 Create new hold child association to link the record to the hold
@@ -81,6 +88,12 @@ public class RMv35HoldNewChildAssocPatchUnitTest
@Mock
private BehaviourFilter mockBehaviourFilter;
@Mock
private TransactionService mockTransactionService;
@Mock
private RetryingTransactionHelper mockRetryingTransactionHelper;
@InjectMocks
private RMv35HoldNewChildAssocPatch patch;
@@ -112,25 +125,63 @@ public class RMv35HoldNewChildAssocPatchUnitTest
/**
* Test secondary associations are created for held items so that they are "contained" in the hold.
*/
@SuppressWarnings("unchecked")
@Test
public void testAddChildDuringUpgrade()
{
when(mockFilePlanService.getFilePlans()).thenReturn(fileplans);
when(mockHoldService.getHolds(filePlanRef)).thenReturn(holds);
when(mockNodeService.getChildAssocs(holdRef, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL)).thenReturn(childAssocs);
when(mockNodeService.getChildAssocs(holdRef, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL, Integer.MAX_VALUE, false))
.thenReturn(childAssocs);
when(childAssociationRef.getChildRef()).thenReturn(heldItemRef);
// setup retrying transaction helper
Answer<Object> doInTransactionAnswer = new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RetryingTransactionCallback callback = (RetryingTransactionCallback) invocation.getArguments()[0];
// when(childAssociationRef.getChildRef()).thenReturn(heldItemRef);
return callback.execute();
}
};
doAnswer(doInTransactionAnswer).when(mockRetryingTransactionHelper)
.<Object> doInTransaction(any(RetryingTransactionCallback.class), anyBoolean(), anyBoolean());
when(mockTransactionService.getRetryingTransactionHelper()).thenReturn(mockRetryingTransactionHelper);
patch.applyInternal();
verify(mockNodeService, times(1)).addChild(holdRef, heldItemRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME);
}
@SuppressWarnings("unchecked")
@Test
public void patchRunWithSuccessWhenNoHeldChildren()
{
when(mockFilePlanService.getFilePlans()).thenReturn(fileplans);
when(mockHoldService.getHolds(filePlanRef)).thenReturn(holds);
when(mockNodeService.getChildAssocs(holdRef, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL)).thenReturn(emptyList());
when(mockNodeService.getChildAssocs(holdRef, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL, Integer.MAX_VALUE, false))
.thenReturn(emptyList());
// setup retrying transaction helper
Answer<Object> doInTransactionAnswer = new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RetryingTransactionCallback callback = (RetryingTransactionCallback) invocation.getArguments()[0];
when(childAssociationRef.getChildRef()).thenReturn(heldItemRef);
return callback.execute();
}
};
doAnswer(doInTransactionAnswer).when(mockRetryingTransactionHelper)
.<Object> doInTransaction(any(RetryingTransactionCallback.class), anyBoolean(), anyBoolean());
when(mockTransactionService.getRetryingTransactionHelper()).thenReturn(mockRetryingTransactionHelper);
patch.applyInternal();

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<modules>

View File

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

View File

@@ -11,7 +11,7 @@ function main()
var params =
{
type: "people",
term: args.t,
term: args.t + " [hint:useCQ]",
maxResults: (args.maxResults !== null) ? parseInt(args.maxResults, 10) : DEFAULT_MAX_RESULTS,
startIndex: (args.startIndex !== null) ? parseInt(args.startIndex, 10) : 0
};

View File

@@ -14,7 +14,7 @@ function main()
maxResults: (args.maxResults !== null) ? parseInt(args.maxResults, 10) : DEFAULT_MAX_RESULTS,
pageSize: (args.pageSize !== null) ? parseInt(args.pageSize, 10) : DEFAULT_PAGE_SIZE,
startIndex: (args.startIndex !== null) ? parseInt(args.startIndex, 10) : 0,
facetFields: args.facetFields,
facetFields: args.facetFields !== null ? args.facetFields.replace( /(<([^>]+)>)/ig, '') : null,
filters: args.filters,
encodedFilters: args.encodedFilters,
spell: (args.spellcheck !== null) ? (args.spellcheck == "true") : false

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005 - 2020 Alfresco Software Limited.
* Copyright 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.

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<dependencies>

View File

@@ -25,6 +25,9 @@ package org.alfresco.error;
*/
public class ExceptionStackUtil
{
private static final String JAVASCRIPT_EXCEPTION = "org.mozilla.javascript.JavaScriptException";
private static final String EXCEPTION_DELIMITER = ":";
/**
* Searches through the exception stack of the given throwable to find any instance
* of the possible cause. The top-level throwable will also be tested.
@@ -38,10 +41,17 @@ public class ExceptionStackUtil
{
while (throwable != null)
{
Class<?> throwableClass = throwable.getClass();
boolean isJavaScriptException = throwableClass.getName().contains(JAVASCRIPT_EXCEPTION);
String throwableMsg = throwable.getMessage() != null ? throwable.getMessage() : "";
for (Class<?> possibleCauseClass : possibleCauses)
{
Class<?> throwableClass = throwable.getClass();
if (possibleCauseClass.isAssignableFrom(throwableClass))
String possibleCauseClassName = possibleCauseClass.getName();
if (possibleCauseClass.isAssignableFrom(throwableClass)
|| (isJavaScriptException && throwableMsg.contains(possibleCauseClassName + EXCEPTION_DELIMITER)))
{
// We have a match
return throwable;

View File

@@ -21,6 +21,7 @@ package org.alfresco.httpclient;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
@@ -57,7 +58,12 @@ public class RequestHeadersHttpClient extends HttpClient
if (defaultHeaders != null)
{
defaultHeaders.forEach((k,v) -> {
method.addRequestHeader(k, v);
Header h = method.getRequestHeader(k);
boolean add = h == null || h.getValue() == null || !h.getValue().equals(v);
if (add)
{
method.addRequestHeader(k, v);
}
});
}
}

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<properties>
@@ -134,7 +134,7 @@
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>6.3.0</version>
<version>6.3.1</version>
</dependency>
<!-- the cxf libs were updated, see dependencyManagement section -->

View File

@@ -346,7 +346,7 @@ public class FTSQueryParser
}
constraints.add(constraint);
}
if (constraints.size() == 1 && Occur.EXCLUDE != constraints.get(0).getOccur())
if (constraints.size() == 1)
{
return constraints.get(0);
}

View File

@@ -69,21 +69,20 @@ public class LuceneDisjunction<Q, S, E extends Throwable> extends BaseDisjunctio
@SuppressWarnings("unchecked")
LuceneQueryBuilderComponent<Q, S, E> luceneQueryBuilderComponent = (LuceneQueryBuilderComponent<Q, S, E>) constraint;
Q constraintQuery = luceneQueryBuilderComponent.addComponent(selectors, functionArgs, luceneContext, functionContext);
queriestoDisjoin.add(new Pair<Constraint, Q>(constraint, constraintQuery));
queriestoDisjoin.add(new Pair<>(constraint, constraintQuery));
if (constraintQuery != null)
{
switch (constraint.getOccur())
{
case DEFAULT:
case MANDATORY:
case OPTIONAL:
expressionBuilder.addOptional(constraintQuery, constraint.getBoost());
break;
case MANDATORY:
expressionBuilder.addRequired(constraintQuery, constraint.getBoost());
break;
case EXCLUDE:
QueryParserExpressionAdaptor<Q, E> subExpressionBuilder = luceneContext.getLuceneQueryParserAdaptor().getExpressionAdaptor();
subExpressionBuilder.addRequired(luceneContext.getLuceneQueryParserAdaptor().getMatchAllNodesQuery());
subExpressionBuilder.addExcluded(constraintQuery);
expressionBuilder.addOptional(subExpressionBuilder.getQuery(), constraint.getBoost());
expressionBuilder.addExcluded(constraintQuery, constraint.getBoost());
break;
}
}

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<dependencies>

View File

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

View File

@@ -1,6 +1,6 @@
# Fetch image based on Tomcat 9.0, Java 17 and Rocky Linux 8
# More infos about this image: https://github.com/Alfresco/alfresco-docker-base-tomcat
FROM alfresco/alfresco-base-tomcat:tomcat9-jre17-rockylinux8-202205140719
FROM alfresco/alfresco-base-tomcat:tomcat9-jre17-rockylinux8-202209261711
# Set default docker_context.
ARG resource_path=target

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<modules>

View File

@@ -1,3 +1,3 @@
SOLR6_TAG=2.0.3
SOLR6_TAG=2.0.5-A2
POSTGRES_TAG=14.4
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8

View File

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

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
TAS_DIRECTORY=$1
cd ${TAS_DIRECTORY}
failures=$(grep 'status="FAIL"' target/surefire-reports/testng-results.xml | sed 's|^.*[ ]name="\([^"]*\)".*$|\1|g')
for failure in ${failures}
do
cat target/reports/alfresco-tas.log | sed '/STARTING Test: \['${failure}'\]/,/ENDING Test: \['${failure}'\]/!d;/ENDING Test: \['${failure}'\]/q'
done

View File

@@ -0,0 +1,495 @@
![in progress](https://img.shields.io/badge/Document_Level-In_Progress-yellow.svg?style=flat-square)
:paw_prints: Back to [TAS Master Documentation](https://gitlab.alfresco.com/tas/documentation/wikis/home)
---
## Table of Contents
* [Synopsis](#synopsis)
* [Prerequisite](#prerequisite)
* [Installation](#installation-if-you-want-to-contribute)
* [Package Presentation](#package-presentation)
* [Sample Usage](#sample-usage)
* [How to write a test](#how-to-write-a-test)
* [How to run tests?](#how-to-run-tests)
* [from IDE](#from-ide)
* [from command line](#from-command-line)
* [Perform CMIS Queries](#perform-cmis-queries)
* [Listeners](#listeners)
* [Test Results](#test-results)
* [Test Rail Integration](#test-rail-integration)
* [Configuration](#configuration)
* [How to enable Test Rail Integration?](#how-to-enable-test-rail-integration)
* [Change Log](docs/CHANGELOG.md) :glowing_star:
* [Reference](#reference)
* [Releasing](#releasing)
* [Contributors](#contributors)
* [License](#license)
## Synopsis
**TAS**( **T**est **A**utomation **S**ystem)- **CMIS** is the project that handles the automated tests related only to CMIS API integrated with Alfresco One [Alfresco CMIS API](http://docs.alfresco.com/5.1/pra/1/topics/cmis-welcome.html).
It is based on Apache Maven, compatible with major IDEs and is using also Spring capabilities for dependency injection.
As a high level overview, this project makes use of the following functionality useful in automation testing as:
* reading/defining test environment settings (e.g. alfresco server details, authentication, etc.)
* managing resource (i.e. creating files and folders)
* test data generators (for site, users, content, etc)
* helpers (i.e. randomizers, test environment information)
* test logging generated on runtime and test reporting capabilities
* test management tool integration (at this point we support integration with [Test Rail](https://alfresco.testrail.net) (v5.2.1)
* health checks (verify if server is reachable, if server is online)
* generic Internal-DSL (Domain Specific Language)
Using Nexus -Release Repository, everyone will be able to use individual interfaces in their projects by extending the automation core functionalities.
**[Back to Top ^](#table-of-contents)**
## Prerequisite
(tested on unix/non-unix distribution)
* [Java SE 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
* [Maven 3.3](https://maven.apache.org/download.cgi) installed and configure according to [Windows OS](https://maven.apache.org/guides/getting-started/windows-prerequisites.html) or [Mac OS](https://maven.apache.org/install.html).
* Configure Maven to use Alfresco alfresco-internal repository following this [Guide](https://ts.alfresco.com/share/page/site/eng/wiki-page?title=Maven_Setup).
* Your favorite IDE as [Eclipse](https://eclipse.org/downloads/) or [IntelliJ](https://www.jetbrains.com/idea).
* Access to [Nexus](https://nexus.alfresco.com/nexus/) repository.
* Access to GitLab [TAS](https://gitlab.alfresco.com/tas/) repository.
* GitLab client for your operating system. (we recommend [SourceTree](https://www.sourcetreeapp.com) - use your google account for initial setup).
* Getting familiar with [Basic Git Commands](http://docs.gitlab.com/ee/gitlab-basics/basic-git-commands.html).
* Getting familiar with [Maven](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html).
* Getting familiar with [Spring](http://docs.spring.io).
* Getting familiar with [TestNG](http://testng.org/doc/index.html)
**[Back to Top ^](#table-of-contents)**
## Installation (if you want to contribute)
* Open your GitLab client and clone the repository of this project.
* You can do this also from command line (or in your terminal) adding:
```bash
$ git clone https://gitlab.alfresco.com/tas/alfresco-tas-cmis-test.git
# this clone will have the latest changes from repository. If you want to checkout a specific version released, take a look at the [Change Log](docs/CHANGELOG.md) page
$ cd alfresco-tas-cmis-test
# this command will checkout the remove v1.0.0 tagged repository and create locally a new branch v1.0.0
$ git checkout tags/v1.0.0 -b v1.0.0
```
* Install and check if all dependencies are downloaded
```bash
$ mvn clean install -DskipTests
# you should see one [INFO] BUILD SUCCESS message displayed
```
**[Back to Top ^](#table-of-contents)**
## Package Presentation
The project uses a maven layout [archetype](https://maven.apache.org/plugins-archives/maven-archetype-plugin-1.0-alpha-7/examples/simple.html):
```ruby
├── pom.xml
├── src
   ├── main
      └── java
      └── org
      └── alfresco
      └── cmis
      ├── (...)
      ├── CmisProperties.java #handles all properties from default.properties
      ├── CmisWrapper.java #wrapper around CMIS API
      └── exception
      └── (...)
   ├── test
      ├── java
         └── org
         └── alfresco
         └── cmis
         ├── CmisDemoTests.java #demo example
         └── CmisTest.java #abstract base class that should be inherited by all tests
      └── resources
      ├── alfresco-cmis-context.xml #spring configuration
      ├── default.properties #all settings related to environment, protocol
      ├── log4j.properties
      └── sanity-cmis.xml # default suite of tests
```
**[Back to Top ^](#table-of-contents)**
## Sample Usage
Following the standard layout for Maven projects, the application sources locate in src/main/java and test sources locate in src/test/java.
Application sources consist in defining the CMIS object that simulates the API calls.
The tests are based on an abstract object: CmisTest.java that handles the common behavior: checking the health status of the test server, configuration settings, getting the general properties, etc.
Please take a look at [CmisDemoTests.java](src/test/java/org/alfresco/cmis/CmisDemoTests.java) class for an example.
Common configuration settings required for this project are stored in properties file, see [default.properties](src/test/resources/default.properties).
Please analyze and update it accordingly with Alfresco test server IP, port, credentials, etc.
Example:
```java
# Alfresco HTTP Server Settings
alfresco.scheme=http
alfresco.server=<add-here-the-ip-of-your-test-server>
alfresco.port=<default-port-for-alfresco-not-share>
```
* optional update the logging level in [log4j](src/test/resources/log4j.properties) file (you can increase/decrease the deails of the [logging file](https://logging.apache.org/log4j/1.2/manual.html), setting the ```log4j.rootLogger=DEBUG``` if you want.)
* go to [running](#how-to-run-tests) section for more information on how to run this tests.
**[Back to Top ^](#table-of-contents)**
### How to write a test
* Tests are organized in java classes and located on src/test/java as per maven layout.
* One test class should contain the tests that cover one functionality as we want to have a clear separation of test scope: tests for sanity/core/full, tests that verify manage of folder/files etc.
* These are the conventions that need to follow when you write a test:
* The test class has @Test annotation with the group defined: protocols, cmis. You can add more groups like sanity, regression
```java
@Test(groups={ "sanity"}
```
* The test has @TestRail annotation in order to assure that the details and results will be submitted on TestRail. The fields for TestRail annotation will be explained on next chapter.
```java
@TestRail(section = { "cmis-api" }, executionType=ExecutionType.SANITY,
description = "Verify admin user creates folder in DocumentLibrary with CMIS")
public void adminShouldCreateFolderInSite() throws Exception
{ cmisApi.usingSite(testSite).createFolder(testFolder).assertExistsInRepo(); }
```
* Use Spring capabilities to initialize the objects(Models, Wrappers) with @Autowired
* We followed Builder pattern to develop specific DSL for simple and clear usage of protocol client in test:
```java
cmisApi.usingSite(testSite) .createFolder(testFolder) .assertExistsInRepo();
```
* To view a simple class that is using this utility, just browse on [CmisDemoTests.java](src/test/java/org/alfresco/cmis/CmisDemoTests.java)
Notice the class definition and inheritance value:
```java
public class CmisDemoTests extends CmisTest
```
* as a convention, before running your test, check if the test environment is reachable and your alfresco test server is online.
(this will stop the test if the server defined in your property file is not healthy - method available in parent class)
```java
@BeforeClass(alwaysRun = true)
public void setupCmisTest() throws Exception {
serverHealth.assertServerIsOnline();
}
```
* the test name are self explanatory:
```java
@TestRail(section = { "cmis-api" }, executionType=ExecutionType.SANITY, description = "Verify admin user creates folder in DocumentLibrary with CMIS")
public void adminShouldCreateFolderInSite() throws Exception
{
cmisApi.usingSite(testSite)
.createFolder(testFolder)
.assertExistsInRepo();
}
```
```java
@TestRail(section = { "cmis-api" }, executionType=ExecutionType.SANITY, description = "Verify admin user creates and renames folder in DocumentLibrary with CMIS")
public void adminShouldRenameFolderInSite() throws Exception
{
cmisApi.usingSite(testSite).createFolder(testFolder)
.and().rename("renamed")
.assertExistsInRepo();
}
```
**[Back to Top ^](#table-of-contents)**
### How to run tests
#### from IDE
* The project can be imported into a development environment tool (Eclipse or IntelliJ). You have the possibility to execute tests or suite of tests using [TestNG plugin](http://testng.org/doc/eclipse.html) previously installed in IDE.
From Eclipse, just right click on the testNG class (something similar to [CmisDemoTests.java](src/test/java/org/alfresco/cmis/CmisDemoTests.java)), select Run As - TestNG Test
You should see your test passed.
* In case you are using the default settings that points to localhost (127.0.0.1) and you don't have Alfresco installed on your machine, you will see one exception thrown (as expected):
```java
org.alfresco.utility.exception.ServerUnreachableException: Server {127.0.0.1} is unreachable.
```
#### from command line
* In terminal or CMD, navigate (with CD) to root folder of your project (you can use the sample project):
The tests can be executed on command line/terminal using Maven command
```bash
mvn test
```
This command with trigger the tests specified in the default testNG suite from POM file: <suiteXmlFile>src/main/resources/shared-resources/cmis-suites.xml</suiteXmlFile>
You can use -Dtest parameter to run the test/suites through command line (http://maven.apache.org/surefire/maven-surefire-plugin/examples/single-test.html).
You can also specify a different suiteXMLFile like:
```bash
mvn test -DsuiteXmlFile=src/resources/your-custom-suite.xml
```
Or even a single test:
```bash
mvn test -Dtest=org.alfresco.cmis.CmisDemoTests
```
But pay attention that you will not have enabled all the [listeners](#listeners) in this case (the Reporting listener or TestRail integration one)
### Perform CMIS Queries
(:glowing_star: please notice that at this point we assert only the results count returned by the query: we plan to extend the functionality to assert on QueryResult iterable objects also: simple modification on [QueryExecutor.java](src/main/java/org/alfresco/cmis/dsl/QueryExecutor.java)
There are a couple of ways to test the results count after performing CMIS queries, choose the one that you like the most:
a) direct queries using a simple TestNG test:
(see example [here](src/test/java/org/alfresco/cmis/search/SorlSearchSimpleQueryTests.java))
```java
public class SorlSearchSimpleQueryTests extends CmisTest
{
@Test
public void simpleQueryOnFolderDesc() throws Exception
{
// create here multiple folder as data preparation
cmisApi.authenticateUser(dataUser.getAdminUser())
.withQuery("SELECT * FROM cmis:folder ORDER BY cmis:createdBy DESC").assertResultsCount().isLowerThan(101);
}
}
```
- just extend CmisTest
- authenticate with your UserModel and perform the query. The DSL will allow you to assert the result count if is equal, lower or greater than to a particular value. You can update the methods in [QueryResultAssertion](src/main/java/org/alfresco/cmis/dsl/QueryExecutor.java) class.
b) define one set of test data (folders, files, etc. ) that you will search in all tests then execute all CMIS queris from one common XML file
- see test class [SolrSearchInFolderTests](src/test/java/org/alfresco/cmis/search/SolrSearchInFolderTests.java)
- see [XML test data](src/main/resources/shared-resources/testdata/search-in-folder.xml) used in [SolrSearchInFolderTests](src/test/java/org/alfresco/cmis/search/SolrSearchInFolderTests.java) into one DataProvider. Notice that XML file has two parameter: the query that will be executed and the expected result count returned.
c) define test data (user, sites, folder, files, aspects, comments, custom models, etc) all into one XML file with all cmis queries related.
- see example on [SolrSearchByIdTests](https://gitlab.alfresco.com/tas/alfresco-tas-cmis-test/blob/master/src/test/java/org/alfresco/cmis/search/SolrSearchByIdTests.java)
- notice the 'NODE_REF[x]'; 'NODE_REF[y]' keywords that will dynamically take the test data identified by id: x, y (you will figure it out based on examples).
**Info**: all search test queries are found [org.alfresco.cmis.search](src/test/java/org/alfresco/cmis/search) package.
**[Back to Top ^](#table-of-contents)**
## Listeners
With the help of Listeners we can modify the behaviour of TestNG framework. There are a lot of testNG listener interfaces that we can override in order to provide new functionalities.
The tas framework provides out of the box a couple of listeners that you could use. These could be enabled and added at the class level or suite level.
### a) org.alfresco.utility.report.ReportListenerAdapter
* if added at the class level:
```java
@Listeners(value=ReportListenerAdapter.class)
public class MyTestClass extends CmisTest
{
(...)
}
```
* or suite xml level
```java
<suite name="Your Suite test" parallel="classes">
<listeners>
<listener class-name="org.alfresco.utility.report.ReportListenerAdapter"></listener>
</listeners>
(...)
</suite>
```
It will automatically generate one html named "report.html" in ./target/report folder.
Please also take a look at [Test Results](#test-results) section.
### b) org.alfresco.utility.testrail.TestRailExecutorListener
It will automatically update Test Rail application with the test cases that you've automated.
Please take a look at [Test Rail Integration](#test-rail-integration) section for more details.
### c) org.alfresco.utility.report.log.LogsListener
This is a new listener that will generate further details in one XML format of the automated test steps that you will write.
Example:
```java
public void myDSLMethod1()
{
STEP("Lorem ipsum dolor sit amet");
//code for first step
STEP("consectetur adipiscing elit");
//code for the next description
}
public void myDSLMethod2()
{
STEP("sed do eiusmod tempor incididunt ut labore");
//code for first step
STEP("et dolore magna aliqua");
//code for the next description
}
```
If these methods will be executed insite a test method, all those steps will be automatically logged in the XML report generated.
Example:
```java
@Test
public void adminShouldCreateFileInSite()
{
myDSLMethod1();
myDSLMethod2()
}
```
So if "testingSomething" will be executed this is what you will see on the XML file generated. (please take a look at [Test Results](#test-results) section for defining the defaul location)
Here is one example of XML file generated with these steps:
![](docs/pics/xml-steps-report.JPG)
**[Back to Top ^](#table-of-contents)**
## Test Results
We already executed a couple of tests using command line as indicated above. Sweet! Please take a look at [sanity-cmis.xml](src/test/resources/sanity-cmis.xml) one more time.
You will see there that we have one listener added:
```java
<listener class-name="org.alfresco.utility.report.ReportListenerAdapter"></listener>
```
This will tell our framework, after we run all tests, to generate one HTML report file with graphs and metrics.
Take a look at the target/reports folder (created after running the tests) and open the report.html file.
![](docs/pics/html-report-sample.JPG)
Playing with this report, you will notice that you will be able to:
* search tests cases by name
* filter test cases by errors, labels, groups, test types, date when it was executed, protocol used, etc.
* view overall pass/fail metrics of current test suite, history of tests execution, etc.
The report path can be configured in default.properties):
```
# The location of the reports path
reports.path=your-new-location-of-reports
```
**[Back to Top ^](#table-of-contents)**
## Test Rail Integration
Alfresco is using now https://alfresco.testrail.net (v5.3.0.3601).
We aim to accelerate the delivery of automated test by minimizing the interaction with the test management tool - TestRail. In this scope we developed the following capabilities:
* creating automatically the manual tests in TestRail
* submitting the test results (with stack trace) after each execution into TestRail Test Runs
* adding the test steps for each test.
### Configuration
In order to use Test Rail Integration you will need to add a couple of information in [default.properties](src/test/resources/default.properties) file:
(the document is pretty self explanatory)
```java
# Example of configuration:
# ------------------------------------------------------
# testManagement.endPoint=https://alfresco.testrail.com/
# testManagement.username=<yourusername-that-you-connect-to-testrail>
# testManagement.apiKey=<api-key>
# testManagement.project=<id-of-your-project
# testManagement.testRun=<test-run-name>
```
!This settings are already defined in default.properties for you.
For generating a new API Key take a look at the official documentation, TestRail [APIv2](http://docs.gurock.com/testrail-api2)
* _testManagement.project= **<id-of-your-project**_ this is the ID of the project where you want to store your test cases.
If you want to use [Alfresco ONE](https://alfresco.testrail.net/index.php?/projects/overview/1) project in TestRail, open that project and notice the URL, after "/overview/**1**" link you will see the ID of the project (1 in this case)
If you want to use [TAS Project](https://alfresco.testrail.net/index.php?/projects/overview/7) you will notice the ID 7, so _"testManagement.project=7"_
* "_testManagement.testRun=<test-run-name>_" this represents the name of the Test Run from your project.
* In Test Rail, navigating to Test Runs & Results, create a new Test Run and include all/particular test cases. If this test run name is "Automation", update _testManagement.testRun= **Automation**_.
All test results will be updated only on this test run at runtime as each test is executed by TAS framework.
### How to enable Test Rail Integration?
We wanted to simplify the Test Rail integration, so we used listeners in order to enable/disable the integration of Test Rail.
* first configure your default.properties as indicated above
* now on your TestNG test, add the @TestRail annotation, so let's say you will have this test:
```java
@Test(groups="sample-tests")
public void thisAutomatedTestWillBePublishedInTestRail()
{
}
```
add now @TestRail integration with mandatory field ```section```. This means that this tests annotated, will be uploaded in TestRail:
```java
@Test(groups="sample-tests")
@TestRail(section = { "protocols", "TBD" })
public void thisAutomatedTestWillBePublishedInTestRail()
{
}
```
The section field, represents an array of strings, the hierarchy of sections that SHOULD be found on TestRail under the project you've selected in default.properties. Follow the TestRail [user-guide](http://docs.gurock.com/testrail-userguide/start) for more information regarding sections.
In our example we created in Test Rail one root section "protocols" with a child section: "TBD" (you can go further and add multiple section as you wish)
* now, lets add the listener, the TestRailExecutorListener that will handle this TC Management interaction.
This listener can be added at the class level or suite level (approach that we embrace)
Take a look at [sanity-cmis.xml](src/test/resources/sanity-cmis.xml) for further example.
```xml
<listeners>
<listener class-name="org.alfresco.utility.testrail.TestRailExecutorListener"></listener>
(...)
</listeners>
```
Right click on cmis-suites.xml file and run it, or just "mvn test" from root if this sample project.
After everything passes, go in Test Rail, open your project and navigate to "Test Cases" section. Notice that under protocols/TBD section, you will see your test case published.
If you defined also the "testManagement.testRun" correctly, you will see under Test Runs, the status of this case marked as passed.
The @TestRail annotation offers also other options like:
- "description" this is the description that will be updated in Test Rail for your test case
- "testType", the default value is set to Functional test
- "executionType", default value is set to ExecutionType.REGRESSION, but you can also use ExecutionType.SMOKE, ExecutionType.SANITY, etc
Take a look at the demo scenarios in this project for further examples.
**[Back to Top ^](#table-of-contents)**
## Reference
* For any improvements, bugs, please use Jira - [TAS](https://issues.alfresco.com/jira/browse/TAS) project.
* Setup the environment using [docker](https://gitlab.alfresco.com/tas/alfresco-docker-provisioning/blob/master/Readme.md).
* [Bamboo Test Plan](https://bamboo.alfresco.com/bamboo/browse/TAS-CMIS)
## Contributors
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other... [more](CODE_OF_CONDUCT.md)
## Releasing
Any commit done on this project should be automatically executed by [TAS Build Plan](https://bamboo.alfresco.com/bamboo/browse/TAS-TAS)
If the build passes, then you didn't broke anything.
If you want to perform a release, open [TAS-CMIS](https://bamboo.alfresco.com/bamboo/browse/TAS-CMIS) Bamboo Build.
Run the Default stage and if it passes, then manually perform the Release stage (this will auto-increment the version in pom.xml)
## License
TBD

View File

@@ -0,0 +1,20 @@
:paw_prints: Back to Utility [README](README.md).
---
# Change Log
All notable changes to this project will be documented in this file.
Each tag bellow has a corresponded version released in [Nexus](https://nexus.alfresco.com/nexus/#welcome).
Currently we are testing [CMIS v1.1](http://docs.oasis-open.org/cmis/CMIS/v1.1/CMIS-v1.1.html) with Alfresco One.
(if you need to update/polish tests please branch from the release tags)
## [[v5.2.0-1] - 2016-12-12](/tas/alfresco-tas-cmis-test/commits/v5.2.0-1)
### TBD
## [[v5.2.0-0] - 2016-12-12](/tas/alfresco-tas-cmis-test/commits/v5.2.0-0)
- works with 5.2 alfresco
- 100% Core tests for CMIS
- 100% Sanity test for CMIS
- use released v1.0.7 utility

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -1,27 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0"?>
<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>
<groupId>org.alfresco.tas</groupId>
<artifactId>alfresco-community-repo-cmis-test</artifactId>
<name>cmis test</name>
<packaging>jar</packaging>
<artifactId>cmis</artifactId>
<name>alfresco-tas-cmis</name>
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<developers>
<developer>
<name>Paul Brodner</name>
<roles>
<role>Test Automation Architect</role>
</roles>
</developer>
</developers>
<organization>
<name>Alfresco Software</name>
<url>http://www.alfresco.com/</url>
</organization>
<properties>
<maven.build.sourceVersion>11</maven.build.sourceVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<chemistry-opencmis-commons-api>1.1.0</chemistry-opencmis-commons-api>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<maven-release.version>2.5.3</maven-release.version>
<java.version>11</java.version>
<suiteXmlFile>${project.basedir}/src/test/resources/cmis-suite.xml</suiteXmlFile>
<cmis.binding />
<cmis.basePath />
@@ -58,10 +58,29 @@
</profiles>
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>4.7.1.Final</version>
</dependency>
<!-- alfresco tester settings -->
<dependency>
<groupId>org.alfresco.tas</groupId>
<artifactId>cmis</artifactId>
<scope>test</scope>
<artifactId>utility</artifactId>
<exclusions>
<exclusion>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- open cmis settings -->
<dependency>
<groupId>org.apache.chemistry.opencmis</groupId>
<artifactId>chemistry-opencmis-commons-api</artifactId>
<version>${chemistry-opencmis-commons-api}</version>
</dependency>
</dependencies>

View File

@@ -0,0 +1,130 @@
package org.alfresco.cmis;
import org.alfresco.utility.data.AisToken;
import org.alfresco.utility.data.auth.DataAIS;
import org.alfresco.utility.model.UserModel;
import org.apache.chemistry.opencmis.commons.SessionParameter;
import org.keycloak.authorization.client.util.HttpResponseException;
import org.keycloak.representations.AccessTokenResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import static org.alfresco.utility.report.log.Step.STEP;
@Service
public class AuthParameterProviderFactory
{
public static String STEP_PREFIX = "CMIS AuthParameterProvider:";
@Autowired
private DataAIS dataAIS;
@Autowired
private CmisProperties cmisProperties;
/**
*
* The default provider uses AIS if support for Alfresco Identity Service is enabled.
* Otherwise a provider which uses Basic authentication is returned.
*
* @return Function which takes a {@link UserModel} and returns a map of
* authentication parameters to be used with {@link CmisWrapper#authenticateUser(UserModel, Function)}
*/
public Function<UserModel, Map<String, String>> getDefaultProvider()
{
if (dataAIS.isEnabled())
{
STEP(String.format("%s Retrieved default AIS auth parameter provider.", STEP_PREFIX));
return new AisAuthParameterProvider();
}
else
{
STEP(String.format("%s Retrieved default Basic auth parameter provider.", STEP_PREFIX));
return new BasicAuthParameterProvider();
}
}
public Function<UserModel, Map<String, String>> getAISProvider()
{
return new AisAuthParameterProvider();
}
public Function<UserModel, Map<String, String>> getBasicProvider()
{
return new BasicAuthParameterProvider();
}
private class BasicAuthParameterProvider implements Function<UserModel, Map<String, String>>
{
@Override
public Map<String, String> apply(UserModel userModel)
{
STEP(String.format("%s Using Basic auth parameter provider.", STEP_PREFIX));
Map<String, String> parameters = new HashMap<>();
parameters.put(SessionParameter.USER, userModel.getUsername());
parameters.put(SessionParameter.PASSWORD, userModel.getPassword());
return parameters;
}
}
private class AisAuthParameterProvider implements Function<UserModel, Map<String, String>>
{
@Override
public Map<String, String> apply(UserModel userModel)
{
Map<String, String> parameters = new HashMap<>();
STEP(String.format("%s Using AIS auth parameter provider.", STEP_PREFIX));
AisToken aisToken = getAisAccessToken(userModel);
parameters.put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS, "org.apache.chemistry.opencmis.client.bindings.spi.OAuthAuthenticationProvider");
parameters.put(SessionParameter.OAUTH_ACCESS_TOKEN, aisToken.getToken());
parameters.put(SessionParameter.OAUTH_REFRESH_TOKEN, aisToken.getRefreshToken());
parameters.put(SessionParameter.OAUTH_EXPIRATION_TIMESTAMP, String.valueOf(System.currentTimeMillis()
+ (aisToken.getExpiresIn() * 1000))); // getExpiresIn is in seconds
parameters.put(SessionParameter.OAUTH_TOKEN_ENDPOINT, cmisProperties.aisProperty().getAdapterConfig().getAuthServerUrl()
+ "/realms/alfresco/protocol/openid-connect/token");
parameters.put(SessionParameter.OAUTH_CLIENT_ID, cmisProperties.aisProperty().getAdapterConfig().getResource());
return parameters;
}
/**
* Returns a valid access token for valid user credentials in userModel.
* An invalid access token is returned for invalid user credentials,
* which can be used for tests involving non existing or unauthorized users.
* @param userModel
* @return
*/
private AisToken getAisAccessToken(UserModel userModel)
{
String badToken = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJUazFPZ2JqVlo1UEw2bmtsNWFvTUlacTZ4cW9PZzc5WGtzdnJTTUcxLUFZIn0.eyJqdGkiOiI3NTVkMGZiOS03NzI5LTQ1NzYtYWM4Ny1hZWZjZWNiZDE0ZGEiLCJleHAiOjE1NTM2MjQ1NDgsIm5iZiI6MCwiaWF0IjoxNTUzNjI0MjQ4LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0L2F1dGgvcmVhbG1zL2FsZnJlc2NvIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6Ijk4NDE0Njg4LTUwMDUtNDVmOS05YTVjLTlkMDRlODMyYTNkMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFsZnJlc2NvIiwiYXV0aF90aW1lIjowLCJzZXNzaW9uX3N0YXRlIjoiNjJlN2U5YzktZmFlNS00N2RhLTk5MDItMTZjYTJhZWUwMWMwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0KiIsImh0dHBzOi8vbG9jYWxob3N0KiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlci12eGlrcXd3cG5jYmpzeHgifQ.PeLGCNCzj-P2m0knwUU9Vfx4dzLLQER9IdV7GyLel9LRN-3J9nh7GBDRQsyDJ0pqhObQyMg4V3wSsrsXRQ6gKhmUyDemmD-w1YMC2a2HKX6GlxsTEF_f1K_R15lIQOawNVErlWjZWORJGCvCYZOJ99SOmeOC6PGY79zLL94MMnf6dXcegePPMOKG-59eNjBkOylTipYebvM40nbbKrS5vzNHQlvUh4ALFeBoMSKGnLSjQd06Dj4SWojG0p1BrxurqDjW0zz6pQlEAm4vcWApRZ6qBLZcMH8adYix07zCDb87GOn1pmfEBWpwd3BEgC_LLu06guaCPHC9tpeIaDTHLg";
String badRefreshToken = "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJmM2YyMjhjYS1jMzg5LTQ5MGUtOGU1Zi02YWI1MmJhZDVjZGEifQ.eyJqdGkiOiIyNmExZWNhYy00Zjk0LTQwYzctYjJjNS04NTlhZmQ3NjBiYWMiLCJleHAiOjE1NTM2MjYwNDgsIm5iZiI6MCwiaWF0IjoxNTUzNjI0MjQ4LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0L2F1dGgvcmVhbG1zL2FsZnJlc2NvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9hdXRoL3JlYWxtcy9hbGZyZXNjbyIsInN1YiI6Ijk4NDE0Njg4LTUwMDUtNDVmOS05YTVjLTlkMDRlODMyYTNkMiIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJhbGZyZXNjbyIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjYyZTdlOWM5LWZhZTUtNDdkYS05OTAyLTE2Y2EyYWVlMDFjMCIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJwcm9maWxlIGVtYWlsIn0.lRBJQc7tj0rk7JBC0zpM0dDdZgDKjm9wcxP8nzLnXe4";
AisToken aisToken;
try
{
// Attempt to get an access token for userModel from AIS
aisToken = dataAIS.perform().getAccessToken(userModel);
}
catch (HttpResponseException e)
{
// Trying to authenticate with invalid user credentials so return an invalid access token
if (e.getStatusCode() == 401)
{
STEP(String.format("%s Invalid user credentials were provided %s:%s. Using invalid token for reqest.",
STEP_PREFIX, userModel.getUsername(), userModel.getPassword()));
aisToken = new AisToken(badToken, badRefreshToken, System.currentTimeMillis(), 300000);
}
else
{
throw e;
}
}
return aisToken;
}
}
}

View File

@@ -0,0 +1,64 @@
package org.alfresco.cmis;
import org.alfresco.utility.TasAisProperties;
import org.alfresco.utility.TasProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@PropertySource("classpath:default.properties")
@PropertySource(value = "classpath:${environment}.properties", ignoreResourceNotFound = true)
public class CmisProperties
{
@Autowired
private TasProperties properties;
@Autowired
private TasAisProperties aisProperties;
public TasProperties envProperty()
{
return properties;
}
public TasAisProperties aisProperty()
{
return aisProperties;
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
{
return new PropertySourcesPlaceholderConfigurer();
}
@Value("${cmis.binding}")
private String cmisBinding;
@Value("${cmis.basePath}")
private String basePath;
public String getCmisBinding()
{
return cmisBinding;
}
public String getBasePath()
{
return basePath;
}
public void setBasePath(String basePath)
{
this.basePath = basePath;
}
public void setCmisBinding(String cmisBinding)
{
this.cmisBinding = cmisBinding;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,185 @@
package org.alfresco.cmis.dsl;
import static org.alfresco.utility.report.log.Step.STEP;
import java.util.Iterator;
import java.util.List;
import org.alfresco.cmis.CmisWrapper;
import org.alfresco.utility.LogFactory;
import org.apache.chemistry.opencmis.client.api.ItemIterable;
import org.apache.chemistry.opencmis.client.api.ObjectType;
import org.apache.chemistry.opencmis.client.api.Tree;
import org.apache.chemistry.opencmis.client.runtime.objecttype.ObjectTypeHelper;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.testng.Assert;
/**
* DSL for preparing calls on getting the type children of a type.
*/
public class BaseObjectType
{
private CmisWrapper cmisAPI;
private String baseTypeID;
private boolean includePropertyDefinition = false;
private Logger LOG = LogFactory.getLogger();
public BaseObjectType(CmisWrapper cmisAPI, String baseTypeID)
{
this.cmisAPI = cmisAPI;
this.baseTypeID = baseTypeID;
}
public BaseObjectType withPropertyDefinitions()
{
this.includePropertyDefinition = true;
return this;
}
public BaseObjectType withoutPropertyDefinitions()
{
this.includePropertyDefinition = false;
return this;
}
/**
* Example of objectTypeID:
* "D:trx:transferReport" - see {@link ObjectTypeHelper} "D:trx:tempTransferStore"
* "D:imap:imapAttach"
*
* @param objectTypeID
*/
public PropertyDefinitionObject hasChildren(String objectTypeID)
{
return checkChildren(objectTypeID, true);
}
/**
* Example of objectTypeID:
* "D:trx:transferReport" - see {@link ObjectTypeHelper} "D:trx:tempTransferStore"
* "D:imap:imapAttach"
*
* @param objectTypeID
*/
public CmisWrapper doesNotHaveChildren(String objectTypeID)
{
checkChildren(objectTypeID, false);
return cmisAPI;
}
/**
* Example of objectTypeID:
* "D:trx:transferReport" - see {@link ObjectTypeHelper} "D:trx:tempTransferStore"
* "D:imap:imapAttach"
*
* @param objectTypeID
*/
private PropertyDefinitionObject checkChildren(String objectTypeID, boolean exist)
{
ItemIterable<ObjectType> values = cmisAPI.withCMISUtil().getTypeChildren(this.baseTypeID, includePropertyDefinition);
boolean foundChild = false;
PropertyDefinitionObject propDefinition = null;
for (Iterator<ObjectType> iterator = values.iterator(); iterator.hasNext();)
{
ObjectType type = (ObjectType) iterator.next();
LOG.info("Found child Object Type: {}", ToStringBuilder.reflectionToString(type, ToStringStyle.MULTI_LINE_STYLE));
if (type.getId().equals(objectTypeID))
{
foundChild = true;
propDefinition = new PropertyDefinitionObject(type);
break;
}
}
Assert.assertEquals(foundChild, exist,
String.format("Object Type with ID[%s] is found as children for Parent Type: [%s]", objectTypeID, this.baseTypeID));
return propDefinition;
}
public class PropertyDefinitionObject
{
ObjectType type;
public PropertyDefinitionObject(ObjectType type)
{
this.type = type;
}
public PropertyDefinitionObject propertyDefinitionIsEmpty()
{
STEP(String.format("%s Verify that property definitions map is empty.", CmisWrapper.STEP_PREFIX));
Assert.assertTrue(type.getPropertyDefinitions().isEmpty(), "Property definitions is empty.");
return this;
}
public PropertyDefinitionObject propertyDefinitionIsNotEmpty()
{
STEP(String.format("%s Verify that property definitions map is not empty.", CmisWrapper.STEP_PREFIX));
Assert.assertFalse(type.getPropertyDefinitions().isEmpty(), "Property definitions is not empty.");
return this;
}
}
private CmisWrapper checkDescendents(int depth, boolean exist, String... objectTypeIDs)
{
List<Tree<ObjectType>> values = cmisAPI.withCMISUtil().getTypeDescendants(this.baseTypeID, depth, includePropertyDefinition);
for (String objectTypeID : objectTypeIDs)
{
boolean foundChild = false;
for (Tree<ObjectType> tree : values)
{
if (tree.getItem().getId().equals(objectTypeID))
{
foundChild = true;
break;
}
}
Assert.assertEquals(foundChild, exist,
String.format("Assert %b: Descendant [%s] is found as descendant for Type: [%s]", exist, objectTypeID, this.baseTypeID));
if (foundChild)
{
STEP(String.format("%s Cmis object '%s' is found as descendant.", CmisWrapper.STEP_PREFIX, objectTypeID));
}
else
{
STEP(String.format("%s Cmis object '%s' is NOT found as descendant.", CmisWrapper.STEP_PREFIX, objectTypeID));
}
}
return cmisAPI;
}
/**
* Assert that specified descendantType is present in the depth of tree
* Depth can be -1 or >= 1
* Example of objectTypeID:
* "D:trx:transferReport" - see {@link ObjectTypeHelper} "D:trx:tempTransferStore"
* "D:imap:imapAttach"
*
* @param objectTypeID
* @param depth
* @return
*/
public CmisWrapper hasDescendantType(int depth, String... objectTypeIDs)
{
return checkDescendents(depth, true, objectTypeIDs);
}
/**
* Assert that specified descendantType is NOT present in the depth of tree
* Depth can be -1 or >= 1
* Example of objectTypeID:
* "D:trx:transferReport" - see {@link ObjectTypeHelper} "D:trx:tempTransferStore"
* "D:imap:imapAttach"
*
* @param objectTypeID
* @param depth
* @return
*/
public CmisWrapper doesNotHaveDescendantType(int depth, String... objectTypeIDs)
{
checkDescendents(depth, false, objectTypeIDs);
return cmisAPI;
}
}

View File

@@ -0,0 +1,78 @@
package org.alfresco.cmis.dsl;
import org.alfresco.cmis.CmisWrapper;
import org.alfresco.utility.Utility;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
import java.util.Map;
/**
* DSL pertaining only to check in a {@link Document}
*/
public class CheckIn
{
private CmisWrapper cmisWrapper;
private boolean version;
private Map<String, ?> properties;
private String content;
private String comment;
public CheckIn(CmisWrapper cmisWrapper)
{
this.cmisWrapper = cmisWrapper;
}
public CheckIn withMajorVersion()
{
this.version = true;
return this;
}
public CheckIn withMinorVersion()
{
this.version = false;
return this;
}
public CheckIn withContent(String content)
{
this.content = content;
return this;
}
public CheckIn withoutComment()
{
this.comment = null;
return this;
}
public CheckIn withComment(String comment)
{
this.comment = comment;
return this;
}
public CmisWrapper checkIn() throws Exception
{
return checkIn(properties);
}
public CmisWrapper checkIn(Map<String, ?> properties) throws Exception
{
ContentStream contentStream = cmisWrapper.withCMISUtil().getContentStream(content);
try
{
Document pwc = cmisWrapper.withCMISUtil().getPWCDocument();
pwc.refresh();
Utility.waitToLoopTime(2);
pwc.checkIn(version, properties, contentStream, comment);
}
catch(CmisStorageException st)
{
cmisWrapper.withCMISUtil().getPWCDocument().checkIn(version, properties, contentStream, comment);
}
return cmisWrapper;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,761 @@
package org.alfresco.cmis.dsl;
import org.alfresco.cmis.CmisWrapper;
import org.alfresco.cmis.exception.InvalidCmisObjectException;
import org.alfresco.utility.LogFactory;
import org.alfresco.utility.Utility;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.exception.IORuntimeException;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.GroupModel;
import org.alfresco.utility.model.UserModel;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.FileableCmisObject;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.ItemIterable;
import org.apache.chemistry.opencmis.client.api.ObjectType;
import org.apache.chemistry.opencmis.client.api.OperationContext;
import org.apache.chemistry.opencmis.client.api.Property;
import org.apache.chemistry.opencmis.client.api.QueryResult;
import org.apache.chemistry.opencmis.client.api.Rendition;
import org.apache.chemistry.opencmis.client.api.SecondaryType;
import org.apache.chemistry.opencmis.client.api.Tree;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.Ace;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.AclCapabilities;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.PermissionMapping;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
import org.apache.chemistry.opencmis.commons.enums.Action;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.chemistry.opencmis.commons.enums.BindingType;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.testng.collections.Lists;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.alfresco.utility.report.log.Step.STEP;
/**
* DSL utility for managing CMIS objects
*/
public class CmisUtil
{
private CmisWrapper cmisAPI;
private Logger LOG = LogFactory.getLogger();
public CmisUtil(CmisWrapper cmisAPI)
{
this.cmisAPI = cmisAPI;
}
/**
* Get cmis object by object id
*
* @param objectId cmis object id
* @return CmisObject cmis object
*/
public CmisObject getCmisObjectById(String objectId)
{
LOG.debug("Get CMIS object by ID {}", objectId);
if (cmisAPI.getSession() == null)
{
throw new CmisRuntimeException("Please authenticate user, call: cmisAPI.authenticate(..)!");
}
if (objectId == null)
{
throw new InvalidCmisObjectException("Invalid content id");
}
return cmisAPI.getSession().getObject(objectId);
}
/**
* Get cmis object by object id with OperationContext
*
* @param objectId cmis object id
* @param context OperationContext
* @return CmisObject cmis object
*/
public CmisObject getCmisObjectById(String objectId, OperationContext context)
{
if (cmisAPI.getSession() == null)
{
throw new CmisRuntimeException("Please authenticate user, call: cmisAPI.authenticate(..)!");
}
if (objectId == null)
{
throw new InvalidCmisObjectException("Invalid content id");
}
return cmisAPI.getSession().getObject(objectId, context);
}
/**
* Get cmis object by path
*
* @param pathToItem String path to item
* @return CmisObject cmis object
*/
public CmisObject getCmisObject(String pathToItem)
{
if (cmisAPI.getSession() == null)
{
throw new CmisRuntimeException("Please authenticate user, call: cmisAPI.authenticate(..)!");
}
if (pathToItem == null)
{
throw new InvalidCmisObjectException("Invalid path set for content");
}
CmisObject cmisObject = cmisAPI.getSession().getObjectByPath(Utility.removeLastSlash(pathToItem));
if (cmisObject instanceof Document)
{
if (!((Document) cmisObject).getVersionLabel().contentEquals("pwc"))
{
// get last version of document
cmisObject = ((Document) cmisObject).getObjectOfLatestVersion(false);
}
else
{
// get pwc document
cmisObject = cmisAPI.getSession().getObject(((Document) cmisObject).getObjectOfLatestVersion(false).getVersionSeriesCheckedOutId());
}
}
return cmisObject;
}
/**
* Get cmis object by path with context
*
* @param pathToItem String path to item
* @param context OperationContext
* @return CmisObject cmis object
*/
public CmisObject getCmisObject(String pathToItem, OperationContext context)
{
if (cmisAPI.getSession() == null)
{
throw new CmisRuntimeException("Please authenticate user!");
}
if (pathToItem == null)
{
throw new InvalidCmisObjectException("Invalid path set for content");
}
CmisObject cmisObject = cmisAPI.getSession().getObjectByPath(Utility.removeLastSlash(pathToItem), context);
if (cmisObject instanceof Document)
{
if (!((Document) cmisObject).getVersionLabel().contentEquals("pwc"))
{
// get last version of document
cmisObject = ((Document) cmisObject).getObjectOfLatestVersion(false, context);
}
else
{
// get pwc document
cmisObject = cmisAPI.getSession().getObject(((Document) cmisObject).getObjectOfLatestVersion(false, context).getVersionSeriesCheckedOutId());
}
}
return cmisObject;
}
/**
* Get Document object for a file
*
* @param path String path to document
* @return {@link Document} object
*/
public Document getCmisDocument(final String path)
{
LOG.debug("Get CMIS Document by path {}", path);
Document d = null;
CmisObject docObj = getCmisObject(path);
if (docObj instanceof Document)
{
d = (Document) docObj;
}
else if (docObj instanceof Folder)
{
throw new InvalidCmisObjectException("Content at " + path + " is not a file");
}
return d;
}
/**
* Get Folder object for a folder
*
* @param path String path to folder
* @return {@link Folder} object
*/
public Folder getCmisFolder(final String path)
{
Folder f = null;
CmisObject folderObj = getCmisObject(path);
if (folderObj instanceof Folder)
{
f = (Folder) folderObj;
}
else if (folderObj instanceof Document)
{
throw new InvalidCmisObjectException("Content at " + path + " is not a folder");
}
return f;
}
/**
* Helper method to get the contents of a stream
*
* @param stream
* @return
* @throws IORuntimeException
*/
protected String getContentAsString(ContentStream stream)
{
LOG.debug("Get Content as String {}", stream);
InputStream inputStream = stream.getStream();
String result;
try
{
result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
}
catch (IOException e)
{
throw new IORuntimeException(e);
}
IOUtils.closeQuietly(inputStream);
return result;
}
/**
* Copy all the children of the source folder to the target folder
*
* @param sourceFolder
* @param targetFolder
*/
protected void copyChildrenFromFolder(Folder sourceFolder, Folder targetFolder)
{
for (Tree<FileableCmisObject> t : sourceFolder.getDescendants(-1))
{
CmisObject obj = t.getItem();
if (obj instanceof Document)
{
Document d = (Document) obj;
d.copy(targetFolder);
}
else if (obj instanceof Folder)
{
copyFolder((Folder) obj, targetFolder);
}
}
}
/**
* Copy folder with all children
*
* @param sourceFolder source folder
* @param targetFolder target folder
* @return CmisObject of new created folder
*/
public CmisObject copyFolder(Folder sourceFolder, Folder targetFolder)
{
Map<String, Object> folderProperties = new HashMap<String, Object>(2);
folderProperties.put(PropertyIds.NAME, sourceFolder.getName());
folderProperties.put(PropertyIds.OBJECT_TYPE_ID, sourceFolder.getBaseTypeId().value());
Folder newFolder = targetFolder.createFolder(folderProperties);
copyChildrenFromFolder(sourceFolder, newFolder);
return newFolder;
}
protected boolean isPrivateWorkingCopy()
{
boolean result;
try
{
result = getPWCDocument().isVersionSeriesPrivateWorkingCopy();
}
catch (CmisVersioningException cmisVersioningException)
{
result = false;
}
return result;
}
/**
* Returns the PWC (private working copy) ID of the document version series
*/
public Document getPWCDocument()
{
Document document = getCmisDocument(cmisAPI.getLastResource());
String pwcId = document.getVersionSeriesCheckedOutId();
if (pwcId != null)
{
return (Document) cmisAPI.getSession().getObject(pwcId);
}
else
{
throw new CmisVersioningException(String.format("Document %s is not checked out", document.getName()));
}
}
public FileModel getPWCFileModel()
{
Document document = getPWCDocument();
String[] pathTokens = cmisAPI.getLastResource().split("/");
String path = "";
for (int i = 0; i < pathTokens.length - 1; i++)
path = Utility.buildPath(path, pathTokens[i]);
path = Utility.buildPath(path, document.getName());
FileModel fileModel = new FileModel();
fileModel.setName(document.getName());
fileModel.setCmisLocation(path);
return fileModel;
}
protected Folder getFolderParent()
{
return getCmisFolder(cmisAPI.getLastResource()).getFolderParent();
}
/**
* @return List<Action> of allowable actions for the current object
*/
protected List<Action> getAllowableActions()
{
return Lists.newArrayList(getCmisObject(cmisAPI.getLastResource()).getAllowableActions().getAllowableActions());
}
/**
* Returns the requested property. If the property is not available, null is returned
*
* @param propertyId
* @return CMIS Property
*/
protected <T> Property<T> getProperty(String propertyId)
{
CmisObject cmisObject = getCmisObject(cmisAPI.getLastResource());
return cmisObject.getProperty(propertyId);
}
protected List<Rendition> getRenditions()
{
OperationContext operationContext = cmisAPI.getSession().createOperationContext();
operationContext.setRenditionFilterString("*");
CmisObject obj = cmisAPI.getSession().getObjectByPath(cmisAPI.getLastResource(), operationContext);
obj.refresh();
List<Rendition> renditions = obj.getRenditions();
int retry = 0;
while ((renditions == null || renditions.isEmpty()) && retry < Utility.retryCountSeconds)
{
Utility.waitToLoopTime(1);
obj.refresh();
renditions = obj.getRenditions();
retry++;
}
return obj.getRenditions();
}
protected List<SecondaryType> getSecondaryTypes()
{
CmisObject obj = getCmisObject(cmisAPI.getLastResource());
obj.refresh();
return obj.getSecondaryTypes();
}
/**
* Get the children from a parent folder
*
* @return Map<ContentModel, ObjectType>
*/
public Map<ContentModel, ObjectType> getChildren()
{
String folderParent = cmisAPI.getLastResource();
ItemIterable<CmisObject> children = cmisAPI.withCMISUtil().getCmisFolder(folderParent).getChildren();
Map<ContentModel, ObjectType> contents = new HashMap<ContentModel, ObjectType>();
for (CmisObject o : children)
{
ContentModel content = new ContentModel(o.getName());
content.setNodeRef(o.getId());
content.setDescription(o.getDescription());
content.setCmisLocation(Utility.buildPath(folderParent, o.getName()));
contents.put(content, o.getType());
}
return contents;
}
/**
* Gets the folder descendants starting with the current folder
*
* @param depth level of the tree that you want to go to
* - currentFolder
* -- file1.txt
* -- file2.txt
* -- folderB
* --- file3.txt
* --- file4.txt
* e.g. A depth of 1 will give you just the current folder descendants (file1.txt, file2.txt, folder1)
* e.g. A depth of -1 will return all the descendants (file1.txt, file2.txt, folder1, file3.txt and file4.txt)
*/
public List<CmisObject> getFolderDescendants(int depth)
{
return getFolderTreeCmisObjects(getCmisFolder(cmisAPI.getLastResource()).getDescendants(depth));
}
/**
* Returns a list of Cmis objects for the provided Content Models
*
* @param contentModels
*/
public List<CmisObject> getCmisObjectsFromContentModels(ContentModel... contentModels)
{
List<CmisObject> cmisObjects = new ArrayList<>();
for (ContentModel contentModel : contentModels)
cmisObjects.add(getCmisObject(contentModel.getCmisLocation()));
return cmisObjects;
}
public ContentStream getContentStream(String content)
{
String fileName = getCmisDocument(cmisAPI.getLastResource()).getName();
return cmisAPI.getDataContentService().getContentStream(fileName, content);
}
public Acl getAcls()
{
OperationContext context = cmisAPI.getSession().createOperationContext();
context.setIncludeAcls(true);
return getCmisObject(cmisAPI.getLastResource(), context).getAcl();
}
/**
* Gets only the folder descendants for the {@link #getLastResource()} folder
*
* @param depth level of the tree that you want to go to
* - currentFolder
* -- folderB
* -- folderC
* --- folderD
* e.g. A depth of 1 will give you just the current folder descendants (folderB, folderC)
* e.g. A depth of -1 will return all the descendants (folderB, folderC, folderD)
*/
public List<CmisObject> getFolderTree(int depth)
{
return getFolderTreeCmisObjects(getCmisFolder(cmisAPI.getLastResource()).getFolderTree(depth));
}
/**
* Helper method for getFolderTree and getFolderDescendants that cycles threw the folder descendants and returns List<CmisObject>
*/
private List<CmisObject> getFolderTreeCmisObjects(List<Tree<FileableCmisObject>> descendants)
{
List<CmisObject> cmisObjectList = new ArrayList<>();
for (Tree<FileableCmisObject> descendant : descendants)
{
cmisObjectList.add(descendant.getItem());
cmisObjectList.addAll(descendant.getChildren().stream().map(Tree::getItem).collect(Collectors.toList()));
}
return cmisObjectList;
}
protected List<Document> getAllDocumentVersions()
{
return getCmisDocument(cmisAPI.getLastResource()).getAllVersions();
}
public List<Document> getAllDocumentVersionsBy(OperationContext context)
{
return getCmisDocument(cmisAPI.getLastResource()).getAllVersions(context);
}
public List<Document> getCheckedOutDocumentsFromSession()
{
return com.google.common.collect.Lists.newArrayList(cmisAPI.getSession().getCheckedOutDocs());
}
public List<Document> getCheckedOutDocumentsFromSession(OperationContext context)
{
return com.google.common.collect.Lists.newArrayList(cmisAPI.getSession().getCheckedOutDocs(context));
}
public List<Document> getCheckedOutDocumentsFromFolder()
{
Folder folder = cmisAPI.withCMISUtil().getCmisFolder(cmisAPI.getLastResource());
return com.google.common.collect.Lists.newArrayList(folder.getCheckedOutDocs());
}
public List<Document> getCheckedOutDocumentsFromFolder(OperationContext context)
{
Folder folder = cmisAPI.withCMISUtil().getCmisFolder(cmisAPI.getLastResource());
return com.google.common.collect.Lists.newArrayList(folder.getCheckedOutDocs(context));
}
protected boolean isCmisObjectContainedInCmisCheckedOutDocumentsList(CmisObject cmisObject, List<Document> cmisCheckedOutDocuments)
{
for (Document cmisCheckedOutDocument : cmisCheckedOutDocuments)
if (cmisObject.getId().split(";")[0].equals(cmisCheckedOutDocument.getId().split(";")[0]))
return true;
return false;
}
public Map<String, Object> getProperties(ContentModel contentModel, String baseTypeId)
{
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(PropertyIds.OBJECT_TYPE_ID, baseTypeId);
properties.put(PropertyIds.NAME, contentModel.getName());
// WebServices binding does not have SecondaryTypes and cannot be added to Object.
// cm:title and cm:description Policies
if (cmisAPI.getSession().getBinding().getBindingType().value().equals(BindingType.WEBSERVICES.value()))
{
return properties;
}
List<Object> aspects = new ArrayList<Object>();
aspects.add("P:cm:titled");
properties.put(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, aspects);
properties.put("cm:title", contentModel.getTitle());
properties.put("cm:description", contentModel.getDescription());
return properties;
}
public OperationContext setIncludeAclContext()
{
OperationContext context = cmisAPI.getSession().createOperationContext();
context.setIncludeAcls(true);
return context;
}
public List<Ace> createAce(UserModel user, UserRole role)
{
List<String> addPermission = new ArrayList<String>();
addPermission.add(role.getRoleId());
Ace addAce = cmisAPI.getSession().getObjectFactory().createAce(user.getUsername(), addPermission);
List<Ace> addAces = new ArrayList<Ace>();
addAces.add(addAce);
return addAces;
}
public List<Ace> createAce(GroupModel group, UserRole role)
{
List<String> addPermission = new ArrayList<String>();
addPermission.add(role.getRoleId());
Ace addAce = cmisAPI.getSession().getObjectFactory().createAce(group.getDisplayName(), addPermission);
List<Ace> addAces = new ArrayList<Ace>();
addAces.add(addAce);
return addAces;
}
public List<Ace> createAce(UserModel user, String... permissions)
{
List<Ace> addAces = new ArrayList<Ace>();
RepositoryInfo repositoryInfo = cmisAPI.getSession().getRepositoryInfo();
AclCapabilities aclCapabilities = repositoryInfo.getAclCapabilities();
Map<String, PermissionMapping> permissionMappings = aclCapabilities.getPermissionMapping();
for (String perm : permissions)
{
STEP(String.format("%s Add permission '%s' for user %s ", CmisWrapper.STEP_PREFIX, perm, user.getUsername()));
PermissionMapping permissionMapping = permissionMappings.get(perm);
List<String> permissionsList = permissionMapping.getPermissions();
Ace addAce = cmisAPI.getSession().getObjectFactory().createAce(user.getUsername(), permissionsList);
addAces.add(addAce);
}
return addAces;
}
public ObjectType getTypeDefinition()
{
CmisObject cmisObject = cmisAPI.withCMISUtil().getCmisObject(cmisAPI.getLastResource());
return cmisAPI.getSession().getTypeDefinition(cmisObject.getBaseTypeId().value());
}
public ItemIterable<ObjectType> getTypeChildren(String baseType, boolean includePropertyDefinitions)
{
STEP(String.format("%s Get type children for '%s' and includePropertyDefinitions set to '%s'", CmisWrapper.STEP_PREFIX, baseType,
includePropertyDefinitions));
return cmisAPI.getSession().getTypeChildren(baseType, includePropertyDefinitions);
}
public List<Tree<ObjectType>> getTypeDescendants(String baseTypeId, int depth, boolean includePropertyDefinitions)
{
STEP(String.format("%s Get type descendants for '%s' with depth set to %d and includePropertyDefinitions set to '%s'", CmisWrapper.STEP_PREFIX,
baseTypeId, depth, includePropertyDefinitions));
return cmisAPI.getSession().getTypeDescendants(baseTypeId, depth, includePropertyDefinitions);
}
public String getObjectId(String pathToObject)
{
return getCmisObject(pathToObject).getId();
}
/**
* Update property for last resource cmis object
*
* @param propertyName String property name (e.g. cmis:name)
* @param propertyValue Object property value
*/
public void updateProperties(String propertyName, Object propertyValue)
{
Map<String, Object> props = new HashMap<String, Object>();
props.put(propertyName, propertyValue);
getCmisObject(cmisAPI.getLastResource()).updateProperties(props);
}
protected boolean isFolderInList(FolderModel folderModel, List<FolderModel> folders)
{
for (FolderModel folder : folders)
{
if (folderModel.getName().equals(folder.getName()))
{
return true;
}
}
return false;
}
protected boolean isFileInList(FileModel fileModel, List<FileModel> files)
{
for (FileModel file : files)
{
if (fileModel.getName().equals(file.getName()))
{
return true;
}
}
return false;
}
protected boolean isContentInList(ContentModel contentModel, List<ContentModel> contents)
{
for (ContentModel content : contents)
{
if (content.getName().equals(content.getName()))
{
return true;
}
}
return false;
}
/**
* Get children folders from a parent folder
*
* @return List<FolderModel>
*/
public List<FolderModel> getFolders()
{
STEP(String.format("%s Get the folder children from '%s'", CmisWrapper.STEP_PREFIX, cmisAPI.getLastResource()));
Map<ContentModel, ObjectType> children = getChildren();
List<FolderModel> folders = new ArrayList<FolderModel>();
for (Map.Entry<ContentModel, ObjectType> entry : children.entrySet())
{
if (entry.getValue().getId().equals(BaseTypeId.CMIS_FOLDER.value()))
{
FolderModel folder = new FolderModel(entry.getKey().getName());
folder.setNodeRef(entry.getKey().getNodeRef());
folder.setDescription(entry.getKey().getDescription());
folder.setCmisLocation(entry.getKey().getCmisLocation());
folder.setProtocolLocation(entry.getKey().getCmisLocation());
folders.add(folder);
}
}
return folders;
}
/**
* Get children documents from a parent folder
*
* @return List<FolderModel>
*/
public List<FileModel> getFiles()
{
STEP(String.format("%s Get the file children from '%s'", CmisWrapper.STEP_PREFIX, cmisAPI.getLastResource()));
Map<ContentModel, ObjectType> children = getChildren();
List<FileModel> files = new ArrayList<FileModel>();
for (Map.Entry<ContentModel, ObjectType> entry : children.entrySet())
{
if (entry.getValue().getId().equals(BaseTypeId.CMIS_DOCUMENT.value()))
{
FileModel file = new FileModel(entry.getKey().getName());
file.setNodeRef(entry.getKey().getNodeRef());
file.setDescription(entry.getKey().getDescription());
file.setCmisLocation(entry.getKey().getCmisLocation());
file.setProtocolLocation(entry.getKey().getCmisLocation());
files.add(file);
}
}
return files;
}
/*
* Get document(set as last resource) content
*/
public String getDocumentContent()
{
Utility.waitToLoopTime(2);
Document lastVersion = getCmisDocument(cmisAPI.getLastResource());
lastVersion.refresh();
LOG.info(String.format("Get the content from %s - node: %s", lastVersion.getName(), lastVersion.getId()));
ContentStream contentStream = lastVersion.getContentStream();
String actualContent = "";
if (contentStream != null)
{
actualContent = getContentAsString(contentStream);
}
else
{
lastVersion = getCmisDocument(cmisAPI.getLastResource());
lastVersion.refresh();
LOG.info(String.format("Retry get content stream for %s node: %s", lastVersion.getName(), lastVersion.getId()));
contentStream = lastVersion.getContentStream();
if (contentStream != null)
{
actualContent = getContentAsString(contentStream);
}
}
if(actualContent.isEmpty())
{
Utility.waitToLoopTime(2);
Document retryDoc = getCmisDocument(cmisAPI.getLastResource());
retryDoc.refresh();
LOG.info(String.format("Retry get content stream for %s node: %s", retryDoc.getName(), retryDoc.getId()));
contentStream = retryDoc.getContentStream();
if (contentStream != null)
{
actualContent = getContentAsString(contentStream);
}
}
return actualContent;
}
/**
* Get user noderef
*
* @param user {@link UserModel}
*/
public String getUserNodeRef(UserModel user)
{
String objectId = "";
ItemIterable<QueryResult> results = cmisAPI.getSession().query("select cmis:objectId from cm:person where cm:userName = '" + user.getUsername() + "'",
false);
for (QueryResult qResult : results)
{
PropertyData<?> propData = qResult.getPropertyById("cmis:objectId");
objectId = (String) propData.getFirstValue();
}
return objectId;
}
}

View File

@@ -0,0 +1,137 @@
package org.alfresco.cmis.dsl;
import static org.alfresco.utility.report.log.Step.STEP;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.alfresco.cmis.CmisWrapper;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.OperationContext;
import org.testng.Assert;
/**
* DSL utility for verifying a document version {@link Document}
*/
public class DocumentVersioning
{
private CmisWrapper cmisWrapper;
private CmisObject cmisObject;
private boolean majorVersion;
private Object versionLabel;
private List<Object> versions;
public DocumentVersioning(CmisWrapper cmisWrapper, CmisObject cmisObject)
{
this.cmisWrapper = cmisWrapper;
this.cmisObject = cmisObject;
}
private DocumentVersioning withLatestMajorVersion()
{
this.majorVersion = true;
return this;
}
private DocumentVersioning withLatestMinorVersion()
{
this.majorVersion = false;
return this;
}
private Document getVersionOfDocument()
{
Document document = (Document) cmisObject;
if (versionLabel != null)
{
List<Document> documents = document.getAllVersions();
for (Document documentVersion : documents)
if (documentVersion.getVersionLabel().equals(versionLabel.toString()))
return documentVersion;
}
else
{
return document.getObjectOfLatestVersion(majorVersion);
}
return document;
}
private List<Object> getDocumentVersions(List<Document> documentList)
{
List<Object> versions = new ArrayList<Object>();
for (Document document : documentList)
{
versions.add(document.getVersionLabel());
}
return versions;
}
public CmisWrapper assertVersionIs(Double expectedVersion)
{
STEP(String.format("%s Verify if document '%s' has version '%s'", cmisWrapper.getProtocolName(), cmisObject.getName(), expectedVersion));
Assert.assertEquals(getVersionOfDocument().getVersionLabel(), expectedVersion.toString(), "File has version");
return cmisWrapper;
}
public CmisWrapper assertLatestMajorVersionIs(Double expectedVersion)
{
STEP(String.format("%s Verify if latest major version of document '%s' is '%s'", cmisWrapper.getProtocolName(), cmisObject.getName(), expectedVersion));
Assert.assertEquals(withLatestMajorVersion().getVersionOfDocument().getVersionLabel(), expectedVersion.toString(), "File has version");
return cmisWrapper;
}
public CmisWrapper assertLatestMinorVersionIs(Double expectedVersion)
{
STEP(String.format("%s Verify if latest minor version of document '%s' is '%s'", cmisWrapper.getProtocolName(), cmisObject.getName(), expectedVersion));
Assert.assertEquals(withLatestMinorVersion().getVersionOfDocument().getVersionLabel(), expectedVersion.toString(), "File has version");
return cmisWrapper;
}
public DocumentVersioning getAllDocumentVersions()
{
setVersions(getDocumentVersions(cmisWrapper.withCMISUtil().getAllDocumentVersions()));
return this;
}
public CmisWrapper assertHasVersions(Object... versions)
{
setVersions(getDocumentVersions(cmisWrapper.withCMISUtil().getAllDocumentVersions()));
List<Object> documentVersions = getVersions();
for (Object version : versions)
{
STEP(String.format("%s Verify if document '%s' has version '%s'", cmisWrapper.getProtocolName(), cmisObject.getName(), version));
Assert.assertTrue(documentVersions.contains(version.toString()),
String.format("Document %s does not have version %s", cmisObject.getName(), version));
}
return cmisWrapper;
}
public DocumentVersioning getAllDocumentVersionsBy(OperationContext context)
{
setVersions(getDocumentVersions(cmisWrapper.withCMISUtil().getAllDocumentVersionsBy(context)));
return this;
}
public CmisWrapper assertHasVersionsInOrder(Object... versions)
{
List<Object> documentVersions = getVersions();
List<Object> expectedVersions = Arrays.asList(versions);
STEP(String.format("%s Verify if document '%s' has versions in this order '%s'", cmisWrapper.getProtocolName(), cmisObject.getName(),
Arrays.toString(expectedVersions.toArray())));
Assert.assertTrue(documentVersions.toString().equals(expectedVersions.toString()),
String.format("Document %s does not have versions in this order %s", cmisObject.getName(), Arrays.toString(expectedVersions.toArray())));
return cmisWrapper;
}
public List<Object> getVersions()
{
return versions;
}
public void setVersions(List<Object> versions)
{
this.versions = versions;
}
}

View File

@@ -0,0 +1,39 @@
package org.alfresco.cmis.dsl;
import org.alfresco.cmis.CmisWrapper;
import org.alfresco.utility.network.Jmx;
import org.alfresco.utility.network.JmxClient;
import org.alfresco.utility.network.JmxJolokiaProxyClient;
/**
* DSL for interacting with JMX (using direct JMX call see {@link JmxClient} or {@link JmxJolokiaProxyClient}
*/
public class JmxUtil
{
@SuppressWarnings("unused")
private CmisWrapper cmisWrapper;
private Jmx jmx;
private final String jmxAuditObjectName = "Alfresco:Type=Configuration,Category=Audit,id1=default";
public JmxUtil(CmisWrapper cmisWrapper, Jmx jmx)
{
this.cmisWrapper = cmisWrapper;
this.jmx = jmx;
}
public void enableCMISAudit() throws Exception
{
if(jmx.readProperty(jmxAuditObjectName, "audit.enabled").equals(String.valueOf(false)))
{
jmx.writeProperty(jmxAuditObjectName, "audit.enabled", String.valueOf(true));
}
jmx.writeProperty(jmxAuditObjectName, "audit.cmischangelog.enabled", String.valueOf(true));
jmx.writeProperty(jmxAuditObjectName, "audit.alfresco-access.enabled", String.valueOf(true));
}
public void disableCMISAudit() throws Exception
{
jmx.writeProperty(jmxAuditObjectName, "audit.cmischangelog.enabled", String.valueOf(false));
jmx.writeProperty(jmxAuditObjectName, "audit.alfresco-access.enabled", String.valueOf(false));
}
}

View File

@@ -0,0 +1,287 @@
package org.alfresco.cmis.dsl;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static org.alfresco.utility.Utility.checkObjectIsInitialized;
import static org.alfresco.utility.report.log.Step.STEP;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.StreamSupport;
import org.alfresco.cmis.CmisWrapper;
import org.alfresco.utility.LogFactory;
import org.alfresco.utility.data.provider.XMLTestData;
import org.alfresco.utility.exception.TestConfigurationException;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestModel;
import org.apache.chemistry.opencmis.client.api.ItemIterable;
import org.apache.chemistry.opencmis.client.api.QueryResult;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.slf4j.Logger;
import org.testng.Assert;
/**
* DSL for CMIS Queries
* This will also handle execution of CMIS queries
*/
public class QueryExecutor
{
static Logger LOG = LogFactory.getLogger();
CmisWrapper cmisWrapper;
private long resultCount = -1;
private String currentQuery = "";
private List<QueryResult> results;
public QueryExecutor(CmisWrapper cmisWrapper, String query)
{
this.cmisWrapper = cmisWrapper;
currentQuery = query;
}
public QueryResultAssertion assertResultsCount()
{
resultCount = executeQuery(currentQuery).getPageNumItems();
return new QueryResultAssertion();
}
public QueryResultAssertion assertColumnIsOrdered()
{
return assertValues();
}
public QueryResultAssertion assertColumnValuesRange()
{
return assertValues();
}
public QueryResultAssertion assertValues()
{
STEP("Sending query " + currentQuery);
results = StreamSupport.stream(executeQuery(currentQuery).spliterator(), false)
.collect(toList());
resultCount = results.size();
STEP("Received results " + results.stream().map(this::resultToString).collect(toList()));
return new QueryResultAssertion();
}
/** Try to return a useful string representation of the CMIS query result. */
private String resultToString(QueryResult result)
{
if (result == null || result.getProperties() == null)
{
return "null";
}
Optional<PropertyData<?>> idProperty = result.getProperties().stream()
.filter(propertyData -> propertyData.getId().equals("cmis:objectId"))
.findFirst();
return idProperty.map(PropertyData::getValues)
.map(values -> values.stream().map(Object::toString).collect(joining(",")))
.orElse(result.getProperties().toString());
}
private ItemIterable<QueryResult> executeQuery(String query)
{
Session session = cmisWrapper.getSession();
checkObjectIsInitialized(session, "You need to authenticate first using <cmisWrapper.authenticateUser(UserModel userModel)>");
return session.query(query, false);
}
/**
* Call getNodeRef on each test data item used in test and replace that with NODE_REF keywords in your Query
*
* @param testData
* @return
*/
public QueryExecutor applyNodeRefsFrom(XMLTestData testData)
{
List<String> dataItems = extractKeywords("NODE_REF");
if (dataItems.isEmpty())
return this;
List<String> nodeRefs = new ArrayList<String>();
for (String dataItemName : dataItems)
{
currentQuery = currentQuery.replace(String.format("NODE_REF[%s]", dataItemName), "%s");
TestModel model = testData.getTestDataItemWithId(dataItemName).getModel();
if (model == null)
throw new TestConfigurationException("No TestData with ID: " + dataItemName + " found in your XML file.");
if (model instanceof SiteModel)
{
nodeRefs.add(cmisWrapper.getDataContentService().usingAdmin().usingSite((SiteModel) model).getNodeRef());
}
else if (model instanceof FolderModel)
{
nodeRefs.add(((FolderModel) model).getNodeRef());
}
else if (model instanceof FileModel)
{
nodeRefs.add(((FileModel) model).getNodeRef());
}
}
try
{
currentQuery = String.format(currentQuery, nodeRefs.toArray());
LOG.info("Injecting nodeRef IDs \n\tQuery: [{}]", currentQuery);
}
catch (Exception e)
{
throw new TestConfigurationException(
"You passed multiple keywords to your search query, please re-analyze your query search format: " + e.getMessage());
}
return this;
}
/**
* if you have in your search 'SELECT * from cmis:document where workspace://SpacesStore/NODE_REF[site1] or workspace://SpacesStore/NODE_REF[site2]'
* and pass key="NODE_REF" this method will get "site1" and "site2" as values
*
* @param key
* @return
* @throws TestConfigurationException
*/
private List<String> extractKeywords(String key) throws TestConfigurationException
{
String[] lines = currentQuery.split(key);
List<String> keywords = new ArrayList<String>();
for (int i = 0; i < lines.length; i++)
{
if (lines[i].startsWith("["))
{
String keyValue = "";
for (int j = 1; j < lines[i].length() - 1; j++)
{
String tmp = Character.toString(lines[i].charAt(j));
if (tmp.equals("]"))
break;
keyValue += tmp;
}
keywords.add(keyValue);
}
}
return keywords;
}
public class QueryResultAssertion
{
public QueryResultAssertion hasLength(long expectedValue)
{
STEP(String.format("Verify that query: '%s' has %d results count returned", currentQuery, expectedValue));
Assert.assertEquals(resultCount, expectedValue, showErrorMessage());
return this;
}
public QueryResultAssertion isGreaterThan(long expectedValue)
{
STEP(String.format("Verify that query: '%s' has more than %d results count returned", currentQuery, expectedValue));
if (expectedValue <= resultCount)
Assert.fail(String.format("%s expected to have more than %d results, but found %d", showErrorMessage(), expectedValue, resultCount));
return this;
}
public QueryResultAssertion isLowerThan(long expectedValue)
{
STEP(String.format("Verify that query: '%s' has more than %d results count returned", currentQuery, expectedValue));
if (resultCount >= expectedValue)
Assert.fail(String.format("%s expected to have less than %d results, but found %d", showErrorMessage(), expectedValue, resultCount));
return this;
}
public QueryResultAssertion isOrderedAsc(String queryName)
{
STEP(String.format("Verify that query: '%s' is returning ascending ordered values for column %s", currentQuery, queryName));
List<Object> columnValues = new ArrayList<>();
results.forEach((r) -> {
columnValues.add(r.getPropertyValueByQueryName(queryName));
});
List<Object> orderedColumnValues = columnValues.stream().sorted().collect(toList());
Assert.assertEquals(columnValues, orderedColumnValues,
String.format("%s column values expected to be in ascendent order, but found %s", queryName, columnValues.toString()));
return this;
}
public QueryResultAssertion isOrderedDesc(String queryName)
{
STEP(String.format("Verify that query: '%s' is returning descending ordered values for column %s", currentQuery, queryName));
List<Object> columnValues = new ArrayList<>();
results.forEach((r) -> {
columnValues.add(r.getPropertyValueByQueryName(queryName));
});
List<Object> reverseOrderedColumnValues = columnValues.stream().sorted(Collections.reverseOrder()).collect(toList());
Assert.assertEquals(columnValues, reverseOrderedColumnValues,
String.format("%s column values expected to be in descendent order, but found %s", queryName, columnValues.toString()));
return this;
}
public QueryResultAssertion isReturningValuesInRange(String queryName, BigDecimal minValue, BigDecimal maxValue)
{
STEP(String.format("Verify that query: '%s' is returning values for column %s in range from %.4f to %.4f", currentQuery, queryName, minValue, maxValue));
results.forEach((r) -> {
BigDecimal value = (BigDecimal) r.getPropertyValueByQueryName(queryName);
if (value.compareTo(minValue) < 0 || value.compareTo(maxValue) > 0)
{
Assert.fail(String.format("%s column values expected to be in range from %.4f to %.4f, but found %.4f", queryName, minValue, maxValue, value));
}
});
return this;
}
public <T> QueryResultAssertion isReturningValues(String queryName, Set<T> values)
{
return isReturningValues(queryName, values, false);
}
public <T> QueryResultAssertion isReturningValues(String queryName, Set<T> values, boolean multivalue)
{
STEP(String.format("Verify that query: '%s' returns the values from %s for column %s", currentQuery, values, queryName));
Function<QueryResult, Object> extractValue = (multivalue ? (r -> r.getPropertyMultivalueById(queryName)) : r -> r.getPropertyValueById(queryName));
Set<Object> resultSet = results.stream().map(extractValue).collect(toSet());
Assert.assertEquals(resultSet, values, "Values did not match - expected " + values + " got " + resultSet);
return this;
}
public <T> QueryResultAssertion isReturningOrderedValues(String queryName, List<T> values)
{
return isReturningOrderedValues(queryName, values, false);
}
public <T> QueryResultAssertion isReturningOrderedValues(String queryName, List<T> values, boolean multivalue)
{
STEP(String.format("Verify that query: '%s' returns the values from %s for column %s", currentQuery, values, queryName));
Function<QueryResult, Object> extractValue = (multivalue ? (r -> r.getPropertyMultivalueById(queryName)) : r -> r.getPropertyValueById(queryName));
List<Object> resultList = results.stream().map(extractValue).collect(toList());
// Include both lists in assertion message as TestNG does not provide this information.
Assert.assertEquals(resultList, values, "Values did not match expected " + values + " but found " + resultList);
return this;
}
private String showErrorMessage()
{
return String.format("Returned results count of Query [%s] is not the expected one:", currentQuery);
}
}
}

View File

@@ -0,0 +1,10 @@
package org.alfresco.cmis.exception;
public class InvalidCmisObjectException extends RuntimeException
{
private static final long serialVersionUID = 1L;
public InvalidCmisObjectException(String reason)
{
super(reason);
}
}

View File

@@ -0,0 +1,12 @@
package org.alfresco.cmis.exception;
public class UnrecognizedBinding extends Exception
{
private static final long serialVersionUID = 1L;
private static final String DEFAULT_MESSAGE = "Unrecognized CMIS Binding [%s]. Available binding options: BROWSER or ATOM";
public UnrecognizedBinding(String binding)
{
super(String.format(DEFAULT_MESSAGE, binding));
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="org.alfresco" />
<import resource="classpath:dataprep-context.xml" />
<import resource="classpath*:alfresco-tester-context.xml" />
</beans>

View File

@@ -0,0 +1,76 @@
# dataprep related
alfresco.scheme=http
alfresco.server=localhost
alfresco.port=8081
# credentials
admin.user=admin
admin.password=admin
solrWaitTimeInSeconds=30
# in containers we cannot access directly JMX, so we will use http://jolokia.org agent
# disabling this we will use direct JMX calls to server
jmx.useJolokiaAgent=false
# Server Health section
# in ServerHealth#isServerReachable() - could also be shown.
# enable this option to view if on server there are tenants or not
serverHealth.showTenants=true
# set CMIS binding to 'browser' or 'atom'
cmis.binding=browser
cmis.basePath=/alfresco/api/-default-/public/cmis/versions/1.1/${cmis.binding}
# TEST MANAGEMENT SECTION - Test Rail
#
# (currently supporting Test Rail v5.2.1.3472 integration)
#
# Example of configuration:
# ------------------------------------------------------
# if testManagement.enabled=true we enabled TestRailExecutorListener (if used in your suite xml file)
# testManagement.updateTestExecutionResultsOnly=true (this will just update the results of a test: no step will be updated - good for performance)
# testManagement.endPoint=https://alfresco.testrail.com/
# testManagement.username=<username>
# testManagement.apiKey=<api-key>
# testManagement.project=<id-of-your-project
# testManagement.testRun=<test-run-name>
# testManagement.includeOnlyTestCasesExecuted=true #if you want to include in your run ONLY the test cases that you run, then set this value to false
# testManagement.rateLimitInSeconds=1 #is the default rate limit after what minimum time, should we upload the next request. http://docs.gurock.com/testrail-api2/introduction #Rate Limit
# testManagement.suiteId=23 (the id of the Master suite)
# ------------------------------------------------------
testManagement.enabled=false
testManagement.endPoint=
testManagement.username=
testManagement.apiKey=
testManagement.project=7
testManagement.includeOnlyTestCasesExecuted=true
testManagement.rateLimitInSeconds=1
testManagement.testRun=MyTestRunInTestRail
testManagement.suiteId=12
# The location of the reports path
reports.path=./target/reports
#
# Database Section
# You should provide here the database URL, that can be a differed server as alfresco.
# https://docs.oracle.com/javase/tutorial/jdbc/basics/connecting.html
#
# Current supported db.url:
#
# MySQL:
# db.url = jdbc:mysql://${alfresco.server}:3306/alfresco
#
# PostgreSQL:
# db.url = jdbc:postgresql://<your-DB-IP>:3306/alfresco
#
# Oracle:
# db.url = jdbc:oracle://<your-DB-IP>:3306/alfresco
#
# MariaDB:
# db.url = jdbc:mariadb://<your-DB-IP>:3306/alfresco
#
db.url = jdbc:mysql://${alfresco.server}:3306/alfresco
db.username = alfresco
db.password = alfresco

View File

@@ -0,0 +1,26 @@
# Root logger option
log4j.rootLogger=INFO, file, stdout
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./target/reports/alfresco-tas.log
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
# TestRail particular log file
# Direct log messages to a log file
log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
log4j.appender.testrailLog.File=./target/reports/alfresco-testrail.log
log4j.appender.testrailLog.MaxBackupIndex=10
log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.category.testrail=INFO, testrailLog
log4j.additivity.testrail=false

View File

@@ -1,9 +1,21 @@
package org.alfresco.cmis.search;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static org.alfresco.utility.report.log.Step.STEP;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.alfresco.cmis.CmisProperties;
import org.alfresco.cmis.dsl.QueryExecutor.QueryResultAssertion;
import org.alfresco.utility.Utility;
import org.alfresco.utility.model.ContentModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -45,32 +57,76 @@ public abstract class AbstractCmisE2ETest extends AbstractE2EFunctionalTest
/**
* Repeat Elastic Query till results count returns expectedCountResults
* @param query CMIS Query to be executed
* @param expectedCountResults Number of results expected
* @param expectedResultsCount Number of results expected
* @return true when results count is equals to expectedCountResults
*/
protected boolean waitForIndexing(String query, long expectedCountResults)
protected boolean waitForIndexing(String query, long expectedResultsCount)
{
for (int searchCount = 1; searchCount <= SEARCH_MAX_ATTEMPTS; searchCount++)
try
{
waitForIndexing(query, execution -> execution.hasLength(expectedResultsCount));
return true;
}
catch (AssertionError ae)
{
STEP("Received assertion error for query '" + query + "': " + ae);
return false;
}
}
/**
* Repeat Elastic Query until we get the expected results or we hit the retry limit.
*
* @param query CMIS Query to be executed
* @param expectedResults The expected results (unordered).
*/
protected void waitForIndexing(String query, ContentModel... expectedResults)
{
Set<String> expectedNames = Arrays.stream(expectedResults).map(ContentModel::getName).collect(toSet());
waitForIndexing(query, execution -> execution.isReturningValues("cmis:name", expectedNames));
}
/**
* Repeat Elastic Query until we get the expected results in the given order or we hit the retry limit.
*
* @param query CMIS Query to be executed
* @param expectedResults The expected results (ordered).
*/
protected void waitForIndexingOrdered(String query, ContentModel... expectedResults)
{
List<String> expectedNames = Arrays.stream(expectedResults).map(ContentModel::getName).collect(toList());
waitForIndexing(query, execution -> execution.isReturningOrderedValues("cmis:name", expectedNames));
}
/**
* Repeat Elastic Query until we get the expected results or we hit the retry limit.
*
* @param query CMIS Query to be executed
* @param assertionMethod A method that will be called to check the response and which will throw an AssertionError if they aren't what we want.
*/
protected void waitForIndexing(String query, Consumer<QueryResultAssertion> assertionMethod)
{
int searchCount = 0;
while (true)
{
try
{
cmisApi.withQuery(query).assertResultsCount().equals(expectedCountResults);
return true;
assertionMethod.accept(cmisApi.withQuery(query).assertValues());
return;
}
catch (AssertionError ae)
{
LOGGER.info(String.format("WaitForIndexing in Progress: %s", ae));
searchCount++;
if (searchCount < SEARCH_MAX_ATTEMPTS)
{
LOGGER.info(String.format("WaitForIndexing in Progress: %s", ae));
Utility.waitToLoopTime(getElasticWaitTimeInSeconds(), "Wait For Indexing");
}
else
{
throw ae;
}
}
Utility.waitToLoopTime(getElasticWaitTimeInSeconds(), "Wait For Indexing");
}
return false;
}
}

View File

@@ -1,12 +1,12 @@
package org.alfresco.cmis.search;
import java.util.List;
import java.util.Set;
import org.alfresco.utility.Utility;
import org.alfresco.utility.data.provider.XMLDataConfig;
import org.alfresco.utility.data.provider.XMLTestDataProvider;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FileType;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.QueryModel;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -17,6 +17,21 @@ public class SearchInFolderTests extends AbstractCmisE2ETest
private FolderModel parentFolder, subFolder1, subFolder2, subFolder3;
private FileModel subFile1, subFile2, subFile3, subFile4, subFile5;
/**
* Create test data in the following format:
* <pre>
* testSite
* +- parentFolder
* +- subFile5 (fifthFile.txt: "fifthFile content")
* +- subFolder1
* +- subFolder2
* +- subFolder3 (subFolder)
* +- subFile1 (firstFile.xls)
* +- subFile2 (.pptx)
* +- subFile3 (.txt)
* +- subFile4 (fourthFile.docx: "fourthFileTitle", "fourthFileDescription")
* </pre>
*/
@BeforeClass(alwaysRun = true)
public void createTestData() throws Exception
{
@@ -51,12 +66,164 @@ public class SearchInFolderTests extends AbstractCmisE2ETest
dataContent.deleteSite(testSite);
}
@Test(dataProviderClass = XMLTestDataProvider.class, dataProvider = "getQueriesData")
@XMLDataConfig(file = "src/test/resources/search-in-folder.xml")
public void executeCMISQuery(QueryModel query)
@Test
public void executeCMISQuery_selectFieldsFromFolder()
{
String currentQuery = String.format(query.getValue(), parentFolder.getNodeRef());
String query = "SELECT cmis:name, cmis:parentId, cmis:path, cmis:allowedChildObjectTypeIds" +
" FROM cmis:folder where IN_FOLDER('%s') AND cmis:name = 'subFolder'";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
Assert.assertTrue(waitForIndexing(currentQuery, query.getResults()), String.format("Result count not as expected for query: %s", currentQuery));
waitForIndexing(currentQuery, subFolder3);
}
@Test
public void executeCMISQuery_selectFieldsFromDocument()
{
String query = "SELECT cmis:name, cmis:objectId, cmis:lastModifiedBy, cmis:creationDate, cmis:contentStreamFileName" +
" FROM cmis:document where IN_FOLDER('%s') AND cmis:name = 'fourthFile'";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexing(currentQuery, subFile4);
}
@Test
public void executeCMISQuery_selectParentId()
{
String query = "SELECT cmis:parentId FROM cmis:folder where IN_FOLDER('%s')";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
// Expect to get the same parent for each of the three matches.
String parentId = parentFolder.getNodeRef();
List<String> expectedParentIds = List.of(parentId, parentId, parentId);
waitForIndexing(currentQuery, execution -> execution.isReturningOrderedValues("cmis:parentId", expectedParentIds));
}
@Test
public void executeCMISQuery_inFolder()
{
String query = "SELECT * FROM cmis:document where IN_FOLDER('%s')";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexing(currentQuery, subFile1, subFile2, subFile3, subFile4, subFile5);
}
@Test
public void executeCMISQuery_orderByNameAsc()
{
String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name NOT LIKE 'file%%' ORDER BY cmis:name ASC";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexingOrdered(currentQuery, subFile5, subFile1, subFile4);
}
@Test
public void executeCMISQuery_orderByNameDesc()
{
String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name NOT LIKE 'file%%' ORDER BY cmis:name DESC";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexingOrdered(currentQuery, subFile4, subFile1, subFile5);
}
@Test
public void executeCMISQuery_orderByLastModifiedAsc()
{
String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') ORDER BY cmis:lastModificationDate ASC";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexingOrdered(currentQuery, subFolder1, subFolder2, subFolder3);
}
@Test
public void executeCMISQuery_orderByLastModifiedDesc()
{
String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') ORDER BY cmis:lastModificationDate DESC";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexingOrdered(currentQuery, subFolder3, subFolder2, subFolder1);
}
@Test
public void executeCMISQuery_orderByCreatedBy()
{
String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') ORDER BY cmis:createdBy DESC";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
// All the results were created by the same user, so we can't assert anything about the order.
waitForIndexing(currentQuery, subFile5, subFile1, subFile2, subFile3, subFile4);
}
@Test
public void executeCMISQuery_documentNameNotNull()
{
String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name IS NOT NULL";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexing(currentQuery, subFile1, subFile2, subFile3, subFile4, subFile5);
}
@Test
public void executeCMISQuery_folderNameNotNull()
{
String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') AND cmis:name IS NOT NULL";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexing(currentQuery, subFolder1, subFolder2, subFolder3);
}
@Test
public void executeCMISQuery_nameLike()
{
String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name LIKE 'fourthFile'";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexingOrdered(currentQuery, subFile4);
}
@Test
public void executeCMISQuery_doubleNegative()
{
String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') AND NOT(cmis:name NOT IN ('subFolder'))";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexingOrdered(currentQuery, subFolder3);
}
@Test
public void executeCMISQuery_nameInList()
{
String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name IN ('fourthFile', 'fifthFile.txt')";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexing(currentQuery, subFile4, subFile5);
}
@Test
public void executeCMISQuery_nameNotInList()
{
String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name NOT IN ('fourthFile', 'fifthFile.txt')";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexing(currentQuery, subFile1, subFile2, subFile3);
}
@Test
public void executeCMISQuery_nameDifferentFrom()
{
String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') AND cmis:name <> 'subFolder'";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
waitForIndexing(currentQuery, subFolder1, subFolder2);
}
@Test
public void executeCMISQuery_selectSecondaryObjectTypeIds()
{
String query = "SELECT cmis:secondaryObjectTypeIds FROM cmis:folder where IN_FOLDER('%s') AND cmis:name = 'subFolder'";
String currentQuery = String.format(query, parentFolder.getNodeRef());
cmisApi.authenticateUser(testUser);
Set<List<String>> expectedSecondaryObjectTypeIds = Set.of(List.of("P:cm:titled", "P:sys:localized"));
waitForIndexing(currentQuery, execution -> execution.isReturningValues("cmis:secondaryObjectTypeIds", expectedSecondaryObjectTypeIds, true));
Assert.assertTrue(waitForIndexing(currentQuery, 1), String.format("Result count not as expected for query: %s", currentQuery));
}
}

View File

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

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<developers>
@@ -73,6 +73,7 @@
<dependency>
<groupId>org.alfresco.tas</groupId>
<artifactId>cmis</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

View File

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

View File

@@ -5,6 +5,7 @@ import java.lang.reflect.Method;
import org.alfresco.dataprep.WorkflowService;
import org.alfresco.rest.core.RestProperties;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.rules.RulesTestsUtils;
import org.alfresco.utility.LogFactory;
import org.alfresco.utility.TasProperties;
import org.alfresco.utility.data.DataContent;
@@ -61,6 +62,9 @@ public abstract class RestTest extends AbstractTestNGSpringContextTests
@Autowired
protected WorkflowService workflow;
@Autowired
protected RulesTestsUtils rulesUtils;
protected SiteModel testSite;
@BeforeSuite(alwaysRun = true)

View File

@@ -2,10 +2,13 @@ package org.alfresco.rest.actions;
import static org.testng.Assert.assertFalse;
import com.google.common.collect.ImmutableMap;
import java.util.List;
import com.google.common.collect.ImmutableMap;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestActionConstraintDataModel;
import org.alfresco.rest.model.RestActionConstraintModel;
import org.alfresco.rest.model.RestActionDefinitionModel;
import org.alfresco.rest.model.RestActionDefinitionModelsCollection;
import org.alfresco.rest.model.RestNodeModel;
@@ -148,4 +151,66 @@ public class ActionsTests extends RestTest
restActionDefinition.getDescription().equals("This will add an aspect to the matched item.");
restActionDefinition.getTitle().equals("Add aspect");
}
@TestRail(section = {TestGroup.REST_API, TestGroup.ACTIONS}, executionType = ExecutionType.SANITY,
description = "Sanity test for ACTIONS endpoint GET action-conditions/{actionConstraintName}")
@Test(groups = {TestGroup.REST_API, TestGroup.ACTIONS, TestGroup.SANITY})
public void testGetSingleActionConstraint()
{
final UserModel testUser = dataUser.createRandomTestUser();
restClient.authenticateUser(testUser);
final String compareOperationsName = "ac-compare-operations";
final RestActionConstraintModel actionConstraintCompareOperations =
restClient.withCoreAPI().usingActions().getActionConstraintByName(compareOperationsName);
restClient.assertStatusCodeIs(HttpStatus.OK);
final RestActionConstraintModel expectedComparatorConstraints = new RestActionConstraintModel();
expectedComparatorConstraints.setConstraintName(compareOperationsName);
expectedComparatorConstraints.setConstraintValues(getComparatorConstraints());
actionConstraintCompareOperations.assertThat().isEqualTo(expectedComparatorConstraints);
}
@TestRail(section = {TestGroup.REST_API, TestGroup.ACTIONS}, executionType = ExecutionType.SANITY,
description = "Sanity test for ACTIONS endpoint GET action-conditions/{actionConstraintName} - non existing constraint name")
@Test(groups = {TestGroup.REST_API, TestGroup.ACTIONS, TestGroup.SANITY})
public void testGetSingleNonExistingActionConstraint()
{
final UserModel testUser = dataUser.createRandomTestUser();
restClient.authenticateUser(testUser);
restClient.withCoreAPI().usingActions().getActionConstraintByName("dummy-name");
restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND);
}
private List<RestActionConstraintDataModel> getComparatorConstraints()
{
final RestActionConstraintDataModel equalsConstraint = new RestActionConstraintDataModel();
equalsConstraint.setValue("EQUALS");
equalsConstraint.setLabel("Equals");
final RestActionConstraintDataModel containsConstraint = new RestActionConstraintDataModel();
containsConstraint.setValue("CONTAINS");
containsConstraint.setLabel("Contains");
final RestActionConstraintDataModel beginsConstraint = new RestActionConstraintDataModel();
beginsConstraint.setValue("BEGINS");
beginsConstraint.setLabel("Begins With");
final RestActionConstraintDataModel endsConstraint = new RestActionConstraintDataModel();
endsConstraint.setValue("ENDS");
endsConstraint.setLabel("Ends With");
final RestActionConstraintDataModel greaterThanConstraint = new RestActionConstraintDataModel();
greaterThanConstraint.setValue("GREATER_THAN");
greaterThanConstraint.setLabel("Greater Than");
final RestActionConstraintDataModel greaterThanEqualConstraint = new RestActionConstraintDataModel();
greaterThanEqualConstraint.setValue("GREATER_THAN_EQUAL");
greaterThanEqualConstraint.setLabel("Greater Than Or Equal To");
final RestActionConstraintDataModel lessThanConstraint = new RestActionConstraintDataModel();
lessThanConstraint.setValue("LESS_THAN");
lessThanConstraint.setLabel("Less Than");
final RestActionConstraintDataModel lessThanEqualConstraint = new RestActionConstraintDataModel();
lessThanEqualConstraint.setValue("LESS_THAN_EQUAL");
lessThanEqualConstraint.setLabel("Less Than Or Equal To");
return List.of(equalsConstraint, containsConstraint, beginsConstraint, endsConstraint, greaterThanConstraint,
greaterThanEqualConstraint, lessThanConstraint, lessThanEqualConstraint);
}
}

View File

@@ -1,15 +1,17 @@
package org.alfresco.rest.actions.access;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gson.Gson;
import org.alfresco.rest.actions.access.pojo.Action;
import org.alfresco.rest.actions.access.pojo.ActionCondition;
import org.alfresco.rest.actions.access.pojo.Rule;
import org.alfresco.utility.model.UserModel;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AccessRestrictionUtil {
public static final String MAIL_ACTION = "mail";
@@ -19,8 +21,8 @@ public class AccessRestrictionUtil {
"Only admin or system user is allowed to define uses of or directly execute this action";
private static final String ERROR_MESSAGE_FAILED_TO_SEND_EMAIL = "Failed to send email to:";
public static Map<String, String> createMailParameters(UserModel sender, UserModel recipient) {
Map<String, String> parameterValues = new HashMap<>();
public static Map<String, Serializable> createMailParameters(UserModel sender, UserModel recipient) {
Map<String, Serializable> parameterValues = new HashMap<>();
parameterValues.put("from", sender.getEmailAddress());
parameterValues.put("to", recipient.getEmailAddress());
parameterValues.put("subject", "Test");
@@ -29,7 +31,7 @@ public class AccessRestrictionUtil {
return parameterValues;
}
public static Rule createRuleWithAction(String actionName, Map<String, String> parameterValues) {
public static Rule createRuleWithAction(String actionName, Map<String, Serializable> parameterValues) {
Rule rule = new Rule();
rule.setId("");
rule.setTitle("Test rule title");
@@ -57,7 +59,7 @@ public class AccessRestrictionUtil {
return rule;
}
public static Action createActionWithParameters(String actionName, Map<String, String> parameterValues) {
public static Action createActionWithParameters(String actionName, Map<String, Serializable> parameterValues) {
Action compositeAction = new Action();
compositeAction.setActionDefinitionName("composite-action");
@@ -76,7 +78,7 @@ public class AccessRestrictionUtil {
}
public static Action createAction(String actionName, Map<String, String> parameterValues) {
public static Action createAction(String actionName, Map<String, Serializable> parameterValues) {
Action action = new Action();
action.setActionDefinitionName(actionName);
action.setParameterValues(parameterValues);

View File

@@ -1,5 +1,15 @@
package org.alfresco.rest.actions.access;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_ACCESS_RESTRICTED;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_FIELD;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.MAIL_ACTION;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.createMailParameters;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.getExpectedEmailSendFailureMessage;
import static org.hamcrest.Matchers.containsString;
import java.io.Serializable;
import java.util.Map;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.core.RestRequest;
import org.alfresco.rest.core.RestResponse;
@@ -13,15 +23,6 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.Map;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_ACCESS_RESTRICTED;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_FIELD;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.MAIL_ACTION;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.createMailParameters;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.getExpectedEmailSendFailureMessage;
import static org.hamcrest.Matchers.containsString;
public class FormProcAdminAccessRestrictionTest extends RestTest {
private static final String ACTION_FORM_PROCESSOR_ENDPOINT = "alfresco/service/api/action/%s/formprocessor";
@@ -75,7 +76,7 @@ public class FormProcAdminAccessRestrictionTest extends RestTest {
.assertThat().body(ERROR_MESSAGE_FIELD, containsString(getExpectedEmailSendFailureMessage(testUser)));
}
private String generateBody(Map<String, String> mailParameters) {
private String generateBody(Map<String, Serializable> mailParameters) {
JSONObject json = new JSONObject();
mailParameters.forEach((key, value) -> json.put(PROPERTY_PREFIX + key, value));

View File

@@ -1,21 +1,20 @@
package org.alfresco.rest.actions.access;
import org.alfresco.rest.RestTest;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.alfresco.rest.core.RestWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_ACCESS_RESTRICTED;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.MAIL_ACTION;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.createMailParameters;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class V1AdminAccessRestrictionTest extends RestTest {
private UserModel adminUser;
@@ -45,7 +44,7 @@ public class V1AdminAccessRestrictionTest extends RestTest {
.executeAction(MAIL_ACTION, testFolder, createMailParameters(adminUser, testUser));
restClient.onResponse()
.assertThat().statusCode(HttpStatus.INTERNAL_SERVER_ERROR.value())
.assertThat().statusCode(HttpStatus.FORBIDDEN.value())
.assertThat().body("entry.id", nullValue());
restClient.assertLastError().containsSummary(ERROR_MESSAGE_ACCESS_RESTRICTED);
}

View File

@@ -1,5 +1,6 @@
package org.alfresco.rest.actions.access.pojo;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
@@ -8,7 +9,7 @@ public class Action {
private String actionedUponNode;
private List<ActionCondition> conditions;
private List<Action> actions;
private Map<String, String> parameterValues;
private Map<String, Serializable> parameterValues;
private boolean executeAsynchronously;
@@ -47,11 +48,11 @@ public class Action {
this.actions = actions;
}
public Map<String, String> getParameterValues() {
public Map<String, Serializable> getParameterValues() {
return parameterValues;
}
public void setParameterValues(Map<String, String> parameterValues) {
public void setParameterValues(Map<String, Serializable> parameterValues) {
this.parameterValues = parameterValues;
}
}

View File

@@ -27,9 +27,15 @@ package org.alfresco.rest.rules;
import static java.util.stream.Collectors.toList;
import static org.alfresco.rest.rules.RulesTestsUtils.createActionModel;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
import static org.alfresco.utility.constants.UserRole.*;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_ACCESS_RESTRICTED;
import static org.alfresco.rest.rules.RulesTestsUtils.ID;
import static org.alfresco.rest.rules.RulesTestsUtils.INVERTED;
import static org.alfresco.rest.rules.RulesTestsUtils.IS_SHARED;
import static org.alfresco.rest.rules.RulesTestsUtils.RULE_NAME_DEFAULT;
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
import static org.alfresco.utility.constants.UserRole.SiteConsumer;
import static org.alfresco.utility.constants.UserRole.SiteContributor;
import static org.alfresco.utility.constants.UserRole.SiteManager;
import static org.alfresco.utility.model.FileModel.getRandomFileModel;
import static org.alfresco.utility.model.FileType.TEXT_PLAIN;
import static org.alfresco.utility.report.log.Step.STEP;
@@ -40,9 +46,12 @@ import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
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.RestCompositeConditionDefinitionModel;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleModelsCollection;
import org.alfresco.utility.constants.UserRole;
@@ -72,18 +81,24 @@ public class CreateRulesTests extends RestTest
ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
}
/** Check we can create a rule. */
/**
* Check we can create a rule.
* <p>
* Also check that the isShared field is not returned when not requested.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void createRule()
{
RestRuleModel ruleModel = createRuleModel("ruleName");
RestRuleModel ruleModel = rulesUtils.createRuleModelWithModifiedValues();
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = rulesUtils.createRuleModelWithModifiedValues();
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().field("id").isNotNull()
.assertThat().field("name").is("ruleName");
rule.assertThat().isEqualTo(expectedRuleModel, ID, IS_SHARED)
.assertThat().field(ID).isNotNull()
.assertThat().field(IS_SHARED).isNull();
}
/** Check creating a rule in a non-existent folder returns an error. */
@@ -97,10 +112,10 @@ public class CreateRulesTests extends RestTest
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("ruleName");
restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.authenticateUser(user).withPrivateAPI().usingNode(nonExistentFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.assertStatusCodeIs(NOT_FOUND);
restClient.assertLastError().containsSummary("fake-id was not found");
restClient.assertLastError().containsSummary("Folder with id fake-id was not found");
}
/** Check creating a rule in a non-existent rule set returns an error. */
@@ -111,20 +126,19 @@ public class CreateRulesTests extends RestTest
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("ruleName");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingRuleSet("fake-id").createSingleRule(ruleModel);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingRuleSet("fake-id").createSingleRule(ruleModel);
restClient.assertStatusCodeIs(NOT_FOUND);
restClient.assertLastError().containsSummary("fake-id was not found");
restClient.assertLastError().containsSummary("Rule set with id fake-id was not found");
}
/** Try to create a rule without a name and check the error. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithEmptyName()
{
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("");
RestRuleModel ruleModel = rulesUtils.createRuleModel("");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Rule name is a mandatory parameter");
@@ -134,11 +148,11 @@ public class CreateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void duplicateRuleNameIsAcceptable()
{
RestRuleModel ruleModel = createRuleModel("duplicateRuleName");
RestRuleModel ruleModel = rulesUtils.createRuleModel("duplicateRuleName");
STEP("Create two identical rules");
RestRuleModel ruleA = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
RestRuleModel ruleB = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
RestRuleModel ruleA = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
RestRuleModel ruleB = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
// Check that the names are the same but the ids are different.
ruleA.assertThat().field("name").is(ruleB.getName());
@@ -157,7 +171,7 @@ public class CreateRulesTests extends RestTest
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("ruleName");
restClient.authenticateUser(user).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.authenticateUser(user).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.assertStatusCodeIs(FORBIDDEN);
restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
@@ -209,7 +223,7 @@ public class CreateRulesTests extends RestTest
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("ruleName");
restClient.authenticateUser(user).withCoreAPI().usingNode(fileModel).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.authenticateUser(user).withPrivateAPI().usingNode(fileModel).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("folder is expected");
@@ -221,9 +235,9 @@ public class CreateRulesTests extends RestTest
{
STEP("Create a list of rules in one POST request");
List<String> ruleNames = List.of("ruleA", "ruleB", "ruleC");
List<RestRuleModel> ruleModels = ruleNames.stream().map(RulesTestsUtils::createRuleModel).collect(toList());
List<RestRuleModel> ruleModels = ruleNames.stream().map(rulesUtils::createRuleModel).collect(toList());
RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
RestRuleModelsCollection rules = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createListOfRules(ruleModels);
restClient.assertStatusCodeIs(CREATED);
@@ -240,18 +254,97 @@ public class CreateRulesTests extends RestTest
public void createRulesWithOneError()
{
STEP("Try to create a three rules but the middle one has an error.");
RestRuleModel ruleA = createRuleModel("ruleA");
RestRuleModel ruleB = new RestRuleModel();
RestRuleModel ruleA = rulesUtils.createRuleModel("ruleA");
RestRuleModel ruleB = rulesUtils.createRuleModel("");
// Don't set a name for Rule B.
RestRuleModel ruleC = createRuleModel("ruleC");
RestRuleModel ruleC = rulesUtils.createRuleModel("ruleC");
List<RestRuleModel> ruleModels = List.of(ruleA, ruleB, ruleC);
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createListOfRules(ruleModels);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().createListOfRules(ruleModels);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Rule name is a mandatory parameter");
}
/** Check we can create a rule without description. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithoutDescription()
{
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().field("id").isNotNull()
.assertThat().field("name").is(RULE_NAME_DEFAULT)
.assertThat().field("description").isNull();
}
/** Check we can create a rule without specifying triggers but with the default "inbound" value. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithoutTriggers()
{
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().field("id").isNotNull()
.assertThat().field("name").is(RULE_NAME_DEFAULT)
.assertThat().field("triggers").is(List.of("inbound"));
}
/** Check we can create a rule without error script. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithoutErrorScript()
{
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().field("id").isNotNull()
.assertThat().field("name").is(RULE_NAME_DEFAULT)
.assertThat().field("errorScript").isNull();
}
/** Check we can create a rule with irrelevant isShared flag, and it doesn't have impact to the process. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithSharedFlag()
{
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
ruleModel.setIsShared(true);
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().field("id").isNotNull()
.assertThat().field("name").is(RULE_NAME_DEFAULT)
.assertThat().field("isShared").isNull();
}
/** Check we can create a rule. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void createRuleAndIncludeFieldsInResponse()
{
RestRuleModel ruleModel = rulesUtils.createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.include("isShared")
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().field("isShared").isNotNull();
}
public RestRuleModel testRolePermissionsWith(UserRole userRole)
{
STEP("Create a user and use them to create a private site containing a folder");
@@ -261,8 +354,273 @@ public class CreateRulesTests extends RestTest
STEP(String.format("Add a user with '%s' role in the private site's folder", userRole.toString()));
UserModel userWithRole = dataUser.createRandomTestUser();
dataUser.addUserToSite(userWithRole, privateSite, userRole);
RestRuleModel ruleModel = createRuleModel("testRule", List.of(createActionModel()));
RestRuleModel ruleModel = rulesUtils.createRuleModel("testRule", List.of(rulesUtils.createAddAudioAspectAction()));
return restClient.authenticateUser(userWithRole).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
return restClient.authenticateUser(userWithRole).withPrivateAPI().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 UserModel admin = dataUser.getAdminUser();
final RestRuleModel rule = restClient.authenticateUser(admin).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createVariousActions());
RestRuleModel expectedRuleModel = rulesUtils.createRuleModelWithDefaultValues();
expectedRuleModel.setActions(rulesUtils.createVariousActions().getActions());
expectedRuleModel.setTriggers(List.of("inbound"));
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, ID, IS_SHARED)
.assertThat().field(IS_SHARED).isNull();
}
/** Check that a normal user cannot create rules that use private actions. */
@Test
public void createRuleWithActions_userCannotUsePrivateAction()
{
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createRuleWithPrivateAction());
restClient.assertStatusCodeIs(FORBIDDEN)
.assertLastError().containsSummary(ERROR_MESSAGE_ACCESS_RESTRICTED);
}
/** Check that an administrator can create rules that use private actions. */
@Test
public void createRuleWithActions_adminCanUsePrivateAction()
{
restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createRuleWithPrivateAction());
restClient.assertStatusCodeIs(CREATED);
}
/**
* Check we get error when attempt to create a rule without any actions.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithoutActionsShouldFail()
{
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
ruleModel.setActions(null);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("A rule must have at least one action");
}
/**
* Check we get error when attempt to create a rule with invalid action.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithInvalidActionsShouldFail()
{
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
final RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
final String actionDefinitionId = "invalid-definition-value";
invalidAction.setActionDefinitionId(actionDefinitionId);
invalidAction.setParams(Map.of("dummy-key", "dummy-value"));
ruleModel.setActions(List.of(invalidAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary(String.format("Invalid action definition requested %s", actionDefinitionId));
}
/**
* Check we get error when attempt to create a rule with missing action parameters.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithMissingActionParametersShouldFail()
{
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
final RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
final String actionDefinitionId = "copy";
invalidAction.setActionDefinitionId(actionDefinitionId);
ruleModel.setActions(List.of(invalidAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary(
String.format("Action parameters should not be null or empty for this action. See Action Definition for action of: %s",
actionDefinitionId));
}
/**
* Check we get error when attempt to create a rule with parameter not fulfilling constraint.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithActionParameterNotFulfillingConstraint()
{
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
final String actionDefinitionId = "script";
final String scriptRef = "script-ref";
final String scriptNodeId = "dummy-script-node-id";
final RestActionBodyExecTemplateModel scriptAction = rulesUtils.createCustomActionModel(actionDefinitionId, Map.of(scriptRef, scriptNodeId));
ruleModel.setActions(List.of(scriptAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
final String acScriptsConstraint = "ac-scripts";
restClient.assertLastError().containsSummary(
String.format("Action parameter: %s has invalid value (%s). Look up possible values for constraint name %s",
scriptRef, scriptNodeId, acScriptsConstraint));
}
/**
* Check we get error when attempt to create a rule with action parameter that should not be passed.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithoutInvalidActionParameterShouldFail()
{
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
final RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
final String actionDefinitionId = "add-features";
invalidAction.setActionDefinitionId(actionDefinitionId);
final String invalidParameterKey = "invalidParameterKey";
invalidAction.setParams(Map.of(invalidParameterKey,"dummyValue"));
ruleModel.setActions(List.of(invalidAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary(
String.format("Action of definition id: %s must not contain parameter of name: %s", actionDefinitionId, invalidParameterKey));
}
/**
* Check we get error when attempt to create a rule with missing mandatory action parameter.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithoutMandatoryActionParametersShouldFail()
{
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
final RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
final String actionDefinitionId = "copy";
invalidAction.setActionDefinitionId(actionDefinitionId);
invalidAction.setParams(Map.of("deep-copy",false));
ruleModel.setActions(List.of(invalidAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Missing action's mandatory parameter: destination-folder");
}
/**
* Check we get error when attempting to create a rule that copies files to a non-existent folder.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleThatUsesNonExistentNode()
{
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
String actionDefinitionId = "copy";
invalidAction.setActionDefinitionId(actionDefinitionId);
invalidAction.setParams(Map.of("destination-folder", "non-existent-node"));
ruleModel.setActions(List.of(invalidAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(NOT_FOUND);
restClient.assertLastError().containsSummary("The entity with id: non-existent-node was not found");
}
/**
* Check we get error when attempting to create a rule that references a folder that the user does not have read permission for.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleThatUsesNodeWithoutReadPermission()
{
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
String actionDefinitionId = "copy";
invalidAction.setActionDefinitionId(actionDefinitionId);
invalidAction.setParams(Map.of("destination-folder", privateFolder.getNodeRef()));
ruleModel.setActions(List.of(invalidAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
restClient.assertStatusCodeIs(NOT_FOUND);
restClient.assertLastError().containsSummary("The entity with id: " + privateFolder.getNodeRef() + " was not found");
}
/**
* Check we can create a rule with multiple conditions
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithConditions()
{
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
ruleModel.setConditions(rulesUtils.createVariousConditions());
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = rulesUtils.createRuleModelWithDefaultValues();
expectedRuleModel.setConditions(rulesUtils.createVariousConditions());
expectedRuleModel.setTriggers(List.of("inbound"));
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, ID, IS_SHARED);
}
/**
* Check we can create a rule with empty list as conditions
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithConditions_emptyConditionList()
{
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
ruleModel.setConditions(rulesUtils.createCompositeCondition(null));
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = rulesUtils.createRuleModelWithDefaultValues();
expectedRuleModel.setTriggers(List.of("inbound"));
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, ID, IS_SHARED);
}
/**
* Check we can NOT create a rule when category ID in condition is invalid, HTTP status code 400 is expected
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithConditions_invalidCategory()
{
STEP("Try to create a rule with non existing category in conditions.");
String fakeCategoryId = "bdba5f9f-fake-id22-803b-349bcfd06fd1";
RestCompositeConditionDefinitionModel conditions = rulesUtils.createCompositeCondition(List.of(
rulesUtils.createCompositeCondition(!INVERTED, List.of(
rulesUtils.createSimpleCondition("category", "equals", fakeCategoryId)
))
));
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
ruleModel.setConditions(conditions);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Category in condition is invalid");
}
}

View File

@@ -27,7 +27,6 @@ package org.alfresco.rest.rules;
import static java.util.stream.Collectors.toList;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
import static org.alfresco.utility.constants.UserRole.SiteContributor;
import static org.alfresco.utility.constants.UserRole.SiteManager;
@@ -83,20 +82,20 @@ public class DeleteRulesTests extends RestTest
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final List<RestRuleModel> createdRules = Stream.of("ruleA", "ruleB", "ruleC")
.map(ruleName -> {
RestRuleModel ruleModel = createRuleModel(ruleName);
return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
RestRuleModel ruleModel = rulesUtils.createRuleModel(ruleName);
return restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
})
.collect(toList());
STEP("Attempt delete one rule");
final RestRuleModel ruleA = createdRules.get(0);
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().deleteRule(ruleA.getId());
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().deleteRule(ruleA.getId());
restClient.assertStatusCodeIs(NO_CONTENT);
STEP("Get and check the rules from the folder after deleting one of them");
final RestRuleModelsCollection rulesAfterDeletion =
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().getListOfRules();
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().getListOfRules();
restClient.assertStatusCodeIs(OK);
rulesAfterDeletion.assertThat().entriesListCountIs(createdRules.size() - 1);
Assert.assertTrue(rulesAfterDeletion.getEntries()
@@ -127,7 +126,7 @@ public class DeleteRulesTests extends RestTest
nonExistingFolder.setNodeRef(FAKE_NODE_REF);
STEP("Attempt delete the rule in non-existing folder");
restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistingFolder).usingDefaultRuleSet().deleteRule(testRule.getId());
restClient.authenticateUser(user).withPrivateAPI().usingNode(nonExistingFolder).usingDefaultRuleSet().deleteRule(testRule.getId());
restClient.assertLastError().statusCodeIs(NOT_FOUND);
}
@@ -142,7 +141,7 @@ public class DeleteRulesTests extends RestTest
final RestRuleModel testRule = createRule(ruleFolder);
STEP("Attempt delete the rule in non-existing rule set");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingRuleSet(FAKE_NODE_REF).deleteRule(testRule.getId());
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingRuleSet(FAKE_NODE_REF).deleteRule(testRule.getId());
restClient.assertLastError().statusCodeIs(NOT_FOUND);
}
@@ -155,7 +154,7 @@ public class DeleteRulesTests extends RestTest
{
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Attempt delete non-existing rule");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().deleteRule(FAKE_NODE_REF);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().deleteRule(FAKE_NODE_REF);
restClient.assertLastError().statusCodeIs(NOT_FOUND);
}
@@ -173,7 +172,7 @@ public class DeleteRulesTests extends RestTest
final FolderModel anotherFolder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Attempt delete an existing rule from a wrong but existing (second) folder");
restClient.authenticateUser(user).withCoreAPI().usingNode(anotherFolder).usingDefaultRuleSet().deleteRule(testRule.getId());
restClient.authenticateUser(user).withPrivateAPI().usingNode(anotherFolder).usingDefaultRuleSet().deleteRule(testRule.getId());
restClient.assertLastError().statusCodeIs(NOT_FOUND);
}
@@ -187,13 +186,13 @@ public class DeleteRulesTests extends RestTest
final UserModel privateUser = dataUser.createRandomTestUser();
final SiteModel privateSite = dataSite.usingUser(privateUser).createPrivateRandomSite();
final FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
final RestRuleModel ruleModel = createRuleModel("Private site rule");
final RestRuleModel ruleModel = rulesUtils.createRuleModel("Private site rule");
final RestRuleModel createdRule =
restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet()
restClient.authenticateUser(privateUser).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Try to delete the rule with another user");
restClient.authenticateUser(user).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().deleteRule(createdRule.getId());
restClient.authenticateUser(user).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().deleteRule(createdRule.getId());
restClient.assertLastError().statusCodeIs(FORBIDDEN);
}
@@ -213,7 +212,7 @@ public class DeleteRulesTests extends RestTest
restClient.authenticateUser(user).withCoreAPI().usingSite(site).addPerson(siteCollaborator);
STEP("Check the manager can delete the rule");
restClient.authenticateUser(siteCollaborator).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
restClient.authenticateUser(siteCollaborator).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.deleteRule(testRule.getId());
restClient.assertLastError().statusCodeIs(FORBIDDEN);
@@ -228,9 +227,9 @@ public class DeleteRulesTests extends RestTest
final UserModel privateUser = dataUser.createRandomTestUser();
final SiteModel privateSite = dataSite.usingUser(privateUser).createPrivateRandomSite();
final FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
final RestRuleModel ruleModel = createRuleModel("Private site rule");
final RestRuleModel ruleModel = rulesUtils.createRuleModel("Private site rule");
final RestRuleModel createdRule =
restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet()
restClient.authenticateUser(privateUser).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Create a manager in the private site");
@@ -239,7 +238,7 @@ public class DeleteRulesTests extends RestTest
restClient.authenticateUser(privateUser).withCoreAPI().usingSite(privateSite).addPerson(siteManager);
STEP("Check the manager can delete the rule");
restClient.authenticateUser(siteManager).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet()
restClient.authenticateUser(siteManager).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet()
.deleteRule(createdRule.getId());
restClient.assertStatusCodeIs(NO_CONTENT);
@@ -248,7 +247,7 @@ public class DeleteRulesTests extends RestTest
private RestRuleModel createRule(FolderModel ruleFolder)
{
STEP("Create a rule in the folder");
final RestRuleModel ruleModel = createRuleModel("Test rule");
return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
final RestRuleModel ruleModel = rulesUtils.createRuleModel("Test rule");
return restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
}
}

View File

@@ -0,0 +1,298 @@
/*
* #%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.rest.rules;
import static org.alfresco.rest.rules.RulesTestsUtils.AUDIO_ASPECT;
import static org.alfresco.rest.rules.RulesTestsUtils.LOCKABLE_ASPECT;
import static org.alfresco.rest.rules.RulesTestsUtils.RULE_NAME_DEFAULT;
import static org.alfresco.utility.report.log.Step.STEP;
import java.util.List;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
import org.alfresco.rest.model.RestNodeModel;
import org.alfresco.rest.model.RestRuleExecutionModel;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.utility.constants.UserRole;
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.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Tests for POST /nodes/{nodeId}/rule-executions.
*/
@Test(groups = { TestGroup.RULES})
public class ExecuteRulesTests extends RestTest
{
private UserModel user;
private SiteModel site;
private FolderModel parentFolder;
private FolderModel childFolder;
private FileModel parentFolderFile;
private FileModel childFolderFile;
private RestRuleModel parentFolderRule;
private RestRuleModel childFolderRule;
@BeforeClass(alwaysRun = true)
public void dataPreparation()
{
STEP("Create user and a site");
user = dataUser.createRandomTestUser();
site = dataSite.usingUser(user).createPublicRandomSite();
}
@BeforeMethod(alwaysRun = true)
public void setUp()
{
STEP("Create parent folder, rule folder and file in it");
parentFolder = dataContent.usingUser(user).usingSite(site).createFolder();
childFolder = dataContent.usingUser(user).usingResource(parentFolder).createFolder();
parentFolderFile = dataContent.usingUser(user).usingResource(parentFolder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
childFolderFile = dataContent.usingUser(user).usingResource(childFolder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Create rules for parent and rule folders");
RestActionBodyExecTemplateModel addLockableAspectAction = rulesUtils.createAddAspectAction(LOCKABLE_ASPECT);
RestRuleModel ruleModel = rulesUtils.createRuleModel(RULE_NAME_DEFAULT, List.of(addLockableAspectAction));
ruleModel.setIsInheritable(true);
parentFolderRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(parentFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
childFolderRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
}
/**
* Execute one rule with one action trying to add audio aspect to a file.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS, TestGroup.SANITY })
public void executeRules_onlyOwnedRules()
{
STEP("Check if file aspects don't contain Audio one");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).notContainsAspects(AUDIO_ASPECT);
STEP("Execute rule");
RestRuleExecutionModel executionResult = restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).executeRules(rulesUtils.createRuleExecutionRequest());
restClient.assertStatusCodeIs(HttpStatus.CREATED);
executionResult.assertThat().field("isEachSubFolderIncluded").is(false);
STEP("Check if only Audio aspect was added");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).containsAspects(AUDIO_ASPECT);
}
/**
* Execute owned rule adding Audio aspect and inherited rule adding Lockable aspect.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS, TestGroup.SANITY })
public void executeRules_includeInheritedRules()
{
STEP("Check if file aspects don't contain Audio and Lockable ones");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).notContainsAspects(AUDIO_ASPECT, LOCKABLE_ASPECT);
STEP("Execute rules including inherited rules");
RestRuleExecutionModel ruleExecutionRequest = rulesUtils.createRuleExecutionRequest();
RestRuleExecutionModel executionResult = restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).executeRules(ruleExecutionRequest);
restClient.assertStatusCodeIs(HttpStatus.CREATED);
executionResult.assertThat().field("isEachSubFolderIncluded").is(false);
STEP("Check if Audio and Lockable aspects were added");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).containsAspects(AUDIO_ASPECT, LOCKABLE_ASPECT);
}
/**
* Execute rules on parent folder (add Lockable aspect) including sub-folder folders (add Audio aspect).
*/
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS, TestGroup.SANITY })
public void executeRules_includeSubFolderRules()
{
STEP("Check if parent folder's file aspects don't contain Audio and Lockable ones");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(parentFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).notContainsAspects(AUDIO_ASPECT, LOCKABLE_ASPECT);
STEP("Check if child folder's file aspects don't contain Audio and Lockable ones");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).notContainsAspects(AUDIO_ASPECT, LOCKABLE_ASPECT);
STEP("Execute rules on parent folder including sub-folders");
RestRuleExecutionModel ruleExecutionRequest = rulesUtils.createRuleExecutionRequest();
ruleExecutionRequest.setIsEachSubFolderIncluded(true);
RestRuleExecutionModel executionResult = restClient.authenticateUser(user).withPrivateAPI().usingNode(parentFolder).executeRules(ruleExecutionRequest);
restClient.assertStatusCodeIs(HttpStatus.CREATED);
executionResult.assertThat().field("isEachSubFolderIncluded").is(true);
STEP("Check if Lockable aspects was added to parent folder's file");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(parentFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode)
.containsAspects(LOCKABLE_ASPECT)
.notContainsAspects(AUDIO_ASPECT);
STEP("Check if Audio and Lockable aspects were added to child folder's file");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode)
.containsAspects(AUDIO_ASPECT, LOCKABLE_ASPECT);
}
/**
* Try to execute disabled rule and check if nothing changed.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS })
public void executeRules_disabledRule()
{
STEP("Disable child rules");
RestRuleModel updatedChildRule = rulesUtils.createRuleModelWithDefaultValues();
updatedChildRule.setIsEnabled(false);
restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).usingDefaultRuleSet().updateRule(childFolderRule.getId(), updatedChildRule);
STEP("Check if file aspects don't contain Audio one");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).notContainsAspects(AUDIO_ASPECT);
STEP("Execute rule");
RestRuleExecutionModel executionResult = restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).executeRules(rulesUtils.createRuleExecutionRequest());
restClient.assertStatusCodeIs(HttpStatus.CREATED);
executionResult.assertThat().field("isEachSubFolderIncluded").is(false);
STEP("Check if Audio aspect is still missing");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).notContainsAspects(AUDIO_ASPECT);
}
/**
* Try to execute inherited parent folder's rule which is not inheritable.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS })
public void executeRules_notInheritableRule()
{
STEP("Set parent rule as not inheritable");
RestRuleModel updatedParentRule = rulesUtils.createRuleModelWithDefaultValues();
updatedParentRule.setIsInheritable(false);
restClient.authenticateUser(user).withPrivateAPI().usingNode(parentFolder).usingDefaultRuleSet().updateRule(parentFolderRule.getId(), updatedParentRule);
STEP("Check if file aspects don't contain Audio and Lockable ones");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).notContainsAspects(AUDIO_ASPECT, LOCKABLE_ASPECT);
STEP("Execute child folder rules including inherited rules");
RestRuleExecutionModel executionResult = restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).executeRules(rulesUtils.createRuleExecutionRequest());
restClient.assertStatusCodeIs(HttpStatus.CREATED);
executionResult.assertThat().field("isEachSubFolderIncluded").is(false);
STEP("Check if Audio aspect is present and Lockable is still missing");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolderFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode)
.containsAspects(AUDIO_ASPECT)
.notContainsAspects(LOCKABLE_ASPECT);
}
/**
* Try to execute private folder's rules by user not added to site and receive 403.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS })
public void executeRules_privateFolderResultsWith403()
{
STEP("Using admin create private site, folder and rule");
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
dataContent.usingAdmin().usingResource(privateFolder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
STEP("Try to execute private folder's rules by user");
restClient.authenticateUser(user).withPrivateAPI().usingNode(privateFolder).executeRules(rulesUtils.createRuleExecutionRequest());
restClient.assertStatusCodeIs(HttpStatus.FORBIDDEN);
}
/**
* Try to execute private folder's rules as site contributor and receive 403.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS })
public void executeRules_privateFolderAsContributorResultsWith403()
{
STEP("Using admin create private site, folder, file in it, rule and add user to site as contributor");
UserModel contributor = dataUser.createRandomTestUser();
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
dataContent.usingAdmin().usingResource(privateFolder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
dataUser.usingAdmin().addUserToSite(contributor, privateSite, UserRole.SiteContributor);
STEP("Try to execute private folder's rules by contributor");
restClient.authenticateUser(contributor).withPrivateAPI().usingNode(privateFolder).executeRules(rulesUtils.createRuleExecutionRequest());
restClient.assertStatusCodeIs(HttpStatus.FORBIDDEN);
}
/**
* Execute private folder's rules as site collaborator.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS })
public void executeRules_privateFolderAsCollaborator()
{
STEP("Using admin create private site, folder, file in it, rule and add user to site as collaborator");
UserModel collaborator = dataUser.createRandomTestUser();
UserModel admin = dataUser.getAdminUser();
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
FileModel privateFile = dataContent.usingAdmin().usingResource(privateFolder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
restClient.authenticateUser(admin).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
dataUser.usingAdmin().addUserToSite(collaborator, privateSite, UserRole.SiteCollaborator);
STEP("Check if file aspects don't contain Audio one");
RestNodeModel fileNode = restClient.authenticateUser(admin).withCoreAPI().usingNode(privateFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).notContainsAspects(AUDIO_ASPECT);
STEP("Execute private folder's rules by collaborator");
restClient.authenticateUser(collaborator).withPrivateAPI().usingNode(privateFolder).executeRules(rulesUtils.createRuleExecutionRequest());
restClient.assertStatusCodeIs(HttpStatus.CREATED);
STEP("Check if Audio aspect is present");
fileNode = restClient.authenticateUser(admin).withCoreAPI().usingNode(privateFile).getNode();
restClient.assertStatusCodeIs(HttpStatus.OK);
rulesUtils.assertThat(fileNode).containsAspects(AUDIO_ASPECT);
}
//TODO: add test(s) that would cover handling executing broken rule and/or broken rule execution (ACS-3699)
}

View File

@@ -0,0 +1,141 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rules;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.testng.Assert.assertEquals;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleModelsCollection;
import org.alfresco.rest.model.RestRuleSetLinkModel;
import org.alfresco.rest.model.RestRuleSetModel;
import org.alfresco.rest.model.RestRuleSetModelsCollection;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Tests for GET /nodes/{nodeId}/rule-sets/{ruleSetId}/rules with rule inheritance.
*/
@Test(groups = {TestGroup.RULES})
public class GetInheritedRulesTests extends RestTest
{
private UserModel user;
private SiteModel site;
@BeforeClass(alwaysRun = true)
public void dataPreparation()
{
STEP("Create a user and site");
user = dataUser.createRandomTestUser();
site = dataSite.usingUser(user).createPublicRandomSite();
}
/**
* Check we can get all the rules for the folder by providing the different rule set ids.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getInheritedRules()
{
STEP("Create a parent and child folder, each with inheriting rules");
FolderModel parent = dataContent.usingUser(user).usingSite(site).createFolder();
FolderModel child = dataContent.usingUser(user).usingResource(parent).createFolder();
RestRuleModel parentRule = rulesUtils.createRuleModelWithDefaultValues();
parentRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(parent).usingDefaultRuleSet().createSingleRule(parentRule);
RestRuleModel childRule = rulesUtils.createRuleModelWithDefaultValues();
childRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(child).usingDefaultRuleSet().createSingleRule(childRule);
STEP("Get the rules in the default rule set for the child folder");
RestRuleModelsCollection rules = restClient.authenticateUser(user).withPrivateAPI().usingNode(child).usingDefaultRuleSet().getListOfRules();
rules.assertThat().entriesListContains("id", childRule.getId())
.and().entriesListCountIs(1);
STEP("Get the rules in the inherited rule set for the child folder");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI().usingNode(child).include("inclusionType").getListOfRuleSets();
String inheritedRuleSetId = ruleSets.getEntries().stream()
.filter(ruleSet -> ruleSet.onModel().getInclusionType().equals("inherited"))
.findFirst().get().onModel().getId();
RestRuleModelsCollection inheritedRules = restClient.authenticateUser(user).withPrivateAPI().usingNode(child).usingRuleSet(inheritedRuleSetId).getListOfRules();
inheritedRules.assertThat().entriesListContains("id", parentRule.getId())
.and().entriesListCountIs(1);
}
/**
* Check that we only get each rule once with linking and inheritance, and the order is correct.
* <p>
* The folder structure for this test is as follows:
* <pre>
* A --[links]-> DRuleSet
* +-B --[owns]-> BRuleSet
* +-C --[owns]-> CRuleSet
* +-D --[owns]--> DRuleSet
* </pre>
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void rulesReturnedAreUnique()
{
STEP("Create four folders with rules");
FolderModel folderA = dataContent.usingUser(user).usingSite(site).createFolder();
FolderModel folderB = dataContent.usingUser(user).usingResource(folderA).createFolder();
FolderModel folderC = dataContent.usingUser(user).usingResource(folderB).createFolder();
FolderModel folderD = dataContent.usingUser(user).usingResource(folderC).createFolder();
RestRuleModel ruleB = restClient.authenticateUser(user).withPrivateAPI().usingNode(folderB).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
RestRuleModel ruleC = restClient.authenticateUser(user).withPrivateAPI().usingNode(folderC).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
RestRuleModel ruleD = restClient.authenticateUser(user).withPrivateAPI().usingNode(folderD).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
STEP("Link folderA to ruleSetD");
RestRuleSetLinkModel linkModel = new RestRuleSetLinkModel();
linkModel.setId(folderD.getNodeRef());
restClient.authenticateUser(user).withPrivateAPI().usingNode(folderA).createRuleLink(linkModel);
STEP("Get the rule sets for the folderD");
List<RestRuleSetModel> ruleSets = restClient.authenticateUser(user).withPrivateAPI().usingNode(folderD).getListOfRuleSets().getEntries();
STEP("Check the rules for each rule set are as expected");
List<RestRuleModel> expectedRuleIds = List.of(ruleD, ruleB, ruleC);
IntStream.range(0, 2).forEach(index -> {
String ruleSetId = ruleSets.get(index).onModel().getId();
List<RestRuleModel> rules = restClient.authenticateUser(user)
.withPrivateAPI()
.usingNode(folderD)
.usingRuleSet(ruleSetId)
.getListOfRules()
.getEntries()
.stream()
.map(RestRuleModel::onModel)
.collect(Collectors.toList());
assertEquals(rules, List.of(expectedRuleIds.get(index)), "Unexpected rules found for rule set " + ruleSetId);
});
assertEquals(ruleSets.size(), 3, "Expected three unique rule sets to be returned but got " + ruleSets);
}
}

View File

@@ -25,17 +25,26 @@
*/
package org.alfresco.rest.rules;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
import static org.alfresco.rest.requests.RuleSettings.IS_INHERITANCE_ENABLED;
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 java.util.List;
import com.google.common.collect.ImmutableMap;
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.rest.model.RestRuleSettingsModel;
import org.alfresco.rest.requests.coreAPI.RestCoreAPI;
import org.alfresco.rest.requests.privateAPI.RestPrivateAPI;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
@@ -52,6 +61,10 @@ public class GetRuleSetsTests extends RestTest
private UserModel user;
private SiteModel site;
private FolderModel ruleFolder;
/** A folder with a rule in a private site owned by admin. */
private FolderModel privateFolder;
private FolderModel inheritingChildFolder;
private FolderModel notInheritingChildFolder;
private RestRuleModel rule;
private String ruleSetId;
@@ -63,16 +76,29 @@ public class GetRuleSetsTests extends RestTest
site = dataSite.usingUser(user).createPublicRandomSite();
ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create two children of the folder - one that inherits rules and one that doesn't");
inheritingChildFolder = dataContent.usingUser(user).usingResource(ruleFolder).createFolder();
notInheritingChildFolder = dataContent.usingUser(user).usingResource(ruleFolder).createFolder();
RestRuleSettingsModel doesntInherit = new RestRuleSettingsModel();
doesntInherit.setValue(false);
restClient.authenticateUser(user).withPrivateAPI().usingNode(notInheritingChildFolder)
.usingIsInheritanceEnabledRuleSetting().updateSetting(doesntInherit);
STEP("Create a rule in the folder.");
RestRuleModel ruleModel = createRuleModel("ruleName");
rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
RestRuleModel ruleModel = rulesUtils.createRuleModel("ruleName");
rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Get the rule sets for the folder and find the rule set id");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder)
.getListOfRuleSets();
ruleSets.assertThat().entriesListCountIs(1);
ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
STEP("Use admin to create a private site containing a rule in a rule set that can be inherited.");
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
privateAPIForAdmin().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithModifiedValues());
}
/** Check we can get an empty list of rule sets. */
@@ -83,7 +109,7 @@ public class GetRuleSetsTests extends RestTest
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Get the rule sets for the folder");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI()
.usingNode(folder).getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
@@ -95,7 +121,7 @@ public class GetRuleSetsTests extends RestTest
public void getRuleSetsList()
{
STEP("Get the rule sets for the folder");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder)
.getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
@@ -111,18 +137,60 @@ public class GetRuleSetsTests extends RestTest
STEP("Try to load rule sets for a non-existent folder.");
FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
nonExistentFolder.setNodeRef("fake-id");
restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).getListOfRuleSets();
restClient.authenticateUser(user).withPrivateAPI().usingNode(nonExistentFolder).getListOfRuleSets();
restClient.assertStatusCodeIs(NOT_FOUND);
}
/** Check that we get a 403 error when trying to get rule sets for a folder we don't have read access to. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetsWithoutPermission()
{
STEP("Check a user cannot list rule sets without read access.");
privateAPIForUser().usingNode(privateFolder).getListOfRuleSets();
restClient.assertStatusCodeIs(FORBIDDEN);
}
/** Check that we can still list some rule sets if we don't have permission to view them all. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void permissionsAreRespectedWhenListingRuleSets()
{
STEP("Create a public site containing a parent and child folder with rule inheritance enabled.");
SiteModel publicSite = dataSite.usingUser(user).createPublicRandomSite();
FolderModel parentFolder = dataContent.usingUser(user).usingSite(publicSite).createFolder();
FolderModel childFolder = dataContent.usingUser(user).usingResource(parentFolder).createFolder();
RestRuleSettingsModel enabled = new RestRuleSettingsModel();
enabled.setValue(true);
privateAPIForUser().usingNode(parentFolder).usingRuleSetting(IS_INHERITANCE_ENABLED).updateSetting(enabled);
STEP("Link the parent folder to a private rule set.");
RestRuleSetLinkModel linkModel = new RestRuleSetLinkModel();
linkModel.setId(privateFolder.getNodeRef());
privateAPIForAdmin().usingNode(parentFolder).createRuleLink(linkModel);
STEP("Create a rule on the child folder.");
privateAPIForUser().usingNode(childFolder).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
STEP("Check admin can view both rule sets.");
RestRuleSetModelsCollection adminViewOfRuleSets = privateAPIForAdmin().usingNode(childFolder).getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
RestRuleSetModel parentRuleSet = adminViewOfRuleSets.getEntries().get(0).onModel();
RestRuleSetModel childRuleSet = adminViewOfRuleSets.getEntries().get(1).onModel();
STEP("Check the normal user can only view the child rule set.");
RestRuleSetModelsCollection userViewOfRuleSets = privateAPIForUser().usingNode(childFolder).getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
userViewOfRuleSets.assertThat().entriesListContains("id", childRuleSet.getId())
.and().entriesListDoesNotContain("id", parentRuleSet.getId());
}
/** Check we can get the id of the folder that owns a list of rule sets. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetsAndOwningFolders()
{
STEP("Get the rule sets and owning folders");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI()
.usingNode(ruleFolder)
.usingParams("include=owningFolder")
.include("owningFolder")
.getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
@@ -132,16 +200,69 @@ public class GetRuleSetsTests extends RestTest
ruleSets.assertThat().entriesListCountIs(1);
}
/** Check we can get the reason that a rule set is included in the list. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetsAndOwnedInclusionType()
{
STEP("Get the rule sets and inclusion type");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI()
.usingNode(ruleFolder)
.include("inclusionType")
.getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
ruleSets.getEntries().get(0).onModel()
.assertThat().field("inclusionType").is("owned")
.assertThat().field("id").is(ruleSetId);
ruleSets.assertThat().entriesListCountIs(1);
}
/** Check we can tell that a rule set has been inherited. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetsAndInheritedInclusionType()
{
STEP("Get the rule sets and inclusion type");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI()
.usingNode(inheritingChildFolder)
.include("inclusionType")
.getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
ruleSets.getEntries().get(0).onModel()
.assertThat().field("inclusionType").is("inherited")
.assertThat().field("id").is(ruleSetId);
ruleSets.assertThat().entriesListCountIs(1);
}
/** Check that a rule set is not inherited if inheriting is disabled. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetsWithoutInheriting()
{
STEP("Get the rule sets and inclusion type");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI()
.usingNode(notInheritingChildFolder)
.getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
ruleSets.assertThat().entriesListCountIs(0);
}
/** Check we can get a rule set by its id. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getRuleSetById()
{
STEP("Get the rule set using its rule set id");
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder)
.getRuleSet(ruleSetId);
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("id").is(ruleSetId);
ruleSet.assertThat().field("id").is(ruleSetId)
// Also check that the optional fields are not included by default.
.assertThat().field("owningFolder").isNull()
.assertThat().field("inheritedBy").isNull()
.assertThat().field("linkedToBy").isNull()
.assertThat().field("isInherited").isNull()
.assertThat().field("isLinkedTo").isNull();
}
/** Check we can get a rule set using the "-default-" synonym. */
@@ -149,7 +270,7 @@ public class GetRuleSetsTests extends RestTest
public void getDefaultRuleSetById()
{
STEP("Get the default rule set for the folder");
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder)
.getDefaultRuleSet();
restClient.assertStatusCodeIs(OK);
@@ -163,7 +284,7 @@ public class GetRuleSetsTests extends RestTest
STEP("Try to load a rule set for a non-existent folder.");
FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
nonExistentFolder.setNodeRef("fake-id");
restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).getDefaultRuleSet();
restClient.authenticateUser(user).withPrivateAPI().usingNode(nonExistentFolder).getDefaultRuleSet();
restClient.assertStatusCodeIs(NOT_FOUND);
}
@@ -173,7 +294,7 @@ public class GetRuleSetsTests extends RestTest
{
STEP("Get the rule set using fake rule set id");
String fakeRuleSetId = "fake-rule-set-id";
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).getRuleSet(fakeRuleSetId);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).getRuleSet(fakeRuleSetId);
restClient.assertStatusCodeIs(NOT_FOUND);
}
@@ -182,13 +303,298 @@ public class GetRuleSetsTests extends RestTest
public void getRuleSetAndOwningFolder()
{
STEP("Get the rule set and owning folder");
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withCoreAPI()
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI()
.usingNode(ruleFolder)
.usingParams("include=owningFolder")
.include("owningFolder")
.getRuleSet(ruleSetId);
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("owningFolder").is(ruleFolder.getNodeRef())
.assertThat().field("id").is(ruleSetId);
}
/**
* Check we can find out the id of any folders that inherit a rule set.
* <p>
* The test checks several different situations:
* <pre>
* folder --[owns]-> rule set
* +- publicFolder --[inherits]-> rule set (user has access)
* +- privateFolder --[inherits]-> rule set (user does not have access)
* +- publicGrandchild --[inherits]-> rule set (user has access again)
* +- nonInheritingFolder (inheritance should be prevented)
* +- linkingFolder --[links]-> rule set (not inherited)
* +- descendantFolder --[inherits]-> rule set (inherited via link)
* </pre>
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetAndInheritedBy()
{
STEP("Create a site owned by admin and add user as a contributor");
SiteModel siteModel = dataSite.usingAdmin().createPrivateRandomSite();
dataUser.addUserToSite(user, siteModel, UserRole.SiteContributor);
STEP("Create the folder structure");
FolderModel folder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
FolderModel publicFolder = dataContent.usingUser(user).usingResource(folder).createFolder();
FolderModel privateFolder = dataContent.usingAdmin().usingResource(folder).createFolder();
dataContent.usingAdmin().usingResource(privateFolder).setInheritPermissions(false);
// Create the grandchild with user and use admin to move it under the private folder.
FolderModel publicGrandchild = dataContent.usingUser(user).usingSite(siteModel).createFolder();
coreAPIForAdmin().usingActions().executeAction("move", publicGrandchild, ImmutableMap.of("destination-folder", "workspace://SpacesStore/" + privateFolder.getNodeRef()));
// Create the non-inheriting folder.
FolderModel nonInheritingFolder = dataContent.usingUser(user).usingResource(folder).createFolder();
RestRuleSettingsModel nonInheriting = new RestRuleSettingsModel();
nonInheriting.setKey(IS_INHERITANCE_ENABLED);
nonInheriting.setValue(false);
privateAPIForUser().usingNode(nonInheritingFolder).usingIsInheritanceEnabledRuleSetting().updateSetting(nonInheriting);
// Create a child that will link to the rule and a child of that to inherit via the link.
FolderModel linkingFolder = dataContent.usingUser(user).usingResource(nonInheritingFolder).createFolder();
FolderModel descendantFolder = dataContent.usingUser(user).usingResource(linkingFolder).createFolder();
STEP("Create an inheritable rule in the folder and get the rule set id.");
RestRuleModel ruleModel = rulesUtils.createRuleModelWithModifiedValues();
privateAPIForUser().usingNode(folder).usingDefaultRuleSet().createSingleRule(ruleModel);
RestRuleSetModelsCollection ruleSets = privateAPIForUser().usingNode(folder).getListOfRuleSets();
String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
STEP("Create the link to the rule from the linking folder");
RestRuleSetLinkModel ruleSetLink = new RestRuleSetLinkModel();
ruleSetLink.setId(folder.getNodeRef());
privateAPIForUser().usingNode(linkingFolder).createRuleLink(ruleSetLink);
STEP("Remove the user from the site");
dataUser.removeUserFromSite(user, siteModel);
STEP("Get the rule set and inheriting folders");
RestRuleSetModel ruleSet = privateAPIForUser().usingNode(folder)
.include("inheritedBy")
.getRuleSet(ruleSetId);
restClient.assertStatusCodeIs(OK);
List<String> expectedInheritors = List.of(publicFolder.getNodeRef(), descendantFolder.getNodeRef(), publicGrandchild.getNodeRef());
ruleSet.assertThat().field("inheritedBy").is(expectedInheritors)
.assertThat().field("id").is(ruleSetId);
}
/** Check we can get the folders that link to a rule set and that this respects permissions. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetsAndLinkedToBy()
{
STEP("Create a site owned by admin and add user as a contributor");
SiteModel siteModel = dataSite.usingAdmin().createPrivateRandomSite();
dataUser.addUserToSite(user, siteModel, UserRole.SiteContributor);
STEP("Create the folder structure");
FolderModel ruleFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
FolderModel publicFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(siteModel).createFolder();
dataContent.usingAdmin().usingResource(privateFolder).setInheritPermissions(false);
STEP("Remove the user from the site");
dataUser.removeUserFromSite(user, siteModel);
STEP("Create a rule in the folder and link to it from the other two.");
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
privateAPIForUser().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
RestRuleSetModelsCollection ruleSets = privateAPIForAdmin().usingNode(ruleFolder).getListOfRuleSets();
String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
RestRuleSetLinkModel ruleSetLink = new RestRuleSetLinkModel();
ruleSetLink.setId(ruleFolder.getNodeRef());
privateAPIForUser().usingNode(publicFolder).createRuleLink(ruleSetLink);
privateAPIForAdmin().usingNode(privateFolder).createRuleLink(ruleSetLink);
STEP("Get the rule set and linkedToBy field");
RestRuleSetModel ruleSet = privateAPIForUser().usingNode(ruleFolder)
.include("linkedToBy")
.getRuleSet(ruleSetId);
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("linkedToBy").is(List.of(publicFolder.getNodeRef()))
.assertThat().field("id").is(ruleSetId);
}
/** Check that a user can see that a rule set is inherited even if they don't have permission to view the inheriting folder. */
@Test
public void getRuleSetAndIsInheritedWithoutPermission()
{
STEP("Create a site owned by admin and add user as a contributor");
SiteModel siteModel = dataSite.usingAdmin().createPrivateRandomSite();
dataUser.addUserToSite(user, siteModel, UserRole.SiteContributor);
STEP("Create a folder with a rule set and a private child folder to inherit it");
FolderModel ruleFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
dataContent.usingAdmin().usingResource(ruleFolder).createFolder();
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
privateAPIForUser().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
STEP("Remove the user from the site");
dataUser.removeUserFromSite(user, siteModel);
STEP("Get the rule set and isInherited field");
RestRuleSetModel ruleSet = privateAPIForUser().usingNode(ruleFolder)
.include("isInherited", "inheritedBy")
.getDefaultRuleSet();
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("isInherited").is(true)
.assertThat().field("inheritedBy").isEmpty();
}
/** Check that the isInherited field includes rule sets which are only inherited via links. */
@Test
public void getRuleSetAndIsInheritedViaLink()
{
STEP("Create a site and a folder with a rule");
SiteModel siteModel = dataSite.usingUser(user).createPublicRandomSite();
FolderModel ruleFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
privateAPIForUser().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
STEP("Create a second folder in the site that links to the rule set");
FolderModel secondFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
dataContent.usingUser(user).usingResource(secondFolder).createFolder();
RestRuleSetLinkModel ruleSetLink = new RestRuleSetLinkModel();
ruleSetLink.setId(ruleFolder.getNodeRef());
privateAPIForUser().usingNode(secondFolder).createRuleLink(ruleSetLink);
STEP("Get the rule set and isInherited field");
RestRuleSetModel ruleSet = privateAPIForUser().usingNode(ruleFolder)
.include("isInherited")
.getDefaultRuleSet();
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("isInherited").is(true);
}
/**
* Check that if a rule set is owned and linked to but not inherited then isInherited returns false.
*/
@Test
public void getRuleSetAndIsInheritedCanBeFalse()
{
STEP("Create a site and a folder with a rule");
SiteModel siteModel = dataSite.usingUser(user).createPublicRandomSite();
FolderModel ruleFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
privateAPIForUser().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
STEP("Create a second folder in the site that links to the rule set");
FolderModel secondFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
RestRuleSetLinkModel ruleSetLink = new RestRuleSetLinkModel();
ruleSetLink.setId(ruleFolder.getNodeRef());
privateAPIForUser().usingNode(secondFolder).createRuleLink(ruleSetLink);
STEP("Get the rule set and isInherited field");
RestRuleSetModel ruleSet = privateAPIForUser().usingNode(ruleFolder)
.include("isInherited")
.getDefaultRuleSet();
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("isInherited").is(false);
}
/** Check that a user can see that a rule set is linked to even if they don't have permission to view the linking folder. */
@Test
public void getRuleSetAndIsLinkedToWithoutPermission()
{
STEP("Create a site owned by admin and add user as a contributor");
SiteModel siteModel = dataSite.usingAdmin().createPrivateRandomSite();
dataUser.addUserToSite(user, siteModel, UserRole.SiteContributor);
STEP("Create a folder with a rule set");
FolderModel ruleFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
privateAPIForUser().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
STEP("Create a private folder linking to the rule set");
FolderModel linkingFolder = dataContent.usingAdmin().usingSite(siteModel).createFolder();
RestRuleSetLinkModel linkModel = new RestRuleSetLinkModel();
linkModel.setId(ruleFolder.getNodeRef());
privateAPIForAdmin().usingNode(linkingFolder).createRuleLink(linkModel);
STEP("Remove the user from the site");
dataUser.removeUserFromSite(user, siteModel);
STEP("Get the rule set and isLinkedTo field");
RestRuleSetModel ruleSet = privateAPIForUser().usingNode(ruleFolder)
.include("isLinkedTo", "linkedToBy", "owningFolder")
.getDefaultRuleSet();
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("isLinkedTo").is(true)
.assertThat().field("linkedToBy").isEmpty();
}
/**
* Check that if a rule set is owned and inherited but not linked to then isLinkedTo returns false.
*/
@Test
public void getRuleSetAndIsLinkedToCanBeFalse()
{
STEP("Create a site, a folder with a rule and a child folder that inherits it");
SiteModel siteModel = dataSite.usingUser(user).createPublicRandomSite();
FolderModel ruleFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder();
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
privateAPIForUser().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
dataContent.usingUser(user).usingResource(ruleFolder).createFolder();
STEP("Get the rule set and isLinkedTo field");
RestRuleSetModel ruleSet = privateAPIForUser().usingNode(ruleFolder)
.include("isLinkedTo")
.getDefaultRuleSet();
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("isLinkedTo").is(false);
}
/** Check that we can only view a rule set if have read permission. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void permissionsChecksForFolderWithPrivateAndPublicRuleSets()
{
STEP("Create a public site containing a parent and child folder with rule inheritance enabled.");
SiteModel publicSite = dataSite.usingUser(user).createPublicRandomSite();
FolderModel parentFolder = dataContent.usingUser(user).usingSite(publicSite).createFolder();
FolderModel childFolder = dataContent.usingUser(user).usingResource(parentFolder).createFolder();
RestRuleSettingsModel enabled = new RestRuleSettingsModel();
enabled.setValue(true);
privateAPIForUser().usingNode(parentFolder).usingRuleSetting(IS_INHERITANCE_ENABLED).updateSetting(enabled);
STEP("Link the parent folder to a private rule set.");
RestRuleSetLinkModel linkModel = new RestRuleSetLinkModel();
linkModel.setId(privateFolder.getNodeRef());
privateAPIForAdmin().usingNode(parentFolder).createRuleLink(linkModel);
STEP("Create a rule on the child folder.");
privateAPIForUser().usingNode(childFolder).usingDefaultRuleSet().createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
STEP("Use the admin user to get both rule sets.");
RestRuleSetModelsCollection adminViewOfRuleSets = privateAPIForAdmin().usingNode(childFolder).getListOfRuleSets();
RestRuleSetModel parentRuleSet = adminViewOfRuleSets.getEntries().get(0).onModel();
RestRuleSetModel childRuleSet = adminViewOfRuleSets.getEntries().get(1).onModel();
STEP("Check the normal user can only view the child rule set.");
privateAPIForUser().usingNode(childFolder).getRuleSet(parentRuleSet.getId());
restClient.assertStatusCodeIs(FORBIDDEN);
privateAPIForUser().usingNode(childFolder).getRuleSet(childRuleSet.getId());
restClient.assertStatusCodeIs(OK);
}
private RestCoreAPI coreAPIForAdmin()
{
return restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI();
}
private RestPrivateAPI privateAPIForUser()
{
return restClient.authenticateUser(user).withPrivateAPI();
}
private RestPrivateAPI privateAPIForAdmin()
{
return restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI();
}
}

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
@@ -27,10 +27,10 @@ package org.alfresco.rest.rules;
import static java.util.stream.Collectors.toList;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
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.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
@@ -60,6 +60,10 @@ 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";
private static final String ACTIONS = "actions";
private static final String CONDITIONS = "conditions";
@BeforeClass(alwaysRun = true)
public void dataPreparation()
@@ -71,8 +75,8 @@ public class GetRulesTests extends RestTest
STEP("Create rules in the folder");
createdRules = Stream.of("ruleA", "ruleB").map(ruleName -> {
RestRuleModel ruleModel = createRuleModel(ruleName);
return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
RestRuleModel ruleModel = rulesUtils.createRuleModel(ruleName);
return restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
}).collect(toList());
createdRuleA = createdRules.get(0);
}
@@ -85,25 +89,30 @@ public class GetRulesTests extends RestTest
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Get the rules that apply to the folder");
RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).usingDefaultRuleSet().getListOfRules();
RestRuleModelsCollection rules = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingDefaultRuleSet().getListOfRules();
restClient.assertStatusCodeIs(NOT_FOUND);
assertTrue("Expected no rules to be present.", rules.isEmpty());
}
/** Check we can get all the rules for a folder. */
/**
* Check we can get all the rules for a folder.
* <p>
* Also check that the isShared field is not returned when not requested.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getRulesList()
{
STEP("Get the rules that apply to the folder");
RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().getListOfRules();
RestRuleModelsCollection rules = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().getListOfRules();
restClient.assertStatusCodeIs(OK);
rules.assertThat().entriesListCountIs(createdRules.size());
IntStream.range(0, createdRules.size()).forEach(i ->
rules.getEntries().get(i).onModel()
.assertThat().field("id").is(createdRules.get(i).getId())
.assertThat().field("name").is(createdRules.get(i).getName()));
.assertThat().field("id").is(createdRules.get(i).getId())
.assertThat().field("name").is(createdRules.get(i).getName())
.assertThat().field("isShared").isNull());
}
/** Check we get a 404 if trying to load rules for a folder that doesn't exist. */
@@ -113,7 +122,7 @@ public class GetRulesTests extends RestTest
STEP("Try to load rules for a non-existent folder.");
FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
nonExistentFolder.setNodeRef("fake-id");
restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).usingDefaultRuleSet().getListOfRules();
restClient.authenticateUser(user).withPrivateAPI().usingNode(nonExistentFolder).usingDefaultRuleSet().getListOfRules();
restClient.assertStatusCodeIs(NOT_FOUND);
}
@@ -124,21 +133,92 @@ public class GetRulesTests extends RestTest
STEP("Create a folder in existing site");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Try to load rules for a non-existent rule set.");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).usingRuleSet("fake-id").getListOfRules();
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingRuleSet("fake-id").getListOfRules();
restClient.assertStatusCodeIs(NOT_FOUND);
}
/** Check we can get a rule by its id. */
/** 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()
{
STEP("Get the rules that apply to the folder");
RestRuleModelsCollection rules = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.include("isShared")
.getListOfRules();
rules.assertThat().entriesListCountIs(createdRules.size());
IntStream.range(0, createdRules.size()).forEach(i ->
rules.getEntries().get(i).onModel()
.assertThat().field("isShared").isNotNull()
.assertThat().field("description").isNull()
.assertThat().field("isEnabled").is(true)
.assertThat().field("isInheritable").is(false)
.assertThat().field("isAsynchronous").is(false)
.assertThat().field("errorScript").isNull()
.assertThat().field("isShared").is(false)
.assertThat().field("triggers").is("[inbound]"));
}
/**
* Check we can get a rule by its id.
* <p>
* Also check that the isShared field is not returned when not requested.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getSingleRule()
{
STEP("Load a particular rule");
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().getSingleRule(createdRuleA.getId());
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().getSingleRule(createdRuleA.getId());
restClient.assertStatusCodeIs(OK);
rule.assertThat().field("id").is(createdRuleA.getId())
.assertThat().field("name").is(createdRuleA.getName());
.assertThat().field("name").is(createdRuleA.getName())
.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 = rulesUtils.createRuleModelWithModifiedValues();
ruleModel.setTriggers(List.of("update"));
UserModel admin = dataUser.getAdminUser();
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleModel rule = restClient.authenticateUser(admin).withPrivateAPI().usingNode(folder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = rulesUtils.createRuleModelWithModifiedValues();
expectedRuleModel.setTriggers(List.of("update"));
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 = rulesUtils.createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleModel rule = restClient.authenticateUser(admin).withPrivateAPI().usingNode(folder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = rulesUtils.createRuleModelWithDefaultValues();
expectedRuleModel.setTriggers(List.of("inbound"));
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. */
@@ -148,7 +228,7 @@ public class GetRulesTests extends RestTest
STEP("Try to load a rule from a non-existent folder.");
FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
nonExistentFolder.setNodeRef("fake-id");
restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).usingDefaultRuleSet().getSingleRule("fake-rule-id");
restClient.authenticateUser(user).withPrivateAPI().usingNode(nonExistentFolder).usingDefaultRuleSet().getSingleRule("fake-rule-id");
restClient.assertStatusCodeIs(NOT_FOUND);
}
@@ -159,7 +239,7 @@ public class GetRulesTests extends RestTest
STEP("Create a folder in existing site");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Try to load rules for a non-existent rule set.");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).usingRuleSet("fake-id").getSingleRule("fake-rule-id");
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingRuleSet("fake-id").getSingleRule("fake-rule-id");
restClient.assertStatusCodeIs(NOT_FOUND);
}
@@ -170,10 +250,22 @@ public class GetRulesTests extends RestTest
STEP("Create a folder in existing site");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Try to load a rule for a wrong but existing folder.");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).usingDefaultRuleSet().getSingleRule(createdRuleA.getId());
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingDefaultRuleSet().getSingleRule(createdRuleA.getId());
restClient.assertStatusCodeIs(NOT_FOUND);
}
/** Check we can get a rule by its id along with any included fields. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getSingleRuleWithIncludedFields()
{
STEP("Load a particular rule");
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.include("isShared")
.getSingleRule(createdRuleA.getId());
rule.assertThat().field("isShared").isNotNull();
}
/** Check that a user without read permission cannot view the folder rules. */
public void requireReadPermissionToGetRule()
{
@@ -183,10 +275,10 @@ public class GetRulesTests extends RestTest
FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("Private site rule");
restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.authenticateUser(privateUser).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
STEP("Try to get the rule with another user");
restClient.authenticateUser(user).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().getListOfRules();
restClient.authenticateUser(user).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().getListOfRules();
restClient.assertLastError()
.statusCodeIs(FORBIDDEN)
@@ -200,8 +292,8 @@ public class GetRulesTests extends RestTest
UserModel privateUser = dataUser.createRandomTestUser();
SiteModel privateSite = dataSite.usingUser(privateUser).createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
RestRuleModel ruleModel = createRuleModel("Private site rule");
restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
RestRuleModel ruleModel = rulesUtils.createRuleModel("Private site rule");
restClient.authenticateUser(privateUser).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
STEP("Create a collaborator in the private site");
UserModel collaborator = dataUser.createRandomTestUser();
@@ -209,9 +301,61 @@ public class GetRulesTests extends RestTest
restClient.authenticateUser(privateUser).withCoreAPI().usingSite(privateSite).addPerson(collaborator);
STEP("Check the collaborator can view the rule");
RestRuleModelsCollection rules = restClient.authenticateUser(collaborator).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().getListOfRules();
RestRuleModelsCollection rules = restClient.authenticateUser(collaborator).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().getListOfRules();
restClient.assertStatusCodeIs(OK);
rules.assertThat().entriesListContains("name", "Private site rule");
}
/**
* Check we can GET Rule's actions.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void getRuleActions()
{
STEP("Create a rule with a few actions");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
final RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createVariousActions());
STEP("Retrieve the created rule via the GET endpoint");
final RestRuleModel getRuleBody = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingDefaultRuleSet().getSingleRule(rule.getId());
STEP("Assert that actions are returned as expected from the GET endpoint");
restClient.assertStatusCodeIs(OK);
getRuleBody.assertThat().field(ACTIONS).contains("actionDefinitionId=copy")
.assertThat().field(ACTIONS).contains("destination-folder=" + rulesUtils.getCopyDestinationFolder().getNodeRef())
.assertThat().field(ACTIONS).contains("deep-copy=true")
.assertThat().field(ACTIONS).contains("actionDefinitionId=check-out")
.assertThat().field(ACTIONS).contains("destination-folder=" + rulesUtils.getCheckOutDestinationFolder().getNodeRef())
.assertThat().field(ACTIONS).contains("assoc-name=cm:checkout");
}
/**
* Check we can GET rule's conditions.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void getRulesConditions()
{
STEP("Create a rule with several conditions");
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
ruleModel.setConditions(rulesUtils.createVariousConditions());
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Retrieve the created rule via the GET endpoint");
final RestRuleModel getRuleBody = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingDefaultRuleSet().getSingleRule(rule.getId());
STEP("Assert that conditions are retrieved using the GET endpoint");
restClient.assertStatusCodeIs(OK);
getRuleBody.assertThat().field(CONDITIONS).contains("comparator=ends")
.assertThat().field(CONDITIONS).contains("field=cm:creator")
.assertThat().field(CONDITIONS).contains("parameter=ski")
.assertThat().field(CONDITIONS).contains("comparator=begins")
.assertThat().field(CONDITIONS).contains("field=cm:modelVersion")
.assertThat().field(CONDITIONS).contains("parameter=1.");
}
}

View File

@@ -0,0 +1,203 @@
/*
* #%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.rest.rules;
import static java.util.stream.Collectors.toList;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.OK;
import java.util.List;
import java.util.stream.IntStream;
import com.google.common.collect.Lists;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleSetModel;
import org.alfresco.utility.constants.UserRole;
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;
@Test (groups = { TestGroup.RULES })
public class ReorderRules extends RestTest
{
private UserModel user;
private SiteModel site;
@BeforeClass (alwaysRun = true)
public void dataPreparation()
{
STEP("Create a user and site.");
user = dataUser.createRandomTestUser();
site = dataSite.usingUser(user).createPublicRandomSite();
}
/** Check we can get the ordered list of rules in a rule set. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getOrderedRuleIds()
{
STEP("Create a folder containing three rules in the existing site");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
List<RestRuleModel> rules = createRulesInFolder(folder, user);
STEP("Get the default rule set for the folder including the ordered rule ids");
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder)
.include("ruleIds").getDefaultRuleSet();
List<String> expectedRuleIds = rules.stream().map(RestRuleModel::getId).collect(toList());
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("ruleIds").is(expectedRuleIds);
}
/** Check that a user can view the order of the rules in a rule set if they only have read permission. */
@Test
public void getRuleSetAndRuleIdsWithReadOnlyPermission()
{
STEP("Create a site owned by admin and add user as a consumer");
SiteModel siteModel = dataSite.usingAdmin().createPrivateRandomSite();
dataUser.addUserToSite(user, siteModel, UserRole.SiteConsumer);
STEP("Use admin to create a folder with a rule set and three rules in it");
FolderModel ruleFolder = dataContent.usingAdmin().usingSite(siteModel).createFolder();
dataContent.usingAdmin().usingResource(ruleFolder).createFolder();
List<RestRuleModel> rules = createRulesInFolder(ruleFolder, dataUser.getAdminUser());
STEP("Get the rule set with the ordered list of rules");
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder)
.include("ruleIds").getDefaultRuleSet();
restClient.assertStatusCodeIs(OK);
List<String> ruleIds = rules.stream().map(RestRuleModel::getId).collect(toList());
ruleSet.assertThat().field("ruleIds").is(ruleIds);
}
/** Check we can reorder the rules in a rule set. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void reorderRules()
{
STEP("Create a folder containing three rules in the existing site");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
List<RestRuleModel> rules = createRulesInFolder(folder, user);
STEP("Reverse the order of the rules within the rule set");
List<String> reversedRuleIds = Lists.reverse(rules.stream().map(RestRuleModel::getId).collect(toList()));
RestRuleSetModel ruleSetBody = new RestRuleSetModel();
ruleSetBody.setId("-default-");
ruleSetBody.setRuleIds(reversedRuleIds);
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder)
.include("ruleIds").updateRuleSet(ruleSetBody);
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("ruleIds").is(reversedRuleIds);
}
/** Check we can reorder the rules in a rule set by editing the response from the GET. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void reorderRulesUsingResponseFromGET()
{
STEP("Create a folder containing three rules in the existing site");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
List<RestRuleModel> rules = createRulesInFolder(folder, user);
STEP("Get the rule set with its id.");
RestRuleSetModel ruleSetResponse = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder)
.include("ruleIds").getDefaultRuleSet();
STEP("Reverse the order of the rules within the rule set");
ruleSetResponse.setRuleIds(Lists.reverse(ruleSetResponse.getRuleIds()));
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI().usingNode(folder)
.include("ruleIds").updateRuleSet(ruleSetResponse);
restClient.assertStatusCodeIs(OK);
List<String> reversedRuleIds = Lists.reverse(rules.stream().map(RestRuleModel::getId).collect(toList()));
ruleSet.assertThat().field("ruleIds").is(reversedRuleIds);
}
/** Check that a user cannot reorder the rules in a rule set if they only have read permission. */
@Test
public void reorderRulesWithoutPermission()
{
STEP("Create a site owned by admin and add user as a consumer");
SiteModel siteModel = dataSite.usingAdmin().createPrivateRandomSite();
dataUser.addUserToSite(user, siteModel, UserRole.SiteContributor);
STEP("Use admin to create a folder with a rule set and three rules in it");
FolderModel ruleFolder = dataContent.usingAdmin().usingSite(siteModel).createFolder();
dataContent.usingAdmin().usingResource(ruleFolder).createFolder();
List<RestRuleModel> rules = createRulesInFolder(ruleFolder, dataUser.getAdminUser());
STEP("Try to reorder the rules as the contributor");
List<String> reversedRuleIds = Lists.reverse(rules.stream().map(RestRuleModel::getId).collect(toList()));
RestRuleSetModel ruleSetBody = new RestRuleSetModel();
ruleSetBody.setId("-default-");
ruleSetBody.setRuleIds(reversedRuleIds);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder)
.include("ruleIds").updateRuleSet(ruleSetBody);
restClient.assertStatusCodeIs(FORBIDDEN);
}
/** Check that a user can reorder the rules in a rule set if they have write permission. */
@Test
public void reorderRulesWithPermission()
{
STEP("Create a site owned by admin and add user as a collaborator");
SiteModel siteModel = dataSite.usingAdmin().createPrivateRandomSite();
dataUser.addUserToSite(user, siteModel, UserRole.SiteCollaborator);
STEP("Use admin to create a folder with a rule set and three rules in it");
FolderModel ruleFolder = dataContent.usingAdmin().usingSite(siteModel).createFolder();
dataContent.usingAdmin().usingResource(ruleFolder).createFolder();
List<RestRuleModel> rules = createRulesInFolder(ruleFolder, dataUser.getAdminUser());
STEP("Try to reorder the rules as the contributor");
List<String> reversedRuleIds = Lists.reverse(rules.stream().map(RestRuleModel::getId).collect(toList()));
RestRuleSetModel ruleSetBody = new RestRuleSetModel();
ruleSetBody.setId("-default-");
ruleSetBody.setRuleIds(reversedRuleIds);
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder)
.include("ruleIds").updateRuleSet(ruleSetBody);
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("ruleIds").is(reversedRuleIds);
}
/** Create three rules in the given folder. */
private List<RestRuleModel> createRulesInFolder(FolderModel folder, UserModel user)
{
return IntStream.range(0, 3).mapToObj(index ->
{
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
return restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).usingDefaultRuleSet().createSingleRule(ruleModel);
}).collect(toList());
}
}

View File

@@ -0,0 +1,502 @@
/*
* #%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.utility.constants.UserRole.SiteConsumer;
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.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.http.HttpStatus.OK;
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 = rulesUtils.createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().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).withPrivateAPI().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).withPrivateAPI().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).withPrivateAPI()
.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).withPrivateAPI()
.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 = rulesUtils.createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().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).withPrivateAPI().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).withPrivateAPI().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).withPrivateAPI()
.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).withPrivateAPI()
.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).withPrivateAPI().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).withPrivateAPI().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 = rulesUtils.createRuleModel("ruleName1");
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder1).usingDefaultRuleSet()
.createSingleRule(ruleModel1);
RestRuleModel ruleModel2 = rulesUtils.createRuleModel("ruleName2");
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder2).usingDefaultRuleSet()
.createSingleRule(ruleModel2);
STEP("Link from a folder with rules");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(folder2.getNodeRef());
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder1).createRuleLink(request);
STEP("Assert link result is 400");
restClient.assertStatusCodeIs(BAD_REQUEST)
.assertLastError().containsSummary(
"Unable to link to a rule set because the folder has pre-existing rules or is already linked to a rule set.");
}
/**
* 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).withPrivateAPI().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 = rulesUtils.createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().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).withPrivateAPI().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).withPrivateAPI().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).withPrivateAPI()
.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).withPrivateAPI()
.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);
}
/**
* Check we get an error when trying to link to a rule set that we can't view.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void linkToRuleSetWithoutPermission()
{
STEP("Use admin to create a private site with a folder containing a rule.");
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
STEP("Use a normal user to try to link to the rule.");
FolderModel publicFolder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(privateFolder.getNodeRef());
restClient.authenticateUser(user).withPrivateAPI().usingNode(publicFolder).createRuleLink(request);
restClient.assertStatusCodeIs(FORBIDDEN);
}
/**
* Check we are able to link to a rule set with only read permission.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void linkToRuleSetWithOnlyReadPermission()
{
STEP("Use admin to create a private site with a folder containing a rule.");
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
STEP("Add the normal user as a consumer.");
dataUser.usingAdmin().addUserToSite(user, privateSite, SiteConsumer);
STEP("Use a normal user to try to link to the rule.");
FolderModel publicFolder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(privateFolder.getNodeRef());
restClient.authenticateUser(user).withPrivateAPI().usingNode(publicFolder).createRuleLink(request);
restClient.assertStatusCodeIs(CREATED);
}
/**
* Check we can DELETE/unlink a ruleset
*
* DELETE /nodes/{folderNodeId}/rule-set-links/{ruleSetId}.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void unlinkRuleSet()
{
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 = rulesUtils.createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withPrivateAPI().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).withPrivateAPI().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).withPrivateAPI().usingNode(folder).createRuleLink(request);
STEP("Unlink the rule set");
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).unlinkRuleSet(ruleSetId);
STEP("Assert unlink result");
restClient.assertStatusCodeIs(NO_CONTENT);
STEP("GET the rule set and isLinkedTo field.");
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder)
.include("isLinkedTo", "linkedToBy", "owningFolder")
.getDefaultRuleSet();
STEP("Assert linkedTo is false.");
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("isLinkedTo").is(false)
.assertThat().field("linkedToBy").isEmpty();
}
/**
* Check a 400 is thrown when using folder/content id instead of a ruleSetId.
*
* DELETE /nodes/{folderNodeId}/rule-set-links/{ruleSetId}
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void unlinkUsingDocumentId()
{
STEP("Create folders in existing site");
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Attempt to unlink the rule set");
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).unlinkRuleSet(folder.getNodeRef());
STEP("Assert unlink result");
restClient.assertStatusCodeIs(BAD_REQUEST)
.assertLastError().containsSummary("NodeId of a rule set is expected!");
}
/**
* Check a 404 is thrown when using non-existent id instead of a ruleSetId.
*
* DELETE /nodes/{folderNodeId}/rule-set-links/{ruleSetId}
*/
//TODO This test may need to be modified once ACS-3616 is done
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void unlinkUsingRandomId()
{
STEP("Create folders in existing site");
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Attempt to unlink the rule set");
restClient.authenticateUser(user).withPrivateAPI().usingNode(folder).unlinkRuleSet("non-existent-id");
STEP("Assert unlink result");
restClient.assertStatusCodeIs(NOT_FOUND)
.assertLastError().containsSummary("Rule set with id non-existent-id was not found");
}
/**
* Check we cannot unlink from a rule set that we can't view.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void unlinkFromRuleSetWithoutPermission()
{
STEP("Use admin to create a private site with a folder containing a rule.");
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
STEP("Add the user as a consumer.");
dataUser.usingAdmin().addUserToSite(user, privateSite, SiteConsumer);
STEP("Use the consumer to create a folder with a link to the private rule set.");
FolderModel publicFolder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(privateFolder.getNodeRef());
restClient.authenticateUser(user).withPrivateAPI().usingNode(publicFolder).createRuleLink(request);
restClient.assertStatusCodeIs(CREATED);
STEP("Remove the user from the private site.");
dataUser.usingAdmin().removeUserFromSite(user, privateSite);
STEP("Use the user to try to unlink from the rule set.");
restClient.authenticateUser(user).withPrivateAPI().usingNode(publicFolder).unlinkRuleSet("-default-");
restClient.assertStatusCodeIs(FORBIDDEN);
}
/**
* Check we can unlink from a rule set if we only have read permission for it.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void unlinkFromRuleSetWithOnlyReadPermission()
{
STEP("Use admin to create a private site with a folder containing a rule.");
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingAdmin().usingSite(privateSite).createFolder();
restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createRuleModelWithDefaultValues());
STEP("Add the user as a consumer.");
dataUser.usingAdmin().addUserToSite(user, privateSite, SiteConsumer);
STEP("Use the consumer to create a folder with a link to the private rule set.");
FolderModel publicFolder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(privateFolder.getNodeRef());
restClient.authenticateUser(user).withPrivateAPI().usingNode(publicFolder).createRuleLink(request);
restClient.assertStatusCodeIs(CREATED);
STEP("Use the consumer to try to unlink from the rule set.");
restClient.authenticateUser(user).withPrivateAPI().usingNode(publicFolder).unlinkRuleSet("-default-");
restClient.assertStatusCodeIs(NO_CONTENT);
}
}

View File

@@ -25,31 +25,164 @@
*/
package org.alfresco.rest.rules;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.MAIL_ACTION;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.createMailParameters;
import static org.alfresco.utility.model.UserModel.getRandomUserModel;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
import org.alfresco.rest.model.RestActionConstraintDataModel;
import org.alfresco.rest.model.RestActionConstraintModel;
import org.alfresco.rest.model.RestActionDefinitionModel;
import org.alfresco.rest.model.RestCompositeConditionDefinitionModel;
import org.alfresco.rest.model.RestNodeModel;
import org.alfresco.rest.model.RestParameterDefinitionModel;
import org.alfresco.rest.model.RestRuleExecutionModel;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestSimpleConditionDefinitionModel;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.data.DataSite;
import org.alfresco.utility.data.DataUserAIS;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
public class RulesTestsUtils
@Service
public class RulesTestsUtils implements InitializingBean
{
static final String RULE_NAME_DEFAULT = "ruleName";
static final String RULE_DESCRIPTION_DEFAULT = "rule description";
static final boolean RULE_ENABLED_DEFAULT = true;
static final boolean RULE_CASCADE_DEFAULT = true;
static final boolean RULE_ASYNC_DEFAULT = true;
static final boolean RULE_SHARED_DEFAULT = false;
static final String RULE_SCRIPT_ID = "script";
static final String RULE_SCRIPT_PARAM_ID = "script-ref";
static final String RULE_ERROR_SCRIPT_LABEL = "Start Pooled Review and Approve Workflow";
static final String INBOUND = "inbound";
static final String UPDATE = "update";
static final String OUTBOUND = "outbound";
static final List<String> RULE_TRIGGERS_DEFAULT = List.of(INBOUND, UPDATE, OUTBOUND);
static final boolean INVERTED = true;
static final String AND = "and";
static final String ID = "id";
static final String IS_SHARED = "isShared";
static final String AUDIO_ASPECT = "audio:audio";
static final String LOCKABLE_ASPECT = "cm:lockable";
public static RestRuleModel createRuleModel(String name) {
return createRuleModel(name, List.of(createActionModel()));
@Autowired
private RestWrapper restClient;
@Autowired
private DataUserAIS dataUser;
@Autowired
private DataSite dataSite;
@Autowired
private DataContent dataContent;
private SiteModel site;
private String reviewAndApproveWorkflowNode;
private FolderModel copyDestinationFolder;
private FolderModel checkOutDestinationFolder;
/**
* Initialise the util class.
*/
@Override
public void afterPropertiesSet()
{
UserModel admin = dataUser.getAdminUser();
// Obtain the node ref for the review and approve workflow.
RestActionDefinitionModel actionDef = restClient.authenticateUser(admin).withCoreAPI().usingActions().getActionDefinitionById(RULE_SCRIPT_ID);
RestParameterDefinitionModel paramDef = actionDef.getParameterDefinitions().stream().filter(param -> param.getName().equals(RULE_SCRIPT_PARAM_ID)).findFirst().get();
String constraintName = paramDef.getParameterConstraintName();
RestActionConstraintModel constraintDef = restClient.authenticateUser(admin).withCoreAPI().usingActions().getActionConstraintByName(constraintName);
RestActionConstraintDataModel reviewAndApprove = constraintDef.getConstraintValues().stream().filter(constraintValue -> constraintValue.getLabel().equals(RULE_ERROR_SCRIPT_LABEL)).findFirst().get();
reviewAndApproveWorkflowNode = reviewAndApprove.getValue();
// Create a couple of public folders to be used as action destinations.
site = dataSite.usingUser(admin).createPublicRandomSite();
copyDestinationFolder = dataContent.usingUser(admin).usingSite(site).createFolder();
checkOutDestinationFolder = dataContent.usingUser(admin).usingSite(site).createFolder();
}
public RestRuleModel createRuleModelWithModifiedValues()
{
return createRuleModelWithModifiedValues(List.of(createAddAudioAspectAction()));
}
/**
* Get the review and approve workflow node (throwing an exception if this utility class has not been initialised).
*
* @return The node ref of the script node.
*/
public String getReviewAndApproveWorkflowNode()
{
return reviewAndApproveWorkflowNode;
}
public FolderModel getCopyDestinationFolder()
{
return copyDestinationFolder;
}
public FolderModel getCheckOutDestinationFolder()
{
return checkOutDestinationFolder;
}
/**
* Create a rule model filled with custom constant values.
*
* @param actions - rule's actions.
* @return The created rule model.
*/
public RestRuleModel createRuleModelWithModifiedValues(List<RestActionBodyExecTemplateModel> actions)
{
RestRuleModel ruleModel = createRuleModel(RULE_NAME_DEFAULT, actions);
ruleModel.setDescription(RULE_DESCRIPTION_DEFAULT);
ruleModel.setIsEnabled(RULE_ENABLED_DEFAULT);
ruleModel.setIsInheritable(RULE_CASCADE_DEFAULT);
ruleModel.setIsAsynchronous(RULE_ASYNC_DEFAULT);
ruleModel.setIsShared(RULE_SHARED_DEFAULT);
ruleModel.setTriggers(RULE_TRIGGERS_DEFAULT);
ruleModel.setErrorScript(getReviewAndApproveWorkflowNode());
return ruleModel;
}
public RestRuleModel createRuleModelWithDefaultValues()
{
return createRuleModel(RULE_NAME_DEFAULT);
}
public RestRuleModel createRuleModel(String name)
{
return createRuleModel(name, List.of(createAddAudioAspectAction()));
}
/**
* Create a rule model.
*
* @param name The name for the rule.
* @param restActionModels Rule's actions.
* @param actions Rule's actions.
* @return The created rule model.
*/
public static RestRuleModel createRuleModel(String name, List<RestActionBodyExecTemplateModel> restActionModels)
public RestRuleModel createRuleModel(String name, List<RestActionBodyExecTemplateModel> actions)
{
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setIsEnabled(true);
ruleModel.setName(name);
ruleModel.setActions(restActionModels);
ruleModel.setActions(actions);
return ruleModel;
}
@@ -58,11 +191,147 @@ public class RulesTestsUtils
*
* @return The created action model.
*/
public static RestActionBodyExecTemplateModel createActionModel()
public RestActionBodyExecTemplateModel createAddAudioAspectAction()
{
return createAddAspectAction(AUDIO_ASPECT);
}
public RestActionBodyExecTemplateModel createAddAspectAction(String aspect)
{
return createCustomActionModel("add-features", Map.of("aspect-name", aspect));
}
public RestActionBodyExecTemplateModel createCustomActionModel(String actionDefinitionId, Map<String, Serializable> params)
{
RestActionBodyExecTemplateModel restActionModel = new RestActionBodyExecTemplateModel();
restActionModel.setActionDefinitionId("add-features");
restActionModel.setParams(Map.of("aspect-name", "{http://www.alfresco.org/model/audio/1.0}audio", "actionContext", "rule"));
restActionModel.setActionDefinitionId(actionDefinitionId);
restActionModel.setParams(params);
return restActionModel;
}
public RestCompositeConditionDefinitionModel createEmptyConditionModel()
{
RestCompositeConditionDefinitionModel conditions = new RestCompositeConditionDefinitionModel();
conditions.setInverted(!INVERTED);
conditions.setBooleanMode(AND);
return conditions;
}
public RestCompositeConditionDefinitionModel createVariousConditions()
{
return createCompositeCondition(List.of(
createCompositeCondition(!INVERTED, List.of(
createSimpleCondition("cm:created", "less_than", "2022-09-01T12:59:00.000+02:00"),
createSimpleCondition("cm:creator", "ends", "ski"),
createSimpleCondition("size", "greater_than", "90000000"),
createSimpleCondition("mimetype", "equals", "video/3gpp"),
createSimpleCondition("encoding", "equals", "utf-8"),
createSimpleCondition("type", "equals", "cm:folder"),
createSimpleCondition("tag", "equals", "uat")
)),
createCompositeCondition(INVERTED, List.of(
createSimpleCondition("aspect", "equals", AUDIO_ASPECT),
createSimpleCondition("cm:modelVersion", "begins", "1.")
))
));
}
public RestRuleModel createVariousActions()
{
final Map<String, Serializable> copyParams =
Map.of("destination-folder", copyDestinationFolder.getNodeRef(), "deep-copy", true);
final RestActionBodyExecTemplateModel copyAction = createCustomActionModel("copy", copyParams);
final Map<String, Serializable> checkOutParams =
Map.of("destination-folder", checkOutDestinationFolder.getNodeRef(), "assoc-name", "cm:checkout",
"assoc-type", "cm:contains");
final RestActionBodyExecTemplateModel checkOutAction = createCustomActionModel("check-out", checkOutParams);
// The counter action takes no parameters, so check we can omit the "params" entry.
final RestActionBodyExecTemplateModel counterAction = createCustomActionModel("counter", null);
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
ruleModel.setActions(Arrays.asList(copyAction, checkOutAction, counterAction));
return ruleModel;
}
public RestRuleModel createRuleWithPrivateAction()
{
RestActionBodyExecTemplateModel mailAction = new RestActionBodyExecTemplateModel();
mailAction.setActionDefinitionId(MAIL_ACTION);
mailAction.setParams(createMailParameters(getRandomUserModel(), getRandomUserModel()));
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
ruleModel.setActions(Arrays.asList(mailAction));
return ruleModel;
}
public RestSimpleConditionDefinitionModel createSimpleCondition(String field, String comparator, String parameter)
{
RestSimpleConditionDefinitionModel simpleCondition = new RestSimpleConditionDefinitionModel();
simpleCondition.setField(field);
simpleCondition.setComparator(comparator);
simpleCondition.setParameter(parameter);
return simpleCondition;
}
public RestCompositeConditionDefinitionModel createCompositeCondition(List<RestCompositeConditionDefinitionModel> compositeConditions)
{
return createCompositeCondition(AND, !INVERTED, compositeConditions, null);
}
public RestCompositeConditionDefinitionModel createCompositeCondition(boolean inverted,
List<RestSimpleConditionDefinitionModel> simpleConditions)
{
return createCompositeCondition(AND, inverted, null, simpleConditions);
}
public RestRuleExecutionModel createRuleExecutionRequest()
{
return createRuleExecutionRequest(false);
}
public RestRuleExecutionModel createRuleExecutionRequest(boolean eachSubFolderIncluded)
{
RestRuleExecutionModel ruleExecutionBody = new RestRuleExecutionModel();
ruleExecutionBody.setIsEachSubFolderIncluded(eachSubFolderIncluded);
return ruleExecutionBody;
}
private RestCompositeConditionDefinitionModel createCompositeCondition(String booleanMode, boolean inverted,
List<RestCompositeConditionDefinitionModel> compositeConditions, List<RestSimpleConditionDefinitionModel> simpleConditions)
{
RestCompositeConditionDefinitionModel compositeCondition = new RestCompositeConditionDefinitionModel();
compositeCondition.setBooleanMode(booleanMode);
compositeCondition.setInverted(inverted);
compositeCondition.setCompositeConditions(compositeConditions);
compositeCondition.setSimpleConditions(simpleConditions);
return compositeCondition;
}
public NodeAssertion assertThat(RestNodeModel node)
{
return new NodeAssertion(node);
}
public class NodeAssertion
{
private final RestNodeModel node;
private NodeAssertion(RestNodeModel node)
{
this.node = node;
}
public NodeAssertion containsAspects(String ...expectedAspects)
{
Arrays.stream(expectedAspects).forEach(aspect -> node.assertThat().field("aspectNames").contains(aspect));
return this;
}
public NodeAssertion notContainsAspects(String ...unexpectedAspects)
{
Arrays.stream(unexpectedAspects).forEach(aspect -> node.assertThat().field("aspectNames").notContains(aspect));
return this;
}
}
}

View File

@@ -0,0 +1,232 @@
/*
* #%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.rest.rules;
import static org.alfresco.rest.requests.RuleSettings.IS_INHERITANCE_ENABLED;
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestRuleSettingsModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Tests for GET and PUT /nodes/{nodeId}/rule-settings/{ruleSettingKey}.
*/
@Test (groups = { TestGroup.RULES })
public class SetInheritanceTests extends RestTest
{
private UserModel siteOwner;
private SiteModel site;
@BeforeClass (alwaysRun = true)
public void dataPreparation()
{
STEP("Create a user, site and folder.");
siteOwner = dataUser.createRandomTestUser();
site = dataSite.usingUser(siteOwner).createPrivateRandomSite();
}
/** Check we can get the -isInheritanceEnabled- rule setting for the folder. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getIsInherited()
{
STEP("Create a folder for the test.");
FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
STEP("Get the -isInheritanceEnabled- rule settings for the folder.");
RestRuleSettingsModel ruleSettingsModel = restClient.authenticateUser(siteOwner)
.withPrivateAPI()
.usingNode(folder)
.usingIsInheritanceEnabledRuleSetting()
.retrieveSetting();
restClient.assertStatusCodeIs(OK);
RestRuleSettingsModel expected = new RestRuleSettingsModel();
expected.setKey(IS_INHERITANCE_ENABLED);
expected.setValue(true);
ruleSettingsModel.assertThat().isEqualTo(expected);
}
/** Check we get an error when trying to get settings from a non-existent folder. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getIsInheritedFromNonExistentFolder()
{
STEP("Try to get the -isInheritanceEnabled- rule settings for a fake folder.");
FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
nonExistentFolder.setNodeRef("fake-id");
restClient.authenticateUser(siteOwner)
.withPrivateAPI()
.usingNode(nonExistentFolder)
.usingIsInheritanceEnabledRuleSetting()
.retrieveSetting();
restClient.assertLastError().statusCodeIs(NOT_FOUND)
.containsSummary("Folder with id fake-id was not found");
}
/** Check we get an error when trying to retrieve a non-existent setting. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getNonExistentSetting()
{
STEP("Create a folder for the test.");
FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
STEP("Try to get a fake setting from the folder.");
restClient.authenticateUser(siteOwner).withPrivateAPI().usingNode(folder).usingRuleSetting("-fakeRuleSetting-")
.retrieveSetting();
restClient.assertLastError().statusCodeIs(NOT_FOUND)
.containsSummary("Unrecognised rule setting key -fakeRuleSetting-");
}
/** Check a user without permission for the folder cannot get the -isInheritanceEnabled- rule setting. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getIsInheritedWithoutPermission()
{
STEP("Create a folder and a user without permission to access it.");
FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
UserModel noPermissionUser = dataUser.createRandomTestUser();
STEP("Try to get the -isInheritanceEnabled- setting without permission.");
restClient.authenticateUser(noPermissionUser)
.withPrivateAPI()
.usingNode(folder)
.usingIsInheritanceEnabledRuleSetting()
.retrieveSetting();
restClient.assertLastError().statusCodeIs(FORBIDDEN)
.containsSummary("Cannot read from this node");
}
/** Check we can change the -isInheritanceEnabled- rule setting for the folder. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void updateIsInherited()
{
STEP("Create a folder for the test.");
FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
STEP("Set -isInheritanceEnabled- to false.");
RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
updateBody.setValue(false);
RestRuleSettingsModel ruleSettingsModel = restClient.authenticateUser(siteOwner)
.withPrivateAPI()
.usingNode(folder)
.usingIsInheritanceEnabledRuleSetting()
.updateSetting(updateBody);
restClient.assertStatusCodeIs(OK);
RestRuleSettingsModel expected = new RestRuleSettingsModel();
expected.setKey(IS_INHERITANCE_ENABLED);
expected.setValue(false);
ruleSettingsModel.assertThat().isEqualTo(expected);
}
/** Check we get an error when trying to set -isInheritanceEnabled- to something other than a boolean. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void updateInheritedWithBadValue()
{
STEP("Create a folder for the test.");
FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
STEP("Try to set -isInheritanceEnabled- to \"banana\".");
RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
updateBody.setValue("banana");
restClient.authenticateUser(siteOwner).withPrivateAPI().usingNode(folder).usingIsInheritanceEnabledRuleSetting()
.updateSetting(updateBody);
restClient.assertLastError().statusCodeIs(BAD_REQUEST)
.containsSummary("Rule setting " + IS_INHERITANCE_ENABLED + " requires a boolean value.");
}
/** Check we get an error when the folder is not found. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void updateInheritedWithNonExistentFolder()
{
STEP("Try to set -isInheritanceEnabled- against a fake folder.");
FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
nonExistentFolder.setNodeRef("fake-id");
RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
updateBody.setValue(true);
restClient.authenticateUser(siteOwner).withPrivateAPI().usingNode(nonExistentFolder).usingIsInheritanceEnabledRuleSetting()
.updateSetting(updateBody);
restClient.assertLastError().statusCodeIs(NOT_FOUND)
.containsSummary("Folder with id fake-id was not found");
}
/** Check we get an error when trying to set a non-existent setting. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void updateNonExistentSetting()
{
STEP("Create a folder for the test.");
FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
STEP("Try to set a fake setting on the folder.");
RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
updateBody.setValue(true);
restClient.authenticateUser(siteOwner).withPrivateAPI().usingNode(folder).usingRuleSetting("-fakeRuleSetting-")
.updateSetting(updateBody);
restClient.assertLastError().statusCodeIs(NOT_FOUND)
.containsSummary("Unrecognised rule setting key -fakeRuleSetting-");
}
/** Check a user without manage permission cannot update the -isInheritanceEnabled- rule setting. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void updateIsInheritedWithoutPermission()
{
STEP("Create a folder and a collaborator.");
FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
UserModel collaborator = dataUser.createRandomTestUser();
collaborator.setUserRole(SiteCollaborator);
restClient.authenticateUser(siteOwner).withCoreAPI().usingSite(site).addPerson(collaborator);
STEP("Try to update the -isInheritanceEnabled- setting without permission.");
RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
updateBody.setValue(true);
restClient.authenticateUser(collaborator).withPrivateAPI().usingNode(folder).usingIsInheritanceEnabledRuleSetting()
.updateSetting(updateBody);
restClient.assertLastError().statusCodeIs(FORBIDDEN)
.containsSummary("Insufficient permissions to manage rules");
}
}

View File

@@ -25,8 +25,14 @@
*/
package org.alfresco.rest.rules;
import static org.alfresco.rest.rules.RulesTestsUtils.createActionModel;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_ACCESS_RESTRICTED;
import static org.alfresco.rest.rules.RulesTestsUtils.ID;
import static org.alfresco.rest.rules.RulesTestsUtils.INBOUND;
import static org.alfresco.rest.rules.RulesTestsUtils.INVERTED;
import static org.alfresco.rest.rules.RulesTestsUtils.IS_SHARED;
import static org.alfresco.rest.rules.RulesTestsUtils.RULE_ASYNC_DEFAULT;
import static org.alfresco.rest.rules.RulesTestsUtils.RULE_CASCADE_DEFAULT;
import static org.alfresco.rest.rules.RulesTestsUtils.RULE_ENABLED_DEFAULT;
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
@@ -34,10 +40,16 @@ import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
import org.alfresco.rest.model.RestCompositeConditionDefinitionModel;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
@@ -64,20 +76,25 @@ public class UpdateRulesTests extends RestTest
ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
}
/** Check we can update a rule. */
/**
* Check we can update a rule.
* <p>
* Also check that the isShared field is not returned when not requested.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRule()
{
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule.");
RestRuleModel updatedRuleModel = createRuleModel("Updated rule name");
RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
RestRuleModel updatedRuleModel = rulesUtils.createRuleModel("Updated rule name");
RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), updatedRuleModel);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().field("id").is(rule.getId())
.assertThat().field("name").is("Updated rule name");
updatedRule.assertThat().field(ID).is(rule.getId())
.assertThat().field("name").is("Updated rule name")
.assertThat().field(IS_SHARED).isNull();
}
/** Check we get a 404 if trying to update a rule in a folder that doesn't exist. */
@@ -92,11 +109,11 @@ public class UpdateRulesTests extends RestTest
RestRuleModel updatedRuleModel = new RestRuleModel();
updatedRuleModel.setName("Updated rule name");
restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).usingDefaultRuleSet()
restClient.authenticateUser(user).withPrivateAPI().usingNode(nonExistentFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), updatedRuleModel);
restClient.assertLastError().statusCodeIs(NOT_FOUND)
.containsSummary("fake-id was not found");
.containsSummary("Folder with id fake-id was not found");
}
/** Check we get a 404 if trying to update a rule in a rule set that doesn't exist. */
@@ -108,11 +125,11 @@ public class UpdateRulesTests extends RestTest
STEP("Try to update a rule in a non-existent rule set.");
RestRuleModel updatedRuleModel = new RestRuleModel();
updatedRuleModel.setName("Updated rule name");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingRuleSet("fake-id")
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingRuleSet("fake-id")
.updateRule(rule.getId(), updatedRuleModel);
restClient.assertLastError().statusCodeIs(NOT_FOUND)
.containsSummary("fake-id was not found");
.containsSummary("Rule set with id fake-id was not found");
}
/** Check we get a 404 if trying to update a rule that doesn't exist. */
@@ -122,7 +139,7 @@ public class UpdateRulesTests extends RestTest
STEP("Try to update a rule that doesn't exist.");
RestRuleModel updatedRuleModel = new RestRuleModel();
updatedRuleModel.setName("Updated rule name");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule("fake-id", updatedRuleModel);
restClient.assertLastError().statusCodeIs(NOT_FOUND)
@@ -143,7 +160,7 @@ public class UpdateRulesTests extends RestTest
dataUser.addUserToSite(collaborator, privateSite, SiteCollaborator);
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("ruleName");
restClient.authenticateUser(user).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.authenticateUser(user).withPrivateAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
restClient.assertStatusCodeIs(FORBIDDEN);
restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
@@ -156,9 +173,8 @@ 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("");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().updateRule(rule.getId(), updatedRuleModel);
RestRuleModel updatedRuleModel = rulesUtils.createRuleModel("");
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().updateRule(rule.getId(), updatedRuleModel);
restClient.assertLastError().statusCodeIs(BAD_REQUEST)
.containsSummary("Rule name is a mandatory parameter");
@@ -171,17 +187,378 @@ public class UpdateRulesTests extends RestTest
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule id and check it isn't changed.");
RestRuleModel updatedRuleModel = createRuleModel("Rule name");
RestRuleModel updatedRuleModel = rulesUtils.createRuleModel("Rule name");
updatedRuleModel.setId("new-rule-id");
RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), updatedRuleModel);
updatedRule.assertThat().field("id").is(rule.getId());
updatedRule.assertThat().field(ID).is(rule.getId());
}
/** Check we can update a rule and get the included fields. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleWithIncludedFields()
{
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule.");
RestRuleModel updatedRuleModel = rulesUtils.createRuleModel("Updated rule name");
RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.include(IS_SHARED)
.updateRule(rule.getId(), updatedRuleModel);
updatedRule.assertThat().field(IS_SHARED).isNotNull();
}
/**
* Check we get error when attempt to update a rule to one without any actions.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void updateRuleWithoutActionsShouldFail()
{
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule - set no actions.");
rule.setActions(null);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.include(IS_SHARED)
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("A rule must have at least one action");
}
/**
* Check we get error when attempt to update a rule to one with invalid action.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void updateRuleWithInvalidActionDefinitionShouldFail()
{
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule - set no actions.");
final RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
final String actionDefinitionId = "invalid-definition-value";
invalidAction.setActionDefinitionId(actionDefinitionId);
invalidAction.setParams(Map.of("dummy-key", "dummy-value"));
rule.setActions(List.of(invalidAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.include(IS_SHARED)
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary(String.format("Invalid action definition requested %s", actionDefinitionId));
}
/** Check we can use the POST response to create the new rule. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateCopyRuleWithResponseFromPOST()
{
FolderModel destination = dataContent.usingUser(user).usingSite(site).createFolder();
RestActionBodyExecTemplateModel copyAction = new RestActionBodyExecTemplateModel();
copyAction.setActionDefinitionId("copy");
copyAction.setParams(ImmutableMap.of("destination-folder", destination.getNodeRef()));
RestRuleModel rule = createAndSaveRule("Rule name", List.of(copyAction));
STEP("Try to update the rule.");
rule.setName("Updated rule name");
RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.include(IS_SHARED)
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().field("name").is("Updated rule name")
.assertThat().field("actions.actionDefinitionId").is(List.of("copy"))
.assertThat().field("actions.params").is(List.of(ImmutableMap.of("destination-folder", destination.getNodeRef())));
}
/** Check we can use the POST response and update rule fields. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleFields()
{
final RestRuleModel rule = createAndSaveRule(rulesUtils.createRuleModelWithModifiedValues());
STEP("Try to update the rule fields.");
rule.setName("Updated rule name");
rule.setTriggers(List.of(INBOUND));
final String updatedDescription = "Updated description";
rule.setDescription(updatedDescription);
rule.setIsEnabled(!RULE_ENABLED_DEFAULT);
rule.setIsInheritable(!RULE_CASCADE_DEFAULT);
rule.setIsAsynchronous(!RULE_ASYNC_DEFAULT);
rule.setErrorScript(null);
final RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().isEqualTo(rule, ID)
.assertThat().field(ID).isNotNull();
}
/** Check we can use the POST response and update rule by adding conditions. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleAddConditions()
{
final RestRuleModel rule = createAndSaveRule(rulesUtils.createRuleModelWithModifiedValues());
STEP("Try to update the rule and add conditions.");
rule.setConditions(rulesUtils.createVariousConditions());
final RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().isEqualTo(rule, ID)
.assertThat().field(ID).isNotNull();
}
/** Check we can use the POST response and update a rule rule without any conditions by adding null conditions. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleAddNullConditions()
{
final RestRuleModel rule = createAndSaveRule(rulesUtils.createRuleModelWithModifiedValues());
STEP("Try to update the rule and add null conditions.");
rule.setConditions(null);
final RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().isEqualTo(rule, ID)
.assertThat().field(ID).isNotNull();
}
/** Check we can use the POST response and update rule by modifying conditions. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleModifyConditions()
{
final RestRuleModel ruleModelWithInitialValues = rulesUtils.createRuleModelWithModifiedValues();
ruleModelWithInitialValues.setConditions(rulesUtils.createVariousConditions());
final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues);
STEP("Try to update the rule and modify conditions.");
final RestCompositeConditionDefinitionModel compositeCondition = rulesUtils.createCompositeCondition(
List.of(rulesUtils.createCompositeCondition(false, List.of(rulesUtils.createSimpleCondition("tag", "equals", "sample_tag")))));
rule.setConditions(compositeCondition);
final RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().isEqualTo(rule, ID)
.assertThat().field(ID).isNotNull();
}
/** Check we can use the POST response and update rule by removing all conditions. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleRemoveAllConditions()
{
final RestRuleModel ruleModelWithInitialValues = rulesUtils.createRuleModelWithModifiedValues();
ruleModelWithInitialValues.setConditions(rulesUtils.createVariousConditions());
final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues);
STEP("Try to update the rule and remove all conditions.");
rule.setConditions(null);
final RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().isEqualTo(rule, ID)
.assertThat().field(ID).isNotNull();
}
/** Check we get a 400 error when using the POST response and update rule by adding condition with invalid category. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleWithInvalidCategoryInConditionAndFail()
{
final RestRuleModel ruleModelWithInitialValues = rulesUtils.createRuleModelWithModifiedValues();
ruleModelWithInitialValues.setConditions(rulesUtils.createVariousConditions());
final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues);
STEP("Try to update the rule with invalid condition.");
final RestCompositeConditionDefinitionModel conditions = rulesUtils.createCompositeCondition(
List.of(rulesUtils.createCompositeCondition(!INVERTED, List.of(rulesUtils.createSimpleCondition("category", "equals", "fake-category-id")))));
rule.setConditions(conditions);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Category in condition is invalid");
}
/** Check we get a 400 error when using the POST response and update rule by adding condition without comparator when it is required. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleWithConditionWithoutComparatorAndFail()
{
final RestRuleModel ruleModelWithInitialValues = rulesUtils.createRuleModelWithModifiedValues();
ruleModelWithInitialValues.setConditions(rulesUtils.createVariousConditions());
final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues);
STEP("Try to update the rule with invalid condition (null comparator when required non-null).");
final RestCompositeConditionDefinitionModel conditions = rulesUtils.createCompositeCondition(
List.of(rulesUtils.createCompositeCondition(!INVERTED, List.of(rulesUtils.createSimpleCondition("size", null, "65500")))));
rule.setConditions(conditions);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Comparator in condition must not be blank");
}
/** Check we get a 400 error when using the POST response and update rule by adding condition without field. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleWithConditionWithoutFieldAndFail()
{
final RestRuleModel ruleModelWithInitialValues = rulesUtils.createRuleModelWithModifiedValues();
ruleModelWithInitialValues.setConditions(rulesUtils.createVariousConditions());
final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues);
STEP("Try to update the rule with invalid condition (null field).");
final RestCompositeConditionDefinitionModel conditions = rulesUtils.createCompositeCondition(
List.of(rulesUtils.createCompositeCondition(!INVERTED, List.of(rulesUtils.createSimpleCondition(null, "greater_than", "65500")))));
rule.setConditions(conditions);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Field in condition must not be blank");
}
/** Check we get a 400 error when using the POST response and update rule by adding condition without parameter value. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void updateRuleWithConditionWithoutParamValueAndFail()
{
final RestRuleModel ruleModelWithInitialValues = rulesUtils.createRuleModelWithModifiedValues();
ruleModelWithInitialValues.setConditions(rulesUtils.createVariousConditions());
final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues);
STEP("Try to update the rule with invalid condition (null parameter).");
final RestCompositeConditionDefinitionModel conditions = rulesUtils.createCompositeCondition(
List.of(rulesUtils.createCompositeCondition(!INVERTED, List.of(rulesUtils.createSimpleCondition("size", "greater_than", "")))));
rule.setConditions(conditions);
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Parameter in condition must not be blank");
}
/**
* Check we can update a rule by adding several actions.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void updateRuleAddActions()
{
final RestRuleModel rule = createAndSaveRule(rulesUtils.createRuleModelWithModifiedValues());
STEP("Try to update the rule by adding several actions");
final Map<String, Serializable> copyParams =
Map.of("destination-folder", rulesUtils.getCopyDestinationFolder().getNodeRef(), "deep-copy", true);
final RestActionBodyExecTemplateModel copyAction = rulesUtils.createCustomActionModel("copy", copyParams);
final Map<String, Serializable> addAspectParams = Map.of("aspect-name", "cm:taggable");
final RestActionBodyExecTemplateModel addAspectAction = rulesUtils.createCustomActionModel("add-features", addAspectParams);
rule.setActions(Arrays.asList(copyAction, addAspectAction));
final RestRuleModel updatedRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().isEqualTo(rule, ID)
.assertThat().field(ID).isNotNull();
}
/**
* Check we get a 400 error when attempting to update a rule by adding action with not allowed parameter.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void updateRuleAddCheckoutActionForOutboundShouldFail()
{
final RestRuleModel rule = createAndSaveRule(rulesUtils.createRuleModelWithModifiedValues());
STEP("Try to update the rule by adding checkout action");
final Map<String, Serializable> checkOutParams =
Map.of("destination-folder", rulesUtils.getCheckOutDestinationFolder().getNodeRef(), "assoc-name", "cm:checkout",
"assoc-type", "cm:contains");
final RestActionBodyExecTemplateModel checkOutAction = rulesUtils.createCustomActionModel("check-out", checkOutParams);
rule.setActions(List.of(checkOutAction));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary("Check out action cannot be performed for the rule type outbound!");
}
/**
* Check we get a 500 error when attempting to update a rule by adding action with parameter with non existing namespace in value.
* In near future we need to fix this kind of negative path to return a 4xx error.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void updateRuleAddActionWithInvalidParamShouldFail()
{
final RestRuleModel rule = createAndSaveRule(rulesUtils.createRuleModelWithModifiedValues());
STEP("Try to update the rule by adding action with invalid parameter (non-existing namespace in value)");
final RestActionBodyExecTemplateModel action = new RestActionBodyExecTemplateModel();
action.setActionDefinitionId("add-features");
final String aspectNameParam = "aspect-name";
final String paramValue = "dummy:dummy";
action.setParams(Map.of(aspectNameParam, paramValue));
rule.setActions(List.of(action));
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(BAD_REQUEST);
restClient.assertLastError().containsSummary(
String.format("Action parameter: %s has invalid value (%s). Look up possible values for constraint name %s",
aspectNameParam, paramValue, "ac-aspects"));
}
/** Check that a normal user cannot create rules that use private actions. */
@Test
public void updateRuleWithActions_userCannotUsePrivateAction()
{
STEP("Using admin create a rule with a private action.");
RestRuleModel rule = restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createRuleWithPrivateAction());
STEP("Try to update the rule with a normal user.");
rule.setName("Updated name");
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(FORBIDDEN)
.assertLastError().containsSummary(ERROR_MESSAGE_ACCESS_RESTRICTED);
}
/** Check that an administrator can create rules that use private actions. */
@Test
public void updateRuleWithActions_adminCanUsePrivateAction()
{
STEP("Using admin create a rule with a private action.");
RestRuleModel rule = restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(rulesUtils.createRuleWithPrivateAction());
STEP("Try to update the rule with the admin user.");
rule.setName("Updated name");
RestRuleModel updatedRule = restClient.authenticateUser(dataUser.getAdminUser()).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), rule);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().field("name").is("Updated name");
}
private RestRuleModel createAndSaveRule(String name)
{
return createAndSaveRule(name, List.of(createActionModel()));
return createAndSaveRule(name, List.of(rulesUtils.createAddAudioAspectAction()));
}
/**
@@ -194,8 +571,21 @@ public class UpdateRulesTests extends RestTest
private RestRuleModel createAndSaveRule(String name, List<RestActionBodyExecTemplateModel> restActionModels)
{
STEP("Create a rule called " + name + ", containing actions: " + restActionModels);
RestRuleModel ruleModel = createRuleModel(name, restActionModels);
return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
RestRuleModel ruleModel = rulesUtils.createRuleModel(name, restActionModels);
return restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
}
/**
* Create a rule for folder and store it.
*
* @param ruleModel RuleModel used as create request
* @return The created rule.
*/
private RestRuleModel createAndSaveRule(final RestRuleModel ruleModel)
{
STEP("Create a rule: " + ruleModel);
return restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
}
}

View File

@@ -35,10 +35,11 @@ public class GetDeploymentsSanityTests extends RestTest
restClient.assertStatusCodeIs(HttpStatus.OK);
deployments.assertThat().entriesListIsNotEmpty();
deployments.getOneRandomEntry().onModel().assertThat()
.fieldsCount().is(3).and()
.fieldsCount().is(4).and()
.field("id").isNotEmpty().and()
.field("deployedAt").isNotEmpty().and()
.field("name").isNotEmpty();
.field("name").isNotEmpty().and()
.field("category").isNotEmpty();
}
}

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>17.78</version>
<version>17.169</version>
</parent>
<properties>

View File

@@ -139,6 +139,33 @@
<param name="cookie">{token}</param>
</action>
</rule>
<rule>
<request>
<method>GET</method>
<path>/s/index|/s/</path>
</request>
<action name="generateToken">
<param name="session">{token}</param>
<param name="cookie">{token}</param>
</action>
</rule>
<rule>
<request>
<method>POST</method>
<path>/s/index|/s/</path>
</request>
<action name="assertToken">
<param name="session">{token}</param>
<param name="parameter">{token}</param>
</action>
<action name="assertReferer">
<param name="referer">{referer}</param>
</action>
<action name="assertOrigin">
<param name="origin">{origin}</param>
</action>
</rule>
<!--
Verify multipart requests contain the token as a parameter

View File

@@ -231,6 +231,12 @@
<url-pattern>/wcs/admin/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CSRF Token Filter</filter-name>
<url-pattern>/s/index</url-pattern>
<url-pattern>/s/</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Security Headers Filter</filter-name>
<url-pattern>/*</url-pattern>

93
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.78</version>
<version>17.169</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -45,24 +45,23 @@
<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>2.0.0-A5</dependency.alfresco-transform-service.version>
<dependency.alfresco-transform-core.version>3.0.0-A6</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>
<dependency.spring.version>5.3.22</dependency.spring.version>
<dependency.antlr.version>3.5.2</dependency.antlr.version>
<dependency.jackson.version>2.13.3</dependency.jackson.version>
<dependency.jackson-databind.version>2.13.3</dependency.jackson-databind.version>
<dependency.spring.version>5.3.23</dependency.spring.version>
<dependency.antlr.version>3.5.3</dependency.antlr.version>
<dependency.jackson.version>2.14.0-rc1</dependency.jackson.version>
<dependency.cxf.version>3.5.3</dependency.cxf.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.webscripts.version>8.31</dependency.webscripts.version>
<dependency.webscripts.version>8.32</dependency.webscripts.version>
<dependency.bouncycastle.version>1.70</dependency.bouncycastle.version>
<dependency.mockito-core.version>4.6.1</dependency.mockito-core.version>
<dependency.assertj.version>3.23.1</dependency.assertj.version>
@@ -74,17 +73,20 @@
<dependency.httpcore.version>4.4.15</dependency.httpcore.version>
<dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version>
<dependency.xercesImpl.version>2.12.2</dependency.xercesImpl.version>
<dependency.slf4j.version>1.7.35</dependency.slf4j.version>
<dependency.gytheio.version>0.16</dependency.gytheio.version>
<dependency.slf4j.version>2.0.1</dependency.slf4j.version>
<dependency.gytheio.version>0.17</dependency.gytheio.version>
<dependency.groovy.version>3.0.12</dependency.groovy.version>
<dependency.tika.version>2.4.1</dependency.tika.version>
<dependency.spring-security.version>5.7.2</dependency.spring-security.version>
<dependency.spring-security.version>5.7.3</dependency.spring-security.version>
<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.poi-ooxml-lite.version>5.2.3</dependency.poi-ooxml-lite.version>
<dependency.keycloak.version>18.0.0</dependency.keycloak.version>
<dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
<dependency.camel.version>3.15.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies (can cause dependency conflicts)-->
<dependency.camel.version>3.18.2</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
<dependency.netty.version>4.1.79.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
<dependency.netty.qpid.version>4.1.72.Final</dependency.netty.qpid.version> <!-- must be in sync with camels transitive dependencies: native-unix-common/native-epoll/native-kqueue -->
<dependency.netty-tcnative.version>2.0.53.Final</dependency.netty-tcnative.version> <!-- must be in sync with camels transitive dependencies -->
<dependency.activemq.version>5.17.1</dependency.activemq.version>
<dependency.apache-compress.version>1.21</dependency.apache-compress.version>
<dependency.apache.taglibs.version>1.2.5</dependency.apache.taglibs.version>
@@ -107,24 +109,23 @@
<dependency.jakarta-json-path.version>2.7.0</dependency.jakarta-json-path.version>
<dependency.jakarta-rpc-api.version>1.1.4</dependency.jakarta-rpc-api.version>
<alfresco.googledrive.version>3.2.2</alfresco.googledrive.version>
<alfresco.aos-module.version>1.4.1</alfresco.aos-module.version>
<alfresco.api-explorer.version>7.2.1</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
<alfresco.googledrive.version>3.3.0-A1</alfresco.googledrive.version>
<alfresco.aos-module.version>1.4.1</alfresco.aos-module.version>
<alfresco.api-explorer.version>7.3.0-A1</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
<alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version>
<license-maven-plugin.version>2.0.1.alfresco-2</license-maven-plugin.version>
<dependency.postgresql.version>42.4.1</dependency.postgresql.version>
<dependency.postgresql.version>42.5.0</dependency.postgresql.version>
<dependency.mysql.version>8.0.30</dependency.mysql.version>
<dependency.mysql-image.version>8</dependency.mysql-image.version>
<dependency.mariadb.version>2.7.4</dependency.mariadb.version>
<dependency.tas-utility.version>3.0.49</dependency.tas-utility.version>
<dependency.rest-assured.version>3.3.0</dependency.rest-assured.version>
<dependency.tas-restapi.version>1.102</dependency.tas-restapi.version>
<dependency.tas-cmis.version>1.31</dependency.tas-cmis.version>
<dependency.tas-email.version>1.8</dependency.tas-email.version>
<dependency.tas-webdav.version>1.6</dependency.tas-webdav.version>
<dependency.tas-ftp.version>1.5</dependency.tas-ftp.version>
<dependency.tas-utility.version>3.0.56</dependency.tas-utility.version>
<dependency.rest-assured.version>5.2.0</dependency.rest-assured.version>
<dependency.tas-restapi.version>1.135</dependency.tas-restapi.version>
<dependency.tas-email.version>1.9</dependency.tas-email.version>
<dependency.tas-webdav.version>1.7</dependency.tas-webdav.version>
<dependency.tas-ftp.version>1.7</dependency.tas-ftp.version>
<dependency.tas-dataprep.version>2.6</dependency.tas-dataprep.version>
<!-- AGS properties shared between community and enterprise -->
@@ -148,7 +149,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.78</tag>
<tag>17.169</tag>
</scm>
<distributionManagement>
@@ -405,7 +406,7 @@
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>5.1.0</version>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
@@ -501,7 +502,7 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${dependency.jackson-databind.version}</version>
<version>${dependency.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
@@ -513,6 +514,11 @@
<artifactId>jackson-dataformat-yaml</artifactId>
<version>${dependency.jackson.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.32</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
@@ -616,6 +622,12 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
<version>${dependency.slf4j.version}</version>
<exclusions>
<exclusion>
<groupId>ch.qos.reload4j</groupId>
<artifactId>reload4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>xerces</groupId>
@@ -650,7 +662,7 @@
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.2</version>
<version>1.15.3</version>
</dependency>
<!-- upgrade dependency from TIKA -->
<dependency>
@@ -701,11 +713,6 @@
<artifactId>restapi</artifactId>
<version>${dependency.tas-restapi.version}</version>
</dependency>
<dependency>
<groupId>org.alfresco.tas</groupId>
<artifactId>cmis</artifactId>
<version>${dependency.tas-cmis.version}</version>
</dependency>
<dependency>
<groupId>org.alfresco.tas</groupId>
<artifactId>email</artifactId>
@@ -729,7 +736,7 @@
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.14</version>
<version>2.11.1</version>
</dependency>
<!-- provided dependencies -->
@@ -845,6 +852,18 @@
<artifactId>camel-mock</artifactId>
<version>${dependency.camel.version}</version>
</dependency>
<!-- Netty non-transitive dependencies declared for depending projects usage in conjunction with Camel's other transitive netty dependencies -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler-proxy</artifactId>
<version>${dependency.netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-classes</artifactId>
<version>${dependency.netty-tcnative.version}</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-spec</artifactId>
@@ -926,7 +945,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.0</version>
<version>3.4.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.78</version>
<version>17.169</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

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* 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
@@ -36,7 +36,7 @@ import org.alfresco.repo.content.metadata.MetadataExtracter;
import org.alfresco.repo.content.metadata.MetadataExtracterRegistry;
import org.alfresco.repo.content.transform.LocalTransformServiceRegistry;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.transform.client.registry.TransformServiceRegistry;
import org.alfresco.transform.registry.TransformServiceRegistry;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;

View File

@@ -78,7 +78,7 @@ public abstract class AbstractRuleWebScript extends DeclarativeWebScript
private static final String RULE_OUTBOUND = "outbound";
private static final String ACTION_CHECK_OUT = "check-out";
private static final String CANNOT_CREATE_RULE = "cannot.create.rule.checkout.outbound";
public static final String CANNOT_CREATE_RULE = "cannot.create.rule.checkout.outbound";
protected NodeService nodeService;
protected RuleService ruleService;

View File

@@ -121,6 +121,13 @@ public class WebDAVServlet extends HttpServlet
startTime = System.currentTimeMillis();
}
if (request.getMethod().equals(WebDAV.METHOD_POST) && !initParams.allowInsecurePOSTMethod())
{
logger.error("POST method is not allowed!");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
return;
}
FileFilterMode.setClient(Client.webdav);
try
@@ -407,6 +414,7 @@ public class WebDAVServlet extends HttpServlet
private String storeName;
private String rootPath;
private String urlPathPrefix;
private boolean allowInsecurePOSTMethod = false;
public boolean getEnabled()
{
@@ -482,5 +490,15 @@ public class WebDAVServlet extends HttpServlet
{
this.urlPathPrefix = urlPathPrefix;
}
public boolean allowInsecurePOSTMethod()
{
return allowInsecurePOSTMethod;
}
public void setAllowInsecurePOSTMethod(boolean allowInsecurePOSTMethod)
{
this.allowInsecurePOSTMethod = allowInsecurePOSTMethod;
}
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2018 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
@@ -29,8 +29,10 @@ package org.alfresco.rest.api;
import org.alfresco.rest.api.model.Action;
import org.alfresco.rest.api.model.ActionDefinition;
import org.alfresco.rest.api.model.ActionParameterConstraint;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
public interface Actions
@@ -45,7 +47,10 @@ public interface Actions
{
NAME,
TITLE
};
}
Action executeAction(Action action, Parameters parameters);
@Experimental
ActionParameterConstraint getActionConstraint(String constraintName);
}

View File

@@ -27,8 +27,8 @@ package org.alfresco.rest.api;
import java.util.List;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.rest.api.model.rules.RuleSetLink;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
@@ -58,4 +58,24 @@ public interface RuleSets
* @return {@link RuleSet} definition
*/
RuleSet getRuleSetById(String folderNodeId, String ruleSetId, List<String> includes);
/**
* Update a rule set - for example to reorder the rules within it.
*
* @param folderNodeId Folder node ID
* @param ruleSet The updated rule set.
* @param includes List of fields to include in the response.
* @return The updated rule set from the server.
*/
RuleSet updateRuleSet(String folderNodeId, RuleSet ruleSet, List<String> includes);
/**
* Link a rule set to a folder
*/
RuleSetLink linkToRuleSet(String folderNodeId, String linkToNodeId);
/**
* Removes the link between a rule set and a folder
*/
void unlinkRuleSet(String folderNodeId, String ruleSetId);
}

View File

@@ -0,0 +1,54 @@
/*
* #%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.api;
import org.alfresco.rest.api.model.rules.RuleSetting;
import org.alfresco.service.Experimental;
/**
* Rule settings API.
*/
@Experimental
public interface RuleSettings
{
/**
* Get the rule setting with the given key.
*
* @param folderId Folder node ID
* @param ruleSettingKey Rule setting key
* @return {@link RuleSetting} The retrieved rule setting object.
*/
RuleSetting getRuleSetting(String folderId, String ruleSettingKey);
/**
* Set the rule setting against the specified folder.
*
* @param folderId The folder to update.
* @param ruleSetting The new rule setting.
* @return The updated rule setting object.
*/
RuleSetting setRuleSetting(String folderId, RuleSetting ruleSetting);
}

Some files were not shown because too many files have changed in this diff Show More